Search This Blog

Thursday, February 22, 2024

[pwn primer] understanding format string vulnerabilities + bypassing stack canary protection

Previously, we've covered techniques like ret2shellcode, which involves injecting shellcode into a vulnerable process to ultimately execute whatever code we want and the use of ROP gadgets, which is ultimately a code reuse attack. We use the code located within the vulnerable program, specifically assembly instructions ending with the 'ret' instruction, to setup the stack to in turn execute whatever code we want, bypassing the Non executable bit that prevents us from injecting shellcode onto the stack and have it execute. 

Another exploitation technique is the use of format string exploits. This technique involves exploiting format specifiers in C. Manipulating format strings in C can basically allow one to read and write from arbitrary memory locations. I've created a reasonably easy C program that's vulnerable to format string vuln. Let's have a look at it and take it from there.



the main function calls vuln, which initializes a buffer on the stack of 64 bytes. after a couple of puts and gets calls are made. puts just outputs predefined text onto the screen and gets is the vulnerable function, vulnerable specifically to a buffer overflow (read man pages to see dangers of using gets). To cut the story short, gets() basically prompts for user input, without providing any bounds checking on how much input is being inserted. 

the format string vulnerability can be spotted on line 13. the printf function in C usually requires a format specifier, specifying how printf should "print" data onto the screen. these specifiers can be seen as %d for decimal, %s for strings etc (more can be found online). in this case, the code does not tell printf how to print the data, hence showing the presence of the vulnerability. We can feed printf any specifier we want and see what contents are spewed from the program.

How does this vulnerability benefit anyone? I'll show you how.

The format string vulnerability can be used to either read or write from arbitrary areas in memory. This can serve useful to us in instances where certain exploitation mitigations such as ASLR or stack canaries need to be bypassed. This post will also go into actually compiling and exploiting the vulnerable program above. This program mimics an easy/medium pwn challenge. Looking at the code overall, we also see a win() function, so this also shows that this is more of a ret2win type of challenge. 

p.s ret2win basically just means that the vulnerable pwn challenge contains a 'win' function that program execution needs to be redirected to, in order to solve the challenge. the 'win' function isnt called initally. that's why the program execution needs to be redirected to that function (usually done when there's a buffer overflow vuln).

The code above can be compiled using the flags in the commented section (one for 32 bit and 64 bit). This demo will look into x64 bit.

After compiling the program, let's have a look at the binary protections and see what exploit mitigations are enabled to have a feel on what we're dealing with.


We have 2 protections enabled. a stack canary and NX bit. The NX bit, we've already discussed. it basically just renders shellcode injections useless as the stack is non executable. cool. but the stack canary is what we haven't covered... and I'd like to do that now.

The stack canary is simply a random value placed on the stack meant to prevent buffer overflows from being successful. Specifically, it is a random value that starts with '/x00' placed at rbp-0x8 (8 bytes before the base pointer in x64). To give more clarity on this, let's have a look at the vulnerable program in a disassembler and see the main function disassembled and see how the canary is initialised.


A quick IDA inspection shows the execution branches of the vuln function where most of the program functionality is. the function prologue at the very beginning shows how 50h bytes have been reserved for this current function on the stack, right after that we see fs:28h being moved into the rax register, and then that value being inserted into a memory location located at rbp+0x8. This is the stack canary being initialised. In gdb, the location is actually at rbp-0x8 instead of rbp+0x8 so it just depends on where you look at it. 

At the end, we see the stack canary being compared with what is on the stack. if the user input overwrited rbp-0x8 or rbp+0x8, and whatever is being written at that area in memory does not equate to the random value assigned by the program at runtime, then the __stack_chk_fail will be called, showing that a buffer overflow has been attempted and the program will exit. 

That's how a stack canary works. 

Since the program has initialized a random value at rbp-0x8, then we need to find a way to use the format string vuln to leak the canary value from the stack, as that will be the mechanism with which the canary protection can be bypassed in this instance. Besides this, you can bruteforce the canary byte by byte, but right now the format string can allow us to leak it directly from the stack.

by inserting %p into the program, we can leak the contents of the stack to stdout, and it turns out that the canary can be found at the 15th position of %p inserted into the program.



since the canary starts with '/x00' as stated earlier, we know that this is the canary. It is shown this way in the leak because of endianness. Least significant byte to be more precise. However, the canary changes with every execution to ASLR being enabled on my system, so the final exploit script will automate this process and make it cleaner. Aside from that, this is how the format string vuln can be used. This is an essential pwn technique and can get a lot more advanced than this. This is as basic as it gets.

The final exploit payload will be the padding + canary_leak + additional 8 bytes to overwrite rbp + address to win function (overwrite rip address with win function)

Final Exploit Script



The exploit script is quite small, but all it will do is exploit the format string vuln to leak the canary to ultimately bypass it. As seen above, once the exploit script is ran, it leaks the canary when the script executes the vulnerable process and shows us the message "you win" signifying that we've successfully redirected execution to the win() function.

Hopefully this gave a bit more light as to how the format string works. This vulnerability can be discovered and used in other ways not mentioned here, but this is enough to serve as a primer to beginners or intermediate pwners who want to up their game up with pwning. Learning the art of pwn requires knowledge of reversing, which is a topic worthy of being discussed in another blog post I will do in future. 

More resources:

pwn.college - Hacking platform maintained by Arizona State University. They also host lectures available on twitch and youtube. Highly recommended for beginner pwners.

CTF-Wiki - Overall CTF wiki teaching basics of pwn as well as other hacking challenges like Crypto, Web and Forensics. Highly Recommended (Translate page to English as its originally compiled in Mandarin)










No comments:

Post a Comment