본문 바로가기

컴퓨터 과학/시스템보안

스택 버퍼 오버플로우 공격3

반응형

스택 버퍼 오버플로우 공격 대응

스택 버퍼 오버플로우 공격을 막기위한 몇 가지 대책 방법이 있다.

프로그램 정적 분석기

Cigtal의 ITS4라는 코드 패턴 검사 경고가 있다.

컴파일러

Stackshield : RET 주소의 사본을 저장하고, 함수 종료 시 RET 주소와 사본을 비교하여 오버플로우 발생 여부를 판단한다.

Stackguard : 버퍼와 RET 주소 사이에 카나리 값을 추가하고 사본을 저장한다. 함수 종료 시 카나리와 사본 카나리를 비교하여 오버플로우 발생 여부를 판단한다.

하드웨어

NX비트 : 데이터에서 코드를 분리하는 CPU 기술이다. 메모리의 특정 영역을 실행 불가능으로 설정한다. 그러나 Return to libc 공격에 취약하다.

운영체제

주소 공간 랜덤화(Address Space Layout Randomization) : 버퍼의 주소 시작을 랜덤화 하여 공격자의 쉘 코드 시작 주소 결정을 어렵게 한다.

반응형

ASLR

RET주소를 악성 코드의 시작 주소로 조작하는 방법은 버퍼의 시작 주소크기 정보를 알아야 가능하다.

컴파일러는 변수에 대한 접근을 ebp, esp와 그 오프셋을 통해 상대 주소의 개념으로 수행하는데 주소 랜덤화를 사용하여 버퍼 또는 스택의 시작 주소 추정을 어렵게 한다.

함수가 매 번 실행 될 때 마다 버퍼 또는 스택의 시작 주소가 바뀐다.

힙, 라이브러리 등 다른 유형의 메모리 위치에도 주소 랜덤화가 적용된다.

리눅스 주소 랜덤화

다음 코드를 보고 실습해 보자.

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

void main(){
    charx[12];
    char *y = malloc(sizeof(char)*12);
    
    printf("addr of x (on stack) : 0x%x\n",x);
    printf("addr of y (on heap) : 0x%x\n",y);
}

이 함수가 실행되면 x와 y가 저장된 위치의 주소를 출력한다.

gcc -o aslr aslr.c

로 컴파일 하여 파일을 생성해주자.

sudo sysctl -w kernel.randomize_va_space=0

./aslr

sysctl 명령어를 사용하여 주소 랜덤화를 꺼준다.

그리고 위 파일을 실행해보자.

몇 번을 실행해도 주소가 같은걸 볼 수 있다.

다음에는 주소 랜덤화를 켜주고 실행해보자.

매 번 실행할 때 마다 주소가 달라진다.

이 방법을 통해 해커가 버퍼 또는 스택의 시작 주소를 추정하기 어렵게 만든다.

사실 이 방법이 무적은 아니다.

무차별 공격을 통해 뚫리긴 한다.

ASRL 무력화 하기

다음 쉘 코드를 작성하여 실습해보자.

#!/bin/bash

SECONDS=0
value=0

while true; do
	value=$(( $value + 1))
    duration=$SECONDS
    min=$(( $duration / 60))
    sec=$(( $duration % 60))
    echo "$min min and $sec sec elapsed."
    echo "The program has been running $value times so far."
    #./stack-L1
    ./stack
done


 아래 stack.c를 새로 작성해준다

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void foo(char *str)
{
        char buf[100];
        strcpy(buf, str);
}

int main(int argc, char** argv)
{
        char str[400];
        FILE *badfile;

        badfile = fopen("badfile", "r");
        fread(str, sizeof(char), 400, badfile);

        foo(str);

        printf("foo() returned~\n");

        return 0;
}

그리고 주소 랜덤화를 실행시키고 위 쉘 코드를 실행해주자.

필자의 경우 운이 별로 없어서 8분동안 주소가 단 한번도 걸리지 않았다.

Stackguard와 스택 카나리 우회

bash 혹은 dash 쉘에서 setuid()를 0으로 설정하면 이를 쉽게 우회할 수 있다.

다음 코드를 실습해보자.

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>

int main()
{
    char *argv[2];
    argv[0] = "/bin/sh";
    argv[1] = NULL;
    
    setuid(0);
    execve("/bin/sh",argv, NULL);
    
    return 0;
}

chown으로 루트 권한으로 바꾸고 4755로 바꿔주고 이 프로그램을 실행하면 쉘 권한을 얻게 된다.

반응형