网鼎杯-半决赛-青龙组-逆向安全
附件太大上传不了,
这里给个百度网盘链接:附件
网络通信流量分析
给了三个附件,一个流量一个客户端和一个服务端。
先看服务端和客户端
客户端
__int64 __fastcall main(int a1, char **a2, char **a3)
{
size_t v4; // rax
size_t v5; // rax
int i; // [rsp+14h] [rbp-53Ch]
int j; // [rsp+18h] [rbp-538h]
uint16_t v8; // [rsp+1Ch] [rbp-534h]
int fd; // [rsp+20h] [rbp-530h]
int v10; // [rsp+24h] [rbp-52Ch]
int v11; // [rsp+24h] [rbp-52Ch]
char *cp; // [rsp+28h] [rbp-528h]
struct sockaddr addr; // [rsp+30h] [rbp-520h] BYREF
char s[256]; // [rsp+40h] [rbp-510h] BYREF
char buf[1032]; // [rsp+140h] [rbp-410h] BYREF
unsigned __int64 v16; // [rsp+548h] [rbp-8h]
v16 = __readfsqword(0x28u);
if ( a1 == 3 )
{
cp = a2[1];
v8 = atoi(a2[2]);
fd = socket(2, 1, 0);
if ( fd < 0 )
{
perror("Socket creation failed");
exit(1);
}
addr.sa_family = 2;
*(_WORD *)addr.sa_data = htons(v8);
*(_DWORD *)&addr.sa_data[2] = inet_addr(cp);
if ( connect(fd, &addr, 0x10u) < 0 )
{
perror("Connection failed");
exit(1);
}
printf("Enter the server's password: ");
fgets(s, 256, stdin);
v4 = strlen(s);
send(fd, s, v4, 0);
v10 = recv(fd, buf, 0x400uLL, 0);
if ( v10 < 0 )
{
perror("Receive failed");
exit(1);
}
printf("Status: ");
for ( i = 0; i < v10; ++i )
putchar(buf[i]);
putchar(10);
fgets(s, 256, stdin);
v5 = strlen(s);
send(fd, s, v5, 0);
v11 = recv(fd, buf, 0x400uLL, 0);
if ( v11 < 0 )
{
perror("Receive failed");
exit(1);
}
printf("Pass Token: ");
for ( j = 0; j < v11; ++j )
putchar(buf[j]);
putchar(10);
close(fd);
return 0LL;
}
else
{
fprintf(stderr, "Usage: %s <Server IP> <Server Port>\n", *a2);
return 1LL;
}
}
就是输入password
服务端
void __fastcall __noreturn main(int a1, char **a2, char **a3)
{
unsigned int v3; // ebx
char *v4; // rax
socklen_t addr_len; // [rsp+0h] [rbp-50h] BYREF
int optval; // [rsp+4h] [rbp-4Ch] BYREF
int fd; // [rsp+8h] [rbp-48h]
int v8; // [rsp+Ch] [rbp-44h]
struct sockaddr addr; // [rsp+10h] [rbp-40h] BYREF
struct sockaddr v10; // [rsp+20h] [rbp-30h] BYREF
unsigned __int64 v11; // [rsp+38h] [rbp-18h]
v11 = __readfsqword(0x28u);
addr_len = 16;
optval = 1;
fd = socket(2, 1, 0);
if ( fd < 0 )
{
perror("Socket creation failed");
exit(1);
}
addr.sa_family = 2;
*(_WORD *)addr.sa_data = htons(0x22B8u);
*(_DWORD *)&addr.sa_data[2] = 0;
if ( setsockopt(fd, 1, 2, &optval, 4u) == -1 )
{
perror("setsockopt faild");
close(fd);
exit(1);
}
if ( bind(fd, &addr, 0x10u) < 0 )
{
perror("Bind failed");
exit(1);
}
if ( listen(fd, 5) < 0 )
{
perror("listen failed");
close(fd);
exit(1);
}
puts("Server is listening on port 8888...");
while ( 1 )
{
while ( 1 )
{
v8 = accept(fd, &v10, &addr_len);
if ( v8 >= 0 )
break;
perror("accept failed");
}
v3 = ntohs(*(uint16_t *)v10.sa_data);
v4 = inet_ntoa(*(struct in_addr *)&v10.sa_data[2]);
printf("Connection from %s:%d\n", v4, v3);
if ( !fork() )
{
close(fd);
check(v8);
exit(0);
}
close(v8);
}
}
unsigned __int64 __fastcall check(int a1)
{
__int64 v2; // [rsp+18h] [rbp-58h] BYREF
__int64 buf[4]; // [rsp+20h] [rbp-50h] BYREF
__int64 v4[4]; // [rsp+40h] [rbp-30h] BYREF
__int16 v5; // [rsp+60h] [rbp-10h]
unsigned __int64 v6; // [rsp+68h] [rbp-8h]
v6 = __readfsqword(0x28u);
memset(buf, 0, sizeof(buf));
v2 = 0LL;
v4[0] = 0xC632A2F05BD9371DLL;
v4[1] = 0x3AA73E7E508CA730LL;
v4[2] = 0x1C6B85816B58C0BALL;
v4[3] = 0x9742C18A7C80F54CLL;
v5 = 0xC790;
recv(a1, buf, 0x20uLL, 0);
*((_BYTE *)buf + strcspn((const char *)buf, "\n")) = 0;
if ( md5_check((__int64)buf) )
{
send(a1, "right\n", 6uLL, 0);
modified_rc4((const char *)buf, (__int64)v4, 0x22uLL);
recv(a1, &v2, 8uLL, 0);
if ( (_BYTE)v2 == 10 )
send(a1, v4, 0x22uLL, 0);
}
else
{
send(a1, "wrong\n", 6uLL, 0);
}
close(a1);
return __readfsqword(0x28u) ^ v6;
}
这里就是创建子进程接收客户端发的字符串,md5_check检查输入字符串的md5值是否等于497556baff45dda628467848cd10d914,如果是就发送right,并用输入的字符串作为key对一段数据进行魔改的rc4解密,这里只是额外xor了0x25。
unsigned __int64 __fastcall sub_1552(const char *a1, __int64 a2, unsigned __int64 a3)
{
char v3; // bl
char v6; // [rsp+27h] [rbp-139h]
char v7; // [rsp+27h] [rbp-139h]
unsigned __int64 i; // [rsp+28h] [rbp-138h]
unsigned __int64 j; // [rsp+28h] [rbp-138h]
__int64 v10; // [rsp+28h] [rbp-138h]
__int64 v11; // [rsp+30h] [rbp-130h]
__int64 v12; // [rsp+30h] [rbp-130h]
unsigned __int64 k; // [rsp+38h] [rbp-128h]
char v14[264]; // [rsp+40h] [rbp-120h] BYREF
unsigned __int64 v15; // [rsp+148h] [rbp-18h]
v15 = __readfsqword(0x28u);
LOBYTE(v11) = 0;
for ( i = 0LL; i <= 0xFF; ++i )
v14[i] = i;
for ( j = 0LL; j <= 0xFF; ++j )
{
v3 = v14[j] + v11;
v11 = (unsigned __int8)(v3 + a1[j % strlen(a1)]);
v6 = v14[j];
v14[j] = v14[v11];
v14[v11] = v6;
}
LOBYTE(v12) = 0;
LOBYTE(v10) = 0;
for ( k = 0LL; k < a3; ++k )
{
v10 = (unsigned __int8)(v10 + 1);
v12 = (unsigned __int8)(v14[v10] + v12);
v7 = v14[v10];
v14[v10] = v14[v12];
v14[v12] = v7;
*(_BYTE *)(a2 + k) ^= v14[(unsigned __int8)(v14[v10] + v14[v12])] ^ 0x25;
}
return __readfsqword(0x28u) ^ v15;
}
流量分析
那么现在只需要找到正确的key就可以对数据进行解密了。
右键追踪TCP流,
翻到流8就可以看到key是WangDingCUPKEY!!。
exp
from struct import unpack, pack
def rc4_main(key, message):
s_box = rc4_init_sbox(key)
crypt = rc4_excrypt(message, s_box)
return crypt
def rc4_init_sbox(key):
s_box = list(range(256))
j = 0
for i in range(256):
j = (j + s_box[i] + ord(key[(i % len(key))])) % 256
s_box[i], s_box[j] = s_box[j], s_box[i]
else:
return s_box
def rc4_excrypt(plain, box):
res = []
i = j = 0
for s in plain:
i = (i + 1) % 256
j = (j + box[i]) % 256
box[i], box[j] = box[j], box[i]
t = (box[i] + box[j]) % 256
k = box[t]
res.append(s ^ k ^ 0x25)
else:
return res
enc = [0x1D, 0x37, 0xD9, 0x5B, 0xF0, 0xA2, 0x32, 0xC6, 0x30, 0xA7, 0x8C, 0x50, 0x7E, 0x3E, 0xA7, 0x3A, 0xBA, 0xC0, 0x58, 0x6B, 0x81, 0x85, 0x6B, 0x1C, 0x4C, 0xF5, 0x80, 0x7C, 0x8A, 0xC1, 0x42, 0x97, 0x90, 0xC7]
key = 'WangDingCUPKEY!!'
print(bytes(rc4_main(key, enc)))
#flag{Welc0me_t0_7he_WangD1ng_CUP!}
python逆向分析
线下赛出pyarmor,无敌了,全场还有一个解,等待大牛解答。
0 条评论
可输入 255 字