Post

(Trend Micro CTF 2017) Forensic

100 - DNSTunnel

DNS query날릴 때 url 앞에 data를 붙여 전송하는 방식으로 조금 씩 데이터를 전송하는 듯. 20byte인걸로 봐서 sha1 인 것 같다. decode해봐야… 안된다. 마지막만 길이가 다른 것도 이상하고… 뭘까?

생각해보니 hash는 아닌 것 같은게 수신 측에서 데이터를 받아 해독해야하는데 hash를 쓸리가 없다.

분명 encryption한걸거고, encryption한걸 잘라서 보냈거나, 조금 씩 encryption해서 보냈을 것 같은데… 후자?가 맞지 않을까?

DES를 비롯해서 몇몇개 알고리즘에 Key를 gzpgs.trendmicro.co.jp로도 해보고 gzpgs로도 해봤는데 안된다. gzpgs는 ceasar cipher 해독하면 tmctf가 나와서 이것도 해봤는데 안된다. * 풀고나서 보니 gzpgs -> tmctf는 풀이와 관련이 없다.

DES는 확실히 아닌게, encrypt하면 특수문자가 등장한다.

encryption 결과가 알파벳과 숫자로만 이루어진 암호화 알고리즘을 찾아야한다.

분명 url로 전송해야 하니까 URL에 들어갈 수 있는 charset만 output으로 나오는걸 선택했을건데… 아니면 encode하거나…

힌트가 base64가 아니라 another base다 라고 적혀있길래,base58로 디코딩 해봤더니 답이 나왔다.

생각해보면 해커 입장에서 victim의 data를 전송받는데 굳이 암호화해서 전송할 필요가 있나 싶다.

인코딩 결과가 알파벳과 숫자로만 이루어진 encoding 방식을 찾는게 답이었음.

TMCTF{DNSTunnelExfil}

200

7z pw는 novirus .img파일인데, vmware에 올려도 되겠지만 일단 볼라틸리티 돌려봤다. pslist 등에는 별 내용이 없는 것 같았고, dlllist에서는

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
explorer.exe pid:    940
Command line : C:\Windows\Explorer.EXE
Service Pack 1

  

Base             Size  LoadCount Path
---------- ---------- ---------- ----
0x00a60000   0x281000     0xffff C:\Windows\Explorer.EXE
...
0x6e490000    0x58000        0x1 C:\Program Files\Common Files\microsoft shared\ink\tiptsf.dll
0x736e0000     0x8000        0x1 C:\Windows\ehome\ehSSO.dll
...

  

svchost.exe pid:   3828
Command line : svchost.exe  1.tmp 0x0 1
Service Pack 1

  

Base             Size  LoadCount Path
---------- ---------- ---------- ----
0x00ed0000     0x6000     0xffff C:\Users\Taro\AppData\Local\Temp\svchost.exe

explorer.exe는 아닌 것 같긴 한데 한 번 확인해볼 필요는 있을 듯. svchost.exe는 좀 많이 의심스럽다. 그래서 dlldump 했다.

1
2
3
4
5
6
7
8
Process(V) Name                 Module Base Module Name          Result
---------- -------------------- ----------- -------------------- ------
0x88abfa78 svchost.exe          0x000ed0000 svchost.exe          OK: module.3828.a269a78.ed0000.dll
0x88abfa78 svchost.exe          0x077560000 ntdll.dll            OK: module.3828.a269a78.77560000.dll
0x88abfa78 svchost.exe          0x06ac10000 MSVCR120.dll         OK: module.3828.a269a78.6ac10000.dll
0x88abfa78 svchost.exe          0x076080000 kernel32.dll         OK: module.3828.a269a78.76080000.dll
0x88abfa78 svchost.exe          0x075730000 KERNELBASE.dll       OK: module.3828.a269a78.75730000.dll

IDA로 열어보니까, 역시나. 이거였다.

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
int \_\_cdecl main(int argc, const char \*\*argv, const char \*\*envp)
{
const char \*v3; // esi@4
void \*v4; // esi@4
int result; // eax@5
DWORD (\_\_stdcall \*v6)(LPVOID); // esi@6
HANDLE v7; // esi@8
DWORD ThreadId; // [sp+Ch] [bp-2728h]@8
FILE \*File; // [sp+10h] [bp-2724h]@4
size\_t Size; // [sp+14h] [bp-2720h]@4
int v11; // [sp+18h] [bp-271Ch]@6
int v12; // [sp+1Ch] [bp-2718h]@4
char DstBuf; // [sp+20h] [bp-2714h]@4

  

if ( argc < 4 )
{
printf("usage: this.exe <input file> <offset> <isLongSleep>\n");
printf("offset eg) 0xFFFF\n");
exit(0);
}
v3 = argv[1];
printf("file name is %s\n", argv[1]);
sscanf(argv[2], "%x", &v12);
printf("offset is %x\n", v12);
File = fopen(v3, "rb");
Size = fread(&DstBuf, 1u, 0x2710u, File);
v4 = VirtualAlloc(0, Size, 0x3000u, 0x40u);    // 0x40은 rwx
if ( v4 )
{
memmove(v4, &DstBuf, Size);
v6 = (DWORD (\_\_stdcall \*)(LPVOID))((char \*)v4 + v12);    // 아마 entry\_point인 듯.
sscanf(argv[3], "%d", &v11);
if ( v11 == 1 )
Sleep(100000u);
v7 = CreateThread(0, 0, v6, 0, 0, &ThreadId);    // Thread를 만들고 entry\_point를 실행.
if ( v7 )
{
printf("Createthread successful!");
WaitForSingleObject(v7, 0xFFFFFFFF);
fclose(File);
result = 0;
}
else
{
printf("CreateThread failed. Error");
result = 1;
}
}
else
{
printf("VirtualAlloc failed. Error");
result = 1;
}
return result;
}

파일을 읽어와서 꽤 오래 대기하고 있다가 Thread를 생성하는 프로그램이었다. 이걸로 뭘 실행하려고 했던건지를 알아내야 한다. 파일 핸들을 가지고 있을 것 같아서 handles 조회해봤다.

1
2
3
4
5
6
7
8
9
10
11
12
Offset(V)     Pid     Handle     Access Type             Details
---------- ------ ---------- ---------- ---------------- -------
0x8db9f5e0   3828        0x4        0x3 Directory        KnownDlls
0x869342c0   3828        0x8   0x100020 File             \Device\HarddiskVolume1\Users\Taro\AppData\Local\Temp
0x89b6b420   3828        0xc   0x1f0003 Event
0x88baf038   3828       0x10   0x1f0001 ALPC Port
0x869e9d98   3828       0x14   0x1f0001 ALPC Port
0x9540c300   3828       0x18    0x20019 Key              MACHINE\SYSTEM\CONTROLSET001\CONTROL\NLS\SORTING\VERS
IONS
0x88bb47c0   3828       0x1c   0x120089 File             \Device\HarddiskVolume1\Users\Taro\AppData\Local\Temp
\1.tmp

마지막에 있는 1.tmp가 의심스러운데… 역시 hxd로 찾아보니 이렇게 실행한 것 같다. 또는 그냥 cmdline을 실행해봐도 된다.

1
2
3
svchost.exe 1.tmp 0x0 1

1
2
3
svchost.exe pid:   3828
Command line : svchost.exe  1.tmp 0x0 1

file handle을 가지고 있는 상태라는건 thread를 생성하기 이전 sleep()에 걸려있는 상태였다는 소리다. 일단 VirtualAlloc()으로 메모리에 파일을 올린 다음에 실행하니까, 프로세스의 메모리에 실행한 파일이 남아있을 것 같다.

Thread로 실행한다는건 1.tmp가 실행 파일일 가능성이 아주 크기 때문에 , memdump에서 MZ로 검색해서 실행파일을 추출해보려고 했으나 같이 로딩된 dll들도 검색되기 때문에 귀찮고 오래걸릴 것 같아서 포기.

잘 포기한게, 1.tmp는 실행파일이 아니라 그냥 raw shellcode였다. 위에서 인자로 넘긴 offset이 0x0이라는 점에서 눈치 챌 수 있음. 아무튼 이런 식으로 실행 파일이라고 단정하게 되면 멀리 돌아가게 된다.

대신 malfind를 해봤더니 다음과 같은 쉘코드가 보인다.

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
Process: svchost.exe Pid: 3828 Address: 0xd0000
Vad Tag: VadS Protection: PAGE\_EXECUTE\_READWRITE
Flags: CommitCharge: 1, MemCommit: 1, PrivateMemory: 1, Protection: 6

  

0x000d0000  90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90   ................
0x000d0010  55 89 e5 83 ec 60 c6 45 da a8 c6 45 db ff c6 45   U....`.E...E...E
0x000d0020  dc 88 c6 45 dd d0 c6 45 de b2 c6 45 df f6 c6 45   ...E...E...E...E
0x000d0030  e0 f8 c6 45 e1 ea c6 45 e2 ff c6 45 e3 ff c6 45   ...E...E...E...E

  

0x000d0000 90               NOP
0x000d0001 90               NOP
0x000d0002 90               NOP
...
0x000d0010 55               PUSH EBP
0x000d0011 89e5             MOV EBP, ESP
0x000d0013 83ec60           SUB ESP, 0x60
0x000d0016 c645daa8         MOV BYTE [EBP-0x26], 0xa8
0x000d001a c645dbff         MOV BYTE [EBP-0x25], 0xff
0x000d001e c645dc88         MOV BYTE [EBP-0x24], 0x88
...

잘려서 끝까지 안보이는데, 아무튼 VirtualAddress 0x000d0000에 있다는거니까, memmap으로 DumpFileOffset을 출력해 대조해 보면 DumpFile에서 어디에 위치해있는지 찾아낼 수 있다.

1
2
3
4
5
svchost.exe pid:   3828
Virtual    Physical         Size DumpFileOffset
---------- ---------- ---------- --------------
0x000d0000 0x09c95000     0x1000        0x13000

쉘코드는 찾아냈는데… 쉘코드에 bp걸고 실행하면 에러나면서 디버거가 꺼져버린다. bp안걸고 그냥 실행하면 잘 됨. 아마 스레드로 넘어가면서 뭔가 에러가 발생하는 것 같다. 쉘코드 보면 스택에 0x50만큼 뭔가를 또 쓰는 것을 볼 수 있는데, 여기에 90이나 c3, e8 등등이 포함되어 있어 이게 또 쉘코드인 줄 알았다.그러나다음 두 가지를 생각해보면 이걸 실행하는게 아니다.

  1. 스택에 실행권한이 없기 때문에 이걸 실행하려면 다시 권한을 조정해야 한다는 점
  2. instruction으로 해석되는 부분이 있기는 하지만 전체적으로 뭔가 이상하다는 점 그래서 쉘코드를 분석해봐야 답이 나오는데, 정적으로는 굉장히 오래걸리고 답이 없을 것 같아서 어떻게든 쉘코드를 실행해봐야 한다. bp걸고 실행하면 디버거가 꺼져버리니까, 그냥 디버거에서 아무 instruction이나 골라서 jmp 0x1d0000으로 패칭했다. 하나 하나 따라가다 보니까, 몇 가지 연산을 거쳐 eax에 flag가 한 글자 씩 찍혔다. 결국 스택에 썼던 데이터는 쉘코드가 아니라 난독화, 암호화된 데이터였음.

TMCTF{static_analyzer}

This post is licensed under CC BY 4.0 by the author.