Cobra代码扫描规则编写

回顾下手动挖洞过程

1.找数据入口点

$get = $_GET['param'];
$post = $_POST['param'];
$request = $_REQUEST['param'];
$cookie = $_COOKIE['param'];

2.跟踪外部数据执行流程,看是否可以利用

// XSS
echo $get;

// SQL注入
insert_database($post);

// 系统命令执行
system($cookie)  

1和2的顺序可以互相调换。

自动代码审计

自动代码审计如果根据1-2这个流程来,会涉及到很多的预发解析,比较复杂。 所以用逆向(2-1)的方式往前推。

思路

先定位一个高危函数,比如system($code),接着跟踪这个$code是否可控,如果可以则算作漏洞(RCE)。

规则设计

每条规则包含两个子规则。

  • 搜索规则(S)-搜索区块(B) - 用来定位风险函数位置
  • 验证规则(V)-验证区块(B) - 验证风险函数参数是否可控(此处扫描引擎会实现)
  • 修复规则(R)-修复区块(B) - 验证风险函数参数是否修复

区块表示的是该规则需要查找的位置,有以下类型:

  1. 函数体内,S规则触发位置之上(0)
  2. 函数体内,S规则触发位置之下(1)

子规则搭配方式

  • (1). [S] - [空] - [空]
  • (2). [S] - [V] - [空]
  • (3). [S] - [V] - [R]

(1). 禁止/检查某类服务/函数调用,比如一些因为安全问题而废弃的函数。

(2). 大部分风险函数的验证需要看参数是否可控才能确定能否被利用。

(3). 哪怕参数是外部传入的,但如果是经过过滤的则无风险。

举个SSRF的🌰

我们拿PHP中的curl造成的SSRF来说。

一. 搜索规则(S)

搜索区块(B)默认为项目全部文件

先用搜索(S)规则来定位项目中所有存在curlsetopt(CURLOPTURL, $url)的文件和行数。

比如下面这处:

/**
 * CURL SSRF Example
 *
 * @author Feei <wufeifei@wufeifei.com>
 * @link   http://wufeifei.com/ssrf
 */
function callback(){  
    $callback_url = $_GET['url'];
    $ch = curl_init();
    /*
     * 搜索规则定位的位置点
     */
    curl_setopt($ch, CURLOPT_URL, $callback_url);
    curl_setopt($ch, CURLOPT_HEADER, 0);
    curl_exec($ch);
    curl_close($ch);
}

那我们的定位规则(regex-location)就可以写成

curl_setopt\s?\(.*,\s?CURLOPT_URL\s?,(.*)\)  

括号匹配的必须是URL的变量名,下一步扫描引擎会拿着参数名去判断参数是否可控。

二. 验证规则(V) - 扫描引擎做的工作

搜索区块(B) 为2.函数体内,S触发规则之下

接着用验证规则(V)搜索区块(2.函数体内,S触发规则之下)curl_setopt($ch, CURLOPT_URL, $url)的$url参数并向上验证$url的赋值方式。

1. 变量被赋值为字符串(两种结果)

被赋值为字符串了就不能被利用,所以直接排除掉。

/**
 * CURL SSRF Example
 *
 * @author Feei <wufeifei@wufeifei.com>
 * @link   http://wufeifei.com/ssrf
 */
function callback(){  
    /*
     * 此处$callback_url为变量被赋值成字符串
     * 此时我们只需要检测该url参数是否有风险
     * 如果URL参数为file:///etc/passwd等非HTTP/HTTPS协议,则存在风险
     * 如果URL参数为普通HTTP/HTTPS服务,则无风险
     */
    $callback_url = 'http://wufeifei.com/cobra';
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $callback_url);
    curl_setopt($ch, CURLOPT_HEADER, 0);
    curl_exec($ch);
    curl_close($ch);
}

2. 取外部参数(取$GET/$POST等值,既可以确定为漏洞)

变量值取的是外部参数,会导致漏洞。

/**
 * CURL SSRF Example
 *
 * @author Feei <wufeifei@wufeifei.com>
 * @link   http://wufeifei.com/ssrf
 */
function callback(){  
    /*
     * 此处$callback_url取外部入参
     * 则直接判定为存在风险
     */
    $callback_url = $_GET['url'];
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $callback_url);
    curl_setopt($ch, CURLOPT_HEADER, 0);
    curl_exec($ch);
    curl_close($ch);
}

3. 函数传参

函数传参类型也会造成多次调用,存在隐患,算做漏洞。

/**
 * CURL SSRF Example
 *
 * @author Feei <wufeifei@wufeifei.com>
 * @link   http://wufeifei.com/ssrf
 */
function callback($callback_url){  
    /*
     * 此处$callback_url取函数入参
     * 扫到这类规则后
     * 需要将callback()函数作为__搜索(S)__规则添加一个新的扫描规则
     */
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $callback_url);
    curl_setopt($ch, CURLOPT_HEADER, 0);
    curl_exec($ch);
    curl_close($ch);
}
三. 修复规则(R)

根据第二点验证规则返回的状态,可以知道是否存在风险。

如果存在风险,则进入修复规则(R)

修复规则一般匹配是否存在过滤操作。

比如SSRF Curl的修复规则为curlsetopt($ch, CURLOPTPROTOCOLS, CURLOPT_HTTP),那我们就可以写一个修复规则来判断定位规则出发点到该函数的末尾处是否有符合修复规则。

# 修复规则
curl_setopt\s?\(.*,\s?CURLOPT_PROTOCOLS\s?,(.*)\)

# 修复区块
1 (搜索规则触发位置到函数体结束处)  
/**
 * CURL SSRF Example
 *
 * @author Feei <wufeifei@wufeifei.com>
 * @link   http://wufeifei.com/ssrf
 */
function callback($callback_url){  
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $callback_url);
    curl_setopt($ch, CURLOPT_HEADER, 0);
    /*
     * 搜索区块(S规则触发位置之下)中是否存在下面这行配置
     * 存在则不会有风险,反之亦然
     */
    curl_setopt($ch, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS);  

    curl_exec($ch);
    curl_close($ch);
}

一个完整的SSRF规则

将这个规则添加到Cobra管理后台的规则里即可扫描项目中的SSRF漏洞。

# 定位规则(regex_location)
curl_setopt\s?\(.*,\s?CURLOPT_URL\s?,(.*)\)

# 修复规则(regex_repair)
curl_setopt\s?\(.*,\s?CURLOPT_PROTOCOLS\s?,(.*)\)

# 修复区块(block_repair)
1  

后续计划

还有些特殊情况需要特殊处理,暂时的规则已经支持扫描大部分常规漏洞。

引用参考