bypass_valid_vtable

oogu ㅣ 2023. 4. 4. 23:11

// Name: bypass_valid_vtable
// gcc -o bypass_valid_vtable bypass_valid_vtable.c -no-pie 
#include <stdio.h>
#include <unistd.h>
FILE *fp;
void init() {
  setvbuf(stdin, 0, 2, 0);
  setvbuf(stdout, 0, 2, 0);
}
int main() {
  init();
  fp = fopen("/dev/urandom", "r");
  printf("stdout: %p\n", stdout);
  printf("Data: ");
  read(0, fp, 300);
  fclose(fp);
}

[그림 1-1]

코드를 보면 libc leak이 가능하고 fp 값을 덮어 쓸 수 있다.

fclose 내부 함수를 system 함수로 변조하여 실행시킬 수 있다.

 

[그림 1-2]

문제에서 라이브러리를 제공해주고 있어 환경 변수인 LD_PRELOAD에 제공된 라이브러리를 넣어 바이너리 실행 시 제공된 라이브러리를 사용할 수 있게 만든다.

[그림 1-3]

libc_base 주소를 이용해 필요한 함수 주소를 가져온다.

1. _IO_str_overflow의 주소를 값으로하는 주소는 _IO_file_jumps + 0xd8 위치에 있다. 

: _IO_file_jumps 구조체 다음에 _IO_str_jumps 구조체가 위치하고 있다. 따라서 구조체이기에 offset이 고정된 값일테니 항상 참조할 수 있는 것이다.

 

2. io_str_overflow - 0x10 한 fake_overflow는 무엇인가?

: fclose 함수를 실행하면 내부 함수에서 vtable 주소 + 0x10 에 위치한 함수 포인터를 실행한다. -> 실행시키고 싶은 함수 주소를 넣는게 아니라 실행시키고 싶은 함수 주소를 값으로 하는 주소를 넣어야 한다! ㄷㄷ;

따라서, _IO_str_overflow 실행시켜야 하므로 fake_overflow 값을 넣는다(_IO_file_overflow 주소를 값으로 함!)

 

3. fp는 왜 구함??

: _IO_FILE 구조체에서 _lock 멤버 변수는 멀티스레딩 환경에서 파일을 읽고 쓸때 race condition을 막기 위해 사용되는 변수로 무조건 쓰기 권한이 있는 영역의 주소를 넣어야 한다. 따라서, 전역변수인 fp를 구했다. -> bss 영역!

한번에 성공하지 못하는 경우가 있으니 offset을 바꿔가며 시도 해보자

 

[그림 1-4]

최종 익스 코드이다. 

payload는 파일 구조체를 덮기위한 값이다. 아래 vtable 다음에 system 주소를 넣는 이유는 _s._allocate_buffer가 vtable 주소 + 8 byte의 위치를 참조하기 때문에 vtable 주소 뒤에 써준 것이다.

 

[그림 1-5]

성공!

 

 

알게 된 점

1. LD_PRELOAD 변수에 라이브러리를 등록하면 해당 라이브러리로 load하여 바이너리를 실행한다.

 

 

 

참고

 

https://wyv3rn.tistory.com/114

 

Bypass IO_validate_vtable

그냥 대충 훑어보면 절대 이해 못한다. 자세히 읽어보고 이해가 되면 넘어가자. 원리 _IO_FILE 구조체에서는 vtable을 참조하는데, vtable 내 함수를 조작할 수 있다면 임의의 함수를 실행할 수 있다. *

wyv3rn.tistory.com

 

'Dreamhack - pwnable' 카테고리의 다른 글

iofile_aaw  (0) 2023.03.27
send_sig  (0) 2023.03.15
Sigreturn-Oriented Progamming  (0) 2023.03.14
rtld  (0) 2023.03.12
environ  (0) 2023.03.06