문제 요구사항
/home/flag15/flag15에서 바이너리를 strace 해봐라.
dlopen man 페이지를 자세히 검토하여 "리눅스에서 공유 라이브러리를 컴파일"하는 방법과 라이브러리를 로드하고 처리하는 방법을 알아보라고한다.
파일 포맷확인
flag15 홈디렉터리에는 setuid 가 설정된 동적링크된 32bit 짜리 실행가능한 리눅스실행파일이라고한다. 또한 not stripped 이라 파일 symbol 을 볼 수 있다.
참고로 strace 는 System Call Trace 로 바이너리가 실행될때 참조하는 Syscall 을 보여주는 도구이다.
파일 실행 및 분석
strace 로 flag15 를 실행해보면 굉장히많은 "No such file or directory" 를 출력한다.리눅스에서 "No such file or directory" 찾고자하는 파일이 없을때발생하는 오류이다. 여기서 이 오류들의 공통점은 결국 C 에서 사용하는 공유라이브러리인 libc.so.6 를 찾고있다는 점과 찾고자하는 libc.so.6 의 경로가 모두 "/var/tmp/flag15/tls" 하위 경로라는 것이다.
(참고로 libc 는 Library for c 라는 뜻이다.)
계속, strace 의 결과를 따라가다 보면 결국 "/lib/i386-linux-gnu" 위치에서 libc.so.6 공유라이브러리를 찾아 오류가 발생하지않음을 확인할 수 있다.
여기서 할 수 있는 생각은 python 에서 library 를 찾는 우선순위를 악용하여 파이썬 라이브러리를 후킹할 수있는 것처럼
C 에서도 libc.so.6 공유라이브러리를 후킹할 수 있는 방법이 있지 않을까라는 생각이다.
결론적으로는 당연히 후킹이 가능하다.
처음에 flag15 를 file 명령어로 분석해봤을때, 동적링크되어있다고 나와있었는데, 여기서 Dynamic link. 즉, 동적링크되어있다는 의미는 해당 바이너리 실행될떄 Linker(링커) 가 해당바이너리가 사용 및 참조하는 공유라이브러리를 연결하여 사용할 수 있게해주는 방식을 의미한다.
하지만, 해당 바이너리가 사용 및 참조하는 공유라이브러의 정보를 알아야하는데, 알아낼수있는 방법은 여러가지 있다.
readelf 의 -d 옵션으로 dynamic section 을 읽어들임으로서 필요한 공유라이브러리의 이름과 그 라이브러리를 찾을 경로인 RPATH 를 알 수 있다.
$readelf -d flag15
또한, 해당 바이너리가 최종적으로 사용하게 되는 공유라이브러리는 ldd 로 확인할 수 있다. (ldd 는 공유라이브러리끼리의 의존성을 확인할 수 있는 도구이다.)
$ldd flag15
그래서 처음에 strace 로 flag15 를 실행했을 때, 공유라이브러리를 찾는 경로인 RPATH 에 명시된것처럼, /var/tmp/flag15 디렉터리부터 차례차례 탐색하고있었던 것이고, 결과적으로 ldd 에서 나와있는것처럼, /lib/i386-linux-gnu 디렉터리에서 공유라이브러리를 찾게된 것이다.
Expliot 코드 작성
여기서 할 수 있는 방법은 라이브러리를 찾는 경로를 명시한 RPATH 경로에 직접만든 libc.so.6 공유라이브러리를 만들어, 원본의 /lib/i386-linux-gnu/libc.so.6 이 실행되기 전에 먼저실행되도록 후킹하는 것이다.
근데 ㅋㅋ 대놓고 여기에다가 후킹하라는 것처럼 RPATH 경로인 /var/tmp/flag15 에 쓰기권한이 있다. ㅋㅋ
strace 가 첫번쨰로 참조하는 RPATH 하위 경로에 공유라이브러리가 없기떄문에, 참조하는 경로를 똑같이만들어준다.
이제 직접 공유라이브러리인 libc.so.6 를 만들고 컴파일해야한다.
__libc_start_main() 과 __cxa_finalize() 기 들어가는 것은 알았지만.. main 함수보다 먼저 실행되는 생성자를 호출하는 방법을 알지못했다. 또한, 컴파일떄 문제나 너무많이생겨서 누군가의 풀이를 봤어야했다 ㅠ
#include <linux/unistd.h>
static void shell() __attribute__((constructor));
void shell() { system("/bin/sh"); }
void __cxa_finialize(void *d) {}
$gcc -shared -fPIC -Wl,-Bstatic -static-libgcc libc.so.6.c -o libc.so.6
여튼 컴파일 후 다시 flag15 를 실행해주면 flag15 의 계정의 쉘이 나오게된다.