Intelliscan / tests /test_injector.py
simoox's picture
Upload 204 files
5e0bd20 verified
Raw
History Blame Contribute Delete
4.79 kB
"""Tests for the Injector target-resolution logic (no live HTTP)."""
from __future__ import annotations
from intelliscan.modules.crawler import CrawlResult, Form, UrlParam
from intelliscan.modules.injector import Injector
class _FakeHttp:
"""Minimal stand-in; target resolution never performs requests."""
def get_csrf_token(self, url): # pragma: no cover - unused in these tests
return None
def _make_injector(crawl_result=None) -> Injector:
return Injector(_FakeHttp(), "http://localhost:8080", crawl_result=crawl_result)
def test_falls_back_to_dvwa_when_no_crawl():
inj = _make_injector(crawl_result=None)
targets = inj._resolve_targets()
assert targets, "expected DVWA fallback targets"
assert all(t.source.startswith("dvwa") for t in targets)
def test_skips_state_mutating_forms():
# security.php (changes the security level) and a password-change form must
# never be injected — doing so corrupts the scan/session state mid-run.
crawl = CrawlResult(
target="http://localhost:8080",
pages_visited=3,
forms=[
Form(
url="http://localhost:8080/security.php",
action="http://localhost:8080/security.php",
method="POST",
inputs=[{"name": "security", "type": "text", "value": ""}],
),
Form(
url="http://localhost:8080/vulnerabilities/csrf/",
action="http://localhost:8080/vulnerabilities/csrf/",
method="GET",
inputs=[
{"name": "password_new", "type": "password", "value": ""},
{"name": "password_conf", "type": "password", "value": ""},
],
),
Form(
url="http://localhost:8080/vulnerabilities/sqli/",
action="http://localhost:8080/vulnerabilities/sqli/",
method="GET",
inputs=[{"name": "id", "type": "text", "value": ""}],
),
],
url_params=[],
)
inj = _make_injector(crawl)
targets = inj._resolve_targets()
urls = {t.url for t in targets}
assert urls == {"http://localhost:8080/vulnerabilities/sqli/"}
def test_empty_crawl_does_not_fall_back_to_dvwa():
# A supplied-but-empty crawl (blocked/unreachable target) must NOT fabricate
# DVWA targets — that produced phantom findings from WAF/error pages.
crawl = CrawlResult(
target="https://blocked.example",
pages_visited=0,
forms=[],
url_params=[],
blocked_responses=1,
start_reachable=False,
)
inj = _make_injector(crawl)
assert inj._resolve_targets() == []
def test_resolves_form_inputs_and_skips_submit():
crawl = CrawlResult(
target="http://localhost:8080",
pages_visited=1,
forms=[
Form(
url="http://localhost:8080/login",
action="http://localhost:8080/login",
method="POST",
inputs=[
{"name": "username", "type": "text", "value": ""},
{"name": "password", "type": "password", "value": ""},
{"name": "Login", "type": "submit", "value": "Login"},
],
)
],
url_params=[],
)
inj = _make_injector(crawl)
targets = inj._resolve_targets()
assert len(targets) == 1
t = targets[0]
assert t.source == "crawl-form"
assert set(t.inject_params) == {"username", "password"} # text fields
assert t.static_fields == {"Login": "Login"} # submit preserved
def test_resolves_url_params():
crawl = CrawlResult(
target="http://localhost:8080",
pages_visited=1,
forms=[],
url_params=[UrlParam(url="http://localhost:8080/item?id=3&cat=2", params=["id", "cat"])],
)
inj = _make_injector(crawl)
targets = inj._resolve_targets()
assert len(targets) == 1
t = targets[0]
assert t.source == "crawl-param"
assert t.method == "GET"
assert t.url == "http://localhost:8080/item" # query stripped
assert "lfi" in t.vuln_types # params probe LFI too
def test_build_tasks_pairs_payloads_with_targets():
crawl = CrawlResult(
target="http://localhost:8080",
pages_visited=1,
forms=[],
url_params=[UrlParam(url="http://localhost:8080/x?q=1", params=["q"])],
)
inj = _make_injector(crawl)
tasks = list(inj._build_tasks(inj._resolve_targets()))
# Every task is (target, vuln_type, payload) and only uses loaded vuln types.
assert tasks
for target, vuln_type, payload in tasks:
assert vuln_type in target.vuln_types
assert isinstance(payload, str) and payload