티스토리 뷰

최종 수정: 2015-11-08

hackability@TenDollar


안녕하세요. Hackability 입니다.


이번에 포스팅 할 내용은 2015 School CTF 의 Exploit 500 문제 입니다.


이 문제에서는 바이너리 하나를 제공합니다. 


메인 함수

1
2
3
4
5
int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
  for ( server_fd = create_server_file_descriptor(); ; handle_client(server_fd, new_client_fd) )
    new_client_fd = create_client_file_descriptor(server_fd);
}
cs

먼저 create_server_file_descriptor()를 통해 서버를 생성하고 접속하는 client를 받습니다.

handle_client 함수

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
int __cdecl handle_client(int fd, int a2)
{
  __pid_t v3; // [sp+1Ch] [bp-Ch]@1
 
  v3 = fork();
  if ( v3 < 0 )
  {
    perror("ERROR on fork");
    exit(1);
  }
  if ( !v3 )
  {
    close(fd);
    play_guess_game(a2);
    exit(0);
  }
  return close(a2);
}
cs

handle client에서는 play_guess_game 으로 이동 합니다.

play_guess_game 함수

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int __cdecl play_guess_game(int fd)
{
  unsigned int v1; // eax@1
  size_t v2; // eax@1
  size_t v3; // eax@1
 
  v1 = time(0);
  srand(v1);
  v2 = strlen(hello);
  write(fd, hello, v2);
  first_try = (try_guess(fd, 0) & 0xF+ 1;
  second_try = try_guess(fd, 1);
  try_guess(fd, 2);
  v3 = strlen(farewell);
  return write(fd, farewell, v3);
}
cs

전체적인 내용은 서버에서 4바이트 랜덤 숫자를 생성하고 3번의 기회안에 맞추는 게임 입니다

만약 틀리면 랜덤 숫자를 보여주고 다시 랜덤 숫자를 생성합니다.

처음 2번은 랜덤한 숫자가 생성되지만 3번째 랜덤은 처음 2개처럼 완전한 랜덤이 아닌 first_try 변수와 second_try 변수에 의해 계산 가능한 값이 나오게 됩니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
int __cdecl next_rand(int a1)
{
  int result; // eax@5
  unsigned int i; // [sp+1Ch] [bp-Ch]@2
 
  if ( a1 == 2 )
  {
    for ( i = 0; i < first_try; ++i )
      unguessable ^= rot(second_try, i + 1);
    result = unguessable;
  }
  else
  {
    result = rand();
  }
  return result;
}
cs

따라서, 처음과 두번째 랜덤 값을 확인 한뒤, 계산하여 3번째 값을 맞출 수 있습니다. 대회 라이트업에서는 2^32-1 (정수 오버플로우 때문에) 값을 2번 입력하면 마지막 세 번째 랜덤 값이 0 이 되어 제일 간단히 할 수 있다고 되어 있는데, 저는 이것과 다르게 문제를 풀었습니다.

먼저 이런식으로 socket을통해 랜덤 값을 생성할때 시간에 따른 시드에 의한 랜덤이기 때문에 제가 강제로 소켓을 (nc) 2개 재빠르게 붙여 놓고 처음 nc 에서 아무거나 쳐서 랜덤 값을 보고 두 번째 nc 에서 처음 nc 에서 뱉은 랜덤값을 넣어 flag를 찾았습니다.

실제 pwnable 문제에서도 이런 socket 류의 문제점인 random, canary 가 고정된다는 점을 이용하여 문제를 제출하기도 합니다.




댓글