SH1R0_HACKER

001. 스택 버퍼 오버플로우 (Stack Buffer Overflow) 본문

System/System Exploitation

001. 스택 버퍼 오버플로우 (Stack Buffer Overflow)

SH1R0_HACKER 2021. 2. 1. 23:26

첫 번째 예시입니다.

// stack-1.c
#include <stdio.h>
#include <stdlib.h>
int main(void) {
    char buf[16];
    gets(buf);
    
    printf("%s", buf);
}

위 코드를 볼 때 gets() 함수에 별도의 길이 제한이 없기 때문에

16바이트를 넘는 데이터를 입력한다면 스택 버퍼 오버플로우가 발생합니다.

 

 

버퍼에 16byte만큼 A를 입력하고 추가로 BBBBCCCC를 입력하자,

SFP가 0x42424242로, RET가 0x43434343로 바뀐 모습을 볼 수 있습니다.

 

이와 같이 스택 버퍼 오버플로우는 프로그램이 스택에 위치한 버퍼에 할당된 것보다

더 많은 데이터를 쓸 때 발생합니다.

 

버퍼 오버 플로우 취약점은 길이 제한이 없는 API 함수들을 사용하거나

버퍼의 크기보다 입력받는 데이터의 길이가 더 크게 될 때 일어납니다.


다음은 두 번째 예시입니다.

// stack-2.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int check_auth(char *password) {
    int auth = 0;
    char temp[16];
    
    strncpy(temp, password, strlen(password));
    
    if(!strcmp(temp, "SECRET_PASSWORD"))
        auth = 1;
    
    return auth;
}
int main(int argc, char *argv[]) {
    if (argc != 2) {
        printf("Usage: ./stack-1 ADMIN_PASSWORD\n");
        exit(-1);
    }
    
    if (check_auth(argv[1]))
        printf("Hello Admin!\n");
    else
        printf("Access Denied!\n");
}

 

먼저 main 함수 코드부터 살펴봅니다.

 

argc가 2가 아니면

Usage: ./stack-1 ADMIN_PASSWORD

를 출력하고 종료합니다.

 

check_auth() 함수로 사용자가 ADMIN_PASSWORD에 입력한 argv[1] 값을 인자로 넘겨줍니다.

이때 check_auth(argv[1])값이 참이면

Hello Admin!

을 출력하고 값이 거짓이면

Access Denied!

를 출력합니다.

 

다음은 check_auth 함수입니다.

 

argv[1] 값을 char *password를 통해서 받아옵니다.

 

strncpy 함수를 이용해 temp[16]에 password값을 password길이만큼 복사합니다.

그래서 인자로 TEST라는 값을 넘겨주면 temp에 "TEST" 가 복사되게 됩니다.

 

그 후 strcmp 함수를 이용해 temp와 "SECRET_PASSWORD" 값을 비교합니다.

두 값이 같다면 0을 반환하기 때문에 strcmp 앞에 ! 를 붙여서 0이 나오면 TRUE로 변경되도록 합니다.

그 후 auth에 1을 대입합니다.

 

이후 auth값을 반환합니다.

 

아래는 인자에 TEST 값을 넘겨주었을 때 결과입니다.

 

이때는 당연히 "TEST"는 "SECRET_PASSWORD"와 다르기 때문에 auth값이 0으로 변동이 없고

Access Denied!

를 출력합니다.

 

그럼 이번에 SECRET_PASSWORD 를 입력하면 어떨까요?

 

Hello Admin!

문구가 출력됩니다.

 

password는 길이제한이 따로 없고 사용자가 입력한대로 문자를 복사하므로

temp 크기인 16byte보다 더 많은 문자를 입력하여 auth 부분(4byte)만큼 을 덮어 버리면

auth가 TRUE로 되면서 check_auth 함수에서 반환하게 됩니다.

 

이렇게 패스워드를 입력하지 않아도 Hello Admin! 이 출력되는걸 확인할 수 있습니다.

여기서 더 많은 문장을 입력하게 되면 RET 값을 변경하면 시스템의 권한을 장악하는 등

더 많은 작업을 할 수 있습니다.

 


3번째 예시입니다.

// stack-3.c
#include <stdio.h>
#include <unistd.h>
int main(void) {
    char win[4];
    int size;
    char buf[24];
    
    scanf("%d", &size);
    read(0, buf, size);
    if (!strncmp(win, "ABCD", 4)){
        printf("Theori{-----------redacted---------}");
    }
}

 

scanf로 값을 입력받아 size에 저장하고

read 함수를 이용해 size만큼 buf 데이터를 입력받습니다.

(0번 파일 디스크립터는 표준입력입니다.)

 

win이 "ABCD"면 Theori{-----------redacted---------} 를 출력하나 봅니다.

redacted 부분을 보기위해선 버퍼오버플로우(BOF) 공격을 해서 win 값을 "ABCD"로 바꿔야 할 것 같습니다.

대충 위의 코드를 스택으로 표현하면 위와 같습니다.

우리는 이제 size에 win[4] + size + buf[24] = 32를 입력한 후에

buf[24]와 size 부분을 의미없는 문자로 가득 채워버리고

win부분에 우리가 원하는 값인 ABCD를 넣어 줄껍니다.

 

공격이 성공하여 Theori 값이 출력되었습니다.


4번째 예시입니다.

// stack-4.c
#include <stdio.h>
int main(void) {
	char buf[32] = {0, };
	read(0, buf, 31);
	sprintf(buf, "Your Input is: %s\n", buf);
	puts(buf);
}

32byte의 buf를 0으로 초기화하고 31byte만큼의 데이터를 입력받은 뒤 buf에 저장합니다.

이후 sprintf 함수를 통해 buf에 값을 씁니다.

 

이 때, buf에는 Your Input is: 라는 문장도 함께 저장됩니다.

따라서 사용자가 아무것도 입력하지 않아도 buf에 이미 15byte만큼이 채워지기 때문에

17byte 이상을 사용자가 입력하게 되면 버퍼오버플로우가 발생합니다.

 

 

이 포스트는 dreamhack.io의 강의를 정리한 게시글입니다.

저작권이나 기타 문제사항이 발생할 경우 포스트가 비공개 처리됩니다.

'System > System Exploitation' 카테고리의 다른 글

006. 초기화되지 않은 메모리  (0) 2021.02.07
005. Double Free & Use After Free  (0) 2021.02.07
004. Format String Bug  (0) 2021.02.07
003. Off-by-one  (0) 2021.02.03
002. OOB (Out Of Boundary)  (0) 2021.02.03