본문으로 바로가기

pwnable.xyz / xor

category Wargame/pwnable.xyz 2020. 1. 13. 17:55
  while ( 1 )
  {
    n = 0LL;
    printf(format);
    c = _isoc99_scanf("%ld %ld %ld", &x, &y, &n);
    
    if ( !x || !y || !n || n > 9 || c != 3 )
      break;
    
    result[n] = y ^ x;
    argv = (const char **)result[n];
    printf("Result: %ld\n"argv);
  }

 

특정 위치에 x^y 의 값을 쓰는 작업을 할 수 있다. n 이 9 초과일 때만 필터링하고, 음수를 넣어 0x202248 이하의 범위의 영역에 값을 자유롭게 쓸 수 있다.

 

바이너리를 실행하고 프로세스의 메모리 매핑 상태를 살펴보니 0x0~0x1000 범위에 RWX 권한이 있다는 점이 눈에 띈다.

 

 

이유를 찾아보니 __do_global_ctors_aux 에서 특정 페이지에 대해 PROT_READ | PROT_WRITE | PROT_EXEC 권한을 주는 것을 볼 수 있었다.

 

int _do_global_ctors_aux()
{
  _DWORD *addr; // [rsp+8h] [rbp-8h]
  
  for ( addr = (_DWORD *)((unsigned __int64)_do_global_ctors_aux & 0xFFFFFFFFFFFFF000LL); *addr != 0x464C457Faddr += 2 ) ;
  return mprotect(addr0x1000uLL7);
}

 

.text section에 write 권한이 있고 0x202248 이하 범위의 영역을 수정할 수 있기 때문에 xor 연산을 통해 dynamic code patch를 할 수 있다. 쉘코드를 직접 쓸 수도 있지만 win 함수가 주어졌고, call win 명령어 1개를 쓰는 게 더 편하고 쉽기 때문에 이 방법을 쓴다.

 

result 가 8바이트 단위의 배열이기 때문에, 주소가 8의 배수인 명령어를 찾아서 고쳐주어야 한다. 적절한 타겟은 main 함수에 있는 0xAC8의 call exit 명령어로, 해당 명령어를 call win 으로 바꾸면 win 함수를 실행할 수 있다. x86-64에서 PIE가 걸려있는 경우 RIP relative addressing 기법을 사용한다. (Ref: https://software.intel.com/en-us/articles/introduction-to-x64-assembly)

 

call exit 를 실행하는 시점에서 rip 레지스터의 값은 0xACD이고 win 의 주소는 0xA21 이다. 즉 call 0xFFFFFF54 를 실행시켜 주어야 하며 해당 명령어를 assemble 하면 E8 54 FF FF FF 이다. 이 위치에 값을 쓰려면 z=-262887 이 되어야 하고 x^y=0x000000FFFFFF54E8 을 만족하는 xy 를 입력하면 플래그를 볼 수 있다.

 

 

 

Last update: 10/22/2020

'Wargame > pwnable.xyz' 카테고리의 다른 글

pwnable.xyz / Free Spirit  (0) 2020.01.13
pwnable.xyz / two targets  (0) 2020.01.13
pwnable.xyz / note  (0) 2020.01.13
pwnable.xyz / GrownUp  (0) 2020.01.13
pwnable.xyz / misalignment  (0) 2020.01.13