We are given a binary and the source challenge.c where we can spot a buffer overflow in scanf
#include <stdio.h>#include <string.h>voidignore_me(){setbuf(stdin,0);setbuf(stdout,0);}voidpew_pew_90s(){printf("🔫 *pew pew* Retro laser gun fires! But it's still just a cat toy from the 90s...\n");}intmain(){ignore_me();charretro_cat[32];int ver =50004;printf("🕹 BLAST TO THE PAST - Cyber Cat Defense %d! 🐱💾\n", ver);printf("Enter your retro cyber-cat's name, dude: "); // Takes in 320 character to a 32 byte bufferscanf("%320s", retro_cat);printf("Radical! %s is locked and loaded with a sweet laser gun!\n", retro_cat);pew_pew_90s();return0;}
Using pwndbg's cyclic, we can easily determine the offset to gain control of our instruction pointer (RIP), which is 56.
As the challenge description suggests, no protections exist for this binary, allow executable stack which can be verified with checksec.
This allows us to execute code or instructions on the stack, allowing us to perform ret2shellcode
We can just search for any x64 linux shellcode online or opt to use pwntool's shellcraft function.
However, we need to somehow redirect execution to the start of our shellcode which is where the RSP register comes in.
RSP points to the top of your stack and by using a gadget like push rsp; ret, it pushes RSP's current value onto the stack before redirecting execution flow through ret.
So putting all the pieces together we need to:
Buffer Overflow till we gain control over RIP
Execute the gadgetpush rsp; ret to redirect execution to our shellcode which is placed after the gadget on the stack
Shellcode execution happens because ret jumps to the address that was pushed (the old RSP value)
You can see this using pwndbg and setting a breakpoint at the end of main