gogogo路径穿越
课堂测试题
解题过程
使用Gemini辅助分析和写脚本
源码分析
从dockerfile可以判断flag所在路径。所以我们的目标是/flag
1 | COPY ./files/flag /flag |
login.php有个简单的密码逻辑$password == md5($auth_code.$username),可以构造账号密码绕过
1 | if($username && $password){ |
skin.php负责读取并输出主题文件内容。核心逻辑是先解码,然后判断路径是否合法,通过后实际读取
1 | $themeRef = decode_theme_ticket($theme); |
decode_theme_ticket会对每个字符减一
1 | function decode_theme_ticket($value) { |
is_theme_reference_allowed函数校验preview_theme_asset得到的文件路径是否合法,包含路径是否以assets/css/开头和是否包含 .. 或 \两种检查
1 | function is_theme_reference_allowed($ref) { |
preview_theme_asset是只包含一次rawurldecode的,但是runtime_theme_asset实际读取时包含两次rawurldecode,这样就有可能利用两次的解码不一致绕过检查
rawurldecode是 PHP 中用于对 URL 编码字符串进行解码的函数。它将字符串中的%xx(十六进制序列)转换回原字符。
1 | function preview_theme_asset($ref) { |
解题思路
我们可以构造一个路径穿越,目标是/flag,起点需要符合assets/css/检查
skin.php源路径是/files/html,结合dockerfile中的
1 | COPY ./files/html/ /var/www/html/ |
可以判断目标路径是/var/www/html/,所以起点的完整路径是/var/www/html/assets/css/,从这个路径到/flag需要穿五层,所以构造的目标路径应该是:
1 | assets/css/../../../../../flag |
然后对其中的..进行两次编码,就能绕过has_parent_marker的检查。最后逆向decode_theme_ticket,需要给每个字符加一
另外编码后的url包含特殊字符,所以还要进行一次url编码(或者用curl)
解密脚本:
1 | import urllib.parse |
运行得到
1 | bttfut0dtt0%26363f%26363f0%26363f%26363f0%26363f%26363f0%26363f%26363f0%26363f%26363f0gmbh |
作为skin.php的参数提交:
1 | http://124.16.75.116:52001/skin.php?theme=bttfut0dtt0%26363f%26363f0%26363f%26363f0%26363f%26363f0%26363f%26363f0%26363f%26363f0gmbh |
得到flag

1 | flag{path_traversal_1s_s0_d4ng3r0us} |
技术点总结
路径遍历:路径遍历是一种利用 Web 应用对文件路径过滤不严的漏洞,通过输入特殊的路径序列(如
../)来访问 Web 根目录之外的文件。其技术原理是操作系统识别路径中的..为“返回上级目录”。如果程序在拼接文件路径时未能进行有效的检查和过滤,攻击者就能通过路径遍历访问设定的权限外的内容。URL 二次编码绕过:URL 编码通过
%加十六进制数来表示特殊字符。二次编码是指将%字符本身再次进行编码(例如.变为%2e,再变为%252e)。如果程序在校验和实际使用时对url编码的处理不一致,就可能通过二次编码绕过校验。