Skip to content
Merged
Show file tree
Hide file tree
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
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ Using GEF you can **start** a **debugging** session and execute **`got`** to see

In a binary the GOT has the **addresses to the functions or** to the **PLT** section that will load the function address. The goal of this arbitrary write is to **override a GOT entry** of a function that is going to be executed later **with** the **address** of the PLT of the **`system`** **function** for example.

Ideally, you will **override** the **GOT** of a **function** that is **going to be called with parameters controlled by you** (so you will be able to control the parameters sent to the system function).
Ideally, you will **override** the **GOT** of a **function** that is **going to be called with parameters controlled by you** (so you will be able to control the parameters sent to the system function).<sup>[[1]](#references)</sup>

If **`system`** **isn't used** by the binary, the system function **won't** have an entry in the PLT. In this scenario, you will **need to leak first the address** of the `system` function and then overwrite the GOT to point to this address.

Expand All @@ -48,7 +48,7 @@ The **GOT of libc** is usually compiled with **partial RELRO**, making it a nice

Common functions of the libc are going to call **other internal functions** whose GOT could be overwritten in order to get code execution.

Find [**more information about this technique here**](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md#1---targetting-libc-got-entries).
Find [**more information about this technique here**](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md#1---targetting-libc-got-entries).<sup>[[3]](#references)</sup>

### **Free2system**

Expand All @@ -72,7 +72,7 @@ Moreover, if `puts` is used with user input, it's possible to overwrite the `str
A common way to obtain RCE from a heap vulnerability is to abuse a fastbin so it's possible to add the part of the GOT table into the fast bin, so whenever that chunk is allocated it'll be possible to **overwrite the pointer of a function, usually `free`**.\
Then, pointing `free` to `system` and freeing a chunk where was written `/bin/sh\x00` will execute a shell.

It's possible to find an [**example here**](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/chunk_extend_overlapping/#hitcon-trainging-lab13)**.**
It's possible to find an [**example here**](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/chunk_extend_overlapping/#hitcon-trainging-lab13)**.**<sup>[[4]](#references)</sup>

## **Protections**

Expand All @@ -85,8 +85,10 @@ The **Full RELRO** protection is meant to protect agains this kind of technique

## References

- [https://ir0nstone.gitbook.io/notes/types/stack/got-overwrite/exploiting-a-got-overwrite](https://ir0nstone.gitbook.io/notes/types/stack/got-overwrite/exploiting-a-got-overwrite)
- [https://ir0nstone.gitbook.io/notes/types/stack/one-gadgets-and-malloc-hook](https://ir0nstone.gitbook.io/notes/types/stack/one-gadgets-and-malloc-hook)
- [1] [Exploiting a GOT overwrite (ir0nstone)](https://ir0nstone.gitbook.io/notes/types/stack/got-overwrite/exploiting-a-got-overwrite)
- [2] [One gadgets and malloc hook (ir0nstone)](https://ir0nstone.gitbook.io/notes/types/stack/one-gadgets-and-malloc-hook)
- [3] [Code execution on the last libc - targetting libc GOT entries (nobodyisnobody)](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md#1---targetting-libc-got-entries)
- [4] [CTF Wiki - chunk extend/overlapping (HITCON Training lab13)](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/chunk_extend_overlapping/#hitcon-trainging-lab13)

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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@

## Overview

An out-of-bounds **zero-write** vulnerability in Apple macOS **Scriptable Image Processing System** (`sips`) ICC profile parser (macOS 15.0.1, `sips-307`) allows an attacker to corrupt heap metadata and pivot the primitive into full code-execution. The bug is located in the handling of the `offsetToCLUT` field of the `lutAToBType` (`mAB `) and `lutBToAType` (`mBA `) tags. If attackers set `offsetToCLUT == tagDataSize`, the parser erases **16 bytes past the end of the heap buffer**. Heap spraying lets the attacker zero-out allocator structures or C++ pointers that will later be dereferenced, yielding an **arbitrary-write-to-exec** chain (CVE-2024-44236, CVSS 7.8).
An out-of-bounds **zero-write** vulnerability in Apple macOS **Scriptable Image Processing System** (`sips`) ICC profile parser (macOS 15.0.1, `sips-307`) allows an attacker to corrupt heap metadata and pivot the primitive into full code-execution. The bug is located in the handling of the `offsetToCLUT` field of the `lutAToBType` (`mAB `) and `lutBToAType` (`mBA `) tags. If attackers set `offsetToCLUT == tagDataSize`, the parser erases **16 bytes past the end of the heap buffer**. Heap spraying lets the attacker zero-out allocator structures or C++ pointers that will later be dereferenced, yielding an **arbitrary-write-to-exec** chain (CVE-2024-44236, CVSS 7.8).<sup>[[1]](#references)</sup>

> Apple patched the bug in macOS Sonoma 15.2 / Ventura 14.7.1 (October 30, 2024). A second variant (CVE-2025-24185) was fixed in macOS 15.5 and iOS/iPadOS 18.5 on April 1, 2025.
> Apple patched the bug in macOS Sonoma 15.2 / Ventura 14.7.1 (October 30, 2024). A second variant (CVE-2025-24185) was fixed in macOS 15.5 and iOS/iPadOS 18.5 on April 1, 2025.<sup>[[2]](#references)</sup>

## Vulnerable Code

Expand Down Expand Up @@ -95,9 +95,7 @@ Opening or processing a crafted ICC profile leads to remote **arbitrary code exe

## References

* Trend Micro Zero Day Initiative advisory ZDI-24-1445 – “Apple macOS ICC Profile Parsing Out-of-Bounds Write Remote Code Execution (CVE-2024-44236)”
https://www.zerodayinitiative.com/advisories/ZDI-24-1445/
* Apple security updates HT213981 “About the security content of macOS Sonoma 15.2”
https://support.apple.com/en-us/HT213981
- [1] [Apple macOS ICC Profile Parsing Out-Of-Bounds Write Remote Code Execution (ZDI-24-1445, CVE-2024-44236)](https://www.zerodayinitiative.com/advisories/ZDI-24-1445/)
- [2] [About the security content of macOS Sonoma 15.2 (Apple HT213981)](https://support.apple.com/en-us/HT213981)

{{#include ../../banners/hacktricks-training.md}}
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ Note that entries in `.fini_array` are called in **reverse** order, so you proba

#### Eternal loop

In order to abuse **`.fini_array`** to get an eternal loop you can [**check what was done here**](https://guyinatuxedo.github.io/17-stack_pivot/insomnihack18_onewrite/index.html)**:** If you have at least 2 entries in **`.fini_array`**, you can:
In order to abuse **`.fini_array`** to get an eternal loop you can [**check what was done here**](https://guyinatuxedo.github.io/17-stack_pivot/insomnihack18_onewrite/index.html)**:** If you have at least 2 entries in **`.fini_array`**, you can:<sup>[[1]](#references)</sup>

- Use your first write to **call the vulnerable arbitrary write function** again
- Then, calculate the return address in the stack stored by **`__libc_csu_fini`** (the function that is calling all the `.fini_array` functions) and put there the **address of `__libc_csu_fini`**
Expand All @@ -53,6 +53,10 @@ In order to abuse **`.fini_array`** to get an eternal loop you can [**check what
> Note that with [**Full RELRO**](../common-binary-protections-and-bypasses/relro.md)**,** the section **`.fini_array`** is made **read-only**.
> In newer versions, even with [**Partial RELRO**] the section **`.fini_array`** is made **read-only** also.

## References

- [1] [guyinatuxedo - Insomni'hack 2018 onewrite (stack pivot / .fini_array loop)](https://guyinatuxedo.github.io/17-stack_pivot/insomnihack18_onewrite/index.html)

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


Expand Down
28 changes: 16 additions & 12 deletions src/binary-exploitation/arbitrary-write-2-exec/www2exec-atexit.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ If you can **modify** the **address** of any of these **functions** to point to
Currently the **addresses to the functions** to be executed are **hidden** behind several structures and finally the address to which it points are not the addresses of the functions, but are **encrypted with XOR** and displacements with a **random key**. So currently this attack vector is **not very useful at least on x86** and **x86_64**.\
The **encryption function** is **`PTR_MANGLE`**. However, the exact implementation is **architecture- and glibc-version-dependent**: the generic glibc header is a no-op, but modern arch-specific implementations exist for important targets such as **x86_64** and **aarch64**. Therefore, **do not assume** that a non-x86 target automatically has **unmangled** exit pointers; check the target build's `pointer_guard.h` / `PTR_MANGLE` macros first.

You can find an in depth explanation on how this works in [https://m101.github.io/binholic/2017/05/20/notes-on-abusing-exit-handlers.html](https://m101.github.io/binholic/2017/05/20/notes-on-abusing-exit-handlers.html)
You can find an in depth explanation on how this works in [https://m101.github.io/binholic/2017/05/20/notes-on-abusing-exit-handlers.html](https://m101.github.io/binholic/2017/05/20/notes-on-abusing-exit-handlers.html)<sup>[[3]](#references)</sup>

## link_map

As explained [**in this post**](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md#2---targetting-ldso-link_map-structure), If the program exits using `return` or `exit()` it'll run `__run_exit_handlers()` which will call registered destructors.
As explained [**in this post**](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md#2---targetting-ldso-link_map-structure), If the program exits using `return` or `exit()` it'll run `__run_exit_handlers()` which will call registered destructors.<sup>[[4]](#references)</sup>

> [!CAUTION]
> If the program exits via **`_exit()`** function, it'll call the **`exit` syscall** and the exit handlers will not be executed. So, to confirm `__run_exit_handlers()` is executed you can set a breakpoint on it.
Expand Down Expand Up @@ -52,8 +52,8 @@ There are a **couple of options**:

- Overwrite the value of `map->l_addr` to make it point to a **fake `fini_array`** with instructions to execute arbitrary code
- Overwrite `l_info[DT_FINI_ARRAY]` and `l_info[DT_FINI_ARRAYSZ]` entries (which are more or less consecutive in memory) , to make them **points to a forged `Elf64_Dyn`** structure that will make again **`array` points to a memory** zone the attacker controlled.
- [**This writeup**](https://github.com/nobodyisnobody/write-ups/tree/main/DanteCTF.2023/pwn/Sentence.To.Hell) overwrites `l_info[DT_FINI_ARRAY]` with the address of a controlled memory in `.bss` containing a fake `fini_array`. This fake array contains **first a** [**one gadget**](../rop-return-oriented-programing/ret2lib/one-gadget.md) **address** which will be executed and then the **difference** between in the address of this **fake array** and the v**alue of `map->l_addr`** so `*array` will point to the fake array.
- According to main post of this technique and [**this writeup**](https://activities.tjhsst.edu/csc/writeups/angstromctf-2021-wallstreet) ld.so leave a pointer on the stack that points to the binary `link_map` in ld.so. With an arbitrary write it's possible to overwrite it and make it point to a fake `fini_array` controlled by the attacker with the address to a [**one gadget**](../rop-return-oriented-programing/ret2lib/one-gadget.md) for example.
- [**This writeup**](https://github.com/nobodyisnobody/write-ups/tree/main/DanteCTF.2023/pwn/Sentence.To.Hell) overwrites `l_info[DT_FINI_ARRAY]` with the address of a controlled memory in `.bss` containing a fake `fini_array`. This fake array contains **first a** [**one gadget**](../rop-return-oriented-programing/ret2lib/one-gadget.md) **address** which will be executed and then the **difference** between in the address of this **fake array** and the v**alue of `map->l_addr`** so `*array` will point to the fake array.<sup>[[5]](#references)</sup>
- According to main post of this technique and [**this writeup**](https://activities.tjhsst.edu/csc/writeups/angstromctf-2021-wallstreet) ld.so leave a pointer on the stack that points to the binary `link_map` in ld.so. With an arbitrary write it's possible to overwrite it and make it point to a fake `fini_array` controlled by the attacker with the address to a [**one gadget**](../rop-return-oriented-programing/ret2lib/one-gadget.md) for example.<sup>[[4]](#references)[[6]](#references)</sup>

Following the previous code you can find another interesting section with the code:

Expand All @@ -65,11 +65,11 @@ if (fini != NULL)
}
```

In this case it would be possible to overwrite the value of `map->l_info[DT_FINI]` pointing to a forged `ElfW(Dyn)` structure. Find [**more information here**](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md#2---targetting-ldso-link_map-structure).
In this case it would be possible to overwrite the value of `map->l_info[DT_FINI]` pointing to a forged `ElfW(Dyn)` structure. Find [**more information here**](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md#2---targetting-ldso-link_map-structure).<sup>[[4]](#references)</sup>

## TLS-Storage dtor_list overwrite in **`__run_exit_handlers`**

As [**explained here**](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md#5---code-execution-via-tls-storage-dtor_list-overwrite), if a program exits via `return` or `exit()`, it'll execute **`__run_exit_handlers()`** which will call any destructors function registered.
As [**explained here**](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md#5---code-execution-via-tls-storage-dtor_list-overwrite), if a program exits via `return` or `exit()`, it'll execute **`__run_exit_handlers()`** which will call any destructors function registered.<sup>[[4]](#references)</sup>

Code from `_run_exit_handlers()`:

Expand Down Expand Up @@ -136,11 +136,11 @@ Finally notice that the stored pointer is not only going to be xored with the co

So you need to take this into account before adding a new address.

Find an example in the [**original post**](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md#5---code-execution-via-tls-storage-dtor_list-overwrite).
Find an example in the [**original post**](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md#5---code-execution-via-tls-storage-dtor_list-overwrite).<sup>[[4]](#references)</sup>

## Other mangled pointers in **`__run_exit_handlers`**

This technique is [**explained here**](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md#5---code-execution-via-tls-storage-dtor_list-overwrite) and depends again on the program **exiting calling `return` or `exit()`** so **`__run_exit_handlers()`** is called.
This technique is [**explained here**](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md#5---code-execution-via-tls-storage-dtor_list-overwrite) and depends again on the program **exiting calling `return` or `exit()`** so **`__run_exit_handlers()`** is called.<sup>[[4]](#references)</sup>

Let's check more code of this function:

Expand Down Expand Up @@ -233,11 +233,11 @@ Moreover, in the options **`ef_on`** and **`ef_cxa`** it's also possible to cont
It's possible to check the **`initial` structure** in a debugging session with GEF running **`gef> p initial`**.

To abuse this you need either to **leak or erase the `PTR_MANGLE`cookie** and then overwrite a `cxa` entry in initial with `system('/bin/sh')`.\
You can find an example of this in the [**original blog post about the technique**](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md#6---code-execution-via-other-mangled-pointers-in-initial-structure).
You can find an example of this in the [**original blog post about the technique**](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md#6---code-execution-via-other-mangled-pointers-in-initial-structure).<sup>[[4]](#references)</sup>

## Practical `__exit_funcs` / `initial` forgery on modern glibc

Since classic hooks such as `__free_hook` disappeared from normal modern-glibc targets, a very common follow-up to an arbitrary write is to **forge a fake `struct exit_function_list`** and then repoint **`__exit_funcs`** to it. This is basically the most practical version of abusing `__run_exit_handlers()` on recent glibc releases.
Since classic hooks such as `__free_hook` disappeared from normal modern-glibc targets, a very common follow-up to an arbitrary write is to **forge a fake `struct exit_function_list`** and then repoint **`__exit_funcs`** to it. This is basically the most practical version of abusing `__run_exit_handlers()` on recent glibc releases.<sup>[[1]](#references)[[2]](#references)</sup>

The important points are:

Expand Down Expand Up @@ -292,8 +292,12 @@ If `__exit_funcs` is already corrupted, inspect the first entry and verify: `fla

## References

- [Code execution part 1: from exit to system](https://blog.rop.la/en/exploiting/2024/06/11/code-exec-part1-from-exit-to-system.html)
- [Dead or Alive - forging custom exit handlers on modern glibc](https://draksec.cz/blog/htb-uni-ctf-24/dead-or-alive/)
- [1] [Code execution part 1: from exit to system](https://blog.rop.la/en/exploiting/2024/06/11/code-exec-part1-from-exit-to-system.html)
- [2] [Dead or Alive - forging custom exit handlers on modern glibc](https://draksec.cz/blog/htb-uni-ctf-24/dead-or-alive/)
- [3] [Notes on abusing exit handlers](https://m101.github.io/binholic/2017/05/20/notes-on-abusing-exit-handlers.html)
- [4] [Code execution on the last libc (nobodyisnobody)](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md)
- [5] [DanteCTF 2023 - Sentence To Hell writeup](https://github.com/nobodyisnobody/write-ups/tree/main/DanteCTF.2023/pwn/Sentence.To.Hell)
- [6] [ångstromCTF 2021 - Wall Street writeup](https://activities.tjhsst.edu/csc/writeups/angstromctf-2021-wallstreet)

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

Expand Down
Loading