1、审计dvwa高难度命令执行漏洞的代码,编写实例说明如下函数的用法
第一部分
当 $_POST['Submit']
被调用时,变量 $target
将被设置为用户输入的 IP 地址。
if( isset( $_POST[ 'Submit' ] ) ) {
$target = trim($_REQUEST[ 'ip' ]);
第二部分
从用户输入中移除特殊字符,例如 '&'
、';'
、'|'
、'-'
、'$'
、 '('
、 ')'
、 和 '||'
。
$substitutions = array(
'&' => '',
';' => '',
'| ' => '',
'-' => '',
'$' => '',
'(' => '',
')' => '',
'`' => '',
'||' => '',
);
$target = str_replace( array_keys( $substitutions ), $substitutions, $target );
第三部分
这部分代码的作用是根据当前操作系统的类型,选择相应的命令进行网络测试。如果当前操作系统是 Windows,那么使用 ping
命令进行测试;否则,使用 ping -c 4
命令进行测试。其中,$target
是需要测试的目标主机的 IP 或域名。
if( stristr( php_uname( 's' ), 'Windows NT' ) ) {
// Windows
$cmd = shell_exec( 'ping ' . $target );
}
else {
// *nix
$cmd = shell_exec( 'ping -c 4 ' . $target );
}
第四部分
这部分代码的作用是将测试结果输出给用户。<pre>
标签用于显示预格式化文本,可以保留文本中的空格和换行符,使输出结果更清晰易读
// Feedback for the end user
echo "<pre>{$cmd}</pre>";
各部分的函数详解:
isset() //函数用于检测变量是否已设置并且非 NULL
trim() //去除字符串首尾处的空白字符(或者其他字符)
$substitutions() //是一个关联数组,它包含了一组需要被替换的字符串键值对。键是需要被替换的字符串,值是替换后的字符串
array_keys($substitutions) //函数会返回$substitutions数组中的所有键,也就是需要被替换的字符串组成的数组。
含义部分:
str_replace()函数会在$target字符串中查找$substitutions数组中的键,然后用对应的值进行替换。具体来说,str_replace( array_keys( $substitutions ), $substitutions, $target )这行代码的作用是将$target字符串中出现的$substitutions数组中的键,替换为对应的值。
举例说明:
str_replace( $search , $replace , $subject )
$search:需要被替换的字符串或字符数组。
$replace:用来替换的字符串或字符数组。
$subject:需要进行替换操作的字符串或字符串数组。
str_replace 函数会在 $subject 字符串中查找 $search,并用 $replace 进行替换。如果 $search 和 $replace 是数组,那么 str_replace 会对 $search 和 $replace 数组中的元素进行一一对应的替换。
stristr() //函数搜索字符串在另一字符串中的第一次出现。该函数是不区分大小写的。若进行区分大小写的搜索使用 strstr() 函数。
举例:
<?php
echo stristr("Hello world!","WORLD"); //查找 "world" 在 "Hello world!" 中的第一次出现,并返回字符串的剩余部分
?>
php_uname() 函数返回一个字符串,包含当前操作系统的相关信息,具体内容取决于参数的值。例如,如果参数为 "s",则返回当前操作系统的名称。
2、审计impossible难度的代码,说明其中函数的作用,不要求每个函数都演示
第一部分
if( isset( $_POST[ 'Submit' ] ) ) {
// Check Anti-CSRF token
checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' ); //在用户提交的请求中获取了一个名为 user_token 的令牌,然后与用户会话中的 session_token 进行比对,以确保请求的合法性。如果验证失败,可能会将用户重定向至 index.php 页面。这样做有助于保护网站免受 CSRF 攻击的威胁。
// Get input
$target = $_REQUEST[ 'ip' ];
$target = stripslashes( $target ); //去除 IP 地址中的反斜杠。
// Split the IP into 4 octects
$octet = explode( ".", $target ); // 这里用 '.' 将 IP 地址进行了分割。
第二部分
这段代码的含义是检查数组 $octet
中的前四个元素是否都是数字,并且数组的大小是否为 4。如果所有这些条件都满足,那么条件语句的结果将为真(true)。然后在下面使用"."再将每一部分的数组内容连接起来。用于验证一个 IP 地址是否符合 IPv4 地址的格式,因为 IPv4 地址由四块由点分隔的数字组成。
// 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];
第三部分
这部分和high级别一样,之前做过说明了,此处就不做解释
// 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() //作用是验证用户提交的令牌是否有效,以防止 CSRF(跨站请求伪造)攻击。
stripslashes() //函数用于移除字符串中的反斜杠(\)。它的作用是将转义过的字符还原为原始的字符形式
explode() //函数使用一个字符串分割另一个字符串,并返回由字符串组成的数组。
is_numeric() //函数用于检测变量是否为数字或数字字符串。
generateSessionToken() 是一个函数,用于生成一个随机的会话令牌(session token),通常用于在 Web 应用程序中保持用户会话的状态。
3、演示命令执行漏洞无回显如何渗透
这里构造了一个代码,呈现出一个命令执行漏洞的页面
<?php
if(isset($_GET['cmd'])){
$cmd=$_GET['cmd'];
`$cmd`;
}else{
echo"?cmd=whoami";
}
?>
当我们访问页面的时候,正常显示代码
从构造来看我们可以借助cmd这个参数来完成命令执行,但是当我们实验的时候,发现结果无法回显在页面上
这里为了证明命令执行漏洞存在,我们可以借助yakit工具实现
我们在yakit的dnslog模块中,新生成一个可用域名,然后我们使用刚刚的页面,对这个域名进行ping命令
ping命令执行后,我们回到yakit页面,点击刷新,发现就在刚刚这个时间点,有一个ip就ping了一下这个刚生成的域名,从侧面证实了命令执行漏洞的存在。
4、编写PHP代码,实现反序列化的时候魔法函数自动调用计算器
以下代码定义了一个简单的类 MyClass
,并对该类进行了序列化和反序列化的操作。在实例化对象时,传入的名称为 “Alice”,然后将对象序列化为字符串。接着,使用 unserialize()
函数将序列化的字符串转换回对象,并自动调用了 __wakeup()
方法。
<?php
class MyClass {
public $name;
public function __construct($name) {
$this->name = $name;
}
public function __wakeup() { // 当调用unserialize()函数时,如果对象中定义了__wakeup()方法,该方法会在反序列化过程中被自动调用
echo 'what do fuck you say?'; //输出一段字符串用于证明魔法函数成功调用
system('calc'); //调用一个计算器
}
}
// 将对象序列化为字符串
$serializedData = serialize(new MyClass("Alice"));
// 反序列化并调用对象的 __wakeup() 方法
$object = unserialize($serializedData);
?>
代码讲解部分:
1.class MyClass { ... }:定义了一个名为 MyClass 的 PHP 类。
2.public $name;:声明了一个公共属性 $name,用于存储对象的名称。
3.public function __construct($name) { ... }:定义了一个构造函数 __construct(),用于在对象实例化时初始化对象的属性。
4.$this->name = $name;:在构造函数中,将传入的名称赋值给对象的 $name 属性。
5.public function __wakeup() { ... }:定义了一个特殊的魔术方法 __wakeup(),该方法会在对象被反序列化后自动调用。
6.echo 'what do fuck you say?'; :在 __wakeup() 方法中,输出一条消息,证明魔法函数被调用了。
此时当我们打开这个页面的时候,就会发现自动弹出计算器,页面上也显示了我们设置的字符串。
5、尝试回答什么是PHP反序列化漏洞
反序列化是将序列化的数据转换回其原始的数据结构或对象的过程。在 PHP 中,可以使用 serialize()
函数将对象或数据结构序列化为字符串,然后使用 unserialize()
函数将其反序列化。
而由于开发者在编写反序列化代码的时候,有时候不经意间会加入一些恶意的代码。从而导致可能出现的反序列化漏洞。
序列化和反序列化本身是为了实现数据在网络上完整高效的传输,但是由于反序列化过程中,对象的魔术方法会自动调用,魔术方法本身调用了别的方法,最终呈现一种链式调用,直到执行任意的代码或者命令。