서론
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
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 버전 찾고 다운로드까지 되는거 진짜 미쳤다.
- 여기서 검색된 버전(여기서는 libc6_2.27-3ubuntu1.4_amd64)을 클릭하면
이렇게 해당되는 libc 버전을 바로 다운로드 할 수 있다. 진짜 미친기능이다.
다운 받은 파일을 pwntools로 제작한 익스플로잇 코드에 같은 경로에 넣고 e=ELF("") 같은 형식으로 libc.so 파일을 열어 내 익스플로잇 코드에서 해당 libc 버전의 오프셋을 다룰 수 있게 된다.
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
참고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 오프셋이 다르다.)
'CTF > CTF_Configuration' 카테고리의 다른 글
CTF-pwnable용 Docker 설치 및 사용법 (0) | 2022.02.16 |
---|---|
main_arena offset 구하기 (0) | 2022.02.09 |
ROPgadget 사용법 (ROP 가젯 찾는법, 리턴가젯 찾아주는 프로그램) (0) | 2022.02.09 |
One_gadget Constraints (원가젯 제약조건) 해석하기 (0) | 2022.02.09 |
one_gadget 설치 및 사용법 (0) | 2022.02.04 |