Notice
Recent Posts
Recent Comments
«   2024/12   »
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 관련한 삽질(Feat. Buffering) 본문

Study/System

Memory Leak 관련한 삽질(Feat. Buffering)

90at 2017. 7. 2. 18:19

Memory Leak 기법을 정리한 게시물의 내용 중


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

라는 내용을 적었었다. RTLMemory Leak을 발생시키는 것에 대한 내용인데, 보통 CTF 문제들로 공부한 내용을 기반으로 정리하다 보니 send, write 함수를 사용하는 게 많아서 저렇게 적었었다. 


근데 이 방법의 기본적인 원리는 단순히 출력(또는 전송)함수를 이용한 RTL로 임의의 주소의 값을 출력하는 것이기 때문에 sendwrite가 아니더라도 뭐 printf라던가 puts 똑같은 역할을 하는 출력함수니까 Memory Leak에 이용할 수 있지 않을까 해서(물론 이 함수들은 Null Byte 앞 까지 출력하므로 원하는 값만 딱 출력할 수는 없겠지만, Memory Leak 자체에 의미를 둠.),그리고 당연히 돼야한다고 생각했기 때문에 한 번 해봤다. (근데 이게 바로 됐으면 이 글 안썼음ㅋ)


[사진 1] 소스코드


실습 바이너리의 소스코드는 [사진 1]과 같다. 

시도한 것은 puts를 이용한 RTLputs@GOTLeak시키는 것. 

이를 위한 Payload는 아래와 같다.


|  DUMMY * 54  |  puts@PLT  |  DUMMY * 4  |  puts@GOT  |


[사진 2] gdb 내의 결과


gdb 안에서 보면 뒤에 뭔가 출력이 또 된 것으로 보아 Leak이 된 거 같은데

그래서 바로 원격으로 시도했다.


[사진 3] ??? 


근데 아무런 값도 오지 않았다. 이게 무슨 경우지 하고 로컬에서도 시도해 봤는데


[사진 4] ??????


모니터에 출력은 되는데 Redirection하면 안에 값이 아무것도 없다

일단 생각이 드는게 Redirection표준 출력을 파일로 재지향 한 것이고, 로컬 바이너리를 원격 바이너리 처럼 만들어주는 socat은 아마 원리가 표준 입/출력을 원격으로 전달해주는 것으로 안다. 그렇다면 모니터에 보이는 저게 어떻게 출력된 지는 모르겠고, 지금 이 바이너리는 표준 출력 결과가 없는 것으로 보인다. 그냥 똑같은 출력 함수writeputs로 바꿨을 뿐인데 왜? 


헤매고 있다가 stack overflow에서 관련된 질문을 찾았는데, 누군가


When you redirect, the output is block-buffered, not line-buffered. If you hit Ctrl-C before a block is full, nothing gets written to the file. You can use fflush(stdout) to make it write to the file immediately.

라고 답변했다. 입출력 버퍼링에 대해서는 모르고 있었으니 block bufferedline buffered가 뭔지 알아야 했다.

찾아보니 C에서는 세 가지 방식으로 버퍼링을 한다고 한다.


 버퍼링

 동작

 Fully(block) Buffered

버퍼에 일정한 블록 이상이 쌓이게 되면 출력한다. 블록이 다 채워지지 않았을 때 출력해야 할 경우 fflush와 같은 함수를 이용해서 스트림을 비울 수 있다. 

 Line Buffered

 버퍼에 개행문자가 입력될 때 출력한다. 대표적으로 printf가 있다.

unbuffered 

버퍼와 같은 경유없이, 쓰기작업 시 바로 출력한다. 대표적으로 write함수, stderr가 있다.


write는 저수준 함수라서 버퍼링을 하지 않았던 거고, putsprintfLine Buffered를 하는 함수였다.

이걸로 미루어봤을 때(확실하진 않지만) 일단 모니터에 출력되는 건 Line Buffered에 의한 것이고. Redirection이나 Socat을 이용한 전송 시에는 Fully Buffered를 이용하기 때문에 블록이 차지않아 결과 값이 없는 것 같다. 근데 이것도 무조건 그런 건 아니고, Overflow가 일어났을 때만 결과 값이 없었는데, 왜 그런진 모르겠다..


어쨌든 fflush를 사용한다면 다른 결과를 얻을 수 있을 것이다.


[사진 5] 수정한 소스코드


그래서 소스코드에 fflush(stdout)을 추가했다.  그리고 주소만 조금 바꾼 뒤 아까와 동일한 Payload 시도해봤다.


[사진 6] 확인


fflush가 동작하여 main의 puts 결과가 제대로 Redirection 됐다. 또한 원격으로도 값이 확인됐다.


Memory Leak 결과까지 확인하기 위해선 RTL을 이용한 puts 이후, fflush 한번 더 실행시켜야 하는데, RTL Chaning으로 fflush를 호출하려면 인자인 stdout의 주소를 알아야하고, 이것은 ASLR 동작할 때 알아낼 수 없으므로 main 코드 fflush의 인자로 stdout 구성하는 부분의 코드를 재사용하는 Payload로 구성했다.


putsMemory Leak을 하는 의미없는.. 최종 Payload는 다음과 같다.


|  DUMMY * 54  |  puts@PLT  |  POP RET gadget  |  puts@GOT  |  CodeReuse  |


[사진 7] Leak! 


성공적으로 Leak된 것 같고, 입력한 문자열의 마지막인 e1 84 04 08 다음 4Byte(개행(0a) 제외)인 0xf7e64ca0이 아마 putsLibrary 주소일 것이다.


[사진 8] FIN


보통 Buffering 때문에 문제가 발생하는 경우는 버퍼링 동작 방식이 다른 함수들을 혼용할 때(puts와 write를 함께 쓴다든지, 이때는 fflush를 써줘야 함.) 종종 생긴다고 하는데, 어쨌든 몰랐던 걸 알게 됐으니 마냥 의미없는 삽질은 아닌..걸로


Ubuntu 16.04 / gcc 5.4.0

'Study > System' 카테고리의 다른 글

Pwnable.kr input 풀다가 궁금한 거  (0) 2017.07.16
Memory Leak 기법  (0) 2017.06.30
Libc-Database를 이용한 함수 주소 구하기  (0) 2017.06.28
Dynamic Link 시 함수 호출 과정  (0) 2017.06.26
함수 주소에 대한 궁금증  (0) 2017.05.20
Comments