[pwnable.xyz] two targets(50 pts) :: Write-Up

두비니

·

2020. 10. 10. 19:18

 

 

Which one would you exploit?

 

 

 

 

 

문제 자체는 되게 직관적이네요. 1~3번으로 준비를 한 뒤에 4번으로 shell을 따면 되려나봐요 그쵸?

아이다로 더 자세히 봅시다.

 

문제분석

 

// local variable allocation has failed, the output may be wrong!
int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
  char *v3; // rsi
  const char *v4; // rdi
  signed int v5; // eax
  char s; // [rsp+10h] [rbp-40h]
  __int64 v7; // [rsp+30h] [rbp-20h]
  char *v8; // [rsp+40h] [rbp-10h]
  unsigned __int64 v9; // [rsp+48h] [rbp-8h]

  v9 = __readfsqword(0x28u);
  setup(*(_QWORD *)&argc, argv, envp);
  v3 = 0LL;
  v4 = &s;
  memset(&s, 0, 0x38uLL);
  while ( 1 )
  {
    while ( 1 )
    {
      print_menu();
      v5 = read_int32(v4, v3);
      if ( v5 != 2 )
        break;
      printf("nationality: ");
      v3 = (char *)&v7;
      v4 = "%24s";
      __isoc99_scanf("%24s", &v7);
    }
    if ( v5 > 2 )
    {
      if ( v5 == 3 )
      {
        printf("age: ");
        v3 = v8;
        v4 = "%d";
        __isoc99_scanf("%d", v8);
      }
      else if ( v5 == 4 )
      {
        v4 = &s;
        if ( (unsigned __int8)auth((__int64)&s) )
          win(&s);
      }
      else
      {
LABEL_14:
        v4 = "Invalid";
        puts("Invalid");
      }
    }
    else
    {
      if ( v5 != 1 )
        goto LABEL_14;
      printf("name: ");
      v3 = &s;
      v4 = "%32s";
      __isoc99_scanf("%32s", &s);
    }
  }
}

 

일단 필요한 부분만 분석을 해봅시다. getshell이 4번 선택지였으니 거기부터 봅시다.

 

      else if ( v5 == 4 )
      {
        v4 = &s;
        if ( (unsigned __int8)auth((__int64)&s) )
          win(&s);
      }

 

auth함수의 인자로 s를 넣어서 리턴값이 1이면 win함수를 실행시켜주네요. 이게 아마 첫 번째 타겟이겠죠?

win함수는

당연히 플래그를 출력시켜주는 함수고, 

 

 

이건 auth함수입니다. 결국 여기서 중요한건 다음 부분인데

 

  for ( i = 0; (unsigned int)i <= 0x1F; ++i )
    s1[i] = ((*(_BYTE *)(a1 + i) >> 4) | 16 * *(_BYTE *)(a1 + i)) ^ *((_BYTE *)main + i);

 

다음 식을 통해서 s1을 구합니다. 맨 처음에 저 수학적 수식을 보고 해석해보려고했는데, 해석이 안될 뿐더러 문제 제목이 two target인걸 보고 그냥 손절했습니다ㅎㅎ 안녕!

 

+) 나중에 추가로 찾아봤는데 리버싱으로 푼 분도 계시더라구요. 뭐 단순히(는 아니겠지만) 역연산을 구하면 되니 적절한 값을 넣어도 할 수는 있겠네요.

 

 

보호기법을 확인해보면, 일단 PIE가 없어서 got overwrite도 생각해 볼 수 있고, full relro가 아니라 bss말고도 다른 영역도 이용할 수 있네요.

 

그래서 일단 다른 부분에서 취약점을 찾아봅시다.

 

 

 

다른곳은 다 괜찮은데 여기 nationality를 입력받는 곳에서 v7에 24바이트만큼 입력을 받는데, v7은 16바이트밖에 되지 않습니다. 즉, v7의 입력을 통해 그 밑의 v8까지 overwrite가 가능합니다.

 

변수들 상황

 

그럼 v8을 가지고 어떻게 할 수 있는가 봅시다.

 

 

아하... 끝나버렸네요

age를 입력하는 부분에서 입력받을 때 v8의 주소인 &v8이 아닌 그냥 v8의 값 자체에 입력을 받고 있습니다. 그러면 시나리오는 다음과 같습니다.

 

 

시나리오

 

1. 국적 입력을 이용하여 v8까지 buffer overflow를 함.

1-2. 이때 v8에 들어갈 내용은 strncmp의 got주소. (PIE기법이 걸려있지 않기 때문에 GOT overwrite 사용 가능)

2. 나이 입력을 이용하여 win함수의 주소를 입력. (단, %d로 받고 있기 때문에 10진수로 입력해야함)

3. 다시 실행시켜서 exploit

 

 

페이로드

 

 

사실 원래는 printf로 덮어서 하려고 했는데 무슨 이유인지 안되더라구요... 이건 알게되면 더 서술함

나중에 역연산도 만드는걸로ㄲ