# Integer overflow in strop.expandtabs

Integer overflow in Python 2 strop.expandtabs line-length accumulator lets a crafted tab/newline string with large tabsize under-allocate a buffer and corrupt heap memory toward code execution.

- Payout: hidden
- Severity: high
- Program: Internet Bug Bounty
- Found by: ianbeer
- Disclosed: 2014-03-31
- Write-up quality: 8/10
- Original: https://hackerone.com/reports/6389
- Library page: https://bugbountylibrary.com/r/h1%3A6389
- Tags: area:oss domain:oss impact:rce kind:bounty platform:hackerone sev:high tech:python technique:incomplete-fix technique:source-review vuln:memory-corruption

**Target:** strop.expandtabs string function (Modules/stropmodule.c)
**Root cause:** The newline branch does `i += j` without checking that i stays within PY_SSIZE_T_MAX, so i can overflow and PyString_FromStringAndSize allocates an undersized buffer for the second expansion loop.
**Steps:**
1. Craft a string of repeated `\t\n` sequences so each line's tab expansion accumulates into i.
2. Pass a large tabsize (e.g. `0x10001`) so i overflows past PY_SSIZE_T_MAX.
3. Call `strop.expandtabs(strs[15], 0x10001)` after heap grooming with large `'\t\n'*0x10000 + 'A'*0x1000000` strings and freeing one slot.
4. Second loop writes expanded spaces past the undersized allocation, overwriting adjacent PyStringObject headers.
**How found:** Code review of stropmodule.c spotted the missing overflow check in the newline branch (`i += j`) while the tab branch had one; noted three copy-paste versions of expandtabs exist and only stringobject.c checked correctly.
**Exploitation:** Heap grooming places the undersized output buffer (h1) inline before the tabstring (h2). Expansion overflows into h2's PyStringObject header, overwriting its tabs with spaces so the second loop stops expanding, limiting corruption to chosen objects. Pointing h2's ob_type to a controlled address with a fake struct _typeobject (tp_dealloc, tp_print, tp_getattr, tp_setattr, tp_compare, tp_repr) yields native code execution when a corresponding Python operation is invoked.
**Escalation:** Controlled heap layout plus fake _typeobject function pointers converts a buffer overflow into arbitrary native code execution.
**Insight:** When auditing C string routines, compare duplicate copy-paste implementations of the same function across files—one variant often has a bounds check the others lack, revealing the missing check.

## Proof of concept (copied exactly from the original report)

**Crashing expandtabs PoC script**

```
import strop

strs = []
for i in range(20):
  strs.append('\t\n' * 0x10000 + 'A' * 0x1000000)
for i in range(20):
  print hex(id(strs[i]))
strs[14] = None
strop.expandtabs(strs[15], 0x10001)
print strs[15]
```

