CryptoCat Pwn Challenges

Still wannabe hacker

This is all that I have learnt using CryptoCat YouTube course. Below are the things I have learnt from each challenge. Challenges can be found here.

1️⃣ Intro Challenge

While this challenge was complete introduction about the tools and buffer overflow, we can still learn how to approach an executable.

📌 vuln is a file that we are inspecting in this challenge.

Basic Info - (file)

1
2
3
# Get information about an executable
$ file vuln
vuln: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked [SNIP] GNU/Linux 3.2.0, not stripped

Above command tells us that file is 32-bit executable, dynamically linked and not stripped.

Dynamically linked means that executable does not contain all the code it needs to run. Instead, it relies on external shared libraries (e.g., .dll in Windows or .so in Linux).

A “not stripped” executable means we can reverse the program and see the function names, variables etc.

Check Security Settings - (checksec)

1
2
# check binary security settings
$ checksec --file vuln

Above command is used to check security settings applied on the binary.

PWNDBG

Pwndbg is a Python module which is loaded directly into GDB, making the process of debugging and reverse-engineering more user-friendly.

1
2
# Load file using `file` command in GDB
$ gdb

With info functions command, we can see the user-defined function names and other libc functions as well such as gets and puts.

Here are some useful pwndbg commands:

Command Info
disassemble main Disassemble function
break main Set break-point on function
info stack Get info about stack
x $eax Get register value
n Go onto next instruction (when hitting a break-point)
c Continue the program
delete breakpoints Delete all breakpoints
run Run program

2️⃣ Overwriting Stack Variables Challenge

📌 login is the file that we are inspecting in this challenge.

Run the binary and if you supply enough characters in the input, it will give Segmentation fault error. That’s because gets function does not check the defined buffer size of the variable (causing buffer overflow).

First, buffer size of password variable is filled up and then authorized variable memory is overwritten which is why we see random number in the output.

Ghidra

If we lookup the binary in Ghidra, there we can see the de-compiled code and even the correct password.

Learnings From Solution

We can modify value of authorized variable to 1 from GDB. First we check flow of program in Ghidra and decide to change variable value when it’s being checked in if statement (if authorized == 0).

  1. Set a breakpoint at the adress of cmp instruction in GDB → break *0x0804921e
  2. Run the program (run) and when breakpoint hits, get the memory address from pointer using command x $ebp - 0xc as that’s what the 0 is being compared to (dword ptr [ebp - 0xc], 0).
  3. Set the value of that address (0xffffcbec) to 1 → set *0xffffcbec=1
  4. Verify the change → x $ebp - 0xc

3️⃣ Overwriting Stack Variables Challenge

We can solve this challenge using the same method like in previous challenge but we should not because in CTFs, binary sits on remote server and we connect to it using netcat. Therefore, we use different approach.

Since gets function is in use, we can get past the allocated buffer and overwrite the variable that holds the value which is being checked with 0xdeadbeef (we know we are overwriting the value because it’s being printed in the response).

Our input variable is assigned size of 32 bytes (1 char = 1 byte), and whatever we supply after 32 characters are overwriting the value that’s being checked against 0xdeadbeef, therefore we overwrite it by supplying 32 characters then our payload.

4️⃣ Ret2Win Challenge

This challenge asks us to overwrite return address to access hidden hacked() function. This is possible because scanf() takes standard input and stores it in the buffer (and user input can exceed 16 bytes).

We can use gdb to find hacked() function’s address.

To know how many characters are required to overwrite return address, we use cyclic 100 command in GDB that lets us generate random characters and find the offset that crashes the program.

Run the program (run) in GDB and paste the characters generated by cyclic. Program will crash and debugging information will be shown.

💡EIP is a register in x86 architectures (32bit). It holds the “Extended Instruction Pointer“ for the stack. In other words, it tells the computer where to go next to execute the next command and controls the flow of a program.

Scroll up to see Invalid address error and EIP pointing at 4 bytes from our payload string.

Enter cyclic -l haaa to find the offset, which comes out to be 28.

We use python2 to craft a payload that fills up the 28 bytes. The buffer[16] variable is assigned buffer of 16 bytes, then extra bytes to cover padding and some other stuff such as saved frame pointer, then our payload to overwrite return address.

0x8049182 is the address of hacked() function which we want to access. Therefore, we will write it like this after 28 bytes: \x82\x91\x04\x08. We wrote the address in reverse because it’s an LSB executable.

Generate payload using the below command:

1
python2 -c 'print("A"*28 + "\x82\x91\x04\x08")' > payload

⚠️ Output has to be saved in a file because \x82\x91.. characters are not printable.

Run the program by supplying payload file as input and we have successfully solved the challenge.

Learning From Solution

If we have access to executable, cyclic command can be used to generate characters and cyclic -l [chars] to find the right offset.

Overwriting address should be done using hex characters via python2 to avoid errors.

In progress…


Comments