(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
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
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
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
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
svchost.exe 1.tmp 0x0 1
1
2
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
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
svchost.exe pid: 3828
Virtual Physical Size DumpFileOffset
---------- ---------- ---------- --------------
0x000d0000 0x09c95000 0x1000 0x13000
쉘코드는 찾아냈는데… 쉘코드에 bp걸고 실행하면 에러나면서 디버거가 꺼져버린다. bp안걸고 그냥 실행하면 잘 됨. 아마 스레드로 넘어가면서 뭔가 에러가 발생하는 것 같다. 쉘코드 보면 스택에 0x50
만큼 뭔가를 또 쓰는 것을 볼 수 있는데, 여기에 90
이나 c3
, e8
등등이 포함되어 있어 이게 또 쉘코드인 줄 알았다. 그러나다음 두 가지를 생각해보면 이걸 실행하는게 아니다.
- 스택에 실행권한이 없기 때문에 이걸 실행하려면 다시 권한을 조정해야 한다는 점
- instruction으로 해석되는 부분이 있기는 하지만 전체적으로 뭔가 이상하다는 점 그래서 쉘코드를 분석해봐야 답이 나오는데, 정적으로는 굉장히 오래걸리고 답이 없을 것 같아서 어떻게든 쉘코드를 실행해봐야 한다. bp걸고 실행하면 디버거가 꺼져버리니까, 그냥 디버거에서 아무 instruction이나 골라서
jmp 0x1d0000
으로 패칭했다. 하나 하나 따라가다 보니까, 몇 가지 연산을 거쳐eax
에 flag가 한 글자 씩 찍혔다. 결국 스택에 썼던 데이터는 쉘코드가 아니라 난독화, 암호화된 데이터였음.
TMCTF{static_analyzer}