编写XSS的suricata规则-测试(9001288-9001300、9001111)

1.主机B开启服务

from __future__ import annotations
import argparse
import socket
import threading
from urllib.parse import urlsplit
def check_port_available(listen_ip: str, port: int) -> None:
    probe = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    probe.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    try:
        probe.bind((listen_ip, port))
    except OSError as exc:
        raise SystemExit(
            f"[server] {listen_ip}:{port} is already in use. "
            f"Run `ss -ltnp | grep :{port}` on the server to find the process."
        ) from exc
    finally:
        probe.close()
def recv_http_request(conn: socket.socket) -> bytes:
    conn.settimeout(0.6)
    chunks: list[bytes] = []
    while True:
        try:
            data = conn.recv(4096)
        except socket.timeout:
            break
        if not data:
            break
        chunks.append(data)
        joined = b"".join(chunks)
        if b"\r\n\r\n" in joined and len(data) < 4096:
            break
    return b"".join(chunks)
def parse_path(request: bytes) -> str:
    first_line = request.split(b"\r\n", 1)[0].decode("latin-1", errors="ignore")
    parts = first_line.split(" ")
    if len(parts) >= 2:
        return parts[1]
    return "/"
def build_response(body: bytes, content_type: str = "text/plain", extra_headers: list[str] | None = None) -> bytes:
    extra_headers = extra_headers or []
    headers = [
        "HTTP/1.1 200 OK",
        "Connection: close",
        f"Content-Length: {len(body)}",
        f"Content-Type: {content_type}",
    ]
    headers.extend(extra_headers)
    headers.extend(["", ""])
    return "\r\n".join(headers).encode("ascii") + body
def response_for_path(path: str) -> tuple[bytes, str, list[str]]:
    route = urlsplit(path).path
    if route == "/dom-message":
        body = (
            b"<html><body><script>"
            b"window.addEventListener(\"message\", function(e){"
            b"document.body.innerHTML = e.data;"
            b"});"
            b"</script></body></html>"
        )
        return body, "text/html", []
    if route == "/dom-hash":
        body = (
            b"<html><body><script>"
            b"var v = location.hash;"
            b"document.write(v);"
            b"</script></body></html>"
        )
        return body, "text/html", []
    if route == "/framework":
        body = (
            b"<html><body><script>"
            b"const demo = { dangerouslySetInnerHTML: '__html' };"
            b"route.query = location.hash;"
            b"</script></body></html>"
        )
        return body, "text/html", []
    if route == "/ticket/view":
        body = b"<html><body><img src=x onerror=alert(1)></body></html>"
        return body, "text/html", []
    if route == "/admin/login":
        body = (
            b"<html><head><title>Admin Login</title></head><body>"
            b"<form><input type=\"password\" name=\"password\"></form>"
            b"<script src=\"//cdn.bad.test/cdn.js\"></script>"
            b"</body></html>"
        )
        return body, "text/html", []
    if route == "/portal/console":
        body = (
            b"<html><head><title>Portal Console</title></head><body>"
            b"<input type=\"password\" name=\"password\">"
            b"<script>console.log('x')</script>"
            b"</body></html>"
        )
        return body, "text/html", ["Content-Security-Policy: script-src 'self' 'unsafe-inline' data:"]
    if route == "/assets/app.js":
        body = (
            b"var x = atob('QQ==');"
            b"var s = document.createElement('script');"
            b"s.src='http://cdn.bad.test/loader.js';"
            b"document.body.appendChild(s);"
        )
        return body, "application/javascript", []
    return b"ok\n", "text/plain", []
def handle_client(conn: socket.socket, addr: tuple[str, int], listen_port: int) -> None:
    try:
        request = recv_http_request(conn)
        path = parse_path(request)
        first_line = request.split(b"\r\n", 1)[0].decode("latin-1", errors="ignore")
        body, content_type, extra_headers = response_for_path(path)
        conn.sendall(build_response(body, content_type, extra_headers))
        print(f"[server:{listen_port}] {addr[0]}:{addr[1]} {first_line}")
    except Exception as exc:  # pragma: no cover - lab helper
        print(f"[server:{listen_port}] handler error from {addr}: {exc}")
    finally:
        try:
            conn.close()
        except OSError:
            pass
def serve(listen_ip: str, port: int, stop_event: threading.Event) -> None:
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    sock.bind((listen_ip, port))
    sock.listen(128)
    sock.settimeout(1.0)
    print(f"[server:{port}] listening on {listen_ip}:{port}")
    try:
        while not stop_event.is_set():
            try:
                conn, addr = sock.accept()
            except socket.timeout:
                continue
            thread = threading.Thread(target=handle_client, args=(conn, addr, port), daemon=True)
            thread.start()
    finally:
        sock.close()
def main() -> None:
    parser = argparse.ArgumentParser(description="Minimal live responder for xss_followon_supplement.rules")
    parser.add_argument("--listen-ip", default="10.10.10.2")
    parser.add_argument("--port", type=int, default=18080)
    args = parser.parse_args()
    check_port_available(args.listen_ip, args.port)
    stop_event = threading.Event()
    thread = threading.Thread(target=serve, args=(args.listen_ip, args.port, stop_event), daemon=True)
    thread.start()
    try:
        thread.join()
    except KeyboardInterrupt:
        print("\n[server] stopping")
        stop_event.set()
if __name__ == "__main__":
    main()

2.主机A发送测试请求

from __future__ import annotations
import argparse
import socket
import time
def send_raw(host: str, port: int, payload: bytes) -> bytes:
    sock = socket.create_connection((host, port), timeout=3)
    sock.settimeout(1.0)
    try:
        sock.sendall(payload)
        response = bytearray()
        while True:
            try:
                data = sock.recv(4096)
            except socket.timeout:
                break
            if not data:
                break
            response.extend(data)
        return bytes(response)
    finally:
        sock.close()
def http_request(method: str, path: str, headers: list[tuple[str, str]] | None = None, body: bytes = b"") -> bytes:
    headers = headers or []
    header_names = {name.lower() for name, _ in headers}
    lines = [f"{method} {path} HTTP/1.1", "Host: xss-lab.local", "Connection: close"]
    if body and "content-length" not in header_names:
        headers.append(("Content-Length", str(len(body))))
    for name, value in headers:
        lines.append(f"{name}: {value}")
    return ("\r\n".join(lines) + "\r\n\r\n").encode("ascii") + body
def send_and_log(name: str, host: str, port: int, payload: bytes) -> None:
    response = send_raw(host, port, payload)
    status_line = response.split(b"\r\n", 1)[0].decode("latin-1", errors="ignore") if response else "no response"
    print(f"[client-send] {name} -> {host}:{port} {status_line}")
    time.sleep(0.2)
def main() -> None:
    parser = argparse.ArgumentParser(description="Send XSS supplement live-test traffic to 10.10.10.2")
    parser.add_argument("--server-ip", default="10.10.10.2")
    parser.add_argument("--port", type=int, default=18080)
    args = parser.parse_args()
    actions: list[tuple[str, bytes]] = [
        (
            "seed-9001288",
            http_request(
                "POST",
                "/comment/submit",
                headers=[("Content-Type", "application/x-www-form-urlencoded")],                body=b"comment=%3Cscript%3Ealert%281%29%3C%2Fscript%3E",
            ),
        ),
        (
            "seed-9001289",
            http_request(
                "POST",
                "/graphql",
                headers=[("Content-Type", "application/json")],
                body=(
                    b'{"message":"\\\\u003cscript>alert(1)\\\\u003c/script>",'
                    b'"template":"v-html","note":"srcdoc=data:text/html"}'
                ),
            ),
        ),
        (
            "alert-9001290",
            http_request(
                "POST",
                "/api/graphql",
                headers=[("Content-Type", "application/json")],
                body=(
                    b'{"dangerouslySetInnerHTML":"location.hash",'
                    b'"payload":"data:text/html,<svg onload=alert(1)>"}'
                ),
            ),
        ),
        ("alert-9001291", http_request("GET", "/dom-message")),
        ("alert-9001292", http_request("GET", "/dom-hash")),
        ("alert-9001293", http_request("GET", "/framework")),
        ("alert-9001294", http_request("GET", "/ticket/view?id=1")),
        ("alert-9001299", http_request("GET", "/admin/login")),
        ("alert-9001300", http_request("GET", "/portal/console")),
        ("alert-9001111", http_request("GET", "/assets/app.js")),
        (
            "alert-9001295",
            http_request("GET", "/collect?cookie=SESSIONTOKEN123456789"),
        ),
        (
            "alert-9001296",
            http_request("GET", "/beacon?owa-canary=CANARYTOKEN123456789"),
        ),
        (
            "alert-9001297",
            http_request(
                "POST",
                "/admin/users",
                headers=[("Content-Type", "application/x-www-form-urlencoded")],
                body=b"password=Reset123456&role=admin&enable=1",
            ),
        ),
        (
            "alert-9001298",
            http_request("GET", "/export/report?format=csv"),
        ),
    ]

    for name, payload in actions:
        send_and_log(name, args.server_ip, args.port, payload)
if __name__ == "__main__":
    main()

 

posted @ 2026-03-30 13:48  岐岐卡卡西  阅读(4)  评论(0)    收藏  举报