Security/Concept

BOF로 알아보는 포너블

criling 2020. 7. 29. 12:56

Bof의 개념 자체는 정말 간단한다.

포너블의 기초라고 하는 이 취약점으로 포너블에 뛰어들게 되었지만 간단하지는 않았다. 버퍼, 메모리, 어셈블리어, 레지스터 등과 관련된 글은 한 번 읽었을 때 와 닿지 않았으며 성격 특성상 이해가 될 때까지 읽었다. 아직 많이 부족하지만 이번 포스팅을 통해 한 번 되짚어 보려고 한다.

 

BOF(Buffer OverFlow)

'버퍼'의 데이터가 흘러넘치는 것

 

심플하다. 근데 이게 왜, 뭐가 문제가 되는지에 대해 실습으로 알아보겠다.

(이를 이해하기 위해선 앞서 말했던 c언어, 버퍼, 메모리, 어셈블리어, 레지스터 등에 대한 사전 지식이 필요하다.)

 

 

메모리 보호 기법인 ASLR을 잠시 꺼두도록 합니다.

sudo sysctcl w kernel.randomize_va_space=0

 

basic_bof.c

 

컴파일

gcc를 이용해 컴파일할 때 메모리 보호 기능들을 사용하지 않도록 컴파일한다.

 

 

<basic_bof> 스택 프레임

코드가 간단한 만큼 스택 프레임도 간단하다. 위의 코드에서의 문제점은 'strcpy' 함수를 사용함에 있다. strcpy함수는 문자열을 복사하여 넣는 기능을 하는데 이때 복사되는 문자열의 길이를 검증하지 않는다. 그렇기에 buf의 길이인 100보다 긴 문자열 입력 시 EBP를 지나 RET를 조작할 수 있다. 이때 buf에 쉘을 실행시킬 수 있는 쉘 코드를 넣고 RET가 buf의 주소를 가리킨다면 쉘을 실행시킬 수 있을 것이다.

<basic_bof> disas main

disas 결과를 통해 ebp-0x64 지점부터 buf [100] 주소가 시작됨을 알 수 있으므로 ebp-0x64를 구하기 위해 strcpy 함수가 실행된 직후에 BP를 걸고 ebp를 확인해 보겠다.

 

 

BP설정 후 인자로 AAAA 전달

 

EBP 확인

ebp는 0xbffff2e8 임을 확인할 수 있고 ebp-0x64에 AAAA가 들어있다면 우리의 예상은 들어맞게 된다.

0xbffff2e8 - 0x64 = 0xbffff284

 

 

ebp-0x64(0xbffff284)의 값 확인

 

buf의 주소가 0xbffff284 임을 알아내었고 이를 바탕으로 페이로드를 작성할 수 있다.

 

쉘 코드를 포함한 buf(100) + EBP(4) + RET(4) = NOP(30) + shellcode(25) + NOP+EBP(49) + RET(4)

이때 RET는 buf의 주소가 들어가야 한다.

 

하지만 이렇게 실행하면 Segmentation fault 오류가 발생한다. 

잘못된 buf의 주소로 인한 Segmentation fault

 

그 이유는 buf의 주소가 잘못되었기 때문이다. buf의 주소가 잘못된 이유는 프로그램이 실행될 땐 해당 프로그램뿐만이 아닌 환경변수, 프로그램에 전달하는 인자, 프로그램 지역 변수들이 자리 잡는데 gdb는 gdb가 자체적으로 사용하는 환경변수들이 있기 때문에 주소가 달라지게 되는 것이다.

 

그렇기에 buf의 주소를 출력하는 구문을 넣어주고 아까 썼던 페이로드를 넘겨준다.

수정 코드

 

 

코드 수정 후 컴파일, buf의 주소 = 0xbffff254
쉘 획득 모습