DVWA 靶场 impossible 级别命令注入代码审计

DVWA 靶场 impossible 级别命令注入代码审计



前言

之前审计了 high 级别的命令注入,这次来尝试 impossible 级别的代码审计,自己的理解,有错误多多担待


函数

checkToken()

这个checkToken()函数的作用是检查用户令牌是否有效。它可以防止跨站伪造请求攻击(CSRF),保护站点免受恶意攻击者伪造合法用户的请求。
以下是checkToken()函数的简单实现:

  1. 创建随机令牌并将其保存在会话变量中(session_token)。
session_start();
$session_token = bin2hex(random_bytes(32));
$_SESSION['session_token'] = $session_token;
  1. 将令牌嵌入HTML表单中,并发送给客户端。
<form method="post" action="process.php">
<input type="hidden" name="user_token" value="<?php echo htmlspecialchars($session_token); ?>">
</form>
  1. 在接收请求时调用checkToken()函数来检查提交的用户令牌是否与服务器上存储的会话令牌相匹配。
session_start();
$user_token = $_REQUEST['user_token'];
$session_token = $_SESSION['session_token'];

function checkToken($user_token, $session_token, $redirect_uri){
    if($user_token !== $session_token){
        header('Location: '.$redirect_uri);
        exit();
    }
}

checkToken($user_token, $session_token, 'index.php');
  1. 如果用户令牌与服务器上的会话令牌不匹配,则重定向回首页。

以上代码示例只是一个基本的实现,实际使用中可能需要根据需求进行调整。例如,为了提高安全性,可以在每次创建新会话时重新生成令牌,并定期更新它。另外,需要注意的是此示例没有考虑其他的安全因素,例如输入验证、错误处理等。建议使用成熟的解决方案,如OWASP CSRFGuard,来更好地保护站点免受CSRF攻击。

$_SESSION

$_SESSION 是一个全局变量,在 PHP 中用于存储会话级别的数据。
在一个 HTTP 请求期间,所有页面都可以访问存储在 $_SESSION 变量中的数据。当用户关闭浏览器时,所有的会话数据都会消失。因此,它常用来实现购物车功能等临时性的数据存储需求。
以下是一个简单的会话跟踪的例子:

// 启动会话处理功能
session_start();

// 存储数据到会话
$_SESSION["cart"][] = array("item"=>"Apple","quantity"=>2,"price"=>1.5);

// 显示购物车内容
foreach ($_SESSION["cart"] as $item) {
    echo "Name:".$item["item"]." Quantity:".$item["quantity"]." Price:".$item["price"]."<br>";
}

// 删除特定商品
unset($_SESSION["cart"][0]);

// 删除整个购物车
unset($_SESSION["cart"]);

需要注意的是,会话数据只能被同一个域名下的网页访问,且必须先使用 session_start() 启动会话才能使用 $_SESSION 变量。为了保持会话的数据持久性,一般还会配合 Cookie 使用,以便下次用户再次访问时能够恢复之前的会话状态。
同时,确保会话数据安全也是非常重要的,可以通过使用 session 锁定机制以及加密传输来防止会话劫持。

stripslashes()

在 PHP 中,stripslashes() 函数的作用是去除字符串中由 \ 符号转义的特殊字符。
\ 符号在 PHP 中用来表示一个特殊字符或转义序列,例如 \n 表示换行符、\t 表示制表符、\r 表示回车符等等。
如果某个字符串是从数据库查询或从 HTML 表单中获取的,那么在字符串中可能会出现一些 \ 符号,这会导致输出的结果不太符合预期。这时就可以使用 stripslashes() 函数来去除这些 \ 符号及其对应的特殊字符。
以下是一个示例:

$str = "He said \"Hello, World!\"";
echo stripslashes($str);  // 输出 "He said "Hello, World!""

在这个例子中,因为 " 是特殊字符,所以它前面加了一个 \ 进行转义。而 stripslashes() 函数则会把这个 \ 符号去掉,让 " 变成普通字符输出出来。
需要注意的是,不要随意使用 stripslashes() 函数,因为它可能会导致安全漏洞。在处理从外部来源(如数据库查询或表单数据)获取的输入时,请务必谨慎使用。

explode()

在 PHP 中,explode() 函数的作用是在字符串中按照指定分隔符拆分出子字符串,并以数组形式返回。
其语法如下:

array explode(string separator,string string [,limit])

其中:

  • separator:要使用的分隔字符。
  • string:要拆分的字符串。
  • limit:可选参数,默认为 -1。如果设置了 limit 参数,并且小于等于0,则把整个字符串当作单一元素处理;如果 limit 大于 0,则返回最多 limit 数目的元素。否则返回所有元素。

以下是一个示例:

$string = "Hello, world!";
$arr = explode(",", $string);

print_r($arr);  // 输出 Array ( [0] => Hello [1] => world! )

在这个例子中,explode() 函数按照逗号拆分出了字符串 $string,并将其结果存储在数组 $arr 中。所以输出的结果就是 Array ( [0] => Hello [1] => world! )
需要注意的是,如果 $separator 是连续出现多次的话,则 $string 中连续出现的部分会被拆分为单独的元素。例如:

$string = "Hello,,,world!";
$arr = explode(",", $string);
print_r($arr);  // 输出 Array ( [0] => Hello [1] => [2] => [3] => world! )
在这个例子中,因为 `$separator` 是连续出现两次,所以第一个逗号后面多出了一个空字符串元素。如果想避免这种情况,可以使用正则表达式的方式来拆分字符串:
$string = "Hello,,,world!";
$arr = preg_split("/,+/", $string);
print_r($arr);  // 输出 Array ( [0] => Hello [1] => world! )
// 这样就不会有多余的空字符串元素了。

is_numeric()

在 PHP 中, is_numeric 函数的作用是判断变量是否为数字或可转化为数字的数值型字符串。
以下是一个示例:

$var1 = "123";
$var2 = "abc";

if(is_numeric($var1))
    echo "$var1 是数字";
else
    echo "$var1 不是数字";

if(is_numeric($var2))
    echo "$var2 是数字";
else
    echo "$var2 不是数字";

输出结果为:

123 是数字
abc 不是数字

需要注意的是,当变量 $var1 被赋值为字符串时,《is_numeric》函数仍然认为它是数字,因为它可以用作数学运算。但是当变量 $var2 被赋值为非数字字符时,《is_numeric》函数会认为它不是数字。如果您只想判断变量是否为纯数字类型,可以使用 ctype_digit() 函数:

if(ctype_digit($var1))
    echo "$var1 是数字";
else
    echo "$var1 不是数字";

if(ctype_digit($var2))
    echo "$var2 是数字";
else
    echo "$var2 不是数字";

输出结果为:

123 是数字
abc 不是数字

现在,即使 $var1 是数字字符组成的字符串,它也不会被认为是数字了。

sizeof()

在 PHP 中,sizeof()count() 函数的别名,用于计算数组或对象中元素的数量。它有两种语法格式:

  1. 对于一维数组,可以直接使用 sizeof() 计算元素数量:
$arr = array("a","b","c");
$count = sizeof($arr);
echo $count;  // 输出 3
  1. 对于二维或多维数组,sizeof() 不能直接计算元素数量,需要配合 foreach 循环遍历数组并统计元素数量:
$arr = array(
    array("a","b"),
    array("c","d")
);
$count = 0;
foreach($arr as $val)
{
    $count += sizeof($val);
}
echo $count;  // 输出 4

需要注意的是,如果传递给 sizeof() 函数的不是一个数组或对象,将会产生错误提示。
例如:

$string = "hello";
$count = sizeof($string);

这段代码会产生以下错误提示:Warning: sizeof(): Parameter must be an array or an object that implements Countable

generateSessionToken()

generateSessionToken() 是一种生成唯一会话令牌的方法,用于避免跨站请求伪造攻击(CSRF)和其他恶意活动。它将生成一个随机的哈希值,然后将此值添加到每个页面上所有表单的隐藏字段中,以供后续页面验证。
以下是一个简单的示例:

function generateSessionToken(){
    if(!isset($_SESSION['session_token']){ $_SESSION['session_token'] = md5(microtime(true)); }

    return $_SESSION['session_token'];
}

// 引入会话保护
$token = generateSessionToken();
session_regenerate_id();

// 验证表单中的 token 值与服务器上的 session_token 是否一致
function validateFormToken($postToken){
    if(isset($_POST['_csrf_token']) && isset($_SESSION['session_token']) && $_POST['_csrf_token'] === $_SESSION['session_token']){
        return true;
    } else {
        return false;
    }
}

这个示例中,每当用户打开一个新的页面时就会生成一个唯一的 session_token,然后使用 session_regenerate_id() 更新当前的 session_id 并将新的 session_token 返回给客户端。客户端在提交表单时,将这个 token 发送到服务器端进行验证,如果 token 不匹配,则拒绝请求。
需要注意的是,这种方法只是防君子不防小人,并不能完全阻止 CSRF 攻击。更好的做法是使用 JWT (JSON Web Token),这样可以在服务器端和客户端之间共享安全令牌,从而加强网站的安全性。

代码审计

在这里插入图片描述

<?php

if( isset( $_POST[ 'Submit' ]  ) ) {
    // Check Anti-CSRF token
// **checkToken 检查用户令牌是否有效, 与 $_SESSION 配合使用
    checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );

    // Get input
    $target = $_REQUEST[ 'ip' ];
// ** stripslashes($target) 将数据中的特殊字符转义为普通字符
    $target = stripslashes( $target );
// **explode 拆分以 '.' 为判断,拆分ip
    // Split the IP into 4 octects
    $octet = explode( ".", $target );
// **is_numeric 判断每个数据是否为整数 
    // 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();

?>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值