Translated ['binary-exploitation/arbitrary-write-2-exec/aw2exec-__malloc

This commit is contained in:
Translator 2024-06-17 09:23:26 +00:00
parent 70a77f1068
commit 660670c534
4 changed files with 284 additions and 303 deletions

View file

@ -2,48 +2,47 @@
<details>
<summary><strong>htARTE (HackTricks AWS Red Team 전문가)로부터 AWS 해킹을 처음부터 전문가까지 배우세요!</strong></summary>
<summary><strong>htARTE (HackTricks AWS Red Team 전문가)</strong>에서 <a href="https://training.hacktricks.xyz/courses/arte"><strong>AWS 해킹을 처음부터 전문가까지 배우세요</strong></a><strong>!</strong></summary>
HackTricks를 지원하는 다른 방법:
* **회사가 HackTricks에 광고되길 원하거나 HackTricks를 PDF로 다운로드**하고 싶다면 [**구독 요금제**](https://github.com/sponsors/carlospolop)를 확인하세요!
* [**공식 PEASS & HackTricks 스왜그**](https://peass.creator-spring.com)를 구매하세요
* [**The PEASS Family**](https://opensea.io/collection/the-peass-family)를 발견하세요, 당사의 독점 [**NFTs**](https://opensea.io/collection/the-peass-family) 컬렉션
* **💬 [Discord 그룹](https://discord.gg/hRep4RUj7f)** 또는 [텔레그램 그룹](https://t.me/peass)에 **가입**하거나 **트위터** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)를 **팔로우**하세요.
* **HackTricks** 및 **HackTricks Cloud** github 저장소에 PR을 제출하여 **해킹 트릭을 공유**하세요.
* **💬 [**Discord 그룹**](https://discord.gg/hRep4RUj7f) 또는 [**텔레그램 그룹**](https://t.me/peass)에 **가입**하거나 **트위터** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**를 팔로우**하세요.
* **해킹 요령을 공유하려면 PR을** [**HackTricks**](https://github.com/carlospolop/hacktricks) 및 [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github 저장소에 제출하세요.
</details>
## **Malloc Hook**
[GNU 공식 사이트](https://www.gnu.org/software/libc/manual/html\_node/Hooks-for-Malloc.html)에 따르면 **`__malloc_hook`** 변수는 `malloc()`이 호출될 때 **호출될 함수의 주소를 가리키는 포인터**로, **libc 라이브러리의 데이터 섹션에 저장**됩니다. 따라서 이 주소가 덮어쓰여지고 `malloc`이 호출되면, 예를 들어 **One Gadget**이 호출됩니다.
[GNU 공식 사이트](https://www.gnu.org/software/libc/manual/html\_node/Hooks-for-Malloc.html)에 따르면 변수 **`__malloc_hook`**은 `malloc()`이 호출될 때 **호출될 함수의 주소를 가리키는 포인터**로, **libc 라이브러리의 데이터 섹션에 저장**됩니다. 따라서 이 주소가 덮어쓰여지고 `malloc`이 호출되면 예를 들어 **One Gadget**으로 덮어쓰인 경우 **One Gadget이 호출**됩니다.
malloc을 호출하는 방법은 프로그램이 호출할 때까지 기다리거나, **`printf("%10000$c")`를 호출**하여 `libc`많은 바이트를 할당하도록 만들어 힙에 할당하도록 하는 것이 가능합니다.
malloc을 호출하는 방법은 프로그램이 호출할 때까지 기다리거나 **`printf("%10000$c")`를 호출**하여 `libc`힙에 그들을 할당하도록 많은 바이트를 할당하게 할 수 있습니다.
One Gadget에 대한 자세한 정보는:
One Gadget에 대한 자세한 정보는 다음에서 확인할 수 있습니다:
{% content-ref url="../rop-return-oriented-programing/ret2lib/one-gadget.md" %}
[one-gadget.md](../rop-return-oriented-programing/ret2lib/one-gadget.md)
{% endcontent-ref %}
{% hint style="warning" %}
훅은 **GLIBC >= 2.34**에서 **비활성화**됩니다. 최신 GLIBC 버전에서 사용할 수 있는 다른 기술이 있습니다. 참조: [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).
후크는 **GLIBC >= 2.34**에서 **비활성화**됩니다. 최신 GLIBC 버전에서 사용할 수 있는 다른 기술이 있습니다. 참조: [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).
{% endhint %}
## Free Hook
이것은 페이지에서 빠른 바이너리 공격을 남용한 후 정렬되지 않은 바이너리 공격을 남용한 예제 중 하나에서 남용되었습니다:
이것은 페이지에서 빠른 bin 공격을 남용한 후 정렬되지 않은 bin 공격을 남용한 예제 중 하나에서 남용되었습니다:
{% content-ref url="../libc-heap/unsorted-bin-attack.md" %}
[unsorted-bin-attack.md](../libc-heap/unsorted-bin-attack.md)
{% endcontent-ref %}
심볼이 있는 경우 이진 파일의 free hook 위치를 찾는 좋은 트릭은 **다음과 같이** 하는 것입니다:
바이너리에 심볼이 있는 경우 다음 명령을 사용하여 `__free_hook`의 주소를 찾을 수 있습니다:
```bash
gef➤ p &__free_hook
```
gef➤ set __free_hook = 0xfacade
gef➤ search-pattern 0xfacade
```
동일한 게시물에서 심볼 없이 free 후크의 주소를 찾는 방법에 대한 단계별 가이드를 찾을 수 있습니다. 요약하면, free 함수에서:
[포스트](https://guyinatuxedo.github.io/41-house\_of\_force/bkp16\_cookbook/index.html)에서는 심볼 없이 free 후크의 주소를 찾는 방법에 대한 단계별 가이드를 찾을 수 있습니다. 요약하면, free 함수에서:
<pre class="language-armasm"><code class="lang-armasm">gef➤ x/20i free
0xf75dedc0 &#x3C;free>: push ebx
@ -52,14 +51,14 @@ gef➤ search-pattern 0xfacade
0xf75dedcc &#x3C;free+12>: sub esp,0x8
0xf75dedcf &#x3C;free+15>: mov eax,DWORD PTR [ebx-0x98]
0xf75dedd5 &#x3C;free+21>: mov ecx,DWORD PTR [esp+0x10]
0xf75dedd9 &#x3C;free+25>: mov eax,DWORD PTR [eax]
<strong>0xf75deddb &#x3C;free+27>: test eax,eax ;&#x3C;--- 여기서 중단
</strong>0xf75deddd &#x3C;free+29>: jne 0xf75dee50 &#x3C;free+144>
<strong>0xf75dedd9 &#x3C;free+25>: mov eax,DWORD PTR [eax]--- 여기서 중단
</strong>0xf75deddb &#x3C;free+27>: test eax,eax ;&#x3C;
0xf75deddd &#x3C;free+29>: jne 0xf75dee50 &#x3C;free+144>
</code></pre>
이전 코드의 중단점에서 `$eax`에 free 후크의 주소가 위치합니다.
이제 **빠른 bin 공격**을 수행합니다:
이제 **빠른 bin 공격**이 수행됩니다:
* 먼저 **`__free_hook`** 위치에서 크기가 200인 빠른 **청크**를 작업할 수 있다는 것을 발견했습니다:
* <pre class="language-c"><code class="lang-c">gef➤ p &#x26;__free_hook
@ -72,9 +71,9 @@ gef➤ x/60gx 0x7ff1e9e607a8 - 0x59
</code></pre>
* 이 위치에 크기가 0x200인 빠른 청크를 얻으면 실행될 함수 포인터를 덮어쓸 수 있습니다.
* 이를 위해 크기가 `0xfc`인 새로운 청크를 만들고 해당 포인터로 두 번 호출하여 크기가 `0xfc*2 = 0x1f8`인 해제된 청크에 대한 포인터를 얻습니다.
* 그런 다음, 이 청크에서 **`fd`** 주소를 수정하기 위해 편집 함수가 호출됩니다. 이를 통해 빠른 bin의 이전 **`__free_hook`** 함수를 가리키도록 합니다.
* 그런 다음, 크기가 `0x1f8`인 청크를 만들어 빠른 bin에서 이전에 사용하지 않았던 청크를 검색하여 **`__free_hook`**에 빠른 bin 청크를 얻습니다. 이 위치에 **`system`** 함수의 주소로 덮어쓰기합니다.
* 마지막으로 `/bin/sh\x00` 문자열을 포함하는 청크를 해제하여 삭제 함수를 호출하고, **`__free_hook`** 함수를 트리거하여 `/bin/sh\x00`을 매개변수로 사용하여 system을 가리키게 합니다.
* 그런 다음, 이 청크에서 **`fd`** 주소를 수정하기 위해 편집 함수가 호출됩니다. 이를 통해 이전 **`__free_hook`** 함수를 가리키도록 빠른 bin의 **`fd`** 주소를 수정합니다.
* 그런 다음, 크기가 `0x1f8`인 청크를 만들어 불필요한 이전 청크를 빠른 bin에서 검색하여 **`__free_hook`**에 빠른 bin 청크를 얻습니다. 이 위치에 **`system`** 함수의 주소로 덮어쓰기합니다.
* 마지막으로 `/bin/sh\x00` 문자열을 포함하는 청크를 삭제 함수를 호출하여 해제하면 **`__free_hook`** 함수가 트리거되어 `/bin/sh\x00`을 매개변수로 사용하여 system을 가리킵니다.
## 참고 자료
@ -83,14 +82,14 @@ gef➤ x/60gx 0x7ff1e9e607a8 - 0x59
<details>
<summary><strong>htARTE (HackTricks AWS Red Team Expert)</strong>를 통해 **제로부터 영웅까지 AWS 해킹을 배우세요</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS Red Team Expert)</strong></a><strong>!</strong></summary>
<summary><strong>htARTE (HackTricks AWS Red Team Expert)</strong>를 통해 **제로부터 영웅까지 AWS 해킹을 배우세요**!</summary>
HackTricks를 지원하는 다른 방법:
* **회사를 HackTricks에서 광고하거나 HackTricks를 PDF로 다운로드**하려면 [**구독 요금제**](https://github.com/sponsors/carlospolop)를 확인하세요!
* [**공식 PEASS & HackTricks 스왜그**](https://peass.creator-spring.com)를 구입하세요
* [**The PEASS Family**](https://opensea.io/collection/the-peass-family)를 발견하세요, 당사의 독점 [**NFTs**](https://opensea.io/collection/the-peass-family) 컬렉션
* **💬 [디스코드 그룹](https://discord.gg/hRep4RUj7f)에 가입하거나 [텔레그램 그룹](https://t.me/peass)에 가입하거나** **트위터** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**를 팔로우하세요.**
* **HackTricks 및 HackTricks Cloud** 깃허브 저장소에 PR을 제출하여 **해킹 트릭을 공유하세요**.
* 독점 [**NFTs**](https://opensea.io/collection/the-peass-family) 컬렉션인 [**The PEASS Family**](https://opensea.io/collection/the-peass-family)를 발견하세요
* 💬 [**디스코드 그룹**](https://discord.gg/hRep4RUj7f) 또는 [**텔레그램 그룹**](https://t.me/peass)에 가입하거나 **트위터** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)를 팔로우하세요.
* **HackTricks****HackTricks Cloud** 깃허브 저장소에 PR을 제출하여 해킹 트릭을 공유하세요.
</details>

View file

@ -2,15 +2,15 @@
<details>
<summary><strong>htARTE (HackTricks AWS Red Team 전문가)로부터 AWS 해킹을 처음부터 전문가까지 배우세요!</strong></summary>
<summary><strong>htARTE (HackTricks AWS Red Team 전문가)</strong>를 통해 **제로부터 영웅까지 AWS 해킹을 배우세요!</summary>
HackTricks를 지원하는 다른 방법:
- **회사가 HackTricks에 광고되길 원하거나 HackTricks를 PDF로 다운로드하고 싶다면** [**구독 요금제**](https://github.com/sponsors/carlospolop)를 확인하세요!
- [**공식 PEASS & HackTricks 스왜그**](https://peass.creator-spring.com)를 구입하세요.
- [**The PEASS Family**](https://opensea.io/collection/the-peass-family)를 발견하세요. 당사의 독점 [**NFTs**](https://opensea.io/collection/the-peass-family) 컬렉션입니다.
- **💬 [디스코드 그룹](https://discord.gg/hRep4RUj7f)** 또는 [텔레그램 그룹](https://t.me/peass)에 **가입**하거나 **트위터** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)를 **팔로우**하세요.
- **HackTricks****HackTricks Cloud** github 저장소에 PR을 제출하여 **해킹 요령을 공유**하세요.
* **회사가 HackTricks에 광고되길 원하거나** **HackTricks를 PDF로 다운로드**하려면 [**구독 요금제**](https://github.com/sponsors/carlospolop)를 확인하세요!
* [**공식 PEASS & HackTricks 스왜그**](https://peass.creator-spring.com)를 얻으세요
* [**The PEASS Family**](https://opensea.io/collection/the-peass-family)를 발견하세요, 우리의 독점 [**NFTs**](https://opensea.io/collection/the-peass-family) 컬렉션
* **💬 [디스코드 그룹](https://discord.gg/hRep4RUj7f)** 또는 [텔레그램 그룹](https://t.me/peass)에 **가입**하거나 **트위터** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)를 **팔로우**하세요.
* **HackTricks****HackTricks Cloud** 깃허브 저장소에 **PR을 제출**하여 **해킹 요령을 공유**하세요.
</details>
@ -18,25 +18,25 @@ HackTricks를 지원하는 다른 방법:
### **GOT: Global Offset Table**
**Global Offset Table (GOT)**은 **동적으로 연결된 이진 파일**에서 **외부 함수의 주소를 관리하는 메커니즘**입니다. 이러한 **주소는 실행 시간까지 알려지지 않기 때문에** (동적 연결 때문에), GOT는 이러한 외부 심볼의 주소가 **한 번 해결되면 해당 주소를 동적으로 업데이트하는 방법**을 제공합니다.
**Global Offset Table (GOT)**은 **동적으로 연결된 이진 파일**에서 **외부 함수의 주소를 관리하는 메커니즘**입니다. 이러한 **주소는 런타임에서 알려지지 않기 때문에** (동적 연결 때문에), GOT은 이러한 외부 심볼의 주소가 **해결된 후에 주소를 동적으로 업데이트하는 방법**을 제공합니다.
GOT의 각 항목은 이진 파일이 호출할 수 있는 외부 라이브러리의 심볼에 해당합니다. **함수가 처음 호출될 때 동적 링커에 의해 실제 주소가 해결되고 GOT에 저장**됩니다. 동일한 함수에 대한 후속 호출은 GOT에 저장된 주소를 사용하여 주소를 다시 해결하는 오버헤드를 피합니다.
### **PLT: Procedure Linkage Table**
**Procedure Linkage Table (PLT)**은 **GOT**과 밀접하게 작하며 외부 함수 호출을 처리하기 위한 트램폴린 역할을 합니다. 바이너리가 **외부 함수를 처음 호출하면 해당 함수와 관련된 PLT 항목으로 제어가 전달**됩니다. 이 PLT 항목은 함수의 주소가 이미 해결되지 않은 경우 동적 링커를 호출하여 주소를 해결합니다. 주소가 해결되면 **GOT**에 저장됩니다.
**Procedure Linkage Table (PLT)**은 **GOT**과 밀접하게 작하며 외부 함수 호출을 처리하기 위한 트램폴린 역할을 합니다. 바이너리가 **외부 함수를 처음 호출하면 해당 함수와 관련된 PLT 항목으로 제어가 전달**됩니다. 이 PLT 항목은 함수의 주소가 이미 해결되지 않은 경우 동적 링커를 호출하여 주소를 해결합니다. 주소가 해결되면 **GOT**에 저장됩니다.
**따라서,** 외부 함수 변수의 주소가 해결되면 **GOT 항목이 직접 사용**됩니다. **PLT 항목은 동적 링커를 통해 이러한 주소의 초기 해결을 용이하게** 합니다.
**따라서,** 외부 함수 또는 변수의 주소가 해결되면 **GOT 항목이 직접 사용**됩니다. **PLT 항목은 동적 링커를 통해 이러한 주소의 초기 해결을 용이하게** 합니다.
## 실행 얻기
### GOT 확인
**`objdump -s -j .got ./exec`** 명령을 사용하여 GOT 테이블의 주소를 얻습니다.
**`objdump -s -j .got ./exec`** 사용하여 GOT 테이블의 주소를 얻습니다.
![](<../../.gitbook/assets/image (121).png>)
GEF에서 **실행 파일을 로드한 후** GOT에 있는 **함수를 볼 수 있습니다**: `gef➤ x/20x 0xDIR_GOT`
GEF에서 **실행 파일을 로드한 후** GOT에 있는 **함수를 볼 수 있습니다**: `gef➤ x/20x 0xADDR_GOT`
![](<../../.gitbook/assets/image (620) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (2) (2) (2).png>)
@ -46,25 +46,31 @@ GEF를 사용하여 **디버깅 세션을 시작**하고 **`got`**을 실행하
### GOT2Exec
이진 파일에서 GOT에는 **함수의 주소 또는** 함수 주소를 로드할 **PLT** 섹션이 포함되어 있습니다. 임의 쓰기의 목표는 나중에 **실행될 함수의 GOT 항목을 덮어쓰는 것**입니다. 이때 **예를 들어 `system` 함수의 PLT 주소로 덮어쓰기**입니다.
바이너리에서 GOT에는 **함수의 주소 또는** 함수 주소를 로드할 **PLT** 섹션이 포함되어 있습니다. 임의 쓰기의 목표는 나중에 **실행될 함수의 GOT 항목을 덮어쓰는 것**입니다. 이때 **예를 들어** **`system`** **함수의 PLT 주소로 덮어쓰는 것**입니다.
이상적으로, **제어할 수 있는 매개변수로 호출될 함수의 GOT를 덮어쓸 것**입니다 (`system` 함수에 전달될 매개변수를 제어할 수 있게 됩니다).
이상적으로, **제어할 수 있는 매개변수로 호출될 함수의 GOT을 덮어쓸 것**입니다 (따라서 시스템 함수에 전달되는 매개변수를 제어할 수 있게 됩니다).
**`system`**이 **스크립트에서 사용되지 않는 경우**, 시스템 함수에는 PLT 항목이 **없을 것**입니다. 이 시나리오에서는 먼저 `system` 함수의 주소를 누출하고 그 주소를 가리키도록 GOT를 덮어쓰어야 합니다.
만약 바이너리에서 **`system`**을 사용하지 않는다면 시스템 함수에 PLT 항목이 **없을 것**입니다. 이러한 시나리오에서는 먼저 `system` 함수의 주소를 누출하고 그 주소로 GOT를 덮어쓰는 작업이 필요합니다.
**`objdump -j .plt -d ./vuln_binary`** PLT 주소를 볼 수 있습니다.
**`objdump -j .plt -d ./vuln_binary`**를 사용하여 PLT 주소를 볼 수 있습니다.
## libc GOT 항목
**libc의 GOT**은 일반적으로 **부분 RELRO**로 컴파일되어 있어서 ([**ASLR**](../common-binary-protections-and-bypasses/aslr/)) 주소를 파악할 수 있다면 좋은 대상이 됩니다.
libc의 일반 함수는 **다른 내부 함수를 호출**하게 되며, 이러한 GOT를 덮어쓰면 코드 실행이 가능해질 수 있습니다.
libc의 일반 함수는 **다른 내부 함수를 호출**하게 되며, 이러한 GOT를 덮어쓰면 코드 실행이 가능해니다.
[**이 기술에 대한 자세한 정보는 여기에서 확인하세요**](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md#1---targetting-libc-got-entries).
이 기술에 대한 **자세한 정보는 여기에서 확인하세요**.
## **Free2system**
힙 취약점 CTF에서는 청크의 내용을 제어할 수 있고 어느 시점에서는 GOT 테이블을 덮어쓸 수도 있습니다. 하나의 가젯이 없는 경우 RCE를 얻는 간단한 트릭은 `free` GOT 주소를 `system`을 가리키도록 덮어쓰고 청크 내부에 `"/bin/sh"`를 쓰는 것입니다. 이렇게 하면 해당 청크가 해제될 때 `system("/bin/sh")`가 실행됩니다.
힙 취약점 CTF에서는 청크의 내용을 제어할 수 있고 어느 순간에는 GOT 테이블을 덮어쓸 수도 있습니다. 사용 가능한 가젯이 없는 경우 RCE를 얻는 간단한 트릭은 `free` GOT 주소를 `system`을 가리키도록 덮어쓰고 청크 내부에 `"/bin/sh"`를 작성하는 것입니다. 이렇게 하면 해당 청크가 해제될 때 `system("/bin/sh")`가 실행됩니다.
## **Strlen2system**
또 다른 일반적인 기술은 **`strlen`** GOT 주소를 **`system`**을 가리키도록 덮어쓰는 것입니다. 따라서 이 함수가 사용자 입력과 함께 호출되면 문자열 `"/bin/sh"`를 전달하여 셸을 얻을 수 있습니다.
또한 사용자 입력과 함께 `puts`가 사용된 경우 `puts` GOT 주소를 `system`을 가리키도록 덮어쓰고 문자열 `"/bin/sh"`를 전달하여 셸을 얻을 수 있습니다. 왜냐하면 **`puts`는 사용자 입력과 함께 `strlen`을 호출**할 것이기 때문입니다.
## **One Gadget**
@ -74,17 +80,17 @@ libc의 일반 함수는 **다른 내부 함수를 호출**하게 되며, 이러
## **힙에서 GOT 남용**
힙 취약점에서 RCE를 얻는 일반적인 방법은 fastbin을 남용하여 GOT 테이블 일부를 fast bin에 추가하여 해당 청크가 할당될 때 함수 포인터를 덮어쓸 수 있도록 하는 것입니다. 그런 다음 `free``system`으로 가리키도록 지정하고 `/bin/sh\x00`가 쓰인 청크를 해제하면 셸이 실행됩니다.
힙 취약점에서 RCE를 얻는 일반적인 방법은 fastbin을 남용하여 GOT 테이블 일부를 fast bin에 추가하여 해당 청크가 할당될 때 함수 포인터를 덮어쓸 수 있도록 하는 것입니다. 그런 다음 `free``system`으로 지정하고 `/bin/sh\x00`가 쓰인 청크를 해제하면 셸이 실행됩니다.
[**여기에서 예제를 찾을 수 있습니다**](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/chunk\_extend\_overlapping/#hitcon-trainging-lab13).
## **보호 기능**
**Full RELRO** 보호는 바이너리가 시작될 때 모든 함수의 주소를 해결하고 **GOT 테이블을 읽기 전용**으로 만들어 이러한 기술을 방지하는 것을 목적으로 합니다:
**Full RELRO** 보호 기능은 실행 파일이 시작될 때 모든 함수의 주소를 해결하고 이후 **GOT 테이블을 읽기 전용**으로 만들어 이러한 기술을 방지하기 위한 것입니다:
{% content-ref url="../common-binary-protections-and-bypasses/relro.md" %}
[relro.md](../common-binary-protections-and-bypasses/relro.md)
{% endcontent-ref %}
## 참고 자료
* [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)
@ -96,10 +102,10 @@ libc의 일반 함수는 **다른 내부 함수를 호출**하게 되며, 이러
HackTricks를 지원하는 다른 방법:
* **회사가 HackTricks에 광고되길 원하거나** **PDF 형식의 HackTricks를 다운로드**하려면 [**구독 요금제**](https://github.com/sponsors/carlospolop)를 확인하세요!
* [**공식 PEASS & HackTricks 스왜그**](https://peass.creator-spring.com)를 구입하세요
* **회사가 HackTricks에 광고되길 원한다면** 또는 **PDF 형식의 HackTricks를 다운로드하고 싶다면** [**구독 요금제**](https://github.com/sponsors/carlospolop)를 확인하세요!
* [**공식 PEASS & HackTricks 굿즈**](https://peass.creator-spring.com)를 구매하세요
* [**The PEASS Family**](https://opensea.io/collection/the-peass-family)를 발견하세요, 당사의 독점 [**NFTs**](https://opensea.io/collection/the-peass-family) 컬렉션
* **💬 [**Discord 그룹**](https://discord.gg/hRep4RUj7f) 또는 [**텔레그램 그룹**](https://t.me/peass)에 가입하거나** 트위터** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**를 팔로우하세요.**
* **HackTricks**[**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github 저장소에 PR을 제출하여 해킹 트릭을 공유하세요.
* **💬 [디스코드 그룹](https://discord.gg/hRep4RUj7f)** 또는 [텔레그램 그룹](https://t.me/peass)에 **가입**하거나 **트위터** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**를 팔로우**하세요.
* **HackTricks****HackTricks Cloud** github 저장소에 PR을 제출하여 **해킹 요령을 공유**하세요.
</details>

View file

@ -2,15 +2,15 @@
<details>
<summary><strong>htARTE (HackTricks AWS Red Team 전문가)로부터 AWS 해킹을 처음부터 전문가까지 배우세요!</strong></summary>
<summary><strong>AWS 해킹을 처음부터 전문가까지 배우세요</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS Red Team Expert)</strong></a><strong>와 함께!</strong></summary>
HackTricks를 지원하는 다른 방법:
* **회사가 HackTricks에 광고되길 원하거나 HackTricks를 PDF로 다운로드하고 싶다면** [**구독 요금제**](https://github.com/sponsors/carlospolop)를 확인하세요!
* **회사가 HackTricks에 광고되길 원하거나** **HackTricks를 PDF로 다운로드**하고 싶다면 [**구독 요금제**](https://github.com/sponsors/carlospolop)를 확인하세요!
* [**공식 PEASS & HackTricks 스왜그**](https://peass.creator-spring.com)를 구매하세요
* [**The PEASS Family**](https://opensea.io/collection/the-peass-family)를 발견하세요, 당사의 독점 [**NFTs**](https://opensea.io/collection/the-peass-family) 컬렉션
* 💬 [**Discord 그룹**](https://discord.gg/hRep4RUj7f) 또는 [**텔레그램 그룹**](https://t.me/peass)에 **가입**하거나 **트위터** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)를 **팔로우**하세요.
* **HackTricks** 및 **HackTricks Cloud** github 저장소에 PR을 제출하여 **해킹 트릭을 공유**하세요.
* **💬 [**Discord 그룹**](https://discord.gg/hRep4RUj7f)에 가입하거나 [**텔레그램 그룹**](https://t.me/peass)에 가입하거나 **트위터** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**를 팔로우하세요.**
* **해킹 요령을 공유하려면 PR을** [**HackTricks**](https://github.com/carlospolop/hacktricks) **및** [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) **깃허브 저장소에 제출하세요.**
</details>
@ -21,14 +21,14 @@ HackTricks를 지원하는 다른 방법:
{% endhint %}
소멸자는 **프로그램이 종료되기 전에 실행되는 함수**입니다 (`main` 함수가 반환된 후).\
이러한 함수들의 주소는 이진 파일의 **`.dtors`** 섹션에 저장되어 있으며, 따라서 **`__DTOR_END__`**에 **쉘코드 주소를 쓰는 데 성공한다면** 프로그램이 종료되기 전에 **실행**됩니다.
이러한 함수들의 주소는 이진 파일의 **`.dtors`** 섹션에 저장되어 있으며, 따라서 **`__DTOR_END__`**에 **쉘코드 주소를 쓰면**, 프로그램이 종료되기 전에 **실행**됩니다.
이 섹션의 주소를 가져오려면:
다음 명령어로 이 섹션의 주소를 얻을 수 있습니다:
```bash
objdump -s -j .dtors /exec
rabin -s /exec | grep “__DTOR”
```
일반적으로 **DTOR** 마커는 `ffffffff``00000000` 값 사이에 있습니다. 따라서 이 값만 보인다면 **등록된 함수가 없다는 것**을 의미합니다. 따라서 **`00000000`**을 **쉘코드의 주소로 덮어씌워** 실행할 수 있습니다.
일반적으로 **DTOR** 마커는 `ffffffff``00000000` 값 사이에 있습니다. 따라서 이 값만 보인다면, **등록된 함수가 없다는 것**을 의미합니다. 따라서 **`00000000`**을 **쉘코드의 주소**로 **덮어쓰세요**.
{% hint style="warning" %}
물론, 나중에 호출하기 위해 **쉘코드를 저장할 위치를 먼저 찾아야** 합니다.
@ -36,7 +36,7 @@ rabin -s /exec | grep “__DTOR”
## **.fini\_array**
이것은 **프로그램이 종료되기 전에 호출되는 함수**를 포함하는 구조체입니다. 이는 **`.dtors`**와 유사합니다. 이는 **주소로 점프하여 쉘코드를 호출**하거나 **취약점을 두 번째로 이용하기 위해 다시 `main`으로 돌아가야 하는 경우**에 흥미로울 수 있습니다.
이것은 기본적으로 프로그램이 끝나기 전에 호출되는 **함수들이 모인 구조**입니다. 이는 **`.dtors`**와 유사합니다. 이는 **주소로 점프하여 쉘코드를 호출**하거나, **취약점을 두 번째로 이용하기 위해 다시 `main`으로 돌아가야 하는 경우**에 흥미로울 수 있습니다.
```bash
objdump -s -j .fini_array ./greeting
@ -47,239 +47,19 @@ Contents of section .fini_array:
#Put your address in 0x8049934
```
참고로 **`.fini_array`**에서 함수가 실행될 때 다음 함수로 이동하므로 여러 번 실행되지 않습니다(무한 루프 방지), 그러나 여기에는 함수의 실행이 1회만 제공됩니다.
#### 무한 루프
**`.fini_array`**에서 함수가 실행될 때 다음 함수로 이동하므로 여러 번 실행되지 않습니다(무한 루프 방지), 그러나 여기에는 함수의 실행을 1회만 제공합니다.
**`.fini_array`**의 항목은 **역순**으로 호출되므로 아마도 마지막 항목부터 쓰기를 시작하려고 할 것입니다.
#### 무한 루프
**`.fini_array`**를 남용하여 무한 루프를 얻으려면 [**여기에서 수행된 작업을 확인하세요**](https://guyinatuxedo.github.io/17-stack\_pivot/insomnihack18\_onewrite/index.html)**:** **`.fini_array`**에 적어도 2개의 항목이 있는 경우 다음을 수행할 수 있습니다:
**`.fini_array`**를 남용하여 무한 루프를 얻기 위해 [**여기에서 수행된 작업을 확인할 수 있습니다**](https://guyinatuxedo.github.io/17-stack\_pivot/insomnihack18\_onewrite/index.html)**:** **`.fini_array`**에 적어도 2개의 항목이 있는 경우 다음을 수행할 수 있습니다:
* 첫 번째 쓰기를 사용하여 **취약한 임의 쓰기 함수를 호출**합니다.
* 첫 번째 쓰기를 사용하여 **취약한 임의 쓰기 함수**를 다시 호출합니다.
* 그런 다음, **`__libc_csu_fini`**에 의해 저장된 스택의 반환 주소를 계산하고 **`__libc_csu_fini`**의 주소를 거기에 넣습니다.
* 이렇게 하면 **`__libc_csu_fini`**가 자신을 다시 호출하여 **`.fini_array`** 함수를 다시 실행하게 만들어 취약한 WWW 함수를 2번 호출하게 됩니다: 하나는 **임의 쓰기**를 위해이고 다른 하나는 다시 **`__libc_csu_fini`의 반환 주소**를 덮어쓰기 위해 스택에 자신을 다시 호출합니다.
* 이렇게 하면 **`__libc_csu_fini`**가 자신을 다시 호출하여 **`.fini_array`** 함수를 다시 실행하게 만들어 **취약한 WWW 함수**를 2번 호출하게 됩니다: 하나는 **임의 쓰기**를 위해이고 다른 하나는 다시 **`__libc_csu_fini`**의 반환 주소를 덮어쓰기 위해 스택에 자신을 다시 호출합니다.
{% hint style="danger" %}
[**Full RELRO**](../common-binary-protections-and-bypasses/relro.md)**로** 설정된 경우 **`.fini_array`** 섹션이 **읽기 전용**으로 만들어집니다.
새로운 버전에서는 [**Partial RELRO**]로 설정되어도 **`.fini_array`** 섹션이 **읽기 전용**으로 만들어집니다.
{% endhint %}
## link\_map
[**이 게시물**](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md#2---targetting-ldso-link\_map-structure)에서 설명한대로, 프로그램이 `return` 또는 `exit()`를 사용하여 종료되면 `__run_exit_handlers()`가 실행되어 등록된 소멸자를 호출합니다.
{% hint style="danger" %}
프로그램이 **`_exit()`** 함수를 통해 종료되면 **`exit` 시스템 호출**을 하고 종료 핸들러가 실행되지 않습니다. 따라서 `__run_exit_handlers()`가 실행되는지 확인하려면 해당 핸들러에 중단점을 설정할 수 있습니다.
{% endhint %}
중요한 코드는 ([원본](https://elixir.bootlin.com/glibc/glibc-2.32/source/elf/dl-fini.c#L131))입니다:
```c
ElfW(Dyn) *fini_array = map->l_info[DT_FINI_ARRAY];
if (fini_array != NULL)
{
ElfW(Addr) *array = (ElfW(Addr) *) (map->l_addr + fini_array->d_un.d_ptr);
size_t sz = (map->l_info[DT_FINI_ARRAYSZ]->d_un.d_val / sizeof (ElfW(Addr)));
while (sz-- > 0)
((fini_t) array[sz]) ();
}
[...]
// This is the d_un structure
ptype l->l_info[DT_FINI_ARRAY]->d_un
type = union {
Elf64_Xword d_val; // address of function that will be called, we put our onegadget here
Elf64_Addr d_ptr; // offset from l->l_addr of our structure
}
```
`map -> l_addr + fini_array -> d_un.d_ptr`을 사용하여 **호출할 함수 배열의 위치를 계산하는 방법**에 주목하세요.
**여러 가지 옵션이** 있습니다:
* `map->l_addr`의 값을 덮어쓰기하여 임의의 코드를 실행하는 **가짜 `fini_array`**를 가리키도록 만듭니다.
* 메모리 상에서 거의 연속적인 `l_info[DT_FINI_ARRAY]``l_info[DT_FINI_ARRAYSZ]` 항목을 덮어쓰기하여 다시 **`array`가 공격자가 제어하는 메모리 영역을 가리키도록 하는** 가짜 `Elf64_Dyn` 구조체를 가리키게 합니다.&#x20;
* [**이 writeup**](https://github.com/nobodyisnobody/write-ups/tree/main/DanteCTF.2023/pwn/Sentence.To.Hell)에서는 `.bss`에 있는 제어된 메모리 주소를 포함하는 `l_info[DT_FINI_ARRAY]`를 덮어쓰고 가짜 `fini_array`를 포함하는 가짜 배열을 만듭니다. 이 가짜 배열은 먼저 실행될 [**원 가젯**](../rop-return-oriented-programing/ret2lib/one-gadget.md) **주소**를 포함하고, 그런 다음 이 **가짜 배열**의 주소와 `map->l_addr`의 **값 사이의 차이**를 포함하여 `*array`가 가짜 배열을 가리키도록 합니다.
* 이 기술의 주요 게시물 및 [**이 writeup**](https://activities.tjhsst.edu/csc/writeups/angstromctf-2021-wallstreet)에 따르면 ld.so는 ld.so에서 이진 `link_map`을 가리키는 스택에 포인터를 남깁니다. 임의의 쓰기를 사용하여 덮어쓰고 공격자가 제어하는 가짜 `fini_array`를 가리키도록 만들고, 예를 들어 [**원 가젯**](../rop-return-oriented-programing/ret2lib/one-gadget.md)의 주소를 포함할 수 있습니다.
이전 코드를 따라가면 코드에서 또 다른 흥미로운 섹션을 찾을 수 있습니다:
```c
/* Next try the old-style destructor. */
ElfW(Dyn) *fini = map->l_info[DT_FINI];
if (fini != NULL)
DL_CALL_DT_FINI (map, ((void *) map->l_addr + fini->d_un.d_ptr));
}
```
이 경우 `map->l_info[DT_FINI]` 값이 조작된 `ElfW(Dyn)` 구조체를 가리키도록 덮어쓸 수 있습니다. [**여기에서 자세한 정보를 확인하세요**](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md#2---targetting-ldso-link\_map-structure).
## TLS-Storage dtor\_list 덮어쓰기 **`__run_exit_handlers`**
[**여기에서 설명된 것**](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md#5---code-execution-via-tls-storage-dtor\_list-overwrite)와 같이, 프로그램이 `return` 또는 `exit()`를 통해 종료되면 **`__run_exit_handlers()`**가 실행되어 등록된 소멸자 함수를 호출합니다.
`_run_exit_handlers()`에서의 코드:
```c
/* Call all functions registered with `atexit' and `on_exit',
in the reverse of the order in which they were registered
perform stdio cleanup, and terminate program execution with STATUS. */
void
attribute_hidden
__run_exit_handlers (int status, struct exit_function_list **listp,
bool run_list_atexit, bool run_dtors)
{
/* First, call the TLS destructors. */
#ifndef SHARED
if (&__call_tls_dtors != NULL)
#endif
if (run_dtors)
__call_tls_dtors ();
```
**`__call_tls_dtors()`** 함수에서의 코드:
```c
void __call_tls_dtors() {
size_t i;
for (i = 0; i < tls_dtor_count; i++) {
if (tls_dtor_array[i] != NULL) {
tls_dtor_array[i]();
}
}
}
```
```c
typedef void (*dtor_func) (void *);
struct dtor_list //struct added
{
dtor_func func;
void *obj;
struct link_map *map;
struct dtor_list *next;
};
[...]
/* Call the destructors. This is called either when a thread returns from the
initial function or when the process exits via the exit function. */
void
__call_tls_dtors (void)
{
while (tls_dtor_list) // parse the dtor_list chained structures
{
struct dtor_list *cur = tls_dtor_list; // cur point to tls-storage dtor_list
dtor_func func = cur->func;
PTR_DEMANGLE (func); // demangle the function ptr
tls_dtor_list = tls_dtor_list->next; // next dtor_list structure
func (cur->obj);
[...]
}
}
```
모든 등록된 함수에 대해 **`tls_dtor_list`**에서 포인터를 **`cur->func`**에서 demangle하고 인자 **`cur->obj`**와 함께 호출합니다.
이 [**GEF의 fork**](https://github.com/bata24/gef)에서 **`tls`** 함수를 사용하면 실제로 **`dtor_list`**가 **스택 캐너리**와 **PTR\_MANGLE 쿠키**에 매우 **가깝다는 것**을 확인할 수 있습니다. 따라서 이를 **오버플로우**하여 **쿠키**와 **스택 캐너리**를 **덮어쓸 수** 있습니다.\
PTR\_MANGLE 쿠키를 덮어쓰면 0x00으로 설정하여 **`PTR_DEMANLE` 함수를 우회**할 수 있습니다. 이는 실제 주소를 얻기 위해 사용된 **`xor`**가 구성된 주소일 뿐이라는 것을 의미합니다. 그런 다음 **`dtor_list`**에 쓰면 함수 **주소**와 **인자**로 **여러 함수를 연결**할 수 있습니다.
마지막으로 저장된 포인터가 쿠키와 **17비트로 회전**됨을 유의하세요:
```armasm
0x00007fc390444dd4 <+36>: mov rax,QWORD PTR [rbx] --> mangled ptr
0x00007fc390444dd7 <+39>: ror rax,0x11 --> rotate of 17 bits
0x00007fc390444ddb <+43>: xor rax,QWORD PTR fs:0x30 --> xor with PTR_MANGLE
```
새 주소를 추가하기 전에 이를 고려해야합니다.
[**원본 게시물**](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md#5---code-execution-via-tls-storage-dtor\_list-overwrite)에서 예제를 찾으세요.
## **`__run_exit_handlers`**에서 다른 망가진 포인터
이 기술은 [**여기에서 설명**](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md#5---code-execution-via-tls-storage-dtor\_list-overwrite)되어 있으며 다시 프로그램이 `return` 또는 `exit()`를 호출하여 종료되면 **`__run_exit_handlers()`**가 호출됩니다.
이 함수의 더 많은 코드를 확인해 봅시다:
```c
while (true)
{
struct exit_function_list *cur;
restart:
cur = *listp;
if (cur == NULL)
{
/* Exit processing complete. We will not allow any more
atexit/on_exit registrations. */
__exit_funcs_done = true;
break;
}
while (cur->idx > 0)
{
struct exit_function *const f = &cur->fns[--cur->idx];
const uint64_t new_exitfn_called = __new_exitfn_called;
switch (f->flavor)
{
void (*atfct) (void);
void (*onfct) (int status, void *arg);
void (*cxafct) (void *arg, int status);
void *arg;
case ef_free:
case ef_us:
break;
case ef_on:
onfct = f->func.on.fn;
arg = f->func.on.arg;
PTR_DEMANGLE (onfct);
/* Unlock the list while we call a foreign function. */
__libc_lock_unlock (__exit_funcs_lock);
onfct (status, arg);
__libc_lock_lock (__exit_funcs_lock);
break;
case ef_at:
atfct = f->func.at;
PTR_DEMANGLE (atfct);
/* Unlock the list while we call a foreign function. */
__libc_lock_unlock (__exit_funcs_lock);
atfct ();
__libc_lock_lock (__exit_funcs_lock);
break;
case ef_cxa:
/* To avoid dlclose/exit race calling cxafct twice (BZ 22180),
we must mark this function as ef_free. */
f->flavor = ef_free;
cxafct = f->func.cxa.fn;
arg = f->func.cxa.arg;
PTR_DEMANGLE (cxafct);
/* Unlock the list while we call a foreign function. */
__libc_lock_unlock (__exit_funcs_lock);
cxafct (arg, status);
__libc_lock_lock (__exit_funcs_lock);
break;
}
if (__glibc_unlikely (new_exitfn_called != __new_exitfn_called))
/* The last exit function, or another thread, has registered
more exit functions. Start the loop over. */
goto restart;
}
*listp = cur->next;
if (*listp != NULL)
/* Don't free the last element in the chain, this is the statically
allocate element. */
free (cur);
}
__libc_lock_unlock (__exit_funcs_lock);
```
변수 `f`**`initial`** 구조체를 가리키며, `f->flavor` 값에 따라 다른 함수가 호출됩니다.\
값에 따라 호출할 함수의 주소는 다른 위치에 있지만 항상 **demangled**됩니다.
또한, **`ef_on`** 및 **`ef_cxa`** 옵션에서 **인수**를 제어할 수도 있습니다.
GDB를 실행한 디버깅 세션에서 **`gef> p initial`**을 입력하여 **`initial` 구조체**를 확인할 수 있습니다.
이를 악용하려면 **`PTR_MANGLE` 쿠키를 노출하거나 지우고** 그 후에 `initial`에서 `cxa` 항목을 `system('/bin/sh')`로 덮어쓰면 됩니다.\
이 기술에 대한 원본 블로그 게시물에서 이에 대한 예시를 찾을 수 있습니다.

View file

@ -1,42 +1,238 @@
# WWW2Exec - atexit()
# WWW2Exec - atexit(), TLS Storage & 기타 망가진 포인터
<details>
<summary><strong>제로부터 히어로가 되기까지 AWS 해킹을 배우세요</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS Red Team 전문가)</strong></a><strong>!</strong></summary>
<summary><strong>htARTE (HackTricks AWS Red Team Expert)</strong>를 통해 제로에서 영웅까지 AWS 해킹을 배우세요!</summary>
HackTricks를 지원하는 다른 방법:
* **회사가 HackTricks에 광고되길 원하거나** **PDF 형식의 HackTricks를 다운로드**하려면 [**구독 요금제**](https://github.com/sponsors/carlospolop)를 확인하세요!
* **회사가 HackTricks에 광고되길 원하거나 HackTricks를 PDF로 다운로드**하고 싶다면 [**구독 요금제**](https://github.com/sponsors/carlospolop)를 확인하세요!
* [**공식 PEASS & HackTricks 굿즈**](https://peass.creator-spring.com)를 구매하세요
* [**The PEASS Family**](https://opensea.io/collection/the-peass-family)를 발견하세요, 당사의 독점 [**NFTs**](https://opensea.io/collection/the-peass-family) 컬렉션
* **💬 [디스코드 그룹](https://discord.gg/hRep4RUj7f)** 또는 [텔레그램 그룹](https://t.me/peass)에 **가입**하거나 **트위터** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**를 팔로우**하세요.
* **HackTricks** 및 **HackTricks Cloud** 깃허브 저장소에 PR을 제출하여 **해킹 트릭을 공유**하세요.
* **💬 [**Discord 그룹**](https://discord.gg/hRep4RUj7f) 또는 [**텔레그램 그룹**](https://t.me/peass)에 **가입**하거나 **트위터** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**를 팔로우**하세요.
* **해킹 트릭을 공유하려면** [**HackTricks**](https://github.com/carlospolop/hacktricks) 및 [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github 저장소에 PR을 제출하세요.
</details>
## **\_\_atexit 구조체**
{% hint style="danger" %}
요즘은 이를 **악용하는 것이 매우 이상합니다!**
요즘은 이를 **exploit하는 것이 매우 이상합니다!**
{% endhint %}
**`atexit()`**은 **매개변수로 전달된 다른 함수들**에 대한 함수입니다. 이러한 **함수들**은 **`exit()`**를 실행하거나 **main****반환** 시에 **실행**됩니다.\
예를 들어 이러한 **함수들** 중 하나의 **주소**를 쉘코드를 가리키도록 수정할 수 있다면, **프로세스를 제어**할 수 있지만, 현재 이 작업은 더 복잡해졌습니다.\
현재 **실행될 함수들의 주소**는 여러 구조체 뒤에 **숨겨져** 있으며, 마지막으로 가리키는 주소는 함수들의 주소가 아니라 **XOR로 암호화**되고 **임의의 키**로 이동됩니다. 따라서 현재 이 공격 벡터는 **적어도 x86** 및 **x64\_86**에서는 **매우 유용하지 않습니다**.\
**암호화 함수**는 **`PTR_MANGLE`**입니다. **m68k, mips32, mips64, aarch64, arm, hppa**와 같은 **다른 아키텍처**는 **암호화 함수를 구현하지 않습니다**. 왜냐하면 입력으로 받은 것과 **동일한 값을 반환**하기 때문입니다. 따라서 이러한 아키텍처는 이 벡터에 의해 공격당할 수 있습니다.
**`atexit()`**은 **다른 함수들이 매개변수로 전달되는 함수**입니다. 이러한 **함수들**은 **`exit()`를 실행하거나** **main의 반환** 시에 **실행**됩니다.\
이러한 **함수들** 중 하나의 **주소**를 예를 들어 셸코드를 가리키도록 **수정**할 수 있다면, **프로세스를 제어**할 수 있지만 현재 이 작업은 더 복잡해졌습니다.\
현재 **실행될 함수들의 주소**는 여러 구조체 뒤에 **숨겨져** 있으며, 마지막으로 그 주소는 함수들의 주소가 아니라 **XOR로 암호화**되고 **임의의 키로 이동**되어 있습니다. 따라서 현재 이 공격 벡터는 **적어도 x86** 및 **x64\_86**에서는 **매우 유용하지 않습니다.**\
**암호화 함수**는 **`PTR_MANGLE`**입니다. **m68k, mips32, mips64, aarch64, arm, hppa**와 같은 **다른 아키텍처**는 **입력으로 받은 것과 동일한 것을 반환**하기 때문에 **암호화 함수를 구현하지 않습니다.** 따라서 이러한 아키텍처는 이러한 벡터에 의해 공격당할 수 있습니다.
이 작동 방식에 대한 자세한 설명은 [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)에서 찾을 수 있습니다.
<details>
## link\_map
<summary><strong>제로부터 히어로가 되기까지 AWS 해킹을 배우세요</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS Red Team 전문가)</strong></a><strong>!</strong></summary>
[**이 게시물**](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md#2---targetting-ldso-link\_map-structure)에서 설명한대로, 프로그램이 `return` 또는 `exit()`를 사용하여 종료되면 등록된 소멸자를 호출하는 `__run_exit_handlers()`가 실행됩니다.
HackTricks를 지원하는 다른 방법:
{% hint style="danger" %}
프로그램이 **`_exit()`** 함수를 통해 종료되면 **`exit` 시스템 호출**이 발생하고 종료 핸들러가 실행되지 않습니다. 따라서 `__run_exit_handlers()`가 실행되는지 확인하려면 해당 부분에 중단점을 설정할 수 있습니다.
{% endhint %}
* **회사가 HackTricks에 광고되길 원하거나** **PDF 형식의 HackTricks를 다운로드**하려면 [**구독 요금제**](https://github.com/sponsors/carlospolop)를 확인하세요!
* [**공식 PEASS & HackTricks 굿즈**](https://peass.creator-spring.com)를 구매하세요
* [**The PEASS Family**](https://opensea.io/collection/the-peass-family)를 발견하세요, 당사의 독점 [**NFTs**](https://opensea.io/collection/the-peass-family) 컬렉션
* **💬 [디스코드 그룹](https://discord.gg/hRep4RUj7f)** 또는 [텔레그램 그룹](https://t.me/peass)에 **가입**하거나 **트위터** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**를 팔로우**하세요.
* **HackTricks****HackTricks Cloud** 깃허브 저장소에 PR을 제출하여 **해킹 트릭을 공유**하세요.
중요한 코드는 ([원본](https://elixir.bootlin.com/glibc/glibc-2.32/source/elf/dl-fini.c#L131))입니다:
```c
ElfW(Dyn) *fini_array = map->l_info[DT_FINI_ARRAY];
if (fini_array != NULL)
{
ElfW(Addr) *array = (ElfW(Addr) *) (map->l_addr + fini_array->d_un.d_ptr);
size_t sz = (map->l_info[DT_FINI_ARRAYSZ]->d_un.d_val / sizeof (ElfW(Addr)));
</details>
while (sz-- > 0)
((fini_t) array[sz]) ();
}
[...]
// This is the d_un structure
ptype l->l_info[DT_FINI_ARRAY]->d_un
type = union {
Elf64_Xword d_val; // address of function that will be called, we put our onegadget here
Elf64_Addr d_ptr; // offset from l->l_addr of our structure
}
```
`map -> l_addr + fini_array -> d_un.d_ptr`을 사용하여 **호출할 함수 배열의 위치를 계산하는 방법**에 주목하세요.
**여러 가지 옵션이** 있습니다:
* `map->l_addr`의 값을 덮어쓰여 가짜 `fini_array`를 가리키도록 만듭니다. 이 가짜 `fini_array`에는 임의의 코드를 실행하는 명령이 포함되어 있습니다.
* 메모리 상에서 거의 연속적인 `l_info[DT_FINI_ARRAY]``l_info[DT_FINI_ARRAYSZ]` 항목을 덮어쓰여, 다시 **`array`가 공격자가 제어하는 메모리 영역을 가리키도록 하는** `Elf64_Dyn` 구조체를 가리키도록 만듭니다.
* [**이 writeup**](https://github.com/nobodyisnobody/write-ups/tree/main/DanteCTF.2023/pwn/Sentence.To.Hell)에서는 `.bss`에 있는 제어된 메모리의 주소로 `l_info[DT_FINI_ARRAY]`를 덮어쓰여 가짜 `fini_array`를 가리키도록 합니다. 이 가짜 배열에는 먼저 실행될 [**원 가젯**](../rop-return-oriented-programing/ret2lib/one-gadget.md) 주소가 포함되어 있으며, 그런 다음 이 **가짜 배열**과 `map->l_addr`의 **값 간의 차이**가 포함되어 있어 `*array`가 가짜 배열을 가리키도록 합니다.
* 이 기술의 주요 게시물 및 [**이 writeup**](https://activities.tjhsst.edu/csc/writeups/angstromctf-2021-wallstreet)에 따르면 ld.so는 ld.so 내의 이진 `link_map`을 가리키는 스택에 포인터를 남깁니다. 임의 쓰기를 사용하여 덮어쓰고 공격자가 제어하는 가짜 `fini_array`를 가리키도록 만들고, 예를 들어 [**원 가젯**](../rop-return-oriented-programing/ret2lib/one-gadget.md)의 주소를 포함할 수 있습니다.
이전 코드를 따라가면 코드에서 또 다른 흥미로운 섹션을 찾을 수 있습니다:
```c
/* Next try the old-style destructor. */
ElfW(Dyn) *fini = map->l_info[DT_FINI];
if (fini != NULL)
DL_CALL_DT_FINI (map, ((void *) map->l_addr + fini->d_un.d_ptr));
}
```
이 경우에는 `map->l_info[DT_FINI]`의 값을 조작하여 위조된 `ElfW(Dyn)` 구조체를 가리킬 수 있습니다. [**여기에서 자세한 정보를 확인하세요**](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md#2---targetting-ldso-link\_map-structure).
## TLS-Storage dtor\_list 덮어쓰기 **`__run_exit_handlers`**
[**여기에서 설명된 것**](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md#5---code-execution-via-tls-storage-dtor\_list-overwrite)과 같이, 프로그램이 `return` 또는 `exit()`를 통해 종료되면 **`__run_exit_handlers()`**가 실행되어 등록된 소멸자 함수를 호출합니다.
`_run_exit_handlers()`에서의 코드:
```c
/* Call all functions registered with `atexit' and `on_exit',
in the reverse of the order in which they were registered
perform stdio cleanup, and terminate program execution with STATUS. */
void
attribute_hidden
__run_exit_handlers (int status, struct exit_function_list **listp,
bool run_list_atexit, bool run_dtors)
{
/* First, call the TLS destructors. */
#ifndef SHARED
if (&__call_tls_dtors != NULL)
#endif
if (run_dtors)
__call_tls_dtors ();
```
**`__call_tls_dtors()`** 함수에서의 코드:
```c
typedef void (*dtor_func) (void *);
struct dtor_list //struct added
{
dtor_func func;
void *obj;
struct link_map *map;
struct dtor_list *next;
};
[...]
/* Call the destructors. This is called either when a thread returns from the
initial function or when the process exits via the exit function. */
void
__call_tls_dtors (void)
{
while (tls_dtor_list) // parse the dtor_list chained structures
{
struct dtor_list *cur = tls_dtor_list; // cur point to tls-storage dtor_list
dtor_func func = cur->func;
PTR_DEMANGLE (func); // demangle the function ptr
tls_dtor_list = tls_dtor_list->next; // next dtor_list structure
func (cur->obj);
[...]
}
}
```
모든 등록된 함수에 대해 **`tls_dtor_list`**에서 포인터를 **`cur->func`**에서 demangle하고 인자 **`cur->obj`**와 함께 호출합니다.
이 [**GEF의 fork**](https://github.com/bata24/gef)에서 **`tls`** 함수를 사용하면 실제로 **`dtor_list`**가 **스택 캐너리**와 **PTR\_MANGLE 쿠키**에 매우 **가깝다는 것**을 확인할 수 있습니다. 따라서 이를 통해 **쿠키**와 **스택 캐너리**를 **덮어쓸 수** 있습니다.\
PTR\_MANGLE 쿠키를 덮어쓰면 0x00으로 설정하여 **`PTR_DEMANLE` 함수를 우회**할 수 있으며, 이는 실제 주소를 얻기 위해 사용된 **`xor`**가 구성된 주소일 뿐이라는 것을 의미합니다. 그런 다음 **`dtor_list`**에 쓰면 함수 **주소**와 **인자**로 **여러 함수를 연결**할 수 있습니다.
마지막으로 저장된 포인터가 쿠키와 **17비트로 회전**됨을 주목하세요:
```armasm
0x00007fc390444dd4 <+36>: mov rax,QWORD PTR [rbx] --> mangled ptr
0x00007fc390444dd7 <+39>: ror rax,0x11 --> rotate of 17 bits
0x00007fc390444ddb <+43>: xor rax,QWORD PTR fs:0x30 --> xor with PTR_MANGLE
```
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).
## 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.
Let's check more code of this function:
```c
while (true)
{
struct exit_function_list *cur;
restart:
cur = *listp;
if (cur == NULL)
{
/* Exit processing complete. We will not allow any more
atexit/on_exit registrations. */
__exit_funcs_done = true;
break;
}
while (cur->idx > 0)
{
struct exit_function *const f = &cur->fns[--cur->idx];
const uint64_t new_exitfn_called = __new_exitfn_called;
switch (f->flavor)
{
void (*atfct) (void);
void (*onfct) (int status, void *arg);
void (*cxafct) (void *arg, int status);
void *arg;
case ef_free:
case ef_us:
break;
case ef_on:
onfct = f->func.on.fn;
arg = f->func.on.arg;
PTR_DEMANGLE (onfct);
/* Unlock the list while we call a foreign function. */
__libc_lock_unlock (__exit_funcs_lock);
onfct (status, arg);
__libc_lock_lock (__exit_funcs_lock);
break;
case ef_at:
atfct = f->func.at;
PTR_DEMANGLE (atfct);
/* Unlock the list while we call a foreign function. */
__libc_lock_unlock (__exit_funcs_lock);
atfct ();
__libc_lock_lock (__exit_funcs_lock);
break;
case ef_cxa:
/* To avoid dlclose/exit race calling cxafct twice (BZ 22180),
we must mark this function as ef_free. */
f->flavor = ef_free;
cxafct = f->func.cxa.fn;
arg = f->func.cxa.arg;
PTR_DEMANGLE (cxafct);
/* Unlock the list while we call a foreign function. */
__libc_lock_unlock (__exit_funcs_lock);
cxafct (arg, status);
__libc_lock_lock (__exit_funcs_lock);
break;
}
if (__glibc_unlikely (new_exitfn_called != __new_exitfn_called))
/* The last exit function, or another thread, has registered
more exit functions. Start the loop over. */
goto restart;
}
*listp = cur->next;
if (*listp != NULL)
/* Don't free the last element in the chain, this is the statically
allocate element. */
free (cur);
}
__libc_lock_unlock (__exit_funcs_lock);
```
변수 `f`**`initial`** 구조체를 가리키며, `f->flavor` 값에 따라 다른 함수가 호출됩니다.
값에 따라 호출할 함수의 주소는 다른 위치에 있지만 항상 **demangled** 상태여야 합니다.
또한, **`ef_on`** 및 **`ef_cxa`** 옵션에서 **인수(argument)**를 제어할 수도 있습니다.
디버깅 세션에서 **`gef> p initial`**을 실행하여 **`initial` 구조체**를 확인할 수 있습니다.
이를 악용하려면 **`PTR_MANGLE` 쿠키를 노출하거나 지우고** 그 후 `initial`에서 `cxa` 항목을 `system('/bin/sh')`로 덮어쓰면 됩니다.
이에 대한 예시는 [**기술에 관한 원본 블로그 게시물**](https://github.com/nobodyisnobody/docs/blob/main/code.execution.on.last.libc/README.md#6---code-execution-via-other-mangled-pointers-in-initial-structure)에서 찾을 수 있습니다.