# CVE-2023-38148 — Windows ICS `ipnathlp.dll` Pre-Auth Stack Overflow via the DHCP Hardware-Address-Length Field

---

## Summary

| | |
|---|---|
| **Product** | Microsoft Windows — `ipnathlp.dll` (Internet Connection Sharing / ICS, NAT helper) |
| **CVE ID** | CVE-2023-38148 |
| **Impact** | Remote Code Execution — **pre-authentication** (network-adjacent) |
| **MSRC severity** | Critical |
| **CWE** | CWE-121: Stack-based Buffer Overflow |
| **Patch Date** | September 12, 2023 |
| **Pre-patch binary** | `ipnathlp.dll` 10.0.22621.963 (Aug 2023) — SHA256 `ff29257cad0e53545286174fd7f04a819bb3989d09a6bcbea5a0f06b50b2a191` |
| **Post-patch binary** | `ipnathlp.dll` 10.0.22621.2283 (Sep 12 2023 fix) — SHA256 `108a9bd863741f51f104c928f075bc5297fc98f9b4ed21bb1140b5c800599a3b` |
| **Fix gating** | **None** — unconditional length check (no CFR/KIR flag) |

---

## Product Description

`ipnathlp.dll` implements **Internet Connection Sharing (ICS)** — the Windows NAT
helper. When ICS is enabled, the service opens a **DHCP server on UDP/67** (plus
DNS/53 and 68) to hand out addresses to the shared network. Those DHCP listeners
parse untrusted packets from any host on the shared segment, **pre-authentication**
— which is what makes a parsing bug here a Critical, network-reachable RCE. ICS is
not on by default, but is widely enabled for hotspot / connection-sharing setups.

---

## Vulnerability Summary

The ICS DHCP server parses the fixed BOOTP/DHCP header, whose **hardware address
length** (`hlen`) byte the client fully controls. The message processor validated
`hlen` weakly, then a downstream ARP-table update `memcpy`'d `hlen` bytes of the
client hardware address into a fixed-size field of a **stack** `MIB_IPNET_ROW2`:

```c
// DhcpAddArpEntry (from the public analysis) — the sink
MIB_IPNET_ROW2 Row;                        // stack struct, 0xA8 bytes
...
Row.PhysicalAddressLength = hlen;          // hlen = DHCP header hardware-addr-length (attacker byte)
memcpy(Row.PhysicalAddress, Src, hlen);    // *** PhysicalAddress is 32 (0x20) bytes ***
CreateIpNetEntry2(&Row);
```

`MIB_IPNET_ROW2.PhysicalAddress` is `IF_MAX_PHYS_ADDRESS_LENGTH` = **32 (0x20)**
bytes. `hlen` is a single header byte (up to `0xFF`). Pre-patch,
`Dhcp[…]ProcessMessage` only *logged* when `hlen > 0x20` and **kept processing**,
so an attacker-chosen `hlen` up to `0xFF` reached the `memcpy` and overran the
`PhysicalAddress` field on the stack — a controlled stack buffer overflow in the
ICS service.

---

## Prerequisites and Constraints

- **Network-adjacent, unauthenticated.** Any host that can send UDP to the ICS
  host's DHCP port (UDP/67) on the shared segment. No credentials.
- ICS must be enabled on the target (the DHCP listener only exists then).
- The overflow bytes are attacker-controlled (the client hardware address),
  making this a *controlled* stack overflow suitable for exploitation, not just a
  crash.

---

## Vulnerability Details

### Call Chain

```
Network-adjacent attacker (no auth), UDP/67:
  crafted BOOTP/DHCP packet with hardware-address-length (hlen) > 0x20
        ↓
ICS service (ipnathlp.dll):
  DhcpProcessMessage / V2DhcpProcessMessage   [weak hlen check]
    → Dhcp(…)ProcessBootpMessage
      → DhcpAddArpEntry                        [*** stack overflow ***]
           memcpy(Row.PhysicalAddress[0x20], Src, hlen)   // hlen up to 0xFF
           CreateIpNetEntry2(&Row)
```

### Root Cause

`hlen` (DHCP header offset — `param_2[0xe6]` in the decompilation) is used as a
`memcpy` length into a 32-byte stack field without being bounded to that size.
The pre-patch processor's only `hlen > 0x20` handling was a trace-log, not a
rejection, so oversized values flowed through to the copy (CWE-121).

### The patch (confirmed — diff, .963 → .2283)

Both `DhcpProcessMessage` and `V2DhcpProcessMessage` are restructured to **reject
`hlen > 0x20` before processing**:

```c
// V2DhcpProcessMessage (10.0.22621.2283) — PATCHED, from our diff
// param_2[0xe6] == hlen
if ((byte)param_2[0xe6] < 0x21) {           // *** only process when hlen <= 0x20 ***
    ... ExtractOptions ...
    if ((byte)param_2[0xe6] < 0x11) {
        V2DhcpProcessBootpMessage(...);     // BOOTP path
        goto LAB_1;
    }
    if (0x10 < (byte)param_2[0xe6]) {        // 0x11..0x20 handled, then bail out cleanly
        ...trace...
        goto LAB_0;
    }
}
// hlen > 0x20 now falls through to the error path — never reaches DhcpAddArpEntry
```

Pre-patch the guard was `if (0x20 < hlen) { …log… }` followed by continued
processing; post-patch the whole message path is gated on `hlen < 0x21`, so an
oversized hardware-address length is refused before the `memcpy` sink. The same
change is applied to `DhcpProcessMessage`.

### Patch Completeness Assessment

**Unconditional fix — no CFR/KIR flag** (`WPP_GLOBAL_Control` references are just
ETW/WPP tracing, not a gate). As with the other 2022–2023 fixes in this corpus
(npfs CVE-2022-22715, DHCPv6 CVE-2023-28231), the length check is always-on and
patch state is determined by file version.

---

## Detection Guidance

**Network.** On an ICS host, DHCP/BOOTP packets to UDP/67 whose **hardware address
length (`hlen`) field exceeds 0x20 (32)** — no legitimate client sets it above 6
(Ethernet) / 16. That single field over 0x20 is the direct exploit indicator.

**Crash signature.** Stack-corruption bugchecks / `__security_check_cookie`
failures (`/GS`) in the ICS host process, stacks through
`ipnathlp!DhcpAddArpEntry` / `DhcpProcessMessage` / `V2DhcpProcessMessage`.

**Exposure.** Inventory hosts with ICS enabled (DHCP listener on UDP/67) and
ensure the shared segment is not reachable by untrusted devices. Disabling ICS
where not required removes the listener entirely.

---

## References

- VictorV — *Windows Internet Connection Sharing (ICS) CVE-2023-38148 分析*.
  `v-v.space/2023/09/13/ics_CVE-2023-38148-readme/`
- MSRC advisory — CVE-2023-38148 (Internet Connection Sharing Remote Code Execution)
- Full binary diff: `/data/patch_diffs/ipnathlp_dll-cve-2023-38148-ghidriff.md`
