결론: 버전 문제
뒤져도 뒤져도 맘에 드는 한국어 글이 없어서 정리한다.
https://dreamhack.io/wargame/challenges/360
Overwrite _rtld_global
Description Exploit Tech: _rtld_global에서 실습하는 문제입니다.
dreamhack.io
해당 문제를 풀면서, `p &_rtld_global._dl_rtld_lock_recursive` 를 찾을 수가 없어서 직접 주소를 찾아보았다.
일단 저 부분이 무엇인지에 대해 알아보자.
프로그램이 시작될 때?
우리는 프로그램을 시작하기에 앞서 _start 를 수행한다.
커널로부터 받은 argc, argv인자를 저장하고 스택을 초기화한 후 glibc내에 정의된 __libc_start_main()를 호출한다.
__libc_start_main() 의 인자는 다음과 같다.
main() 주소, 인자의 개수, 인자 (array) ---> 해당 인자들을 이용하여 main (int argc, char* argv[]) 호출
init 함수
- main 호출 전 선행되어야하는 초기화 작업 수행
- 오브젝트 파일 로드할 때 실행되는 코드(프로세스 초기화 코드)
fini 함수
- main 이후 정리해주는 작업 수행 (할당 해제)
- 프로그램 종료시 수행될 프로그램들(함수들)이 .fini_array에 함수 포인터로 저장되어있다.
- 프로세스 종료 전에 실행되는 코드(프로세스 종료 코드)
rtld_fini
- cpp의 destructor 처럼 메모리 할당한걸 free해준다.
- libc같은곳에서 끌어와 실행을 하게되는데, 이런 것들을 다 정리해주는 작업을 한다.
위 세 함수들은 프로그램이 실행될 때 무조건 불리게되는 함수들이다. 종료될 때는 fini와 rtld_fini에 무조건 실행되는 프로그램들이 정의 되어있다고 볼 수 있다.
공격자가 쓸 수 있어야 init이나 fini 함수 포인터를 조작할 수 있는데, partial RELO나, fulll RELO의 경우는 절대 불가능하다.
따라서 쓸 수 없는 경우에는 rtld_fini를 공략하면된다.
프로그램이 종료될 때?
fini array에있는 함수들과 dl_fini가 실행이된다.
- main에서 ret을 호출한다.
- caller인 __libc_start_main으로 돌아가게 되고 내부에서 exit함수를 호출한다.
- exit 함수 내부에서 __run_exit_handlers 를 호출한다. (두번째 인자 rsi로 받는 부분이 함수 포인터 배열이다. 즉, 실행시 등록했던 핸들러가 여기서 실행이 된다.)
glibc 에서 실제로 코드를 직접 살펴보면, 핸들러로 등록된 함수들을 호출하는 것을 볼 수 있다.
그 함수들 중 하나가 `_dl_fini()` 인 것이다.
_dl_fini
_dl_fini() 내부에서 __rtld_lock_lock_recursive라는 함수를 호출하고, 인자로 dl_load_lock 을 보내준다.
디버거에서 직접 살펴보면,
디버거를 통해서는 실제로 ___rtld_mutex_lock 이게 dl_load_lock로 불러온다는 것을 알 수 있다.
# 0x7ffff7ffda48 <_rtld_global+2568> 이부분을 통해 인자로 _rtld_global+2568을 불러온다는 것도 알 수 있다.
즉, 정리하자면, rtld_global 구조체는 dynamic linker인 ld.so 에서 사용하는 값들을 담고 있다.
static binary가 아니라면 파일이 실행될 때 언제나 링크가 필요하다.
프로그램이 종료될 때 동적할당된걸 풀어주는 loader가 필요한 값들을 담고있는 구조체가 rtld_global이라고 할 수 있다.
파일이 실행할 때, 로더가 어떤 동적 라이브러리들을 어디에서 호출해야할지 호출하고 실행할 때 어떤값이 필요한지 rtld 구조체 안에 모두 담게되고, 프로그램이 종료될 때는 로더가 구조체 내에있는 내용을 참고해서 할당된 것을 다시 풀어주는 역할을 한다.
=> 런타임에 구조체 내용이 써진다 ? 런타임에 rw가 가능하다?
그럼. 어떻게 rtld overwrite를 하냐.
함수포인터 rtld_lock_default_lock_recursive() -> system()
인자인 _rtld_global+2568 -> "/bin/sh"
인자 개수가 안맞다.
해당함수는 rtld 구조체에 들어있지않다.
그냥 버전이 달라서 여기서는 해당 방법이 불가능하다는 생각이 든다.
'Pwn' 카테고리의 다른 글
CTF 문제풀이에서 Dockerfile 활용법 (0) | 2025.03.13 |
---|---|
[PWN Dreamhack] PIE & RELRO (0) | 2025.03.13 |
[PWN Dreamhack] basic_rop_x64 & basic_rop_x86 (0) | 2025.03.10 |
ROP 완벽 이해와 추가 예제 풀이 (0) | 2025.02.26 |
[PWN Dreamhack] RTL, ROP (0) | 2025.02.22 |