网鼎杯-半决赛-青龙组-逆向安全
想成为安卓高手 发表于 湖北 CTF 118浏览 · 2024-11-24 11:39

附件太大上传不了,
这里给个百度网盘链接:附件

网络通信流量分析

给了三个附件,一个流量一个客户端和一个服务端。


先看服务端和客户端

客户端

__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