dvwa-command injection 代码审计
low
<?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>";
}
?>
isset( $_POST[ 'Submit' ]
此代码判断接受的post参数是否为空
$target = $_REQUEST[ 'ip' ];
request方式接受ip参数
stristr( php_uname( 's' ), 'Windows NT'
此参数为真时,执行ping命令(意为在windows系统中执行ping命令)
否则执行ping命令4次(意为在unix或linux中执行ping4次)
其中的stristr函数如下
stristr()函数在PHP中用于在字符串中查找子字符串,并返回第一个匹配的子字符串及其后面的部分,而且不区分大小写
示例
$str = "Hello, World!"; $substring = "world"; $result = stristr($str, $substring); echo $result; // 输出 "World!"
php_uname()函数如下,此代码中即为查看系统信息是否为Windows NT
在PHP中,php_uname()函数用于获取操作系统的信息。该函数返回一个包含系统信息的字符串,包括操作系统名称、主机名、内核版本、发布版本等
- “a”:默认值,返回所有系统信息
- “s”:返回操作系统名称
- “n”:返回主机名
- “r”:返回内核版本
- “v”:返回发布版本
- “m”:返回机器类型
最后则返回执行结果
medium
<?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>";
}
?>
该级别代码几乎和low一致,仅添加两个过滤
关键代码部分
$substitutions = array( '&&' => '', ';' => '', );
此代码为使用array函数快速定义一个数组,并将其值赋给substitutions
$target = str_replace( array_keys( $substitutions ), $substitutions, $target );
array_keys( $substitutions )
该函数为获取变量中的 键 即key
<?php $substitutions = array( '&&' => '', ';' => '', ); var_dump($substitutions); print("<br/>"); $a=array_keys($substitutions); var_dump($a); ?>
输出结果
然后使用srt_replace()函数进行字符串替换
该函数如下
str_replace()函数用于在字符串中替换指定的子字符串。它可以用于执行简单的字符串替换操作,例如将一个子字符串替换为另一个子字符串
str_replace (mixed $search , mixed $replace , mixed $subject [, int &$count ]) : mixed
search是要搜索的字符串或字符串数组,replace是要替换为的字符串或字符串数组,subject是被搜索的原始字符串,count是一个可选参数,用于存储替换操作的次数
示例
$string = "Hello, World!"; $new_string = str_replace("World", "PHP", $string); echo $new_string;
输出结果即为 Hello, PHP!
此处即,搜索输入的target的值,将其中substitutions数组中的键替换成substitutions变量中该键所对应的值,从而达成将输入的&&
或者;
进行置空过滤
high
<?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>";
}
?>
相较上一关,该难度差别在如下代码
$target = trim($_REQUEST[ 'ip' ]);
// Set blacklist
$substitutions = array(
'&' => '',
';' => '',
'| ' => '',
'-' => '',
'$' => '',
'(' => '',
')' => '',
'`' => '',
'||' => '',
);
增加了过滤项,但是原理不变
除此之外添加了trim()处理输入的内容
trim()函数用于删除字符串开头和结尾处的空白字符(空格、制表符、换行符等)或者其它指定字符
string trim ( string $str [, string $character_mask = " \t\n\r\0\x0B" ] )
str是要处理的字符串,character_mask是一个可选参数,用于指定要删除的字符。如果不指定$character_mask参数,默认会删除空格、制表符、换行符、回车符、空字符和垂直制表符
示例
$str = " Hello, World! "; $new_str = trim($str); echo $new_str;
输出结果为 Hello, World!
impossible
<?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();
?>
checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );
将三个参数传递给checktoken函数,checktoken函数一般用于验证匹配用户token和用户session是否匹配,如不匹配则跳转到index.php
$_REQUEST[ 'user_token' ]
:这是一个 PHP 超全局数组,用于获取 HTTP 请求中的参数。在这里,$_REQUEST['user_token']
用于获取名为user_token
的参数的值。
$_SESSION['session_token']
:这是 PHP 的会话(Session)变量,用于在用户会话之间存储数据。在这里,$_SESSION['session_token']
用于获取名为session_token
的会话变量的值
index.php
:这是一个字符串,表示一个重定向页面的 URL。如果checkToken
函数判断验证失败,用户将被重定向到这个页面
$target = stripslashes( $target );
该行代码为过滤输出内容
stripslashes()
函数用于去除由addslashes()
函数添加的反斜杠。在 PHP 中,addslashes()
用于在特定字符前添加反斜杠,以防止 SQL 注入和其他安全漏洞。而stripslashes()
则用于将这些反斜杠去除,恢复原始的字符串
$octet = explode( ".", $target );
该行explode函数通过 点 将输入的内容分段,被分割的部分会以数组的形式存储在变量中
if( ( is_numeric( $octet[0] ) ) && ( is_numeric( $octet[1] ) ) && ( is_numeric( $octet[2] ) ) && ( is_numeric( $octet[3] ) ) && ( sizeof( $octet ) == 4 ) ) {
该行代码使用is_numeric函数判断该分割后的数组中的每个元素是否为数字,当全部都为数字时判断为真,才会向下执行,is_numric函数会将十六进制也视为数字,可以考虑将代码编程16进制,但是由于有分段组合成ip的这一步,所以该方法也不能实现
$target = $octet[0] . '.' . $octet[1] . '.' . $octet[2] . '.' . $octet[3];
重新将该数组拼接,然后剩下的代码就与之前一样了
可以说是限制了所有字符和字母
numeric( $octet[3] ) ) && ( sizeof( $octet ) == 4 ) ) {`该行代码使用is_numeric函数判断该分割后的数组中的每个元素是否为数字,当全部都为数字时判断为真,才会向下执行,is_numric函数会将十六进制也视为数字,可以考虑将代码编程16进制,但是由于有分段组合成ip的这一步,所以该方法也不能实现
$target = $octet[0] . '.' . $octet[1] . '.' . $octet[2] . '.' . $octet[3];
重新将该数组拼接,然后剩下的代码就与之前一样了
可以说是限制了所有字符和字母