公交车司机
bash
有一名黑客入侵了公交车交通系统,我们需要分析流量中的蛛丝马迹,找到FLAG
给了一个流量包,打开分析全是Modbus/TCP,拿脚本分析一下内容
python
import pyshark
def get_code():
captures = pyshark.FileCapture(
r'D:\应急\公交车\modbus.pcapng',
tshark_path=r'D:\tool\wireshark\tshark.exe'
)
func_codes = {}
for c in captures:
for pkt in c:
if pkt.layer_name == "modbus":
func_code = int(pkt.func_code)
if func_code in func_codes:
func_codes[func_code] += 1
else:
func_codes[func_code] = 1
print(func_codes)
if __name__ == '__main__':
get_code()
//{16: 150}
只有16(预置多个寄存器)功能码,分析当前功能码的数据
python
import pyshark
def hex_to_ascii(hexstr: str) -> str:
try:
data = bytes.fromhex(hexstr)
except ValueError:
return "[invalid hex]"
return ''.join(chr(b) if 32 <= b <= 126 else '.' for b in data)
def find_flag():
cap = pyshark.FileCapture(
r'D:\应急\公交车\modbus.pcapng',
tshark_path=r'D:\tool\wireshark\tshark.exe'
)
for idx, pkt in enumerate(cap, 1):
try:
if not (hasattr(pkt, "modbus") and hasattr(pkt, "tcp")):
continue
if int(pkt.modbus.func_code) != 16:
continue
payload = str(pkt.tcp.payload).replace(":", "")
print(f"[{idx}] func_code = 16")
print("HEX :", payload)
print("ASCII:", hex_to_ascii(payload))
print("-" * 60)
except AttributeError:
pass
cap.close()
if __name__ == '__main__':
find_flag()
输出的数据去分析,可以发现这批数据其实是组很规律的数据,真正变化的是低位两位字节的数据变化,拿脚本提取出来
python
import pyshark
import re
def extract_flag():
cap = pyshark.FileCapture(
r'D:\应急\公交车\modbus.pcapng',
tshark_path=r'D:\tool\wireshark\tshark.exe'
)
chars = []
for pkt in cap:
try:
if not hasattr(pkt, "modbus") or not hasattr(pkt, "tcp"):
continue
if int(pkt.modbus.func_code) != 16:
continue
low = bytes.fromhex(str(pkt.tcp.payload).replace(":", ""))[-1]
ch = chr(low).lower()
if ch in "0123456789abcdef":
chars.append(ch)
except (AttributeError, ValueError, IndexError):
continue
cap.close()
s = ''.join(chars)
start_tag = "666c61677b"
pos = s.find(start_tag)
if pos == -1:
print("not found")
return
s2 = s[pos:]
if len(s2) % 2 == 1:
s2 = s2[:-1]
try:
decoded = bytes.fromhex(s2).decode(errors="ignore")
m = re.search(r'flag\{[^}]+\}', decoded)
if m:
print(m.group(0))
else:
print("not found")
except ValueError:
print("not found")
if __name__ == "__main__":
extract_flag()
可疑文件
给了flag.enc文件和一个test.dll,可以知道加密方法大概率是在dll文件里面,ida审计一下,没有找到main,但是找到了一个HelloWorld
c
__int64 HelloWorld_0()
{
char *v0; // rdi
__int64 i; // rcx
_BYTE v3[32]; // [rsp+0h] [rbp-20h] BYREF
char v4; // [rsp+20h] [rbp+0h] BYREF
const char *v5; // [rsp+28h] [rbp+8h]
const char *v6; // [rsp+48h] [rbp+28h]
const char *v7; // [rsp+68h] [rbp+48h]
_BYTE v8[64]; // [rsp+88h] [rbp+68h] BYREF
__int64 v9; // [rsp+C8h] [rbp+A8h]
__int64 v10; // [rsp+E8h] [rbp+C8h]
v0 = &v4;
for ( i = 58; i; --i )
{
*(_DWORD *)v0 = -858993460;
v0 += 4;
}
sub_1800770F7(&unk_1801AD0A3);
v5 = "f.txt";
v6 = "f.enc";
v7 = "qewuri";
sub_18007B180("qewuri", v8);
v9 = sub_18007462C(v5, "rb");
v10 = sub_18007462C(v6, "wb");
sub_18007B240(v9, v10, v8);
sub_1800753BF(v9);
sub_1800753BF(v10);
sub_180076850(v3, &unk_180167E40);
return 1;
}
基于固定口令 "qewuri" 的文件加密流程,将 f.txt 读取后加密输出到 f.enc。
然后去看sub_18007B180和sub_18007B240中的加密逻辑
c
__int64 __fastcall sub_18007B180(__int64 a1, __int64 a2)
{
unsigned __int64 v3; // [rsp+28h] [rbp+8h]
__int64 v4; // [rsp+F8h] [rbp+D8h]
sub_1800770F7(&unk_1801AD0A3);
v3 = sub_180075635(a1);
sub_180076477(a2, 0, 32);
if ( v3 <= 0x20 )
v4 = v3;
else
v4 = 32;
return sub_1800757E3(a2, a1, v4);
}
c
__int64 __fastcall sub_18007B240(__int64 a1, __int64 a2, __int64 a3)
{
char *v3; // rdi
__int64 i; // rcx
_BYTE v6[32]; // [rsp+0h] [rbp-20h] BYREF
char v7; // [rsp+20h] [rbp+0h] BYREF
_DWORD v8[4]; // [rsp+30h] [rbp+10h] BYREF
_DWORD v9[9]; // [rsp+40h] [rbp+20h] BYREF
int v10; // [rsp+64h] [rbp+44h] BYREF
_BYTE v11[56]; // [rsp+88h] [rbp+68h] BYREF
_BYTE v12[96]; // [rsp+C0h] [rbp+A0h] BYREF
_BYTE v13[88]; // [rsp+120h] [rbp+100h] BYREF
unsigned __int64 v14; // [rsp+178h] [rbp+158h]
unsigned __int64 j; // [rsp+198h] [rbp+178h]
v3 = &v7;
for ( i = 102; i; --i )
{
*(_DWORD *)v3 = -858993460;
v3 += 4;
}
sub_1800770F7(&unk_1801AD0A3);
memset(v11, 0, 0xCu);
qmemcpy(v8, "expand 32-byte k", sizeof(v8));
sub_1800757E3(v9, a3, 32);
v9[8] = 0;
sub_1800757E3(&v10, v11, 12);
while ( 1 )
{
v14 = sub_180074E79(v13, 1, 64, a1);
if ( !v14 )
break;
sub_18007ABE0(v8, v12);
for ( j = 0; j < v14; ++j )
{
v13[j] ^= v12[j];
++v13[j];
}
sub_1800772F0(v13, 1, v14, a2);
}
return sub_180076850(v6, &unk_180167DA0);
}
一个魔改的chacha20的算法
python
import struct
from pathlib import Path
BLOCK_SIZE = 64
KEY = b"qewuri".ljust(32, b"\x00")
NONCE = b"\x00" * 12
def rotl32(x, n):
return ((x << n) & 0xffffffff) | (x >> (32 - n))
def quarter_round(a, b, c, d):
a = (a + b) & 0xffffffff; d ^= a; d = rotl32(d, 16)
c = (c + d) & 0xffffffff; b ^= c; b = rotl32(b, 12)
a = (a + b) & 0xffffffff; d ^= a; d = rotl32(d, 8)
c = (c + d) & 0xffffffff; b ^= c; b = rotl32(b, 7)
return a, b, c, d
def chacha20_block(key, counter, nonce):
constants = b"expand 32-byte k"
state = (
list(struct.unpack("<4I", constants))
+ list(struct.unpack("<8I", key))
+ [counter]
+ list(struct.unpack("<3I", nonce))
)
working = state.copy()
for _ in range(10):
working[0], working[4], working[8], working[12] = quarter_round(working[0], working[4], working[8], working[12])
working[1], working[5], working[9], working[13] = quarter_round(working[1], working[5], working[9], working[13])
working[2], working[6], working[10], working[14] = quarter_round(working[2], working[6], working[10], working[14])
working[3], working[7], working[11], working[15] = quarter_round(working[3], working[7], working[11], working[15])
working[0], working[5], working[10], working[15] = quarter_round(working[0], working[5], working[10], working[15])
working[1], working[6], working[11], working[12] = quarter_round(working[1], working[6], working[11], working[12])
working[2], working[7], working[8], working[13] = quarter_round(working[2], working[7], working[8], working[13])
working[3], working[4], working[9], working[14] = quarter_round(working[3], working[4], working[9], working[14])
result = [(working[i] + state[i]) & 0xffffffff for i in range(16)]
return struct.pack("<16I", *result)
def decrypt_file(infile="flag.enc", outfile="f.dec", preview=True):
data = Path(infile).read_bytes()
plaintext = bytearray()
for counter, start in enumerate(range(0, len(data), BLOCK_SIZE)):
block = data[start:start + BLOCK_SIZE]
keystream = chacha20_block(KEY, counter, NONCE)
plaintext.extend((((b - 1) & 0xff) ^ keystream[i]) for i, b in enumerate(block))
Path(outfile).write_bytes(plaintext)
print(outfile)
if preview:
print(plaintext[:200].decode(errors="ignore"))
if __name__ == "__main__":
decrypt_file()
喜欢这篇文章的人也看了
评论
隐私政策
0/500
滚动到此处加载评论...
