Overview:
As a community volunteer @Winja I created reverse engineering ctf challenges for Wicked 6 Winja CTF for Women. Without wasting further time let’s jump in!
d3bug-th1s
Challenge Name: d3bug-th1s
Category: Reverse Engineering
Challenge Description: The space station provides a nice environment for enthusiasts to discover their potential. You are given a linux executable which says “segmentation fault” on running can you find out what the binary is doing and get the flag.
Solution
Analyze the binary using gdb
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
gdb-peda ./space
Reading symbols from ./space...
(No debugging symbols found in ./space)
gdb-peda$ info functions
All defined functions:
Non-debugging symbols:
0x0000000000001000 _init
0x0000000000001090 __cxa_finalize@plt
0x00000000000010a0 getenv@plt
0x00000000000010b0 strncmp@plt
0x00000000000010c0 puts@plt
0x00000000000010d0 __stack_chk_fail@plt
0x00000000000010e0 printf@plt
0x00000000000010f0 strcat@plt
0x0000000000001100 _start
0x0000000000001130 deregister_tm_clones
0x0000000000001160 register_tm_clones
0x00000000000011a0 __do_global_dtors_aux
0x00000000000011e0 frame_dummy
0x00000000000011e9 banner
0x0000000000001205 main
0x0000000000001340 __libc_csu_init
0x00000000000013b0 __libc_csu_fini
0x00000000000013b8 _fini
gdb-peda$
Let’s have a look at the disassembly of the main function
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
gdb-peda$ disassemble main
Dump of assembler code for function main:
0x0000000000001205 <+0>: endbr64
0x0000000000001209 <+4>: push rbp
0x000000000000120a <+5>: mov rbp,rsp
0x000000000000120d <+8>: sub rsp,0x40
0x0000000000001211 <+12>: mov rax,QWORD PTR fs:0x28
0x000000000000121a <+21>: mov QWORD PTR [rbp-0x8],rax
0x000000000000121e <+25>: xor eax,eax
0x0000000000001220 <+27>: mov eax,0x0
0x0000000000001225 <+32>: call 0x11e9 <banner>
0x000000000000122a <+37>: lea rdi,[rip+0x1212] # 0x2443
0x0000000000001231 <+44>: call 0x10a0 <getenv@plt>
0x0000000000001236 <+49>: mov QWORD PTR [rbp-0x30],rax
0x000000000000123a <+53>: mov WORD PTR [rbp-0x22],0x6d
0x0000000000001240 <+59>: mov WORD PTR [rbp-0x20],0x78
0x0000000000001246 <+65>: mov WORD PTR [rbp-0x1e],0x61
0x000000000000124c <+71>: mov WORD PTR [rbp-0x1c],0x71
0x0000000000001252 <+77>: mov WORD PTR [rbp-0x1a],0x72
0x0000000000001258 <+83>: mov WORD PTR [rbp-0x18],0x6a
0x000000000000125e <+89>: mov WORD PTR [rbp-0x16],0x73
0x0000000000001264 <+95>: mov WORD PTR [rbp-0x14],0x74
0x000000000000126a <+101>: mov WORD PTR [rbp-0x12],0x75
0x0000000000001270 <+107>: mov WORD PTR [rbp-0x10],0x76
0x0000000000001276 <+113>: mov WORD PTR [rbp-0xe],0x77
0x000000000000127c <+119>: mov WORD PTR [rbp-0xc],0x78
0x0000000000001282 <+125>: mov WORD PTR [rbp-0xa],0x79
0x0000000000001288 <+131>: mov BYTE PTR [rbp-0x23],0x0
0x000000000000128c <+135>: lea rdx,[rbp-0x22]
0x0000000000001290 <+139>: lea rax,[rbp-0x23]
0x0000000000001294 <+143>: mov rsi,rdx
0x0000000000001297 <+146>: mov rdi,rax
0x000000000000129a <+149>: call 0x10f0 <strcat@plt>
We see there is a call to getenv function, that’s interesting the binary is looking for an environment variable. Let’s set a break point at the main function and then run step by step in gdb.
1
2
3
4
gdb-peda$ b * main
Breakpoint 1 at 0x1205
gdb-peda$ r
Now single step forward till we reach the call to getenv
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
gdb-peda$ ni
[----------------------------------registers-----------------------------------]
RSI: 0x555555556442 --> 0x74656e616c7000 ('')
RDI: 0x555555556443 --> 0xa0074656e616c70 ('planet')
RBP: 0x7fffffffdec0 --> 0x0
RSP: 0x7fffffffde80 --> 0x7fffffffdea6 --> 0x5555555551000000 ('')
RIP: 0x555555555231 (<main+44>: call 0x5555555550a0 <getenv@plt>)
R8 : 0x400
R9 : 0x43a
R10: 0x7ffff7faabe0 --> 0x5555555596a0 --> 0x0
R11: 0x246
R12: 0x555555555100 (<_start>: endbr64)
R13: 0x7fffffffdfb0 --> 0x1
R14: 0x0
R15: 0x0
EFLAGS: 0x202 (carry parity adjust zero sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
0x555555555220 <main+27>: mov eax,0x0
0x555555555225 <main+32>: call 0x5555555551e9 <banner>
0x55555555522a <main+37>: lea rdi,[rip+0x1212] # 0x555555556443
=> 0x555555555231 <main+44>: call 0x5555555550a0 <getenv@plt>
0x555555555236 <main+49>: mov QWORD PTR [rbp-0x30],rax
0x55555555523a <main+53>: mov WORD PTR [rbp-0x22],0x6d
0x555555555240 <main+59>: mov WORD PTR [rbp-0x20],0x78
0x555555555246 <main+65>: mov WORD PTR [rbp-0x1e],0x61
Guessed arguments:
arg[0]: 0x555555556443 --> 0xa0074656e616c70 ('planet')
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffde80 --> 0x7fffffffdea6 --> 0x5555555551000000 ('')
0008| 0x7fffffffde88 --> 0x55555555538d (<__libc_csu_init+77>: add rbx,0x1)
0016| 0x7fffffffde90 --> 0x7ffff7faf2e8 --> 0x0
0024| 0x7fffffffde98 --> 0x555555555340 (<__libc_csu_init>: endbr64)
0032| 0x7fffffffdea0 --> 0x0
0040| 0x7fffffffdea8 --> 0x555555555100 (<_start>: endbr64)
0048| 0x7fffffffdeb0 --> 0x7fffffffdfb0 --> 0x1
0056| 0x7fffffffdeb8 --> 0xd934b04a72b2e000
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
0x0000555555555231 in main ()
gdb-peda$
It looks like the binary is looking for an environment variable called planet.
Let’s continue executing one machine instruction at a time.
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
[----------------------------------registers-----------------------------------]
RAX: 0x0
RBX: 0x555555555340 (<__libc_csu_init>: endbr64)
RCX: 0x7fffffffde9d --> 0x710061007372616d ('mars')
RDX: 0x73 ('s')
RSI: 0x7fffffffdeaa --> 0x76007500740073 ('s')
RDI: 0x7fffffffdea0 --> 0x72007100610073 ('s')
RBP: 0x7fffffffdec0 --> 0x0
RSP: 0x7fffffffde80 --> 0x7fffffffdea6 --> 0x740073006a0072 ('r')
RIP: 0x5555555552e0 (<main+219>: mov edx,0x6)
R8 : 0x400
R9 : 0x7fffffffde9d --> 0x710061007372616d ('mars')
R10: 0x7ffff7faabe0 --> 0x5555555596a0 --> 0x0
R11: 0x246
R12: 0x555555555100 (<_start>: endbr64)
R13: 0x7fffffffdfb0 --> 0x1
R14: 0x0
R15: 0x0
EFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
0x5555555552d3 <main+206>: call 0x5555555550f0 <strcat@plt>
0x5555555552d8 <main+211>: lea rcx,[rbp-0x23]
0x5555555552dc <main+215>: mov rax,QWORD PTR [rbp-0x30]
=> 0x5555555552e0 <main+219>: mov edx,0x6
0x5555555552e5 <main+224>: mov rsi,rcx
0x5555555552e8 <main+227>: mov rdi,rax
0x5555555552eb <main+230>: call 0x5555555550b0 <strncmp@plt>
0x5555555552f0 <main+235>: mov DWORD PTR [rbp-0x34],eax
[------------------------------------stack-------------------------------------]
A bunch of calls to strcat and a string “mars” has been formed, let’s give it a shot!
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
sid@sid-Inspiron-5547:~/Documents/WinjaCTF_Wicked6/d3bug-th1s!$ export planet=mars
sid@sid-Inspiron-5547:~/Documents/WinjaCTF_Wicked6/d3bug-th1s!$ ./space
/\/\/\ / \
| \ / | / \
| \/ | / \
| /\ |----------------------| /\ |
| / \ | | / \ |
|/ \| | / \ |
|\ /| | | ( ) | |
| \ / | | | ( ) | |
| \/ | /\ | | | | /\
| /\ | / \ | | | | / \
| / \ | |----| | | | | |----|
|/ \|---------------| | | /| . |\ | | |
|\ /| | | / | . | \ | |
| \ / | | / | . | \ |
| \/ | | / | . | \ |
| /\ |---------------|/ | . | \|
| / \ | / CTF | . | CTF \
|/ \| ( | | )
|/\/\/\| | | |--| |--| | |
------------------------/ \-----/ \/ \-----/ \--------
\\// \\//\\// \\//
\/ \/ \/ \/
flag{off_to_mars_2022}
We got the flag!!
Unreachable
Challenge: Unreachable
Category: Reverse Engineering
Description: Our engineers said that it was impossible to reach the flag printing function for this program, can you do the impossible? reach the unreachable?
Solution
On analyzing the binary we find that our input’s length is being compared to 5 and 7 and we can not have an input which can be of length 5 and 7 at the same time so, we can either patch the binary using IDA or simply set the instruction pointer to the give flag function using gdb.
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
gdb-peda ./a.out
Reading symbols from ./a.out...
(No debugging symbols found in ./a.out)
gdb-peda$ info functions
All defined functions:
Non-debugging symbols:
0x0000000000001000 _init
0x0000000000001090 __cxa_finalize@plt
0x00000000000010a0 putchar@plt
0x00000000000010b0 puts@plt
0x00000000000010c0 strlen@plt
0x00000000000010d0 __stack_chk_fail@plt
0x00000000000010e0 printf@plt
0x00000000000010f0 exit@plt
0x0000000000001100 _start
0x0000000000001130 deregister_tm_clones
0x0000000000001160 register_tm_clones
0x00000000000011a0 __do_global_dtors_aux
0x00000000000011e0 frame_dummy
0x00000000000011e9 giveflag
0x0000000000001299 main
0x0000000000001340 __libc_csu_init
0x00000000000013b0 __libc_csu_fini
0x00000000000013b8 _fini
gdb-peda$ b * main
Breakpoint 1 at 0x1299
gdb-peda$ r
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
gdb-peda$ info functions
File xpg_basename.c:
25: char *__xpg_basename(char *);
Non-debugging symbols:
0x0000555555555000 _init
0x0000555555555090 __cxa_finalize@plt
0x00005555555550a0 putchar@plt
0x00005555555550b0 puts@plt
0x00005555555550c0 strlen@plt
0x00005555555550d0 __stack_chk_fail@plt
0x00005555555550e0 printf@plt
0x00005555555550f0 exit@plt
0x0000555555555100 _start
0x0000555555555130 deregister_tm_clones
0x0000555555555160 register_tm_clones
0x00005555555551a0 __do_global_dtors_aux
0x00005555555551e0 frame_dummy
0x00005555555551e9 giveflag
Now we will set the instruction pointer $rip to point to the giveflag function.
1
2
3
4
5
6
gdb-peda$ set $rip=0x00005555555551e9
gdb-peda$ c
Continuing.
flag{0h_s0_y0u_kN0w_P4tch1ng}[Inferior 1 (process 10177) exited normally]
Warning: not running
gdb-peda$
easy-rev
Challenge Name : Easy-Rev
Category : Reverse Engineering
Description: you are given a 64 bit linux executable named easy-rev.out execute it on your linux systems using ./easy-rev.out. It asks for 3 passwords if you give the correct passwords the flag will be printed.
Flag format: flag{some_thing_here}
Solution
On analyzing the bianry with radare2 we can clearly see that the binary will ask for 3 passwords and if we give the correct passwords we will get the flag.
Let’s use the “aa” command to analyze the binary and use “afl” to list all the functions in the disassembly.
1
2
3
4
5
6
7
8
9
10
11
12
13
➜ easy-rev r2 easy-rev.out
[0x00001070]> aa
[x] Analyze all flags starting with sym. and entry0 (aa)
[0x00001070]> afl
0x00001070 1 42 entry0
0x00001030 1 6 sym.imp.strncmp
0x00001040 1 6 sym.imp.printf
0x00001050 1 6 sym.imp.__isoc99_scanf
0x00001155 8 298 main
0x00001150 5 133 -> 56 entry.init0
0x00001110 5 57 -> 50 entry.fini0
0x000010a0 4 41 -> 34 fcn.000010a0
[0x00001070]>
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
; DATA XREF from entry0 @ 0x108d
/ 298: int main (int argc, char **argv, char **envp);
| ; var int64_t var_1ch @ rbp-0x1c
| ; var int64_t var_18h @ rbp-0x18
| ; var int64_t var_12h @ rbp-0x12
| ; var int64_t var_ah @ rbp-0xa
| ; var int64_t var_6h @ rbp-0x6
| ; var int64_t var_4h @ rbp-0x4
| 0x00001155 55 push rbp
| 0x00001156 4889e5 mov rbp, rsp
| 0x00001159 4883ec20 sub rsp, 0x20
| 0x0000115d c745f6000000. mov dword [var_ah], 0
| 0x00001164 66c745fa0000 mov word [var_6h], 0
| 0x0000116a 48b872616461. movabs rax, 0x32657261646172 ; 'radare2'
| 0x00001174 488945ee mov qword [var_12h], rax
| 0x00001178 488d3d890e00. lea rdi, qword str.Enter_the_first_password ; 0x2008 ; "Enter the first password => "
| 0x0000117f b800000000 mov eax, 0
| 0x00001184 e8b7feffff call sym.imp.printf ; int printf(const char *format)
| 0x00001189 488d45f6 lea rax, qword [var_ah]
| 0x0000118d 4889c6 mov rsi, rax
| 0x00001190 488d3d8e0e00. lea rdi, qword [0x00002025] ; "%s"
| 0x00001197 b800000000 mov eax, 0
| 0x0000119c e8affeffff call sym.imp.__isoc99_scanf ; int scanf(const char *format)
| 0x000011a1 488d55ee lea rdx, qword [var_12h]
| 0x000011a5 488d45f6 lea rax, qword [var_ah]
| 0x000011a9 4889d6 mov rsi, rdx
| 0x000011ac 4889c7 mov rdi, rax
| 0x000011af e87cfeffff call sym.imp.strncmp ; int strncmp(const char *s1, const char *s2, size_t n)
| 0x000011b4 8945fc mov dword [var_4h], eax
| 0x000011b7 837dfc00 cmp dword [var_4h], 0
| ,=< 0x000011bb 0f85aa000000 jne 0x126b
| | 0x000011c1 488d3d600e00. lea rdi, qword str.Enter_the_second_password ; 0x2028 ; "Enter the second password => "
| | 0x000011c8 b800000000 mov eax, 0
| | 0x000011cd e86efeffff call sym.imp.printf ; int printf(const char *format)
| | 0x000011d2 488d45e8 lea rax, qword [var_18h]
| | 0x000011d6 4889c6 mov rsi, rax
| | 0x000011d9 488d3d660e00. lea rdi, qword [0x00002046] ; "%d"
| | 0x000011e0 b800000000 mov eax, 0
| | 0x000011e5 e866feffff call sym.imp.__isoc99_scanf ; int scanf(const char *format)
| | 0x000011ea 8b45e8 mov eax, dword [var_18h]
| | 0x000011ed 83f80f cmp eax, 0xf
| ,==< 0x000011f0 7566 jne 0x1258
| || 0x000011f2 488d3d500e00. lea rdi, qword str.Enter_the_third_password ; 0x2049 ; "Enter the third password => "
| || 0x000011f9 b800000000 mov eax, 0
| || 0x000011fe e83dfeffff call sym.imp.printf ; int printf(const char *format)
| || 0x00001203 488d45e4 lea rax, qword [var_1ch]
| || 0x00001207 4889c6 mov rsi, rax
| || 0x00001211 b800000000 mov eax, 0
| || 0x00001216 e835feffff call sym.imp.__isoc99_scanf ; int scanf(const char *format)
| || 0x0000121b 8b45e4 mov eax, dword [var_1ch]
| || 0x0000121e 3d39050000 cmp eax, 0x539 ; 1337
| ,===< 0x00001223 7520 jne 0x1245
| ||| 0x00001225 8b4de4 mov ecx, dword [var_1ch]
| ||| 0x00001228 8b55e8 mov edx, dword [var_18h]
| ||| 0x0000122b 488d45f6 lea rax, qword [var_ah]
| ||| 0x0000122f 4889c6 mov rsi, rax
| ||| 0x00001232 488d3d2d0e00. lea rdi, qword str.flag__s__d__d ; 0x2066 ; "flag{\%s_%d_%d}"
| ||| 0x00001239 b800000000 mov eax, 0
| ||| 0x0000123e e8fdfdffff call sym.imp.printf ; int printf(const char *format)
| ,====< 0x00001243 eb37 jmp 0x127c
| |`---> 0x00001245 488d3d2c0e00. lea rdi, qword str.Incorrect_password___Exiting... ; 0x2078 ; "Incorrect password!! Exiting..."
| | || 0x0000124c b800000000 mov eax, 0
| | || 0x00001251 e8eafdffff call sym.imp.printf ; int printf(const char *format)
| |,===< 0x00001256 eb24 jmp 0x127c
| ||`--> 0x00001258 488d3d190e00. lea rdi, qword str.Incorrect_password___Exiting... ; 0x2078 ; "Incorrect password!! Exiting..."
| || | 0x0000125f b800000000 mov eax, 0
| || | 0x00001264 e8d7fdffff call sym.imp.printf ; int printf(const char *format)
| ||,==< 0x00001269 eb11 jmp 0x127c
| |||`-> 0x0000126b 488d3d060e00. lea rdi, qword str.Incorrect_password___Exiting... ; 0x2078 ; "Incorrect password!! Exiting..."
| ||| 0x00001272 b800000000 mov eax, 0
| ||| 0x00001277 e8c4fdffff call sym.imp.printf ; int printf(const char *format)
| ||| ; CODE XREFS from main @ 0x1243, 0x1256, 0x1269
| ```--> 0x0000127c 90 nop
| 0x0000127d c9 leave
\ 0x0000127e c3 ret
[0x00001070]>time.sleep(2)
Now let’s take a look at the interesting pieces…
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
0x0000116a 48b872616461. movabs rax, 0x32657261646172 ; 'radare2'
| 0x00001174 488945ee mov qword [var_12h], rax
| 0x00001178 488d3d890e00. lea rdi, qword str.Enter_the_first_password ; 0x2008 ; "Enter the first password => "
| 0x0000117f b800000000 mov eax, 0
| 0x00001184 e8b7feffff call sym.imp.printf ; int printf(const char *format)
| 0x00001189 488d45f6 lea rax, qword [var_ah]
| 0x0000118d 4889c6 mov rsi, rax
| 0x00001190 488d3d8e0e00. lea rdi, qword [0x00002025] ; "%s"
| 0x00001197 b800000000 mov eax, 0
| 0x0000119c e8affeffff call sym.imp.__isoc99_scanf ; int scanf(const char *format)
| 0x000011a1 488d55ee lea rdx, qword [var_12h]
| 0x000011a5 488d45f6 lea rax, qword [var_ah]
| 0x000011a9 4889d6 mov rsi, rdx
| 0x000011ac 4889c7 mov rdi, rax
| 0x000011af e87cfeffff call sym.imp.strncmp ; int strncmp(const char *s1, const char *s2, size_t n)
So our input which will be taken via scanf is being compared against a string “radare2” as the first password, alright we got the first piece to the puzzle.
1
2
3
4
5
6
7
8
9
10
11
12
| ,=< 0x000011bb 0f85aa000000 jne 0x126b
| | 0x000011c1 488d3d600e00. lea rdi, qword str.Enter_the_second_password ; 0x2028 ; "Enter the second password => "
| | 0x000011c8 b800000000 mov eax, 0
| | 0x000011cd e86efeffff call sym.imp.printf ; int printf(const char *format)
| | 0x000011d2 488d45e8 lea rax, qword [var_18h]
| | 0x000011d6 4889c6 mov rsi, rax
| | 0x000011d9 488d3d660e00. lea rdi, qword [0x00002046] ; "%d"
| | 0x000011e0 b800000000 mov eax, 0
| | 0x000011e5 e866feffff call sym.imp.__isoc99_scanf ; int scanf(const char *format)
| | 0x000011ea 8b45e8 mov eax, dword [var_18h]
| | 0x000011ed 83f80f cmp eax, 0xf
| ,==< 0x000011f0 7566 jne 0x1258
For the second password we can see our input is being compared using a cmd instruction (cmd eax,0xf), now 0xf is 15 is hex…
Similarly for the third part, we can see our input is being compared against 0x539 which is 1337.
1
2
3
4
5
6
7
8
9
|| 0x00001216 e835feffff call sym.imp.__isoc99_scanf ; int scanf(const char *format)
| || 0x0000121b 8b45e4 mov eax, dword [var_1ch]
| || 0x0000121e 3d39050000 cmp eax, 0x539 ; 1337
| ,===< 0x00001223 7520 jne 0x1245
| ||| 0x00001225 8b4de4 mov ecx, dword [var_1ch]
| ||| 0x00001228 8b55e8 mov edx, dword [var_18h]
| ||| 0x0000122b 488d45f6 lea rax, qword [var_ah]
| ||| 0x0000122f 4889c6 mov rsi, rax
| ||| 0x00001232 488d3d2d0e00. lea rdi, qword str.flag__s__d__d ; 0x2066 ; "flag{\%s_%d_%d}"
Let’s put all the pieces together
1
2
3
4
5
➜ easy-rev ./easy-rev.out
Enter the first password => radare2
Enter the second password => 15
Enter the third password => 1337
flag{radare_15_1337}% ➜ easy-rev
packed-locker
Challenge Name: packed-locker
Category: Reverse Engineering
Description: You are given a 64 bit linux executable with some defense mechanisms which will make reverse engineering difficult,find the password!.
flag format is flag{s0me_text}
Solution
While making the challenge I did the following things to prevent the solver from simply using ghidra to read the code.
- The binary is compiled using gcc test.c -static -fvisibility=hidden -fvisibility-inlines-hidden -s -o a.out
- The binary is stripped and the functions have been inlined so as to prevent reverse engineering to some extent.
- The binary is then packed using upx 9 a.out
Let’s run the file command to get some information about the elf file.
1
2
3
➜ packed-locker git:(main) file packed-locker.out
packed-locker.out: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, no section header
➜ packed-locker git:(main)
So the given binary is a 64 bit elf executable, it is statically linked and has no section header.
The section header table has all of the information necessary to locate and isolate each of the file’s sections. A section header entry in a section header table contains information characterizing the contents of the corresponding section, if the file has such a section.
source for the above defintion
Well, if I were to simply open the binary in ghidra it should first of all take a lot of time to analyze since it is statically linked so all the libc functions are inside the binary that would make it a pain to analyze it in ghidra.
Running strings on the binary reveals UPX both at the starting and at the end of dump.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
➜ packed-locker git:(main) strings packed-locker.out |head
VUPX!
`o_`o
O`)
d9o6
WB!#/
c/p_?h.v
_`/@0
?Xg_P
F^P[
$IX/
➜ packed-locker git:(main) strings packed-locker.out |tail
gcNdcept=
l"tEtbss
sub #IO_v
sbssq
comRn=
vQ0r
ON.v
]l'/
UPX!
UPX!
➜ packed-locker git:(main)
UPX is an opensource packer for executables, we can unpack our executable using upx -d
1
2
3
4
5
6
7
8
9
10
11
➜ packed-locker git:(main) ✗ upx -d packed-locker.out
Ultimate Packer for eXecutables
Copyright (C) 1996 - 2020
UPX 3.96 Markus Oberhumer, Laszlo Molnar & John Reiser Jan 23rd 2020
File size Ratio Format Name
-------------------- ------ ----------- -----------
834064 <- 322080 38.62% linux/amd64 packed-locker.out
Unpacked 1 file.
➜ packed-locker git:(main) ✗
Now let’s again run the file command on the executable.
1
2
3
➜ packed-locker git:(main) ✗ file packed-locker.out
packed-locker.out: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, BuildID[sha1]=1081ae4afbad864cafbd64396f36e5c0a39aa171, for GNU/Linux 3.2.0, stripped
➜ packed-locker git:(main) ✗
Alright now let’s analyze it using radare2, using aa to analyze the program and afl to list all the functions.
1
2
3
4
5
6
7
8
➜ packed-locker git:(main) ✗ r2 packed-locker.out
[0x00401b90]> aa
[x] Analyze all flags starting with sym. and entry0 (aa)
[0x00401b90]> afl
0x00401b90 1 43 entry0
0x00402190 102 1745 -> 1742 fcn.00402190
0x00401cad 4 193 main
[0x00401b90]>
Great we we can see the main function, let’s take a look at the disassembly of this function.
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
[0x00401b90]> pdf @main
; DATA XREF from entry0 @ 0x401bad
/ 193: int main (int argc, char **argv, char **envp);
| ; var int64_t var_40h @ rbp-0x40
| ; var int64_t var_38h @ rbp-0x38
| ; var int64_t var_30h @ rbp-0x30
| ; var int64_t var_28h @ rbp-0x28
| ; var int64_t var_26h @ rbp-0x26
| ; var int64_t var_20h @ rbp-0x20
| ; var int64_t var_18h @ rbp-0x18
| ; var int64_t var_10h @ rbp-0x10
| ; var int64_t var_8h @ rbp-0x8
| ; var int64_t var_4h @ rbp-0x4
| 0x00401cad 55 push rbp
| 0x00401cae 4889e5 mov rbp, rsp
| 0x00401cb1 4883ec40 sub rsp, 0x40
| 0x00401cb5 48c745e00000. mov qword [var_20h], 0
| 0x00401cbd 48c745e80000. mov qword [var_18h], 0
| 0x00401cc5 48c745f00000. mov qword [var_10h], 0
| 0x00401ccd c645f800 mov byte [var_8h], 0
| 0x00401cd1 48b873557033. movabs rax, 0x74735f7233705573 ; 'sUp3r_st'
| 0x00401cdb 48ba526f6e67. movabs rdx, 0x7361705f676e6f52 ; 'Rong_pas'
| 0x00401ce5 488945c0 mov qword [var_40h], rax
| 0x00401ce9 488955c8 mov qword [var_38h], rdx
| 0x00401ced 48b873776f72. movabs rax, 0x33323164726f7773 ; 'sword123'
| 0x00401cf7 488945d0 mov qword [var_30h], rax
| 0x00401cfb 66c745d82123 mov word [var_28h], 0x2321 ; '!#'
| 0x00401d01 c645da00 mov byte [var_26h], 0
| 0x00401d05 488d3dfcc209. lea rdi, qword str.Enter_the_password ; 0x49e008 ; "Enter the password"
| 0x00401d0c e88f5b0100 call 0x4178a0
| 0x00401d11 488d45e0 lea rax, qword [var_20h]
| 0x00401d15 4889c6 mov rsi, rax
| 0x00401d18 488d3dfcc209. lea rdi, qword [0x0049e01b] ; "%s"
| 0x00401d1f b800000000 mov eax, 0
| 0x00401d24 e857710000 call 0x408e80
| 0x00401d29 488d55c0 lea rdx, qword [var_40h]
| 0x00401d2d 488d45e0 lea rax, qword [var_20h]
| 0x00401d31 4889d6 mov rsi, rdx
| 0x00401d34 4889c7 mov rdi, rax
| 0x00401d37 e834f3ffff call 0x401070
| 0x00401d3c 8945fc mov dword [var_4h], eax
| 0x00401d3f 837dfc00 cmp dword [var_4h], 0
| ,=< 0x00401d43 751a jne 0x401d5f
| | 0x00401d45 488d45e0 lea rax, qword [var_20h]
| | 0x00401d49 4889c6 mov rsi, rax
| | 0x00401d4c 488d3dcdc209. lea rdi, qword str.Congrats__the_flag_is_flag__s ; 0x49e020 ; "Congrats, the flag is flag{\%s}"
| | 0x00401d53 b800000000 mov eax, 0
| | 0x00401d58 e8936f0000 call 0x408cf0
| ,==< 0x00401d5d eb0c jmp 0x401d6b
| |`-> 0x00401d5f 488d3dd9c209. lea rdi, qword str.The_password_is_incorrect ; 0x49e03f ; "The password is incorrect"
| | 0x00401d66 e8355b0100 call 0x4178a0
| | ; CODE XREF from main @ 0x401d5d
| `--> 0x00401d6b 90 nop
| 0x00401d6c c9 leave
\ 0x00401d6d c3 ret
[0x00401b90]>
And we can see the password right there in the disassembly “sUp3r_stRong_password123!#”
1
2
3
4
5
➜ packed-locker git:(main) ✗ ./packed-locker.out
Enter the password
sUp3r_stRong_password123!#
Congrats, the flag is flag{sUp3r_stRong_password123!#}%
➜ packed-locker git:(main) ✗
Thank you for reading, if you have any doubts you can contact me on twitter @siddhantc_