Back to projects
Photo of a metal wall

IDPS AI Project Summary

Project Description

The project uses machine learning to build an application that intercepts HTTP/HTTPS attacks using logistic regression.

Model

The model was trained on data available on the Kaggle platform, which provides datasets for model training. Using the data obtained, the model gained the ability to detect XSS, Command Injection, and SQL Injection attacks. At this stage, the model achieves 73% accuracy, as determined by an automated test — more details in the "Tests" section.

Application Architecture

The application is built on the "Man-in-the-Middle Proxy" library, which simplifies intercepting HTTP and HTTPS traffic, removing the need to write code for tunnel setup and certificate exchange, and allows writing plugins that act as filters, enabling requests to be blocked, read, or modified.

Libraries

Man-in-the-Middle Proxy Library

The main library, responsible for establishing the monitored connection between the user and the application server.

Scikit-Learn Library

A library offering ready-made classes for training basic models, including regression models.

Pandas Library

A library supporting data operations for machine learning.

OS Library

A built-in Python collection of system functions, including path operations.

Plugin Class Structure


class AIIDS:
    def **init**(self):
        # Initialize the class, set up machine learning parameters

    def train(self):
        # Train the model on data from a file

    def predict(self, text):
        # Attempt to predict whether the given text is an attack

    def request(self, flow: http.HTTPFlow):
        # Method required by mitmproxy, called every time traffic is routed to the application

    # Required declaration so mitmproxy knows which class is responsible for intercepting traffic
addons = [AIIDS()]

Tests

Cases

# Payload Attack Type Expected Received Status
11 UNION SELECT null, username || '\~' || password FROM users --SQLI403403OK
2105' OR 1=1SQLI403200FAIL
3' OR EXISTS(SELECT \* FROM users WHERE username='admin') --SQLI403403OK
4'; EXEC xp_cmdshell('dir'); --SQLI403403OK
5' AND SLEEP(5) --SQLI403403OK
6" OR "" = "SQLI403403OK
7abcSQLI200200OK
8105SQLI200200OK
91 ORDER BY 10 --SQLI403403OK
101; SHUTDOWN --SQLI403200FAIL
11<iframe src='javascript:alert(1)'></iframe>XSS403403OK
12<body onload=alert('test')>XSS403403OK
13<math><mi>x</mi><mtext><svg onload=alert(1)></svg></mtext></math>XSS403403OK
14<div onmouseover=alert(1)>XSS</div>XSS403403OK
15";alert(1);//XSS403403OK
16Welcome back!XSS200200OK
17<a href='http://example.com'>Click me</a>XSS200200OK
18XSSXSS200200OK
19<b>bold</b>XSS200200OK
20<img src='x' onerror='console.log(1)'>XSS403200FAIL
218.8.8.8; rm -rf /CMDI403200FAIL
22127.0.0.1 && sleep 5CMDI403403OK
23localhost | whoamiCMDI403200FAIL
24;echo vulnerableCMDI403200FAIL
25192.168.1.1CMDI200200OK
26127.0.0.1CMDI200403FAIL
278.8.4.4CMDI200200OK
28;ping -c 4 evil.comCMDI403200FAIL
29|| lsCMDI403403OK
30| idCMDI403403OK

Automated Test Structure


 # Test parameters
BASE_URL = "http://localhost"
TIMEOUT = 5

 # Payload omitted here — see the "Cases" section
 # Declarations of individual endpoints in the DVWA application
def sqli(payload: str) -> int:
    endpoint = f"{BASE_URL}/vulnerabilities/sqli/"
    params = {"id": payload, "Submit": "Submit"}
    resp = requests.get(endpoint, params=params, timeout=TIMEOUT)
    return resp.status_code

def xss(payload: str) -> int:
    endpoint = f"{BASE_URL}/vulnerabilities/xss_r/"
    params = {"name": payload, "Submit": "Submit"}
    resp = requests.get(endpoint, params=params, timeout=TIMEOUT)
    return resp.status_code

def cmdi(payload: str) -> int:
    endpoint = f"{BASE_URL}/vulnerabilities/exec/"
    data = {"ip": payload, "Submit": "Submit"}
    resp = requests.post(endpoint, data=data, timeout=TIMEOUT)
    return resp.status_code

 # Map from text label to the corresponding method
method_map = {
    "sqli": sqli,
    "xss": xss,
    "cmdi": cmdi,
}
 # Method responsible for running the automated tests based on the declared cases
def run_tests():
    total = len(tests)
    correct = 0
    failed_cases = []

    print("\n=== Running tests ===\n")
    for i, (payload, method_name, expected_status) in enumerate(tests, 1):
        test_func = method_map[method_name]
        try:
            actual_status = test_func(payload)
            match = actual_status == expected_status
            if match:
                correct += 1
                status = "[OK]"
            else:
                status = "[FAIL]"
                failed_cases.append(
                    (i, payload, method_name, expected_status, actual_status)
                )
        except Exception as e:
            status = "[ERROR]"
            failed_cases.append(
                (i, payload, method_name, expected_status, f"ERROR: {e}")
            )
            actual_status = "ERR"

        print(
            f"{status} {i:02d} | {method_name.upper()} | payload={repr(payload):<30} | "
            f"expected={expected_status}, got={actual_status}"
        )

    # Print the test summary to the console
    print("\n=== Summary ===")
    print(f"Correct: {correct}/{total}")
    print(f"Accuracy: {correct / total \* 100:.2f}%")

    if failed_cases:
        print("\n Failed cases:")
        for i, payload, method, expected, got in failed_cases:
            print(
                f" - Test {i}: {method.upper()} | {repr(payload)} | expected={expected}, got={got}"
            )
 # Good practice that prevents the code from running when the file is imported as a library
if **name** == "**main**":
    run_tests()

Results

=== Running tests ===

[OK] 01 | SQLI | payload="1 UNION SELECT null, username || '\~' || password FROM users --" | expected=403, got=403
[FAIL] 02 | SQLI | payload='105 OR 1=1' | expected=403, got=200
[OK] 03 | SQLI | payload="' OR EXISTS(SELECT \* FROM users WHERE username='admin') --" | expected=403, got=403
[OK] 04 | SQLI | payload="'; EXEC xp_cmdshell('dir'); --" | expected=403, got=403
[OK] 05 | SQLI | payload="' AND SLEEP(5) --" | expected=403, got=403
[OK] 06 | SQLI | payload='" OR "" = "' | expected=403, got=403
[OK] 07 | SQLI | payload='abc' | expected=200, got=200
[OK] 08 | SQLI | payload='105' | expected=200, got=200
[OK] 09 | SQLI | payload='1 ORDER BY 10 --' | expected=403, got=403
[FAIL] 10 | SQLI | payload='1; SHUTDOWN --' | expected=403, got=200
[OK] 11 | XSS | payload="<iframe src='javascript:alert(1)'></iframe>" | expected=403, got=403
[OK] 12 | XSS | payload="<body onload=alert('test')>" | expected=403, got=403
[OK] 13 | XSS | payload='<math><mi>x</mi><mtext><svg onload=alert(1)></svg></mtext></math>' | expected=403, got=403
[OK] 14 | XSS | payload='<div onmouseover=alert(1)>XSS</div>' | expected=403, got=403
[OK] 15 | XSS | payload='";alert(1);//' | expected=403, got=403
[OK] 16 | XSS | payload='Welcome back!' | expected=200, got=200
[OK] 17 | XSS | payload="<a href='http://example.com'>Click me</a>" | expected=200, got=200
[OK] 18 | XSS | payload='XSS' | expected=200, got=200
[OK] 19 | XSS | payload='<b>bold</b>' | expected=200, got=200
[FAIL] 20 | XSS | payload="<img src='x' onerror='console.log(1)'>" | expected=403, got=200
[FAIL] 21 | CMDI | payload='8.8.8.8; rm -rf /' | expected=403, got=200
[OK] 22 | CMDI | payload='127.0.0.1 && sleep 5' | expected=403, got=403
[FAIL] 23 | CMDI | payload='localhost | whoami' | expected=403, got=200
[FAIL] 24 | CMDI | payload=';echo vulnerable' | expected=403, got=200
[OK] 25 | CMDI | payload='192.168.1.1' | expected=200, got=200
[FAIL] 26 | CMDI | payload='127.0.0.1' | expected=200, got=403
[OK] 27 | CMDI | payload='8.8.4.4' | expected=200, got=200
[FAIL] 28 | CMDI | payload=';ping -c 4 evil.com' | expected=403, got=200
[OK] 29 | CMDI | payload='|| ls' | expected=403, got=403
[OK] 30 | CMDI | payload='| id' | expected=403, got=403

=== Summary ===
Correct: 22/30
Accuracy: 73.33%

Failed cases:

- Test 2: SQLI | '105 OR 1=1' | expected=403, got=200
- Test 10: SQLI | '1; SHUTDOWN --' | expected=403, got=200
- Test 20: XSS | "<img src='x' onerror='console.log(1)'>" | expected=403, got=200
- Test 21: CMDI | '8.8.8.8; rm -rf /' | expected=403, got=200
- Test 23: CMDI | 'localhost | whoami' | expected=403, got=200
- Test 24: CMDI | ';echo vulnerable' | expected=403, got=200
- Test 26: CMDI | '127.0.0.1' | expected=200, got=403
- Test 28: CMDI | ';ping -c 4 evil.com' | expected=403, got=200

Conclusions

The system correctly classified 22 out of 30 cases, achieving an accuracy of 73.33%. In most cases, classic forms of SQLi and XSS attacks were correctly detected, confirming the effectiveness of the text-based payload analysis approach. Problems arose mainly with less obvious forms of CMDi attacks and more subtle XSS variants.

The application shows good effectiveness in detecting typical forms of application-layer attacks. Its detection capability could, however, be improved by accounting for more subtle or less common attack patterns and by refining the Command Injection classification process.

Error Analysis (False Negatives and False Positives)

The misclassifications concerned eight cases:

  • SQL Injection: '105 OR 1=1' and '1; SHUTDOWN --' were not recognized as attacks. This may suggest that the model doesn't flag simple logical operators or commands as malicious if their form doesn't deviate significantly from the training data.

  • XSS:

    <img src='x' onerror='console.log(1)'>was classified as safe, despite containing an active XSS vector. This error may result from insufficient representation of onerror-based XSS in the training set, or from a heuristic limited to the word "alert".

  • Command Injection:
    As many as five cases involved CMDi classification errors, including:
    8.8.8.8; rm -rf /
    localhost | whoami
    ;echo vulnerable
    ;ping -c 4 evil.com
    Additionally, one false positive was recorded – the harmless payload 127.0.0.1 was incorrectly blocked.

Possible Directions for Development

  • Expanding the training dataset with more diverse CMDi and XSS examples, including ones using JavaScript functions other than alert() and additional shell commands.
  • Adding a heuristic or context-filtering layer, e.g. flagging strings starting with ;, |, && in IP address fields as suspicious.
  • Using a multiclass classifier (e.g. SQLi, XSS, CMDi, Benign) to enable more precise assignment of the attack type.
  • Reviewing false-positive cases may also point to the need for greater precision in classifying benign data, such as IP addresses.
  • Adding a graphical interface for the application
  • Collecting logs into a dedicated application
  • Blocking an IP after too many attempts identified as an attack