return v3() 부분을 one 함수 대신 print_flag 함수 주소로 overwrite할 수 있을 것으로 보임
IDA 분석 - one 함수
int one()
{
return puts("This is function one!");
}
IDA 분석 - two 함수
int two()
{
return puts("This is function two!");
}
IDA 분석 - print_flag 함수
int print_flag()
{
char i; // al@1
FILE *fp; // [esp+Ch] [ebp-Ch]@1
puts("This function is still under development.");
fp = fopen("flag.txt", "r");
for ( i = _IO_getc(fp); i != -1; i = _IO_getc(fp) )
putchar(i);
return putchar(10);
}
rax레지스터에 0x96000이 있는 것으로 보아 해당 값과 사용자의 입력 값을 비교하는 것을 알 수 있음
→ 사용자는 9830400을 입력 해야 flag 획득을 위한 분기문에 접근할 수 있음
9830400 입력 시, 특정 문구와 함께 gets함수로 사용자의 입력을 받음
→ BOF 발생, 그러나 shell을 실행할 수 있는 함수나 코드가 존재하지 않음
→ ROP를 이용하여 system(”/bin/sh”)를 실행하도록 조작
문제 해결
💡 1. gets 함수를 통해 BOF 공격 → RET 부분을 이용해 ROP 공격 2. printf나 puts 함수를 이용해 offset 구하기 2. got주소 - symbols 주소를 통해 offset 구하기 → libc_base 주소 구할 수 있음 3. libc_base + system offset / libc_base + binsh offset으로 실제 주소 구하기 4. dummy + system + ret + /bin/sh 형태의 exploit
gets 함수를 통해 BOF 공격 발생
BOF 공격을 위해서는 buffer 크기(dummy)를 알아야 함
사용자의 입력은 0x7fffffffde4e에 저장됨
0x7fffffffde68에서 __libc_start_main+231 확인
사용자의 입력~0x7fffffffde68까지의 offset = 26(0x1a)
2. puts 함수를 이용해 offset 구하기
puts, printf, write 등의 함수는 사용자에게 특정한 값을 출력해주는 함수임
문제에서는 puts함수나 printf 함수를 이용할 수 있음
ALSR이 적용된 바이너리에서 주소들의 base를 구하기 위해서는 현재 바이너리에 puts 함수를 나타내는 symbols 주소와 GOT 주소의 차를 통해 offset를 구해야 함.
이를 위해서는 바이너리를 실행했을 때 설정된 got 주소를 출력해줘야 함. 구한 값을 사용하기 위해서는 사용자에게 출력해주고, 이를 pwntools에서 recv 함수를 통해 즉석으로 받아오는 과정이 필요함. → memory leak
puts 함수의 인자를 빼준 후(pop rdi; ret), 해당 인자를 puts 함수의 got으로 넣어주면 puts(puts@got)으로 사용자에게 got주소를 출력해줄 것임
[Binary Boss]
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)
ASLR: Enable
Binary Boss live in 0xf7f213d0
Binart Boss HP is 140 + Armor + 4
2. Make Money
This world is F*cking JabonJui
1) Farming... -> 100 gold
2) Item selling... -> 350 gold
3) Hunting... -> 500 gold
(Job)>>>
++ 4) Wow! you can find Hidden number!
Life is Just a One Shot...
Gambling...
-> 1714636915 gold
3. Get the System Armor
System Armor : 0xf7d5a2e0
4. Get the Shell Sword
Shell Sword : 0xf7e9b0af
5. Kill the Binary Boss!!!
IDA 분석 - main 함수
int __cdecl main(int argc, const char **argv, const char **envp)
{
int result; // eax@14
int v4; // [esp+10h] [ebp-90h]@5
char buf; // [esp+14h] [ebp-8Ch]@14
void *v6; // [esp+94h] [ebp-Ch]@1
void *handle; // [esp+98h] [ebp-8h]@1
void *s1; // [esp+9Ch] [ebp-4h]@1
setvbuf(stdout, 0, 2, 0);
handle = dlopen("/lib/i386-linux-gnu/libc.so.6", 1);
v6 = dlsym(handle, "system");
dlclose(handle);
for ( s1 = v6; 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();
printf(">>> ");
__isoc99_scanf("%d", &v4);
switch ( v4 )
{
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:
Get_Money(gold);
break;
case 3:
if ( gold <= 1999 )
{
puts("You don't have gold... :(");
}
else
{
gold -= 1999;
printf("System Armor : %p\\n", v6);
}
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;
}
}
}
Binary Boss information을 통해 boss의 주소를 알 수 있음 → 하위 1.5byte는 3d0으로 고정됨(ASLR)
Binart Boss HP is 140 + Armor + 4을 보아 dummy(140) + binsh+ ret(4) + system 형태로 입력하는 것이 아닐까 추측
1999 gold로 system address 획득
2999 gold로 binsh address 획득
1024byte만큼 attack에 입력 가능
IDA 분석 - Get_Money 함수
int Get_Money()
{
int result; // eax@1
int v1; // [esp+8h] [ebp-Ch]@1
int v2; // [esp+Ch] [ebp-8h]@1
int v3; // [esp+10h] [ebp-4h]@1
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;
}
hidden number를 통해 한번에 gold를 충족할 수 있음
IDA 분석 - Menu 함수
int Menu()
{
puts("======= Welcome to RTL World =======");
puts("1) Information the Binary Boss!");
puts("2) Make Money");
puts("3) Get the System Armor");
puts("4) Get the Shell Sword");
puts("5) Kill the Binary Boss!!!");
puts("6) Exit");
return puts("====================================");
}