Wróć do projektów
Zdjęcie metalowego muru

Podsumowanie projektu IDPS AI

Opis projektu

Projekt zakłada wykorzystanie uczenia maszynowego do stworzenia aplikacji przechwytującej ataki po protokołach HTTP/HTTPS za pomocą regresji logistycznej.

Model

Model został wytrenowany na danych dostępnych na portalu Kaggle, udostępniającym dane do trenowania modeli. Z danych, które udało się uzyskać model nabył zdolność do wykrywania ataków XSS, Command Injection I SQL injection. Na ten moment model ma skuteczność 73% stwierdzoną na podstawie automatycznego testu, więcej w rozdziale "Testy"

Architektura Aplikacji

Aplikacja została zbudowana w oparciu o bibliotkę "Man In The Middle Proxy", która ułatwia przechwytywanie ruchu HTTP i HTTPS, likwidując potrzebę pisania kodu do zestawiania tunelu, wymiany certyfikatów i umożliwia pisanie wtyczek, które zachowują się jak filtry, pozwalając na blokowanie, odczyt lub modyifikacje zapytań

Biblioteki

Biblioteka Man In The Middle Proxy

Główna biblioteka, odpowiadająca za zestawie monitorowanego połączenia między użytkownikiem a serwerem aplikacji.

Biblioteka Scikit-Learn

Biblioteka oferująca gotowe klasy do trenowania podstawowych modeli w tym modeli regresyjnych.

Biblioteka Pandas

Biblioteka wspomagająca operacje na danych do uczenia maszynowego

Bibilioteka OS

Wbudowany w python zbiór funkcji systemowych, między innymi operacje na ścieżkch

Struktura klasy wtyczki


class AIIDS:
    def **init**(self):
        # Inicjalizacja klasy, ustawienie parametów uczenia maszynowego

    def train(self):
        # Trenowanie modelu na danych z pliku

    def predict(self, text):
        # Próba przewidzenia czy podany text jest atakiem

    def request(self, flow: http.HTTPFlow):
        # Metoda wymagana przez mitm proxy, jest wywoływana za każdym razem kiedy do aplikacji kierowany jest ruch

    # Dopisek wymagany, aby mitm proxy wiedziało która klasa jest odpowiedzialna z przechwytywanie ruchu
addons = [AIIDS()]

Testy

Przypadki

# Payload Typ ataku Oczekiwany Otrzymany 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

Struktura Testu Automatcznego


 # Parametry testu
BASE_URL = "http://localhost"
TIMEOUT = 5

 # Payload został wycięty ze względu na rozdział "Przypadki"
 # Deklaracje poszczególnych punktów końcowych w aplikacji DVWA
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

 # Mapa zamiany tekstu na konkretną metodę
method_map = {
    "sqli": sqli,
    "xss": xss,
    "cmdi": cmdi,
}
 # Metoda odpowiedzialna za odpalanie testów automatycznych na podstawie zadeklarowanych przypadków
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}"
        )

    # Wydruk podsumowania testu w konsoli
    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}"
            )
 # Dobra praktyka, która blokuje uruchamianie kodu w przypadku importu pliku jako biblioteki
if **name** == "**main**":
    run_tests()

Wyniki

=== 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

Wnioski

System poprawnie sklasyfikował 22 spośród 30 przypadków, osiągając skuteczność na poziomie 73,33%. W większości przypadków poprawnie wykryto klasyczne formy ataków SQLi oraz XSS, co potwierdza skuteczność podejścia bazującego na analizie tekstowej payloadów. Problemy pojawiły się przede wszystkim w kontekście mniej oczywistych form ataków CMDi oraz bardziej subtelnych wariantów XSS.

aplikacja wykazuje dobrą skuteczność w wykrywaniu typowych form ataków aplikacyjnych. Jego zdolność detekcji można jednak zwiększyć poprzez uwzględnienie bardziej subtelnych lub rzadziej spotykanych wzorców ataków oraz dopracowanie procesu klasyfikacji Command Injection.

Analiza błędów (False Negative i False Positive)

Błędne klasyfikacje dotyczyły ośmiu przypadków:

  • SQL Injection: '105 OR 1=1' oraz '1; SHUTDOWN --' nie zostały rozpoznane jako ataki. Może to sugerować, że model nie rozpoznaje prostych operatorów logicznych lub poleceń jako szkodliwych, jeśli ich forma nie odbiega znacznie od danych treningowych.
  • XSS:

<img src='x' onerror='console.log(1)'> został sklasyfikowany jako bezpieczny, mimo że zawiera aktywny wektor XSS. Błąd ten może wynikać z niedostatecznej reprezentacji XSS z onerror w zbiorze treningowym lub z heurystyki ograniczającej się do słowa alert.

  • Command Injection:
    Aż pięć przypadków dotyczyło błędów klasyfikacji CMDi, w tym:
    8.8.8.8; rm -rf /
    localhost | whoami
    ;echo vulnerable
    ;ping -c 4 evil.com
    Dodatkowo odnotowano jedno false positive – nieszkodliwy payload 127.0.0.1 został niesłusznie zablokowany.

Możliwe kierunki rozwoju

  • Rozbudowa zbioru treningowego o bardziej różnorodne przykłady CMDi i XSS, w tym takie zawierające inne niż alert() funkcje JavaScript oraz polecenia shellowe.
  • Dodanie warstwy heurystycznej lub filtrującej kontekst, np. rozpoznającej ciągi zaczynające się od ;, |, && w polach adresów IP jako podejrzane.
  • Zastosowanie klasyfikatora typu multiclass (np. SQLi, XSS, CMDi, Benign) w celu umożliwienia dokładniejszego przypisania typu ataku.
  • Weryfikacja przypadków false positive może również sugerować potrzebę większej precyzji w klasyfikacji danych nieszkodliwych, np. adresów IP.
  • Dodanie interfejsu do obsługi graficznej aplikacji
  • Zbieranie logów dodedykowanej aplikacji
  • Blokada ip po zbyt wielu próbach zidentyfikowanych jako atak