Major Study./System hacking

BOF - 01.buffer over flow? 메모리 구조, 레지스터

sosal 2009. 11. 1. 02:39
반응형
/*
 http://sosal.tistory.com/
 * made by so_Sal
 */



:: 버퍼 오버플로우 ::

어떤 메모리 공간에 사용자가 데이타를 입력할 수 있는 기회가 생겼을 때,
시스템이 원하는 메모리 공간 이상의 코드를 대입하여 ret라는 녀석을 조절하여
시스템에게 사용자가 원하는 행동을 하도록 합니다.
이게 무슨뜻이냐면.. 천천히 내려갑시다.

아래는 시스템 메모리 구조를 나타낸다.


환경변수, 프로그램 인자값중 문자열
환경변수, Argv 포인터
인자값의 수
스택 영역.


heap 영역.
초기화 되지 않은 변수
초기화 된 변수
읽을 수 있는 부분이 있으나, 변조될 경우 Segfault 발생

인텔 80x86 CPU 레지스터

- 범용 레지스터 -
AX - Accumulator :: 산술연산
BX - Base Register :: 베이스의 주소를 저장
CX - Count Register :: 반복적으로 실행되는 특정 명령에 사용
DX - Data Register :: 일반 자료 저장

- Offset Register -
BP :: Base Pointer :: 스택 내의 변수 값을 읽는 데 사용
IP  :: Instructuon Pointer :: 명령어가 흘러가는 위치 Offset을 저장하며, 다음에 수행될 명령어의 주소 형성
SP :: Stack pointer :: 스택의 가장 끝 주소를 가리킨다.
DI :: Destination Index :: 다음 목적지 주소에 대한 값 저장
SI :: 출발지 주소에 대한 값 저장

- Segment Register -
DS :: Data Segment Register :: 변수의 기본 베이스 주소 저장
ES :: Extra Segment Register :: 변수의 추가 베이스 주소 저장
SS :: Stack Segment Register :: 스택의 베이스 주소 저장
CS :: Code Segment Register :: 명령어 코드의 베이스 주소 저장

본문을 읽다 보면 ESP와 같은 레지스터 종류를 볼 수 있는데,
위 내용의 레지스터들은 16비트에서의 이름이고,
사실 32비트로 프로세서가 커지면서 Extended 라는 의미를 표현하기 위해
각 레지스터 앞에 'E' 를 붙이게 되었다.

mov, add, 등의 연산 명령 뒤에는 l (long), w(word), b(byte)와 같은 문자가 붙어
연산하게 될 자료의 크기를 정할 수 있다. (movl , movb, addw 등)


버퍼 오버플로우 공격의 시작이었던 스택 버퍼 오버플로우 공격에 대해서
먼저 살펴보려 합니다.
*/ abc 라는 파일의 소스 abc.c이다. /*

#include<stdio.h>
int main(){
    char a[3] = "abc";
}

이 프로그램의 구조를 알기위해 gdb를 이용하여 disassemble 해봅시당.
//GDB에 대한 내용은 다음절에 자세히 설명할께요
gdb ./abc
-> gdb가 켜진후
disassemble main을 입력


GDB가 켜졌다고 폼을 잡고있다.

여기서부터 main을 disas한다.
리눅스은 왼쪽있는 값을
오른쪽에 대입합니다.

push ebp :: 베이스 포인터 생성
mov esp, ebp :: esp 스택포인터를 기본 base 포인터로 옮김
sub 0x10 esp 스택포인터의
위치를 10만큼 낮춤으로써
스택의 크기를 10만큼 보유함







위 그림처럼 stack의 크기를 계산하는게 스택 오버플로우에서 가장 중요한 일입니다.
스택의 크기와 문자열이 대입되는 위치를 파악하여 버퍼를 넘치게 합니다.
그럼 스택 버퍼의 크기를 넘치게 하여 무엇을 하느냐?


옆그림을 보면 메모리 흐름에서
새로운 프로그램을 불러드려
잠깐 프로그램 A 영역 메모리로
이동하여 일을 수행한후
다시 프로그램 A를 실행시킨
곳으로 돌아와 하던일을
계속 하게 됩니다.

여기가 중요 포인트입니다.
RET. return이란 녀석이
어떤 주소값을 가지고 있는데
그게 자신을 실행 시키기전의
메모리 위치입니다.
그 메모리 위치를 기억하여
프로그램이 끝나면
이전에 하던일을 계속
하게 되는것입니다.





buffer를 overflow 시킨다면 return 값을 내 마음대로 조절할 수 있다는 것이겠죠?

만약 프로그램 A에게 Setuid가 걸려있다면
실행시키는 순간 파일의 주인의 권한을 갖게 되고,
그 권한으로 다른 프로그램을 실행시 킬 수 있는것입니다.
return 값을 /bin/bash로 한다면
그 권한으로 쉘을 얻을 수 있습니다.

만약 A프로그램의 주인이 root 였고, setuid가 걸려 있었다면
root의 권한을 관리자가 저항할 여지도 없이 공격자에게
모든 권한을 주게 되는것이죠.

================
BOF 실습해보기
LINK_
================

다음 2번글에서는 GDB에 대한 분석을 해보겠습니다.