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