CTF/CTF_Configuration

libc 버전 찾기/버전 별로 다운로드하기 (libc_database 사용법, libc.blukat.me 사용법)

JUNFUTURE 2022. 2. 4. 16:48

서론

CTF 문제를 풀다보면 리눅스의 공유 라이브러리 libc.xx.so 파일들이 필요할때가 있다.

(PLT/GOT를 배우고, NX bit를 배워 스택영역에서 코드를 실행할 수 없을때)
(이를 위해 라이브러리 파일을 이용해야할때 - hook overwrite.. Gadget이용.. etc)

CTF 문제를 풀며 서버에 올라가있는 바이너리에 링크되는 libc.so 파일을 주는 경우는 감지덕지이지만,
주지 않더라도 이를 극복할 수 있어야한다. 오늘은 그러한 libc.so를 주지 않는 문제들을 위해
서버의 libc 버전을 알아내고 / libc 파일을 다운로드 하는 방법을 알아보고자 한다.

 

libc 버전 찾기

libc_database

libc_database는 리눅스에 다운로드 받아서 사용하는 프로그램으로
git hub에 코드가 공개되어 요기를 참고하면 다운로드 받을 수 있다.

https://github.com/niklasb/libc-database

 

GitHub - niklasb/libc-database: Build a database of libc offsets to simplify exploitation

Build a database of libc offsets to simplify exploitation - GitHub - niklasb/libc-database: Build a database of libc offsets to simplify exploitation

github.com

get ./all 뒤에 사용하면 될텐데, 이게 시간이 꽤 오래 걸린다. (libc를 버전별로 수집하는거라고 한다.)

  • find ⇒ 심볼로 버전검색
./find system 410
ubuntu-glibc (libc6_2.31-0ubuntu9.2_amd64)
ubuntu-glibc (libc6_2.31-0ubuntu9_amd64)
ubuntu-glibc (libc6-i386_2.31-0ubuntu9.4_amd64)
  • dump ⇒ 심볼로 버전검색하고 offset 검색
./dump libc6_2.31-0ubuntu9.2_amd64 __libc_start_main
offset___libc_start_main = 0x0000000000026fc0

libc.blukat.me

  • 실제함수 주소 끝 3자리(PLT, GOT 주소가 아니라 매번 실행될때마다 메모리로 실제 올라가는 해당 함수의 주소 끝 3자리)랑 심볼로 버전검색
  • 검색하고 다운로드

libc database search

  • 여기서 libc 버전 찾고 다운로드까지 되는거 진짜 미쳤다.
  • 여기서 검색된 버전(여기서는 libc6_2.27-3ubuntu1.4_amd64)을 클릭하면

해당 되는 libc 버전을 바로 다운로드 할 수 있다. 진짜 미친거 아니냐?

이렇게 해당되는 libc 버전을 바로 다운로드 할 수 있다. 진짜 미친기능이다.

 

다운 받은 파일을 pwntools로 제작한 익스플로잇 코드에 같은 경로에 넣고 e=ELF("") 같은 형식으로 libc.so 파일을 열어 내 익스플로잇 코드에서 해당 libc 버전의 오프셋을 다룰 수 있게 된다.

이런식으로.. 서버의 libc버전이 libc-2.27.so 였는데 해당파일을 못구해 직접 오프셋을 넣어줬다.

pwnable exploit의 관점에서 사실 서버의 libc 버전만 알면 수동으로 오프셋을 구해 (앞선 도구들 이용) 수작업을 통해 익스플로잇을 진행할 수 있으나, 직접 libc 파일을 다운받으면 pwntools의 ELF를 통해 로컬 libc.so 로 오프셋을 너무나도 편하게 다룰 수 있어서 다운로드하는게 매우 편하다. 사실 pwntools ELF 쓰려고 엄청 다운로드 하는법 찾아다녔다.


(pwntools의 ELF() 기능은 당연히 내 로컬의 파일 밖에 못 연다. 우리가 공격해야하는 대상은 서버이기 때문에. 또 서버에서 사용하는 libc 파일을 제공해주지 않는 경우이기 때문에 지금까지 우리가 직접 서버에서 사용중인 libc 버전을 찾고, 해당 libc파일을 구했다!! ELF()기능은 그걸 이용해서 파일 간의 오프셋 값만 편하게 구하기 위함이다. 절대 서버의 libc를 자동으로 알아내주고 해당 파일을 분석해준다거나 하는 말도안되는 천사같은 기능이 아니다.)

 

참고0) 메모리에 매핑되는 라이브러리 함수 주소 찾기

공유 라이브러리, PLT/GOT를 학습하면 메모리에 매핑되는 함수 주소를 찾기 위한 방법이 궁금해진다.

이는 별도의 익스플로잇(오버플로우 이용하여 메모리 값 출력)이나 GOT가 호출하는 주소 디버깅 등의 방법으로 알아내야 하며 드림핵 ROP 강의를 수강하면 좀 더 자세히 이해할 수 있습니다.

https://dreamhack.io/learn/84#1

 

로그인 | Dreamhack

 

dreamhack.io

 

참고1) libc_database에 입력하는 3글자 - 실제 함수 주소란?

바이너리가 실행되는 시점에 진짜 함수 주소(메모리에 매핑된) 이다.

PLT / GOT가 아니라 실제로 메모리에 매핑된 함수주소이다.

=> 프로그램이 실행될때마다 공유 라이브러리의 함수가 메모리에 매핑되고, 매 시점 다른 주소에 매핑되는데 실제 메모리에 매핑된 함수주소 맨 끝에 3자리는 버전마다 같다고 한다. (버전마다 libc_base의 주소가 시작되는 위치와 offset이 같기 때문) 그래서 이걸 이용해서 libc version을 추적하는 것.

 

참고2) start_main이랑 start_main_ret offset차이 libc-database 이용해서 구하기

  • 2.31에서 start_main이랑 start_main_ret offset차이
  • ⇒ 243

  • 2.27에서 start_main이랑 start_main_ret offset차이
  • ⇒ 231 미쳤다. (짤막 상식 : libc 버전에 따라 libc_start_main ~ libc_start_main_ret 오프셋이 다르다.)