Skip to content
KitploitKITPLOIT
도구익스플로잇블로그
Log in
제출
도구익스플로잇블로그
제출

해킹, 침투 테스트 및 사이버 보안 도구를 당신의 보안 무기고에!

Kitploit은 해킹, 사이버 보안 및 침투 테스트 도구 디렉토리입니다. 최신 프로젝트 업데이트를 발견하여 취약점을 찾고, 시스템을 분석하고, 테스트를 자동화하고, 보안을 강화하세요.

피드문의개인정보© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
how-to-bypass-aslr-on-linux-x86_64 — ASLR 우회, 정보 유출 없이 | Kitploit
도구/GitHubGitHub/nick0ve/how-to-bypass-aslr-on-linux-x86_64
ExploitationCTFLearning & EducationBinary Exploitation
GitHubnick0ve/how-to-bypass-aslr-on-linux-x86_64

how-to-bypass-aslr-on-linux-x86_64

ASLR 우회, 정보 유출 없이

저장소 보기

인기

모두 보기 →

커뮤니티에서 가장 많이 사용되는 도구를 찾아보세요.

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유
16717164년 전Kitploit 검토 완료

Breaking 64 bit aslr on Linux x86-64

이 글에서는 Samuel Groß가 자신의 Remote iPhone Exploitation Part 2: Bringing Light into the Darkness -- a Remote ASLR Bypass에서 설명한 기법을 Linux x86_64에서 ASLR을 우회하기 위해 적용하는 방법에 대해 다루겠습니다.

이를 보여주기 위해 Buckeye CTF의 pwnable 챌린지인 guess_god를 풀어보겠습니다.

가능한 한 초보자 친화적으로 내용을 작성하려고 하니, 자신 있다면 각 섹션을 건너뛰고 익스플로잇만 보고 싶어도 괜찮습니다.

0. 서론


저는 CTF에 참가하지 않았지만, fibonhack 디스코드에서 Guray00이 어떤 암호학 관련 문제에 대해 도움을 요청하면서 CTF 종료 약 2시간 전에 이 챌린지에 관심을 가지게 되었습니다.

저는 그를 도와줄 수 없었지만, pwnable 챌린지들을 살펴보았고 P0 블로그 게시물을 이해하는 것이 좋겠다고 생각했으며, hopefully 그 현상금을 받을 수도 있겠다고 생각했습니다.

1. ASLR과 이를 우회하는 방법

1.1 ASLR이란 무엇인가?

주소 공간 레이아웃 무작위화(ASLR) 는 프로세스의 주소 공간에서 실행 파일의 베이스 주소와 라이브러리, 힙, 스택의 위치를 무작위로 배치하는 컴퓨터 보안 기술입니다.

1.2 Linux에서의 ASLR

Linux에서는 프로세스의 pid가 주어졌을 때, /proc/<pid>/maps 파일을 읽어 해당 프로세스의 메모리 매핑을 확인할 수 있습니다. 이는 procfs를 통해 가능합니다.

여러분이 프로세스이고 자신의 메모리 매핑을 알고 싶다면 /proc/self/maps를 읽으면 됩니다.

예를 들어, cat으로 /proc/self/maps를 읽어볼 수 있습니다:``` root@088ec31b2ce9:/home/ctf/challenge# cat /proc/self/maps 55faeb01c000-55faeb01e000 r--p 00000000 fe:01 2497233 /usr/bin/cat 55faeb01e000-55faeb023000 r-xp 00002000 fe:01 2497233 /usr/bin/cat 55faeb023000-55faeb026000 r--p 00007000 fe:01 2497233 /usr/bin/cat 55faeb026000-55faeb027000 r--p 00009000 fe:01 2497233 /usr/bin/cat 55faeb027000-55faeb028000 rw-p 0000a000 fe:01 2497233 /usr/bin/cat 55faeb115000-55faeb136000 rw-p 00000000 00:00 0 [heap] 7fe15dfb1000-7fe15dfd5000 rw-p 00000000 00:00 0 7fe15dfd5000-7fe15dffb000 r--p 00000000 fe:01 2761561 /usr/lib/x86_64-linux-gnu/libc-2.33.so 7fe15dffb000-7fe15e166000 r-xp 00026000 fe:01 2761561 /usr/lib/x86_64-linux-gnu/libc-2.33.so 7fe15e166000-7fe15e1b2000 r--p 00191000 fe:01 2761561 /usr/lib/x86_64-linux-gnu/libc-2.33.so 7fe15e1b2000-7fe15e1b5000 r--p 001dc000 fe:01 2761561 /usr/lib/x86_64-linux-gnu/libc-2.33.so 7fe15e1b5000-7fe15e1b8000 rw-p 001df000 fe:01 2761561 /usr/lib/x86_64-linux-gnu/libc-2.33.so 7fe15e1b8000-7fe15e1c3000 rw-p 00000000 00:00 0 7fe15e1c7000-7fe15e1c8000 r--p 00000000 fe:01 2761539 /usr/lib/x86_64-linux-gnu/ld-2.33.so 7fe15e1c8000-7fe15e1ef000 r-xp 00001000 fe:01 2761539 /usr/lib/x86_64-linux-gnu/ld-2.33.so 7fe15e1ef000-7fe15e1f9000 r--p 00028000 fe:01 2761539 /usr/lib/x86_64-linux-gnu/ld-2.33.so 7fe15e1f9000-7fe15e1fb000 r--p 00031000 fe:01 2761539 /usr/lib/x86_64-linux-gnu/ld-2.33.so 7fe15e1fb000-7fe15e1fd000 rw-p 00033000 fe:01 2761539 /usr/lib/x86_64-linux-gnu/ld-2.33.so 7fff4388f000-7fff438b0000 rw-p 00000000 00:00 0 [stack] 7fff43989000-7fff4398d000 r--p 00000000 00:00 0 [vvar] 7fff4398d000-7fff4398f000 r-xp 00000000 00:00 0 [vdso] ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]

root@088ec31b2ce9:/home/ctf/challenge# cat /proc/self/maps 55ffc0b1b000-55ffc0b1d000 r--p 00000000 fe:01 2497233 /usr/bin/cat 55ffc0b1d000-55ffc0b22000 r-xp 00002000 fe:01 2497233 /usr/bin/cat 55ffc0b22000-55ffc0b25000 r--p 00007000 fe:01 2497233 /usr/bin/cat 55ffc0b25000-55ffc0b26000 r--p 00009000 fe:01 2497233 /usr/bin/cat 55ffc0b26000-55ffc0b27000 rw-p 0000a000 fe:01 2497233 /usr/bin/cat 55ffc2108000-55ffc2129000 rw-p 00000000 00:00 0 [heap] 7f1ec6e0f000-7f1ec6e33000 rw-p 00000000 00:00 0 7f1ec6e33000-7f1ec6e59000 r--p 00000000 fe:01 2761561 /usr/lib/x86_64-linux-gnu/libc-2.33.so 7f1ec6e59000-7f1ec6fc4000 r-xp 00026000 fe:01 2761561 /usr/lib/x86_64-linux-gnu/libc-2.33.so 7f1ec6fc4000-7f1ec7010000 r--p 00191000 fe:01 2761561 /usr/lib/x86_64-linux-gnu/libc-2.33.so 7f1ec7010000-7f1ec7013000 r--p 001dc000 fe:01 2761561 /usr/lib/x86_64-linux-gnu/libc-2.33.so 7f1ec7013000-7f1ec7016000 rw-p 001df000 fe:01 2761561 /usr/lib/x86_64-linux-gnu/libc-2.33.so 7f1ec7016000-7f1ec7021000 rw-p 00000000 00:00 0 7f1ec7025000-7f1ec7026000 r--p 00000000 fe:01 2761539 /usr/lib/x86_64-linux-gnu/ld-2.33.so 7f1ec7026000-7f1ec704d000 r-xp 00001000 fe:01 2761539 /usr/lib/x86_64-linux-gnu/ld-2.33.so 7f1ec704d000-7f1ec7057000 r--p 00028000 fe:01 2761539 /usr/lib/x86_64-linux-gnu/ld-2.33.so 7f1ec7057000-7f1ec7059000 r--p 00031000 fe:01 2761539 /usr/lib/x86_64-linux-gnu/ld-2.33.so 7f1ec7059000-7f1ec705b000 rw-p 00033000 fe:01 2761539 /usr/lib/x86_64-linux-gnu/ld-2.33.so 7ffc72fa4000-7ffc72fc5000 rw-p 00000000 00:00 0 [stack] 7ffc72fe7000-7ffc72feb000 r--p 00000000 00:00 0 [vvar] 7ffc72feb000-7ffc72fed000 r-xp 00000000 00:00 0 [vdso] ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]

### 메모리 매핑 패턴

이 작업을 몇 번 반복하다 보면 다음을 추론할 수 있습니다:
* 바이너리 PIE 베이스는 0x00005500_00000000-0x00005700_00000000 범위에 있어야 하며, 즉 가능한 주소는 2TB입니다.
* 힙은 바이너리 근처에 있습니다.
* 라이브러리는 0x00007f00_00000000 - 0x00007fff_ffffffff 범위에 있으며, 가능한 주소는 1TB입니다.
* 스택은 (대부분의 경우) 0x00007ffc_00000000 - 0x00007fff_ffffffff 범위에 있으며, 가능한 주소는 16gb입니다.
* 0xffffffffff600000 - 0xffffffffff601000 범위는 항상 매핑되어 있습니다. 그것이 무엇인지 궁금하다면 [이 문서](http://terenceli.github.io/%E6%8A%80%E6%9C%AF/2019/02/13/vsyscall-and-vdso)를 읽어보세요.

## 1.3 정보 누출 없이 ASLR 우회하기

정보 누출이 불가능할 때 ASLR을 우회하기 위해 무엇을 할 수 있는지 논의해 보겠습니다.

이 글은 Saelo의 블로그 포스트에서 얻은 내용을 요약한 것입니다.

ASLR을 우회하려면 다음이 필요합니다:
* 지정된 주소 범위에 원하는 크기의 연속 메모리를 매핑할 수 있는 메모리 스프레이 기법.
  
  그가 말했듯이 이를 수행하는 방법은 두 가지입니다:
  1. 메모리 누수(정보 누출이 아니라!)를 악용하는 방법. 메모리 청크가 “잊혀져” 해제되지 않는 버그를 여러 번 트리거하여 원하는 만큼의 메모리가 누출될 때까지 반복하는 방식입니다.
  2. “증폭 가젯”을 찾아 악용하는 방법. 기존 데이터 청크를 가져와 잠재적으로 여러 번 복사하는 코드 조각으로, 공격자가 상대적으로 적은 수의 바이트만 전송해도 대량의 메모리를 스프레이할 수 있습니다.
* `isAddressMapped` 오라클. 주소가 주어지면 해당 주소가 매핑되어 있는지 여부를 알려줍니다.

### Linux에서 ASLR 우회 PoC

Linux에서 ASLR을 완전히 깨는 saelo의 PoC를 재현해 봅시다.

<p align="center"> <img src="https://assets.kitploit.com/production/public/readmes/48660/93fcc6aff8ffd2e8395f34b35bc2f5d244e74a53b2fac39c3dae35c802227339.png" > <i> saelo의 PoC</i> <p/> <br/>

Linux에서는 그렇게 쉽지 않습니다. 16TB의 메모리를 할당할 수 있어야만 ASLR을 완전히 깨는 것이 가능합니다.```C
#include <stdio.h>
#include <stdlib.h>

int main()
{
    // 64gb
    size_t size = 0x1000000000;

    // 16TB allocations
    for (int i = 0; i < 256; i++) {
        void *mem = malloc(size); // this ends up calling mmap
        if (!mem) {
            puts("Failed");
            return 1;
        }
        printf("%p\n", mem);
    }

    unsigned int *mem = (void*)0x7f0000000000ULL;
    *mem = 0x41414141;
    printf("R/W to %p: %x\n", mem, *mem);

    return 0;
}

glibc 메모리 할당에 관한 참고 사항

man malloc 문서의 참고 사항:

  • 일반적으로 malloc()은 sbrk(2)를 사용하여 힙에서 메모리를 할당하고 필요에 따라 힙 크기를 조정합니다. MMAP_THRESHOLD 바이트보다 큰 메모리 블록을 할당할 때 glibc malloc() 구현은 mmap(2)을 사용하여 메모리를 private anonymous mapping으로 할당합니다. MMAP_THRESHOLD는 기본적으로 128kB이며 mallopt(3)을 사용하여 조정할 수 있습니다. mmap(2)을 사용한 할당은 RLIMIT_DATA 자원 제한의 영향을 받지 않습니다(getrlimit(2) 참조).

따라서 void *mem = malloc(size)는 결국 mmap(size + malloc_metadata_size, ...)을 호출하게 됩니다.

라이브러리는 ld에 의해 mmap을 통해 프로세스에 매핑되므로 이러한 할당은 결국 라이브러리 근처에 위치하게 됩니다.

도구 다운로드