[ENG] Wanna Play a Game? - reversing

mntly·2024년 12월 30일
0

CTF

목록 보기
9/9

I explained the process of the functions in the binary given by pwnable problem, Wanna Play a Game, in 0xL4ugh CTF.

Fortunately, the binary was not stripped, so analyzing is easy.

function main

int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
  __int64 v3; // [rsp+0h] [rbp-10h]
  __int64 v4; // [rsp+8h] [rbp-8h]

  setup();
  printf("[*] NickName> ");
  if ( read(0, &username, 0x40uLL) == -1 )
  {
    perror("READ ERROR");
    exit(-1);
  }
  while ( 1 )
  {
    menu();
    func = read_int();
    printf("[*] Guess>");
    param = read_int();
    ((void (__fastcall *)(__int64))conv[func - 1])(param);
  }
}

This function sets default configuration settings using the function setup, then it stores the string to username from user. After then, it performs the functions in menu based on the user input. At this time, the method to call the functions is implemented by accessing the element from function array (conv) by getting the index from user, not using conditional jump.

function setup

void setup()
{
  unsigned int v0; // eax

  setvbuf(stdin, 0LL, 2, 0LL);
  setvbuf(_bss_start, 0LL, 2, 0LL);
  setvbuf(stderr, 0LL, 2, 0LL);
  signal(14, handler);
  alarm(0x3Cu);
  change_passcode();
  v0 = time(0LL);
  srand(v0);
}

To prevent the string stored in Bufferend I/O is printed after the Buffered I/O is full, the function setup initializes the buffer. Then, it sets the time restriction of the exploit by 0x3C second using SIGALRM(14). After, it sets the passcode generated from /dev/random by calling the function change_passcode. Finally, it sets the seed for pseudo-random as current time (srand(time(NULL))).

function change_passcode

int change_passcode()
{
  int fd; // [rsp+Ch] [rbp-4h]

  fd = open("/dev/random", 0);
  if ( fd < 0 )
  {
    perror("OPEN ERROR");
    exit(-1);
  }
  if ( read(fd, &passcode, 8uLL) == -1 )
  {
    perror("READ ERROR");
    exit(-1);
  }
  puts("[*] PASSCODE CHANGED!");
  return close(fd);
}

This sets 8 byte random value to the passcode by opening /dev/random file. /dev/random file stores the random value generated by system noise, etc.

function menu

int menu()
{
  puts("= = = = = CAN YOU BEAT ME! = = = = =");
  puts("[1] Easy");
  return puts("[2] Hard");
}

This prints the menu, which represents the difficulty of a passcode leak.

function read_int

__int64 read_int()
{
  __int64 buf[6]; // [rsp+0h] [rbp-30h] BYREF

  buf[5] = __readfsqword(0x28u);
  memset(buf, 0, 32);
  printf("> ");
  if ( read(0, buf, 0x20uLL) == -1 )
  {
    perror("READ ERROR");
    exit(-1);
  }
  return atol((const char *)buf);
}

Ignore buf[5] = __readfsqword(0x28u); because it is related to Stack Canary.

This function translates 32byte string from user input to integer, then returns it.

function in array conv - easy

int __fastcall easy(__int64 param)
{
  if ( param == rand() )
    return printf("[+] NICE GUESS!!\n[*] Current Score: %lu\n", score);
  else
    return puts("[-] WRONG GUESS :(");
}

This checks the random value generated from rand() is the same as the given value param. In addition, the score is the global variable.

function in array conv - hard

unsigned __int64 __fastcall hard(__int64 param)
{
  int i; // [rsp+14h] [rbp-2Ch]
  char path[8]; // [rsp+2Fh] [rbp-11h] BYREF
  char v4; // [rsp+37h] [rbp-9h]
  unsigned __int64 v5; // [rsp+38h] [rbp-8h]

  v5 = __readfsqword(0x28u);
  strcpy(path, "<qz}<`{");
  v4 = 0;
  for ( i = 0; i <= 6; ++i )
    path[i] ^= 0x13u;
  if ( param == passcode )
  {
    puts("[+] WINNNN!");
    execve(path, 0LL, 0LL);
  }
  else
  {
    puts("[-] YOU ARE NOT WORTHY FOR A SHELL!");
  }
  change_passcode();
  return v5 - __readfsqword(0x28u);
}

This checks the random value read from /dev/random is the same as the given value param. If they are the same, then execute shell, if not, this function changes the passcode by calling the function change_passcode.

[Fig 1] Check the final value of the path used as the parameter of function execve

0개의 댓글

관련 채용 정보