php审计初探:dvwa之命令注入
Low
代码:
<?phpif( 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()
stristr()
php_uname()
shell_exec()
代码分析:
- 是否点击submit提交按钮。
- 服务器通过GPC方式获取了一个IP地址,赋值给变量$target。
- 使用php_name(‘s’)获取到主机名,并通过stristr函数判断是windows系统还是*nix系统
- 根据不同的主机名拼接不同的ping命令(linux系统需要限制ping的次数,否则会一直ping)。
- 由shell_exec() 运行拼接后的命令。
- 当web用户点击submit时,服务器执行了1条命令。
- 一个字符串是否可以执行多条命令呢?
GPC
(Get/Post/Cookie)通常指的是一种获取网页表单数据的方法,是 PHP 中一种非常常用的编程技巧。GPC 方法包括 GET、POST 和 COOKIE,它们各自有不同的用途和特点。
- GET:GET 方法通过 URL 将数据传送到服务器,在URL地址栏中可以看到这些参数及其值。由于GET 方法只能传输少量数据(大约 2KB 左右),且数据不安全,所以不适合传递敏感信息。
- POST:POST 方法将数据封装在 HTTP 请求体中,因此不会出现在 URL 地址栏中,而且传输的数据量较大(理论上不受限制),适合传输大量数据和敏感信息。
- COOKIE:COOKIE 是存储在客户端的一小段数据,可以在多个页面间共享数据。它可以保存用户的个人信息和偏好设置,还可以用于实现身份验证等功能。 在实际编程中,可以综合运用这三种方法,根据需求和安全性要求灵活使用。
漏洞利用:
127.0.0.1&whoami127.0.0.1&&whoami127.0.0.1|whoami127.0.0.1.1||whoami
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>";
}
?>
涉及函数:
isset()
str_replace()
array_keys()
stristr()
php_uname()
shell_exec()
代码分析:
- 是否点击submit提交按钮。
- 服务器通过GPC方式获取了一个IP地址,赋值给变量$target。
- 定义了一个数组$substitutions,存储了黑名单
&&
和;
。- 使用函数array_keys获取数组 s u b s t i t u t i o n s 的键值,然后使用函数 s t r r e p l a c e 将其替换成空,并最后重新赋值给 substitutions的键值,然后使用函数str_replace将其替换成空,并最后重新赋值给 substitutions的键值,然后使用函数strreplace将其替换成空,并最后重新赋值给target。
- 使用php_name(‘s’)获取到主机名,并通过stristr函数判断是windows系统还是*nix系统
- 根据不同的主机名拼接不同的ping命令(linux系统需要限制ping的次数,否则会一直ping)。
- 由shell_exec() 运行拼接后的命令。
- 当web用户点击submit时,无法使用
&&
和;
拼接的多条命令语句- 寻找其他可以执行多条命令的语句
漏洞利用:
127.0.0.1&whoami127.0.0.1|whoami127.0.0.1.1||whoami
High
代码:
<?phpif( 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>";
}?>
涉及函数:
isset()
trim()
str_replace()
array_keys()
stristr()
shell_exec()
php_uname()
代码分析:
- 设置了黑名单,
&
,;
,|+空格
,-
,(
,)
,$
,||
,反引号
。- 漏掉了关键字符
|
漏洞利用:
127.0.0.1|whoami
Impossible
代码:
<?phpif( 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();?>
涉及函数:
isset()
stristr()
php_uname()
array_keys()
str_replace()
trim()
checkToken()
stripslashes()
explode()
is_numeric()
代码分析:
- 是否点击submit提交按钮。
- 服务器通过GPC方式获取了一个Token值校验token是否有效。
- 服务器通过GPC方式获取了一个ip并存储到变量$target中。
- 使用函数stripslashes过滤了下字符串中的反斜杠。
- 使用函数explode以字符’.'切割了字符串并组成一个数组赋值给变量 $octet
- 判断如果 o c t e t [ 0 ] 、 octet[0]、 octet[0]、octet[1]、 o c t e t [ 2 ] 、 octet[2]、 octet[2]、octet[3]都为数字并且, o c t e t 数组长度等于 4 时,拼接字符串赋值为 octet数组长度等于4时,拼接字符串赋值为 octet数组长度等于4时,拼接字符串赋值为target,否则输出“ERROR:
You have entered an invalid IP.”。- 使用php_name(‘s’)获取到主机名,并通过stristr函数判断是windows系统还是*nix系统
- 根据不同的主机名拼接不同的ping命令(linux系统需要限制ping的次数,否则会一直ping)。
- 由shell_exec() 运行拼接后的命令。
- 当web用户点击submit时,无法使用
&&
和;
拼接的多条命令语句- 寻找其他可以执行多条命令的语句
漏洞利用:
无
相关函数的作用及示例:
isset()
isset函数用于检测变量是否已经设置且不为空
<?php
$myVar = "Hello World";
if(isset($myVar)){
echo "$myVar is set.";
}else{
echo "$myVar is not set.";
}
//输出:Hello World is set.
?>
stristr()
注意:stristr函数是strstr函数的忽略大小写版本
<?php
$text = "Hello World";
$find = "World";
$result = stristr($text,$find);
echo $result;//输出:"World"
?>
php_uname()
php_uname()函数用于获取操作系统的信息,包括操作系统的名称、版本号、发布日期等。
例如:以下代码会输出服务器的主机名:
<?php
echo php_uname('n');//输入:WIN-37QPUN7NO81
?>
而以下代码则会输出更全面的系统信息:
<?php
print_r(php_uname());//输入:Windows NT WIN-37QPUN7NO81 6.2 build 9200 (Windows Server 2012 Standard Edition) i586
?>
php_uname 相关的其他参数
‘a’: 包含 ‘s’, ‘n’, ‘r’, ‘v’, ‘m’ 所有的模式.
‘s’: 操作系统名称。
‘n’: 主机名。
‘r’: 内核版本。
‘v’: 系统版本。
‘m’: 硬件平台。
‘p’: 进程器类型。
‘i’: 设备节点名。
‘c’: CPU 架构。
‘x’: 不同于 ‘i’ 的设备节点名。
‘O’: 发行版名称和版本号。
‘L’: Linux 标识符。
‘S’: 安全标识符。
‘M’: MAC 地址。
‘B’: BIOS 版本。
‘H’: Hardware 平台。
‘U’: 内部 Unicos 计划 ID ‘t’: 时间支持。
‘C’: 软件计数器。
‘D’: 定义域。
‘Z’: 额外的 z/OS 信息。
‘W’: Windows 注册表的 PHP 部分。
‘V’: php cgi-fcgi 版本信息
str_replace()
str_replace() 函数用于在字符串中替换指定的字符或字符串。
例如,假设有以下的 PHP 代码:
<?php
$str = "Hello World!";
$new_str = str_replace("World", "Universe", $str);
echo $new_str;
?>
上述代码将输出:
Hello Universe!
在这个例子中,str_replace() 函数将字符串 $str中的"World"替换为"Universe",并将替换后的结果存储在new_str 中。这对于在字符串中进行简单的替换操作非常有用。
array_keys
array_keys() 函数用于返回数组中所有的键名
例如,假设有以下的 PHP 代码:
<?php
$age = array("Peter"=>"35", "Ben"=>"37", "Joe"=>"43");
print_r(array_keys($age));
?>
上述代码将输出:
Array
(
[0] => Peter
[1] => Ben
[2] => Joe
)
shell_exec()
用于执行外部命令并返回输出。
<?php
$output = shell_exec('whoami');
echo "<pre>$output</pre>";//输出结果:win-37qpun7no81\administrator
?>
trim()
trim函数的作用是去除字符串两端的空格或其他指定字符。
例如:
$str = " hello world ";
echo trim($str); // 输出 "hello world"$str2 = "###hello world###";
echo trim($str2, "#"); // 输出 "hello world"
在第一个例子中,trim函数去除了字符串两端的空格,使得输出的字符串只包含"hello world"。
在第二个例子中,trim函数去除了字符串两端的"#“字符,使得输出的字符串只包含"hello world”。
checkToken()
用于检测用户的访问令牌是否有效。
<?php
// 定义checkToken()函数
function checkToken($token) {
// 假设$validToken是一个有效的访问令牌
$validToken = "abc123";
// 验证传入的令牌是否与有效令牌匹配
if ($token === $validToken) {
return true; // 令牌有效
} else {
return false; // 令牌无效
}
}
// 获取用户提交的访问令牌
$userToken = $_POST['token'];
// 调用checkToken()函数验证用户的访问令牌
if (checkToken($userToken)) {
echo "he access token is valid and allows the user to access the page";
} else {
echo "The access token is invalid and access is denied";
}
?>
token校验不通过:
token校验通过:
stripslashes()
stripslashes() 函数用于删除由 addslashes() 函数添加的反斜杠。
在某些情况下,需要对字符串进行转义,比如在将数据插入数据库之前。但是在从数据库中取出数据后,可能需要去除这些转义字符,这时就可以使用 stripslashes() 函数。
<?php
$str = "This is some text with a \"quoted\" word";
echo $str;
echo "<br>";// 添加转义字符
$str = addslashes($str);
echo $str;
echo "<br>";// 删除转义字符
$str = stripslashes($str);
echo $str;
?>
explode()
我们想要将这个字符串按照逗号分隔成一个数组,可以使用explode()函数来实现
<?php
$str = "apple,banana,orange";
$arr = explode(",", $str);
print_r($arr);
//输出结果:Array ( [0] => apple [1] => banana [2] => orange )
?>
is_numeric()
is_numeric()函数用于检查变量是否是一个数字或数字字符串。
以下是一个示例:
<?php
$num1 = 123;
$num2 = "456";
$str1 = "456abc";
$str2 = "abc";var_dump(is_numeric($num1)); // 输出: bool(true)
var_dump(is_numeric($num2)); // 输出: bool(true)
var_dump(is_numeric($str1)); // 输出: bool(false)
var_dump(is_numeric($str2)); // 输出: bool(false)
?>
我们想要将这个字符串按照逗号分隔成一个数组,可以使用explode()函数来实现
<?php
$str = "apple,banana,orange";
$arr = explode(",", $str);
print_r($arr);
//输出结果:Array ( [0] => apple [1] => banana [2] => orange )
?>
is_numeric()
is_numeric()函数用于检查变量是否是一个数字或数字字符串。
以下是一个示例:
<?php
$num1 = 123;
$num2 = "456";
$str1 = "456abc";
$str2 = "abc";var_dump(is_numeric($num1)); // 输出: bool(true)
var_dump(is_numeric($num2)); // 输出: bool(true)
var_dump(is_numeric($str1)); // 输出: bool(false)
var_dump(is_numeric($str2)); // 输出: bool(false)
?>
发表评论 取消回复