第七届"湖湘杯"网络安全大赛 - 初赛writeup


Web

easywill

解题思路

湖湘杯-WriteUp
变量覆盖

http://eci-2zej1goyn9jh8hty6ton.cloudeci1.ichunqiu.com/?name=cfile&value=/etc/passwd

P神博客最近的文章利用pearcmd:https://tttang.com/archive/1312/

湖湘杯-WriteUp
湖湘杯-WriteUp
湖湘杯-WriteUp

Pentest in Autumn

解题思路
http://eci-2ze40jm526y24nv2lkl3.cloudeci1.ichunqiu.com:8888/ 权限绕过 /;/actuator/env /;/actuator/heapdump

湖湘杯-WriteUp

解密脚本

import base64
import struct

print(base64.b64encode(struct.pack('<bbbbbbbbbbbbbbbb', -126,-67,24,-71,-62,-122,61,-52,91,77,-110,115,-43,100,-88,103)))

#gr0YucKGPcxbTZJz1WSoZw==
湖湘杯-WriteUp

flag{3fa31850-8ee6-40f2-9b18-9ecf6cac176c}

Reverse

Hideit

解题思路

打开之后发现有SMC,单步调试总是找不到主函数

发现输出字符串,在puts下断点,第二次断下后回溯到主函数处,向上一直到函数头,反编译

__int64 __fastcall sub_24D61161BB0(__int64 a1)
{
  //...
  if ( !(unsigned int)off_24D61163000(-2147483646i64, aSoftwareClasse, &v24) )
  {
    v23 = 0;
    ((void (__fastcall *)(char *, _QWORD, __int64))unk_24D61162A0C)(v21, 0i64, 520i64);
    v22 = 66;
    if ( !(unsigned int)off_24D61163008(v24, aKeysSecret, 0i64, &v23, v21, &v22) )
      off_24D61163020(0i64, 0i64, v21, 0xFFFFFFFFi64, v14, 260, 0i64, 0i64);
  }
  off_24D611630F8(aFirstSecretHer);
  v10 = 0i64;
  v11 = 0;
  ((void (__fastcall *)(void *, __int64 *))unk_24D61161B50)(&unk_24D6116324C, &v10);
  v12 = 0i64;
  strcpy((char *)&v12, (const char *)&v10);
  v13[0] = 114;
  v13[1] = 514;
  v13[2] = 19;
  v13[3] = 19;
  ((void (__fastcall *)(char *, _QWORD, __int64))unk_24D61162A0C)(v20, 0i64, 512i64);
  v3 = HIDWORD(v12);
  v4 = 32;
  v5 = v12;
  v6 = HIDWORD(v12);
  v7 = 0;
  do
  {
    v7 -= 1640531527;
    v8 = (v7 >> 2) & 3;
    v5 += ((v7 ^ v3) + (v6 ^ v13[v8])) ^ (((16 * v6) ^ (v3 >> 3)) + ((v6 >> 5) ^ (4 * v3)));
    v3 += ((v7 ^ v5) + (v5 ^ v13[v8 ^ 1])) ^ (((16 * v5) ^ (v5 >> 3)) + ((v5 >> 5) ^ (4 * v5)));
    v6 = v3;
    --v4;
  }
  while ( v4 );
  if ( v5 == 288407067 && v3 == 1668576323 )
  {
    v17 = 0i64;
    v18 = (unsigned __int8)v10 | ((BYTE1(v10) | (WORD1(v10) << 8)) << 8);
    v19 = BYTE4(v10) | ((BYTE5(v10) | (HIWORD(v10) << 8)) << 8);
    ((void (__fastcall *)(_DWORD *, __int64))unk_24D61161000)(v16, a1);// 密钥扩展
    sub_24D61161150(v16, v14, v20); // 第二步加密
    while ( byte_24D611631D0[v2] == v20[v2] )
    {
      if ( ++v2 >= 32 )
        return off_24D611630F8(aYouFindLastSec);
    }
  }
  return 0i64;
}

先进行类tea加密,这8个字符合法的话再进行第二步加密 类tea加密解出字符串dotitsit,第二段加密如下

_DWORD *__fastcall sub_24D61161150(_DWORD *a1, __int128 *a2, _BYTE *a3)
{
  // ...
  if ( a2 )
  {
    v13 = (char *)a2 - (char *)&v122;
    v14 = &v122;
    do
    {
      *(_BYTE *)v14 = *((_BYTE *)v14 + v13);
      v14 = (__int128 *)((char *)v14 + 1);
      --v11;
    }
    while ( v11 );
    v127 = &v122;
  }
  // key operation
  while ( 1 )
  {
    // key operation
  }
  //...
  if ( v127 )
  {
// 在这里下断点,查看v76...的值就可以异或处原始数据
    v76 ^= *(unsigned __int8 *)v127 | ((*((unsigned __int8 *)v127 + 1) | (*((unsigned __int16 *)v127 + 1) << 8)) << 8);
    v77 ^= *((unsigned __int8 *)v127 + 4) | ((*((unsigned __int8 *)v127 + 5) | (*((unsigned __int16 *)v127 + 3) << 8)) << 8);
    v78 ^= *((unsigned __int8 *)v127 + 8) | ((*((unsigned __int8 *)v127 + 9) | (*((unsigned __int16 *)v127 + 5) << 8)) << 8);
    v79 ^= *((unsigned __int8 *)v127 + 12) | ((*((unsigned __int8 *)v127 + 13) | (*((unsigned __int16 *)v127 + 7) << 8)) << 8);
    v80 ^= *((unsigned __int8 *)v127 + 16) | ((*((unsigned __int8 *)v127 + 17) | (*((unsigned __int16 *)v127 + 9) << 8)) << 8);
    v129 ^= *((unsigned __int8 *)v127 + 20) | ((*((unsigned __int8 *)v127 + 21) | (*((unsigned __int16 *)v127 + 11) << 8)) << 8);
    LODWORD(v97) = (*((unsigned __int8 *)v127 + 24) | ((*((unsigned __int8 *)v127 + 25) | (*((unsigned __int16 *)v127
                                                                                           + 13) << 8)) << 8)) ^ v97;
    HIDWORD(v97) ^= *((unsigned __int8 *)v127 + 28) | ((*((unsigned __int8 *)v127 + 29) | (*((unsigned __int16 *)v127
                                                                                           + 15) << 8)) << 8);
    v81 ^= *((unsigned __int8 *)v127 + 32) | ((*((unsigned __int8 *)v127 + 33) | (*((unsigned __int16 *)v127 + 17) << 8)) << 8);
    v86 ^= *((unsigned __int8 *)v127 + 36) | ((*((unsigned __int8 *)v127 + 37) | (*((unsigned __int16 *)v127 + 19) << 8)) << 8);
    v87 ^= *((unsigned __int8 *)v127 + 44) | ((*((unsigned __int8 *)v127 + 45) | (*((unsigned __int16 *)v127 + 23) << 8)) << 8);
    v82 ^= *((unsigned __int8 *)v127 + 48) | ((*((unsigned __int8 *)v127 + 49) | (*((unsigned __int16 *)v127 + 25) << 8)) << 8);
    v83 ^= *((unsigned __int8 *)v127 + 52) | ((*((unsigned __int8 *)v127 + 53) | (*((unsigned __int16 *)v127 + 27) << 8)) << 8);
    v84 ^= *((unsigned __int8 *)v127 + 56) | ((*((unsigned __int8 *)v127 + 57) | (*((unsigned __int16 *)v127 + 29) << 8)) << 8);
    v85 ^= *((unsigned __int8 *)v127 + 60) | ((*((unsigned __int8 *)v127 + 61) | (*((unsigned __int16 *)v127 + 31) << 8)) << 8);
    v75 ^= *((unsigned __int8 *)v127 + 40) | ((*((unsigned __int8 *)v127 + 41) | (*((unsigned __int16 *)v127 + 21) << 8)) << 8);
  }
  // data copy
  do
  {
    *v90 = v90[(char *)&v122 - a3];
    ++v90;
    --v91;
  }
  while ( v91 );
  result = a1;
  a1[12] = v105;
  a1[13] = v100;
  return result;
}

这个函数看起来复杂,实际上就是把key进行很复杂的操作之后,和输入进行异或,所以只需要dump出key就可以得到flag

exp

#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <string.h>
#include "defs.h"
#include <stdint.h>

void decrypt(uint32_t *v)
{
    uint32_t v7, v8, v6, v5, v4, v3;
    v4 = 32;
    uint32_t v11[] = {114, 514, 19, 19};
    v7 = 0x9e3779b9 * 32;
    v5 = 0x1130BE1B;
    v3 = 0x63747443;

    do
    {
        v8 = (v7 >> 2) & 3;
        v3 -= ((v7 ^ v5) + (v5 ^ v11[v8 ^ 1])) ^ (((16 * v5) ^ (v5 >> 3)) + ((v5 >> 5) ^ (4 * v5)));
        v6 = v3;
        v5 -= ((v7 ^ v3) + (v6 ^ v11[v8])) ^ (((16 * v6) ^ (v3 >> 3)) + ((v6 >> 5) ^ (4 * v3)));
        --v4;
        v7 -= 0x9e3779b9;
    } while (v4);
    v[0] = v5;
    v[1] = v3;
}

int main()
{
    uint32_t k[] = {114, 514, 19, 19};
    uint8_t p[] = "12345678";
    uint32_t c[] = {288407067, 1668576323};
    decrypt(c);
    printf("%sn", c);
    for (size_t i = 0; i < 8; i++)
    {
        printf("0x%02x,", *(uint8_t *)&c[i]);
    }
    printf("n");
    char key[] = "expand 32-byte k0N3@aYI_M3l0dy_KurOm1_W_Suk1dqy0x01x00x00x00x00x00x00x00dotitsit";
    uint8_t data[] = {0xeb, 0x8e, 0x5c, 0xa5, 0x62, 0xb4, 0x1c, 0x84, 0x5c, 0x59, 0xfc, 0xd, 0x43, 0x3c, 0xab, 0x20, 0xd8, 0x93, 0x33, 0x13, 0xa1, 0x9e, 0x39, 0x0, 0x76, 0x14, 0xb5, 0x4, 0x58, 0x9d, 0x6, 0xb8};
    uint8_t res[128] = {0};
    uint32_t k0=0xC23DE28D;
    uint32_t *d=(uint32_t*)data;
    d[0]^=k0;
    d[1]^=0xca2df219;
    d[2]^=0x52cf1418;
    d[3]^=0x139c5a77;
    d[4]^=0x5b04ccaa;
    d[5]^=0x680cc192;
    d[6]^=0x47F95845;
    d[7]^=0xC535D968;
    printf("%sn",d);
}

shell

解题思路

main中创建了子进程,父子进程反调试 找到个dump 子进程的程序 https://github.com/glmcdona/Process-Dump

pd -pid <子进程pid>

其中子进程pid可以调试获得 ida打开dump后的子进程如下

.text:000001FA6C311160                 push    rsi
.text:000001FA6C311161                 push    rdi
.text:000001FA6C311162                 sub     rsp, 28h
.text:000001FA6C311166                 lea     rcx, Format     ; "plz input your flagn"
.text:000001FA6C31116D                 call    sub_1FA6C3112B0
.text:000001FA6C311172                 lea     rcx, a42s       ; "%42s"
.text:000001FA6C311179                 lea     rsi, known_string ; 这个就是0x40a0
.text:000001FA6C311180                 mov     rdx, rsi
.text:000001FA6C311183                 call    scanf
.text:000001FA6C311188                 int     3               ; Trap to Debugger
.text:000001FA6C311189 ; ---------------------------------------------------------------------------
.text:000001FA6C311189                 mov     rcx, rsi        ; Str
.text:000001FA6C31118C                 call    strlen
.text:000001FA6C311191                 cmp     rax, 0C9h
.text:000001FA6C311197                 jb      short near ptr unk_1FA6C31119E
.text:000001FA6C311199                 call    sub_1FA6C311020
.text:000001FA6C311199 ; ---------------------------------------------------------------------------
.text:000001FA6C31119E unk_1FA6C31119E db 0C4h                 ; CODE XREF: main+37↑j
.text:000001FA6C31119F                 db 12h

结合主进程中的调试函数

int __fastcall sub_7FF6C56B1560(_DWORD *a1)
{
  // ...
  if ( *a1 == 0x80000003 )
  {
    v5 = qword_7FF6C56B5630;
    if ( qword_7FF6C56B5630 )
    {
      Context.ContextFlags = 1048587;
      if ( !GetThreadContext(hThread, &Context) )
      {
        v6 = GetLastError();
        printf("GetThreadContext failed: %llxn", v6);
      }
      ReadProcessMemory(hProcess, (LPCVOID)(qword_7FF6C56B5638 + 0x40A0), v13, 0x2Aui64, &NumberOfBytesRead);
      v7 = _mm_load_si128((const __m128i *)&xmmword_7FF6C56B3420);
      for ( i = 0i64; i < 32; i += 16i64 )
        *(__m128i *)&v13[i] = _mm_xor_si128(_mm_loadu_si128((const __m128i *)&v13[i]), v7);
      for ( j = 32i64; j < 42; ++j )
        v13[j] ^= 0x78u;
      WriteProcessMemory(hProcess, (LPVOID)(qword_7FF6C56B5638 + 0x40A0), v13, 0x2Aui64, &NumberOfBytesRead);
      v5 = qword_7FF6C56B5630;
    }
    v1 = v5 + 1;
    qword_7FF6C56B5630 = v1;
    goto LABEL_21;
  }
  if ( (_DWORD)v1 == 0xC000001D )
  {
    Context.ContextFlags = 1048587;
    if ( !GetThreadContext(hThread, &Context) )
    {
      v2 = GetLastError();
      printf("GetThreadContext failed: %llxn", v2);
    }
    ReadProcessMemory(hProcess, (LPCVOID)(Context.Rip + 1), Buffer, 1ui64, &NumberOfBytesRead);
    if ( Buffer[0] == 0x12 )
    {
      v3 = qword_7FF6C56B5638 + 0x1035;
    }
    else
    {
      if ( Buffer[0] != 0x48 )
        goto LABEL_10;
      v3 = qword_7FF6C56B5638 + 0x1242;
    }
    Context.Rip = v3;
LABEL_10:
    LODWORD(v1) = SetThreadContext(hThread, &Context);
    if ( !(_DWORD)v1 )
    {
      v4 = GetLastError();
      LODWORD(v1) = printf("SetThreadContext failed: %llxn", v4);
    }
LABEL_21:
    *(_QWORD *)&dwContinueStatus = 65537i64;
  }
  return v1;
}

可以得到替换了三处 1.用户的输入都异或0x78 2.如果遇到未知指令且指令下一个字节是0x12就去0x1035文件偏移 3.如果遇到未知指令且指令下一字节是0x48就去0x1242文件偏移 此时再看子进程主函数,可以得到流程

0x1035文件偏移为

.text:000001FA6C311035                 mov     [rsp+arg_28], 0
.text:000001FA6C31103D
.text:000001FA6C31103D loc_1FA6C31103D:                        ; CODE XREF: sub_1FA6C311020+A5↓j
.text:000001FA6C31103D                 cmp     [rsp+arg_28], 2Ah ; '*'
.text:000001FA6C311042                 jge     near ptr unk_1FA6C3110CA
.text:000001FA6C311048                 movsxd  rax, [rsp+arg_28]
.text:000001FA6C31104D                 lea     rcx, known_string
.text:000001FA6C311054                 mov     al, [rcx+rax]
.text:000001FA6C311057                 mov     [rsp+arg_25], al
.text:000001FA6C31105B                 mov     eax, [rsp+arg_28]
.text:000001FA6C31105F                 mov     [rsp+arg_24], al
.text:000001FA6C311063                 movzx   eax, [rsp+arg_25]
.text:000001FA6C311068                 movzx   ecx, [rsp+arg_24]
.text:000001FA6C31106D                 and     eax, ecx
.text:000001FA6C31106F                 xor     eax, 0FFFFFFFFh
.text:000001FA6C311072                 mov     [rsp+arg_23], al
.text:000001FA6C311076                 movzx   eax, [rsp+arg_23]
.text:000001FA6C31107B                 movzx   ecx, [rsp+arg_25]
.text:000001FA6C311080                 and     eax, ecx
.text:000001FA6C311082                 xor     eax, 0FFFFFFFFh
.text:000001FA6C311085                 mov     [rsp+arg_27], al
.text:000001FA6C311089                 movzx   eax, [rsp+arg_23]
.text:000001FA6C31108E                 movzx   ecx, [rsp+arg_24]
.text:000001FA6C311093                 and     eax, ecx
.text:000001FA6C311095                 xor     eax, 0FFFFFFFFh
.text:000001FA6C311098                 mov     [rsp+arg_26], al
.text:000001FA6C31109C                 movzx   eax, [rsp+arg_27]
.text:000001FA6C3110A1                 movzx   ecx, [rsp+arg_26]
.text:000001FA6C3110A6                 and     eax, ecx
.text:000001FA6C3110A8                 xor     eax, 0FFFFFFFFh
.text:000001FA6C3110AB                 movsxd  rcx, [rsp+arg_28]
.text:000001FA6C3110B0                 lea     rdx, known_string
.text:000001FA6C3110B7                 mov     [rdx+rcx], al
.text:000001FA6C3110BA                 mov     eax, [rsp+arg_28]
.text:000001FA6C3110BE                 add     eax, 1
.text:000001FA6C3110C1                 mov     [rsp+arg_28], eax
.text:000001FA6C3110C5                 jmp     loc_1FA6C31103D
.text:000001FA6C3110C5 ; ---------------------------------------------------------------------------
.text:000001FA6C3110CA unk_1FA6C3110CA db 0C4h                 ; CODE XREF: sub_1FA6C311020+22↑j
.text:000001FA6C3110CB                 db 48h
接下来是0x1242
.text:000001FA6C311242                 mov     eax, 2
.text:000001FA6C311247                 lea     rcx, unk_1FA6C314030
.text:000001FA6C31124E                 xchg    ax, ax
.text:000001FA6C311250
.text:000001FA6C311250 loc_1FA6C311250:                        ; CODE XREF: main+117↓j
.text:000001FA6C311250                 movzx   edx, byte ptr [rax+rsi-2]
.text:000001FA6C311255                 cmp     dl, [rax+rcx-2]
.text:000001FA6C311259                 jnz     short loc_1FA6C31128E
.text:000001FA6C31125B                 movzx   edx, byte ptr [rax+rsi-1]
.text:000001FA6C311260                 cmp     dl, [rax+rcx-1]
.text:000001FA6C311264                 jnz     short loc_1FA6C31128E
.text:000001FA6C311266                 movzx   edx, byte ptr [rax+rsi]
.text:000001FA6C31126A                 cmp     dl, [rax+rcx]
.text:000001FA6C31126D                 jnz     short loc_1FA6C31128E
.text:000001FA6C31126F                 add     rax, 3
.text:000001FA6C311273                 cmp     rax, 2Ch ; ','
.text:000001FA6C311277                 jnz     short loc_1FA6C311250
.text:000001FA6C311279                 lea     rcx, aWin       ; "winn"
.text:000001FA6C311280                 call    sub_1FA6C3112B0
.text:000001FA6C311285                 xor     eax, eax
.text:000001FA6C311287                 add     rsp, 28h
.text:000001FA6C31128B                 pop     rdi
.text:000001FA6C31128C                 pop     rsi
.text:000001FA6C31128D                 retn
.text:000001FA6C31128E ; ---------------------------------------------------------------------------
.text:000001FA6C31128E
.text:000001FA6C31128E loc_1FA6C31128E:                        ; CODE XREF: main+F9↑j
.text:000001FA6C31128E                                         ; main+104↑j ...
.text:000001FA6C31128E                 lea     rcx, aWrong     ; "wrongn"
.text:000001FA6C311295                 call    sub_1FA6C3112B0
.text:000001FA6C31129A                 call    cs:getchar
.text:000001FA6C3112A0                 xor     ecx, ecx        ; Code
.text:000001FA6C3112A2                 call    cs:__imp_exit
.text:000001FA6C3112A2 ; ---------------------------------------------------------------------------
.text:000001FA6C3112A8                 db 0CCh
.text:000001FA6C3112A8 main            endp

用户输入先异或0x78,再异或数组下标 exp

a=[0x1e, 0x15, 0x1b, 0x1c, 0x7, 0x4d, 0x1f, 0x1b, 0x12, 0x17, 0x4b, 0x44, 0x47, 0x58, 0x12, 0x47, 0x58, 0x58, 0x47, 0x5f, 0x54, 0x54, 0x5
8, 0x42, 0x59, 0x57, 0x50, 0x1, 0x49, 0x51, 0x53, 0x57, 0x3d, 0x6b, 0x3e, 0x6f, 0x3d, 0x6d, 0x6c, 0x3e, 0x69, 0x2c, 0x0, 0x0, 0x0]        
b=[a[i]^i^0x78 
for i in range(len(a))]
print(bytes(b))
posted @ 2021-12-22 17:23  渗透测试中心  阅读(408)  评论(0编辑  收藏  举报