手把手教你学会代码审计之命令注入漏洞

原文链接: https://mp.weixin.qq.com/s?__biz=Mzg3MzUxNDQwNg==&mid=2247483998&idx=1&sn=1fc9a29ab6682685a8fa8f63c3c5fe97

手把手教你学会代码审计之命令注入漏洞

原创 uuwan SecurityBug 2025-07-18 16:01

本文由作者uuwan原创,禁止转载。      请点击文末#代码审计标签查看合集,或者关注公众号点击底部【源码审计】子菜单,如果对您有帮助还请点赞、在看、评论、转发、关注、打赏哦,您的互动就是我更新最大的动力!

已知X产品bookmark即书签功能中存在命令注入漏洞,但是无法得知攻击者的攻击方式。

登录X产品操作系统后台

find / -name "*bookmark*"

找到了关键文件bookmark.php和paaa.php

下文仅展示关键代码,可以不看后面的解析,给自己五分钟的时间分析一下命令注入漏洞的位置。

手把手教你学会代码审计之命令注入漏洞

bookmark.php
<?php
    include_once &#34;bookmark_db.php&#34;;
    require_once(dirname(__FILE__).'/'.&#34;../paaa.php&#34;);
    $dbname = $_COOKIE['site_name'];
    $uname = $_COOKIE['user_name'];
    $role_names = $_COOKIE['roles'];
    $action = $_REQUEST['action'];
    if(!$dbname || !$uname || !$action){
        exit(&#34;action is null!&#34;);
    }
    $cmd = 'bookmark status'; 
    $mycli = new cli(); 
    //此处调用了cmd_direct函数
    $cli_res = $mycli->cmd_direct($cmd, $dbname);
    $dbname  = &#34;auth_&#34; . $dbname;
    $db_conn = new MP\DB\BookMark_db($dbname);


if($action == 'add') {
        $url = $_POST['url'];
        $type = $_POST['type'];
        $desc = $_POST['description'];
        if(!$url || !$desc){
            exit(&#34;url/description is null!&#34;);
        }
        header(&#34;Content-Type: text/html&#34;);
        if($db_conn->sql_inj($desc) || $db_conn->sql_inj($url) || !is_numeric($type)) {
            echo &#34;Fail to add the bookmark!&#34;;
        }
        $res = $db_conn->addBookMarkCheck($uname,$url,$type,$desc);
        if($res){
            $cmd = 'sync sql &#34;insert into tbl_bookmark(url,type,user_name,description) values(&'.
                $url.'&,'.$type.',&'.$uname.'&,&'.$desc.'&)&#34;';
            $mycli = new cli();
            //此处调用了cmd_direct函数
            $cli_res = $mycli->cmd_direct($cmd , $_COOKIE['site_name']);
            if($cli_res[&#34;result&#34;]){
                echo &#34;add successfully!&#34;;
                echo &#34;<script>history.go(-2);</script>&#34;;
            } else {
                echo &#34;Fail to add the bookmark!&#34;;
            }
        }else{
            echo &#34;Fail to add the bookmark! One user only can own 100 bookmarks.&#34;;
        }
    } else {
        exit(&#34;invalid action&#34;);
    }
?>
paaa.php
<?php
    function cmd_direct($cmd, $shell)
    {
        global $debugLog ;
        global $logFile;
        if ($debugLog) {
            $t_fileRef = fopen($logFile,'a');
            fwrite($t_fileRef, &#34;\t&#34; . $cmd . &#34;\n&#34;);
        }
        if(empty($shell)||!isset($shell)){
            $shell = &#34;global&#34;;
        }
        $f_eop = chr(252); 
        $cmd .= $f_eop;
        $cmd = escapeshellarg($cmd);
        //反引号`在php中可以执行命令
        $output = `/ca/bin/backend -s &#34;$shell&#34;  -c $cmd`;
        $output = trim($output, $f_eop);


        if ($debugLog) {
            $t_fileRef = fopen($logFile,'a');
            fwrite($t_fileRef, &#34;\t&#34; . $output . &#34;\n&#34;);
        }
        $output = backend_format($output);
        $json = json_decode($output,true);
        if(!$json){
            return $output;
        }
        return foreach_trim($json);
    }
?>

手把手教你学会代码审计之命令注入漏洞

此处我们开始解析。

我们可以看到paaa.php中有一个明显的漏洞。

反引号``在php中可以执行命令,也是命令注入代码审计的关键函数
传参$cmd和参数$shell都可以传入反引号中被执行。
也就是说这个函数cmd_direct可以进行命令注入。
function cmd_direct($cmd, $shell)
{
    $output = `/ca/bin/backend -s &#34;$shell&#34;  -c $cmd`;
}


再看下bookmark.php中有两处调用了cmd_direct()

第15行     
$cli_res = $mycli->cmd_direct($cmd, $dbname);
第36行
if($action == 'add') 
{
    $cli_res = $mycli->cmd_direct($cmd , $_COOKIE['site_name']);
}


经过分析第15行处的命令注入更容易触发。
这里是一个经验点,这处的行数靠前,经过的代码少。
所以保证了它更容易被执行到。
我们取出前15行进行分析。


此处是一个require_once函数,
它可以把paaa.php中的代码包含在bookmark.php中
通俗的来说,也就是此时在bookmark.php中
可以调用paaa.php的全部代码包含参数和函数
聪明的你一定意识到了,正是因为有这个require_once函数
我们才可以在bookmark.php中调用paaa.php中的cmd_direct()函数
从而形成命令执行。


require_once(dirname(__FILE__).'/'.&#34;../paaa.php&#34;);
$dbname = $_COOKIE['site_name'];
//$_COOKIE获取cookie中参数site_name的值
$uname = $_COOKIE['user_name'];
$role_names = $_COOKIE['roles'];
//$_REQUEST获取cookie、get、post请求中参数action的值
$action = $_REQUEST['action'];


要确保代码能执行到cmd_direct(),那这块的if条件一定不能满足
如果满足了,bookmark.php的执行就会在exit处跳出结束。
也就是说dbname和uname和action一定得有参数值
if(!$dbname || !$uname || !$action){
        exit(&#34;action is null!&#34;);
}
$cmd = 'bookmark status'; 
$mycli = new cli(); 
//此处调用了cmd_direct函数
$cli_res = $mycli->cmd_direct($cmd, $dbname);

我们用burpsuite抓住一个正常的编辑书签的请求。

手把手教你学会代码审计之命令注入漏洞

可以看到此时action是有值的,但是cookie中并没有参数user_name和参数site_name

所以正常发送的请求肯定会因为不满足存在参数值,而退出exit,进而无法走到cmd_direct函数中。

那很简单了!

我们在cookie中增加两个参数user_name=aaa;site_name=bbb;

$cmd = 'bookmark status'; 
$mycli = new cli(); 


//此时我们成功调用了cmd_direct函数
//cmd的值是固定的bookmark status
//那么我们只能在dbname中进行命令注入


$cli_res = $mycli->cmd_direct($cmd, $dbname);
进入cmd_direct函数
 function cmd_direct($cmd, $shell)
{
    $output = `/ca/bin/backend -s &#34;$shell&#34;  -c $cmd`;
}


$dbname = $_COOKIE['site_name'],我们只需要构造site_name=&#34;;sleep 33;&#34;
`/ca/bin/backend -s &#34;$shell&#34;  -c $cmd`;
就变成下文的样子
`/ca/bin/backend -s &#34;&#34;;sleep 33;&#34;&#34;  -c bookmark status`;
这样子就可以成功执行命令啦!
实际操作中我们对site_name的值进行url编码
因为cookie的值在后端后被自动url解码
site_name=%22%3bsleep+3322%3b

最终的攻击包如下图

手把手教你学会代码审计之命令注入漏洞

手把手教你学会代码审计之命令注入漏洞

这就是复现命令注入的全过程啦

是不是很简单呢。

#代码审计
#漏洞教学