DragonFlyBSD Kernel Audit
DF-0494 / leak_sample.txt
← back to finding ↓ download raw
DF-0494 — captured kernel-memory leak samples (raw bytes from ARP REPLY)
=======================================================================

All bytes below were returned by the victim kernel inside an ARP REPLY frame
that the victim generated in response to a single crafted ARP REQUEST.  The
attacker never sent these bytes; they are out-of-bounds kernel reads driven
by the attacker-controlled ar_hln / ar_pln fields.

Guest: DragonFly 6.5-DEVELOPMENT #0  (tap0 = 10.99.99.1, attacker = 10.99.99.2)

================================================================
[1] HEAP LEAK  --  ar_hln=100, ar_pln=4  (memcpy(ar_sha, IF_LLADDR, ar_hln))
================================================================
Reply ar_sha field (100 bytes).  Bytes [0..5] = tap0 real MAC.  Bytes [6..99]
= 94 bytes of adjacent kernel heap past the interface's sockaddr_dl link
address.  NOTE: the attacker's request filler was 0xCC; none of the leaked
bytes are 0xCC -> this is genuine kernel memory, not echoed request data.

  0000: 00 bd d1 86 02 00 00 00 00 00 00 00 00 00 00 00   [0..5]=real MAC
  0010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0020: 00 00 00 00 00 00 00 00 00 00 00 00 0c 00 00 00   +0x2c: 0x0c (kernel field)
  0030: 00 00 00 00 ff ff ff ff 00 00 00 00 00 00 00 00   +0x34: 0xffffffff (INADDR_BROADCAST / ~0 marker)
  0040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0060: 00 00 00 00

Leak size scales perfectly with ar_hln (proof it is the ar_hln-driven OOB):
    ar_hln=16  -> 10 bytes leaked  (16-6)
    ar_hln=32  -> 26 bytes leaked  (32-6)
    ar_hln=48  -> 42 bytes leaked
    ar_hln=64  -> 58 bytes leaked
    ar_hln=100 -> 94 bytes leaked
  => leaked_bytes == ar_hln - 6   (attacker controls the size, up to 249 on
                                   real hardware; tap harness mbuf-chaining
                                   caps the demo at ar_hln<=~106)

================================================================
[2] STACK LEAK  --  ar_hln=6, ar_pln=100  (memcpy(ar_spa, &taddr, ar_pln))
================================================================
Reply ar_spa field (100 bytes).  Bytes [0..3] = victim IP (10.99.99.1 =
0a 63 63 01).  Bytes [4..99] = 96 bytes of in_arpreply()'s stack frame and
the frames above it (return addresses, saved rbp, locals, arguments).

  0000: 0a 63 63 01 80 8a 1f 8d 00 f8 ff ff d2 b1 67 80   [0..3]=victim IP
  0010: ff ff ff ff 1f 00 00 00 00 00 00 00 20 00 00 00
  0020: 00 00 00 00 30 f0 ab 8b 00 f8 ff ff 00 f0 ab 8b
  0030: 00 f8 ff ff 00 f0 ab 8b 00 f8 ff ff 40 60 17 81
  0040: ff ff ff ff b0 8a 1f 8d 00 f8 ff ff a9 64 74 80
  0050: ff ff ff ff 40 60 17 81 ff ff ff ff 00 20 8c 81
  0060: ff ff ff ff

Kernel-pointer scan of the 96 stack-leak bytes (10 canonical kernel addresses):

  stack+ 0 (abs  4): 0xfffff8008d1f8a80   kernel virtual (struct/heap ptr)
  stack+ 8 (abs 12): 0xffffffff8067b1d2   kernel .text  *** RETURN ADDRESS ***
  stack+32 (abs 36): 0xfffff8008babf030   kernel virtual (struct/heap ptr)
  stack+40 (abs 44): 0xfffff8008babf000   kernel virtual (struct/heap ptr)
  stack+48 (abs 52): 0xfffff8008babf000   kernel virtual (struct/heap ptr)
  stack+56 (abs 60): 0xffffffff81176040   kernel .text  (return address)
  stack+64 (abs 68): 0xfffff8008d1f8ab0   kernel virtual (struct/heap ptr)
  stack+72 (abs 76): 0xffffffff807464a9   kernel .text  (return address)
  stack+80 (abs 84): 0xffffffff81176040   kernel .text  (return address)
  stack+88 (abs 92): 0xffffffff818c2000   kernel .text/.data

VERIFICATION that the leaked text pointers are real (not garbage):
  - Guest kernel .text/.data symbol range:  0xffffffff80200000 .. 0xffffffff81b25e20
    (from `nm /boot/kernel/kernel`).  ALL four 0xffffffff80?????? leaked values
    fall inside this range.
  - objdump pinpoints 0xffffffff8067b1d2 exactly:
        ffffffff8067b1cd:  e8 0e 5c 00 00   callq  ffffffff80680de0 <ssleep>
        ffffffff8067b1d2:  85 c0            test   %eax,%eax
    i.e. it is the return address immediately following a call to ssleep() --
    a real call-stack return address leaked to userspace.

IMPACT: direct KASLR defeat (kernel-text base disclosed) + kernel heap-pointer
disclosure + stack-layout disclosure, all from one unauthenticated ARP REQUEST
on the same L2 segment.  No credentials, no session, single packet.