Explanation of the binary exploitation flags #11
eclairevoyant
started this conversation in
Ideas
Replies: 1 comment
-
Thank you! I'll reference this in pwn/binex |
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
Seems like you were least familiar with pwning/binary exploitation so I figured I'd explain the parts missing from your writeup. Hope this helps.
For "Stonks", the first place I looked at was
scanf("%300s", user_buf)
. it might have been pwnable, but they prevented a buffer overflow there - by using "%300s", they limit user input to the first 300 characters, and if you seeuser_buf
is allocated with301
bytes, which means it's also properly null-terminated. So we can't exploit that line of code.The next place to look then, is the
printf
call. Any time you see a single non-constant arg toprintf
, it's probably pwnable.printf(user_buf);
is insecure because the format string is now controlled by user input. (The way they should've written the code isprintf("%s", user_buf)
orputs(user_buf)
. In fact, if you compile the source code the compiler should warn you about this line actually for this exact reason. So yeah then you can spam a bunch of "%p"'s and get the program to spit out the list of memory addresses that are on the stack. See https://owasp.org/www-community/attacks/Format_string_attack.If you want to know why it spits out what's on the stack, my understanding is that it's due to x86 calling conventions. TLDR generally extra arguments get pulled from the stack, and since you didn't provide enough arguments in the function (
printf("%p %p")
for example is still looking for two more arguments that you didn't pass in), it starts looking for them on the stack. Technically for x86_64, it checks 4 (windows) or 6 (mac, linux) registers first, but eventually it goes to the stack too.You also guessed correctly in your writeup about why the bytes come out backwards in groups of 4. It's likely compiled as 32-bit (meaning 4-byte boundaries) LSB (Least Significant Byte first, aka little-endian) binary.
To figure out how many %p you need, you can either try compiling the binary in the same way then run it through a debugger to figure out what's on the stack, or just keep trying more %p's until you get what you're looking for.
For "What's your input", the hint points at this, but basically
input()
in python2 will evaluate whatever you type in as python code. If you wanted to provide a string, you actually need to put quotes around it. See https://stackoverflow.com/a/4960216/950837.The correct way to get user input in python2 is
raw_input()
(which just stores a string and doesn't eval anything). So if you see any call toinput()
it's pwnable. (This is fixed in python3, which gets rid ofraw_input()
and just makesinput()
use strings. This is why the hint wanted you to pay attention to the python version.)Let me know if I can clear up anything else on these. Congrats on your first CTF!
Beta Was this translation helpful? Give feedback.
All reactions