-
Jmp table - pwnable.xyzWrite-ups/pwnable.xyz 2020. 2. 12. 20:26
Prob Info
Prob Info Checksec int __cdecl __noreturn main(int argc, const char **argv, const char **envp) { signed int v3; // [rsp+Ch] [rbp-4h] setup(); while ( 1 ) { print_menu(); printf("> ", argv); v3 = read_long(); if ( v3 <= 4 ) (*(&vtable + v3))(); else puts("Invalid."); } }
main 함수의 내용이다. 여기서 vtable은 bss영역에 존재하는 전역변수이다.
.data:00000000006020B0 public size .data:00000000006020B0 ; size_t size .data:00000000006020B0 size dq 1 ; DATA XREF: do_malloc+1E↑w .data:00000000006020B0 ; do_malloc+25↑r ... .data:00000000006020B8 public heap_buffer .data:00000000006020B8 ; void *heap_buffer .data:00000000006020B8 heap_buffer dq 1 ; DATA XREF: do_malloc+3F↑w .data:00000000006020B8 ; do_malloc+50↑w ... .data:00000000006020C0 public vtable .data:00000000006020C0 vtable dq offset do_exit ; DATA XREF: main+4E↑o .data:00000000006020C8 dq offset do_malloc .data:00000000006020D0 dq offset do_free .data:00000000006020D8 dq offset do_read .data:00000000006020E0 dq offset do_write .data:00000000006020E0 _data ends
5가지 함수 포인터가 있으며 0 ~ 4까지 메뉴를 선택할 수 있다. (*(&vtable + v3))(); 부분을 어셈블리어로 다시 보면 아래와 같다.
mov eax, [rbp+var_4] cdqe lea rdx, ds:0[rax*8] lea rax, vtable mov rax, [rdx+rax] mov rdx, rax mov eax, 0 call rdx
v3의 값을 더하는데 [rdx + rax]를 진행한다. read_long에서 -1을 입력하면 0xffffffffffffffff이 반환되기 때문에 OOB가 가능하다. vtable 바로 위에는 do_malloc에서 사용되는 두 변수가 있다.
void *do_malloc() { unsigned __int64 v0; // rax void *result; // rax printf("Size: "); v0 = read_long(); size = v0; result = malloc(v0); if ( result ) heap_buffer = result; else heap_buffer = (void *)1; return result; }
size는 할당되는 힙의 사이즈, heap_buffer는 할당된 힙을 가리키고 있다. 두 변수중에 호출할 수 있는 값을 넣어야 하는데, heap_buffer는 힙영역 주소가 들어가 우리가 적당히 조절할 수 없다. 그래서 size에 _ 함수 주소를 넣고 인덱스를 -2로 해주면 된다.
'Write-ups > pwnable.xyz' 카테고리의 다른 글
Game - pwnable.xyz (0) 2020.02.12 l33t-ness - pwnable.xyz (0) 2020.02.12 TLSv00 - pwnable.xyz (0) 2020.02.12 Free Spirit - pwnable.xyz (0) 2020.02.12 two targets - pwnable.xyz (0) 2020.02.12