본문 바로가기

Layer7/동아리 숙제

Codegate 2018 BaskinRobins31

1. 프로그램 분석
더보기

프로그램을 보면 유명한 베스킨라빈스31 게임을 하는 프로그램임을 알 수 있다.

우선 How many numbers do you want to take ? (1-3) 라는 문자열 뒤에

숫자를 입력 받고,

해당 숫자를 출력해준다.

 

바로 입력을 받을 때 BufferOverFlow를 할 수 있다는 것을 알 수 있다.

 

그럼 보호기법을 확인해 보자

NX 보호기법이 켜져 있는 것을 알 수 있다.

그러므로 지금까지 했던 방법을 할 수 없다는 것을 알 수 있다. (FSB제외)

오늘은 Memory Leaking을 하는 다른 방법인 ROP를 해볼 것이다.

 

2. 버퍼의 길이 구하기
더보기

gdb-peda로 프로그램의 흐름을 보자

1. 프로그램 분석에서 봤듯이 프로그램이 실행될때 규칙을 설명하고 사용자에게 your_turn함수로 가는 것을 알 수 있다.

 

IDA나 Ghidra같은 정적디버거를 사용해서 your_turn함수의 코드를 확인해 보자

보면 사용자에게 입력을 받는 부분이다.

s라는 변수로 입력을 받는데 이 s의 길이는 0xB0이라는 것을 알 수 있다.

 

3. Exploit 코드 짜기
더보기

1. 먼저 입력 받기 전인 (1-3)이 있는 구간까지 문자열을 받는다.

2. 그리고 SFP까지 아무값이나 채워준다.

3. 가젯을 이용해서 인자를 받고, got를 이용해서 printf함수의 주소를 구한뒤, plt로 puts를 실행시켜준다.

그러면 puts([printf함수의 주소]);가 출력된다.

4. main함수의 주소를 대입해준다.

(printf의 주소를 출력하면 ret값이 달려져 코드가 망가지기 때문에 다시 복구시켜 주는 것이다.)

5. 문자를 잘못 입력하면 아래 문자열이 출력된다는 것을 이용해서

   위 문자열까지 받고, 그뒤에 출력될 문자열인 printf함수의 주소를 리틀엔디안 방식으로 6자리 받는다.

   그리고 언패킹의 방식을 지키기 위해서 8자리를 비어있는 값으로 꽉 채워준다.(\x00\x00)

   그 뒤, printf의 Offset을 빼주면 라이브러리의 베이스주소를 구할 수 있다.

6. 그 뒤, 프로그램이 재시작되니까 다시 문자열을 입력받고

7. rdi를 넣어주고,

   + pwntools의 search기능으로 "/bin/sh"의 문자열의 Offset을 찾은 뒤 라이브러리 베이스 주소를 더해주어서

   "/bin/sh"을 더해준다. (symbols는 only 함수만)

   + 라이브러리 베이스 주소에 system의 Offset을 더해서 system함수를 호출 해 준다.

8. 마지막으로 작성한 payload를 입력해준다.

 

4. 시행착오
더보기

1. ASCII 문자열이 아닌 \web 문자열이 있다면서 오류를 뿜어냈다.

Sol) 아래 코드를 맨 위에 삽입해준다.

의외로 한국어 블로그에서 발견했다.

 

2. 버퍼의 크기 0x190? 0xB0?

처음에 read 0x190을 보고 영락없이 버퍼의 크기가 190인줄 알았다. 그런데 B0이다.

Sol) 왜 0xB0일까? MSDN을 보자

190은 받을 수 있는 버퍼의 크기를 의미한다.

그래서 버퍼의 크기는 0xB0이고, 입력할 수 있는 버퍼의 크기는 0x190이 되는 것이다.

그래서 BufferOverFlow가 일어나는 것이다.

 

3. 라이브러리 베이스 주소를 구할 때 처음에는 라이브러리 함수가 0x7F부터 시작한다는 규칙을 이용해 아래 주석처럼 받을려고 했지만, 잘 되지 않았다.

Sol) 그래서 알아보니 주소위에 AAAAAAAAAAAAAA...까지 다 받고 있었던 것이다.

Sol-Err) 7f.. 으로 시작하는데 7F로 적어서 그런거일 수도 있다.

그러면 :( 까지 받아주고, 진짜는 그 뒤부터 6자리 (라이브러리주소는 6자리)를 받으면 되지 않을까? 해서 아래처럼 코드를 고쳤다.

 

5. 결과 확인

 

6. 참고
더보기

Exploit 코드