Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions src/binary-exploitation/array-indexing.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,50 @@

Array-indexing vulnerabilities occur when a program fails to validate an index before using it to read or write an array. An out-of-bounds access may disclose memory, corrupt adjacent objects, or alter control data. The exploitation strategy depends on the array layout, the attacker's control over the index and value, and the binary's mitigations.<sup>[[5]](#references)</sup>

## Read-dependent constrained OOB writes

An unchecked integer used to index a pointer table can produce more than a simple OOB read when the surrounding logic reads the slot and conditionally updates it. Audit patterns equivalent to the following, including indexes parsed from database rows, configuration objects, or plugin input.<sup>[[6]](#references)</sup>

```c
entry = table[node][index];
if (entry == NULL) {
table[node][index] = current;
} else {
while (entry->next != NULL)
entry = entry->next;
entry->next = current;
}
```

The initial access selects `B + index * sizeof(pointer)`. A negative index reaches memory before `B`, while an index at or above the element count reaches memory after the array. The value read determines which constrained corruption primitive follows:<sup>[[6]](#references)</sup>

- **Zero slot:** the code writes the live `current` object pointer to the same attacker-selected relative slot. The destination is partially controlled, but the written value is not.
- **Nonzero slot:** unrelated memory is type-confused as an object. The loop follows fixed-offset `next` pointers until a NULL field is found and then writes `current` there. Useful exploitation requires a readable pointer chain; otherwise the process crashes during traversal.

A very large index is useful for confirming the missing check because it normally reaches unmapped memory, but this demonstrates only a crash. Turning the primitive into a security-sensitive write usually requires a reachable mapped offset, a zero slot or predictable pointer chain, an address disclosure when ASLR is enabled, heap-layout control, and a target that is useful when replaced with the constrained object pointer.<sup>[[6]](#references)</sup>

### Native-extension example: PostGIS `address_standardizer`

PostGIS `address_standardizer` illustrated this pattern in native code running inside the PostgreSQL backend. A caller could select a rules table whose rule strings end in attacker-controlled `Type` and `Weight` integers; the path `standardize_address()` → `load_rules()` → `parse_rule()` → `rules_add_rule()` → `classify_link()` validated token symbols but previously allowed `Type` to reach a five-entry `KW *` table without a `0..4` bounds check. On a 64-bit build the selected address was therefore `B + Type * 8`, so `Type = -1` selected the qword immediately before the 40-byte row and `Type = 5` selected the first qword after it.<sup>[[6]](#references)</sup>

The following authenticated crash probe uses a caller-owned rules table and a distant index. Run denial-of-service probes only in an isolated test instance because the affected backend can terminate.<sup>[[6]](#references)</sup>

```sql
CREATE TEMP TABLE poc_rules_oob (
id serial PRIMARY KEY,
rule text NOT NULL
);
INSERT INTO poc_rules_oob(rule)
VALUES ('29 -1 1 -1 2147483647 1');

SELECT standardize_address(
'us_lex', 'us_gaz', 'poc_rules_oob',
'123 Main St', 'Springfield'
);
```

This primitive does not return the OOB value to SQL and does not by itself provide an arbitrary-value write or defeat ASLR. The reported full chain paired it with a separate address disclosure and targeted backend-local cached authorization state; this is an example of converting a relative, pointer-valued write into privilege escalation by corrupting process-local security state rather than persistently modifying database catalogs.<sup>[[6]](#references)</sup>

## Examples

- **SwampCTF 2019 - dreamheaps:** Two arrays store allocation addresses and sizes. Their indexes overlap, so an out-of-bounds operation can turn a size entry into an attacker-chosen pointer. The exploit redirects a write to `free@GOT`, replaces it with `system`, and frees a buffer containing `/bin/sh`.<sup>[[1]](#references)</sup>
Expand All @@ -20,5 +64,6 @@ Array-indexing vulnerabilities occur when a program fails to validate an index b
- [3] [Faraz - SECCON CTF 2019 sum write-up](https://faraz.faith/2019-10-20-secconctf-2019-sum/)
- [4] [Nightmare - TUCTF guestbook](https://guyinatuxedo.github.io/14-ret_2_system/tu_guestbook/index.html)
- [5] [MITRE CWE-129 - Improper validation of array index](https://cwe.mitre.org/data/definitions/129.html)
- [6] [Systemic Risks in Managed PostgreSQL: Exploiting PostGIS address_standardizer Memory Corruption](https://mehmetince.net/part-1-6-systemic-risks-in-the-managed-postgresql-industry-extension-risks-are-real-exploiting-postgis-memory-corruption-bug-at-neondb-supabase-and-many-more)

{{#include ../banners/hacktricks-training.md}}