Notice
Recent Posts
Recent Comments
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Today
Total
관리 메뉴

9oat's LAB

Memory Leak 기법 본문

Study/System

Memory Leak 기법

90at 2017. 6. 30. 00:30

원격 Exploit에서 함수 주소 offset 계산과 함께 사용하는 기법인 Memory Leak에 대하여 알아보자.


Memory Leak은 말 그대로 메모리를 유출시키는 것인데 방법에 따라서 인접 메모리 영역의 값을 유출시킬 수도 있고, 특정한 주소의 값을 유출 시킬 수도 있다. 


여러가지 방법들이 있겠지만 본 게시물은 Buffer Overflow를 이용한 기본적인 Memory Leak 두 가지를 다룬다. 사실 이것밖에 모름


1. Overflow를 이용해 변수와 변수 사이의 Null을 덮어씌워 인접한 메모리의 값유출시키는 기법

2. Return To Library를 이용해 특정 주소의 값 유출시키는 기법


첫 번째 방법부터 보자.


변수와 변수 사이에는 Null Byte가 존재하고, 보통 출력 함수들이 값을 출력할 땐 이 Null Byte를 만날 때 까지 출력하는데, Overflow를 이용하여 Null Byte를 덮어씌움으로써 인접한 메모리 값까지 이어서 출력하게 되는 것이다. 


무조건 되는 것은 아니고, 입력 값의 끝에 Null Byte가 삽입되면 안된다.

보통 로컬에서 버퍼에 입력 값을 저장할 때 사용하는 함수인 strcpy, fgetsscanf 등은 입력한 값의 끝에 Null Byte를 삽입하기 때문에 이 방법으로 Memory Leak을 할 수 없다. 하지만 recvread 등의 함수들은 입력 값에 별다른 처리를 하지 않기 때문에 이 방법으로 Memory Leak이 가능하다. 


[사진 1] 예제 Binary


예제로 쓸 Binary는 2017 HUST의 문제 중 하나인 attackme를 사용했다. 간단한 Bof문제이므로 이것저것 해보기에 좋았다.

read를 이용해 200자까지 입력받고 입력 값의 길이 만큼 다시 출력하는 프로그램으로, 별다른 보호기법도 없기 때문에 Memory Leak을 하기에 딱 적당하다. 버퍼의 크기가 100이므로 104만큼 입력하면 return address를 출력할 것이다. 


[사진 2] Leak


A를 104개 넣었더니 A 뒤에 알 수 없는 값들이 함께 출력됐다. 보통 메모리에 있는 값은 ASCII로 표현되지 않는 값들이니 Leak된 게 분명하다.

다만 정확히 어떤 값인 지는 알 수 없는데, 그래서 생각해 낸 방법으로 Redirection을 이용하는 것이다.


[사진 3] 확인


파일출력 결과저장하고, 해당 파일을 Winhex와 같은 Hex Editor로 열어보면 값을 확인할 수 있다. 

return address0xf7e1d637이다.


[사진 4] __libc_start_main+247


게시물의 주제에서 좀 벗어난 내용이지만 알아두면 좋은 정보로, 

mainreturn address에는 보통 __libc_start_main 이라는 함수의 +247 주소가 저장된다. 이 주소는 Libc-Database에서 offset을 제공하는 주소로, offset___libc_start_main_ret이라는 이름으로 offset 정보를 제공한다. 그러니까 이 주소를 Leak할 수 있으면 Libc-Database를 이용하여 exploit에 사용할 수 있다는 것.


다음은 두 번째 방법으로, Return To Library를 이용해 특정 주소의 값 유출시키는 기법이다.


아무 함수로 RTL하는 건 아니고 send write같은 함수를 이용한다. 이 같은 함수들은 특정 값(buf 등)을 출력하거나 전송할 수 있는 함수들인데,  이 특정 값내가 원하는 주소로 인자를 구성한 뒤 RTL하여 값을 출력시키는 것이다. 


이것도 조금은 주제에서 벗어난 이야기지만, 보통 CTF 등의 문제를 풀 때 Memory Leak의 목적함수 offset을 계산하기 위함이다. 그래서 이 방법으로 가장 많이 Leak하는 것은 함수 GOT의 값으로, 예를 들어


write(1,&write@GOT,4);


이런식으로 인자를 구성하여 RTL한다면 write@GOT에 저장된 writeLibrary주소Leak할 수 있는 것이다. write [사진 4]에서 볼 수 있듯이 Libc-Database에서 offset 정보를 제공한다. 그래서 writeLibrary 주소를 획득하면 exploit에 사용할 수 있을 것이다.


예제 Binary는 첫 번째 방법 때와 동일하다. 



[사진 5] write@PLT, write@GOT


PLTGOT주소는 Binary 에서 쉽게 확인 가능하고 변하지 않기에 RTL하기 좋다.

Memory Leak을 위한 Payload는 다음과 같다.


|  DUMMY * 104  |  write@PLT  |  DUMMY * 4  |  0x1  |  write@GOT  | 0x4  |

               Buf+SFP                  main's ret                     write's ret          stdout                                             size


이렇게 하면 Write Library 주소Leak할 수 있을 것이다.


[사진 6] Leak!


정상적으로 Payload가 동작한 것 같다. 끝에 주소로 보이는 0xf7edab60이 출력되었다.


[사진 7] write


확인해보니 write의 주소가 맞았다. 


지금은 Memory Leak을 하는 것이 목적이므로 간단히 RTL을 이용하여 함수의 Library 주소만 획득했지만, 만약 을 획득해야하는 상황이고 ASLR이 동작하는 환경이라면 여기에 다른 함수를 추가한 RTL Chaining으로 Payload를 구성하면 된다.


이것으로 Memory Leak은 끝. 다른 Leak기법이 생기면 추가해야지


참고문서 : MEMORY_LEAK_TECHNIQUES_cd80

Ubuntu 16.04 / gcc 5.4.0

Comments