본문 바로가기
리버싱

pwnable-Bof write up

by 웹하는빡통 2020. 4. 16.

 

이번 시간에는 pwnable.kr에서 bof문제에 대해 write up해보겠다. 

해당 bof writeup을 하기 전 간단하게 assembly 언어의 기본 명령어 부터 숙지하자. 

 

opcode(CPU에서 실행할 수 있는 단일 명령어)

push -스택에 값을 넣음
pop - 스택에 값을 뺀다
add - 값을 더한다. 
sub - 값을 뺀다. 
mov - 값을 넣음 ex) a=b ebp=esp
lea - 값 대신 주소를 넣음 
cmp - 두값을 비교 
call - 함수를 호출 
ret - call로 호출된 함수를 종료하고 그 다음 명령줄로 이동하는 명령어

 

operand(피연산자)

eax - 함수의 리턴값이 여기에 들어감(+,- 연산)
edx - eax와 역할은 같지만 함수의 리턴값이 없음 
ecx -  카운터 역할(ex for문에서 ++같은 역할임)
esi - 복사할 데이터의 주소가 저장
edi -  데이터를 복사할때 목적지 주소가 저장
esp - 스택 프레임의 끝지점 주소가 저장
ebp - 스택 프레임의 시작지점 주소가 저장 

 

해당 사이트에 접속하여 bof문제에 접속해보자. 

 

그러면 해당 창이 뜨는데 wget 명령어를 이용하여 다운로드 받자.

ex)) wget http://pwnable.kr/bin/bof,wget http://pwnable.kr/bin/bof.c 이 두개를 입력하여 다운하면 된다. 

 

vim을 통해 bof.c의 코드 내부이다. 먼저 main함수 부터 살펴보자 main함수에 func()를 호출하는데 인자로"0xdeadbeef"를 전달한다. 그리고 func() 함수 내에서 지역변수인 char overflowme[32]를 선언하고 배열의 크기만큼 gets()함수를 통해 입력받는다. 여기서 gets()는 취약한 함수 이므로 버퍼 오버플로우에 취약하다는 것을 알 수 있다.

 

gdb를 이용하여 bof.c를 어셈블리로 분석해보자. disas main과 disas func을 입력하면 된다. 

 

여기 func()애서 우리가 봐야할 핵심은 바로 저 2개이다. 우리가 해당 코드를 오버플로우 시킬려면 key값의 주소와 overflowme의 주소를 알아한다. 

 

먼저 cmp를 주목하자 cmp는 두 값을 비교해주는 명령어이다. 여기서 cmp DWORD PTR[ebp+0x8],0xcafebabe를 비교하고 있다.

C코드에서는 이 부분을 말하고있다. 그럼 여기서 key 주소ebp+0x8이라는 얘기다. 그럼 일단 key값의 주소를 알아냈다. 하지만 우리는 시작 주소를 모른다. 시작 주소를 알아야 시작 주소부터 얼만큼 덮어씌어야ebp+0x8까지 갈 수 있는지 알 수 있기 때문이다. 그럼 시작 주소는 어디인가?? 바로 overflowme가 시작 주소이다. 

func()의 disassembly 코드에서 4번의 call이 있는 것을 알 수 있다.

각각 printf(), gets(), system(), printf() 이다. 

 

gets() 안에 인자로 overflowme가 들어가고 lea eax,[ebp-0x2c]위치에 있는 것을 확인 할 수 있었다.  우리가 입력값으로 aaaa를 입력을 하면 ebp-0x2c에 입력값이 저장이되고 eax로 값이 저장이 된다. [ebp-0x2c] --->eax 여기서 lea는 값 대신 주소가 들어간다.

 

 C코드에서 이 부분이 [ebp-0x2c]인 것이다. 

 

자 그럼 key값의 주소overflowme의 주소를 알아냈다. 그 다음 이 둘이 얼마큼 떨어져 있는지 확인만 하면 된다. 확인 방법은 python으로 간단하게 확인 할 수 있다. 

 

확인 결과 key값의 주소(0x8)overflowme 주소(-0x2c)52byte만큼 떨어져있는 것을 알 수 있다.  이제 우리는 52byte만큼 아무 값이나 넣어주고 그 옆으로 cafebabe를 넣어주면 된다. 

 

이제 파이썬으로 명령어로 값을 넣어주면 되는데 여기서 Little endian 방식으로 넣어주자 "\xBE\xBA\xFE\xCA"(Little endain 방식) 

그리고 | A(표준출력) | B(표준입력)를 의미하는데 B(nc pwnable.kr 9000)를 입력해서 A를 출력 하겠다는 의미이다.

그 다음 ls명령어를 입력하면 flag가 보이는데 cat을 이용하여 해당 flag값을 확인하면 된다. 

 

 

'리버싱' 카테고리의 다른 글

리버싱 기초- 간단한 C코드로 코드분석  (2) 2020.04.17

댓글