_IO_FILE_plus의 모든 것.

2022. 8. 21. 17:16·Tips & theory
728x90
반응형

자꾸 헷갈려서 간단하게 요약해본다.

추가로 확인되는 사항이 있으면 지속적으로 update 할 예정이다.


_IO_FILE_plus

많은 함수들이 단독으로 존재하는 것 같지만 사실은 _IO_FILE_plus 라는 구조체의 형식으로 존재하는 것들이 많다.

파일을 열고 닫는 함수들이 대부분 해당되며, stdin, stdout, stderr 등도 이 형식을 띄고 있다.

 

_IO_FILE_plus 는

_IO_FILE 구조체와

vtable 구조체의 집합이다.

 

_IO_FILE_plus 구조체의 모양은 아래와 같다.

struct _IO_FILE_plus
{
  FILE file;
  const struct _IO_jump_t *vtable;
};

 

_IO_FILE 구조체

_IO_FILE 구조체의 형식은 아래와 같다.

struct _IO_FILE
{
  int _flags;		/* High-order word is _IO_MAGIC; rest is flags. */
  /* The following pointers correspond to the C++ streambuf protocol. */
  char *_IO_read_ptr;	/* Current read pointer */
  char *_IO_read_end;	/* End of get area. */
  char *_IO_read_base;	/* Start of putback+get area. */
  char *_IO_write_base;	/* Start of put area. */
  char *_IO_write_ptr;	/* Current put pointer. */
  char *_IO_write_end;	/* End of put area. */
  char *_IO_buf_base;	/* Start of reserve area. */
  char *_IO_buf_end;	/* End of reserve area. */
  /* The following fields are used to support backing up and undo. */
  char *_IO_save_base; /* Pointer to start of non-current get area. */
  char *_IO_backup_base;  /* Pointer to first valid character of backup area */
  char *_IO_save_end; /* Pointer to end of non-current get area. */
  struct _IO_marker *_markers;
  struct _IO_FILE *_chain;
  int _fileno;
  int _flags2;
  __off_t _old_offset; /* This used to be _offset but it's too small.  */
  /* 1+column number of pbase(); 0 is unknown. */
  unsigned short _cur_column;
  signed char _vtable_offset;
  char _shortbuf[1];
  _IO_lock_t *_lock;
#ifdef _IO_USE_OLD_IO_FILE
};

_IO_file 구조체의 각 offset은 아래와 같다.

0x0   _flags
0x8   _IO_read_ptr
0x10  _IO_read_end
0x18  _IO_read_base
0x20  _IO_write_base
0x28  _IO_write_ptr
0x30  _IO_write_end
0x38  _IO_buf_base
0x40  _IO_buf_end
0x48  _IO_save_base
0x50  _IO_backup_base
0x58  _IO_save_end
0x60  _markers
0x68  _chain
0x70  _fileno
0x74  _flags2
0x78  _old_offset
0x80  _cur_column
0x82  _vtable_offset
0x83  _shortbuf
0x88  _lock
0x90  _offset
0x98  _codecvt
0xa0  _wide_data
0xa8  _freeres_list
0xb0  _freeres_buf
0xb8  __pad5
0xc0  _mode
0xc4  _unused2
0xd8  vtable

구조체 내에 주요 변수들은 아래와 같다.

 

_flags

이는 파일의 권한을 압축해서 알려준다.

자세한 사항은 아래 링크의 _flags 참조.

https://wyv3rn.tistory.com/110

 

_IO_FILE Arbitrary Address Read

원리 여러개의 파일을 열지만 읽기 권한이 없는 경우, 예를 들어 관리자가 작성한 암호 파일과 유저가 작성한 파일을 열어 그 내용을 비교한다고 가정할 때 관리자 파일에 읽기 권한이 없는 경

wyv3rn.tistory.com

 

_read (임의의 주소에 데이터 입력 시 사용)

기본사항

fread 함수의 경우 결국 read 함수를 참조하여 동작하는데,

read 함수의 구조는

read(f->_fileno, _IO_buf_base, _IO_buf_end - _IO_buf_base);

이며, 각 인자는 아래와 같이 사용 가능하다.

fileno : 읽어들일 방식, 보통 표준 입력하면 되기에 0을 사용

_IO_buf_base : 입력을 시작할 주소

_IO_buf_end : 입력을 종료할 주소

유의사항

  • _flag 값은 0xfbad2488 이어야 한다.
  • 만약 100 byte로 선언된 buffer 변수에 overwrite 하기 위해서는
    _IO_buf_ end > _IO_buf_base + 100
    이어야 한다.
  • 삽입되는 값의 크기는
    data = _IO_buf_end - _IO_buf_base
    이어야 한다.

 

_write(임의 위치의 값을 출력할때 사용)

기본사항

fwrite 함수 또한 결국 write 함수를 참조하여 동작하는데,

write 함수의 구조는

read(f->_fileno, _IO_buf_base, _IO_buf_end - _IO_buf_base);

이며, 각 인자는 아래와 같이 사용 가능하다.

fileno : 출력 방식, 보통 표준 출력하면 되기에 1을 사용

_IO_buf_base : 출력을 시작할 주소

_IO_buf_end : 출력을 종료할 주소

유의사항

  • _flags의 값은 0xfbad1000 이어야 한다.
  • _IO_read_end에는 값이 있어야하며, _IO_write_base와 같은 값을 삽입하면 된다.

 

_buf(stdin으로 값을 삽입하거나 stdout으로 출력 시 사용)

기본사항

stdin / stdout 함수 또한 _IO_FILE 구조체를 따른다.

특히 stdin 구조체의 buf_base 변수가 변경되어있다면, 

fgets(buf, size, stdin)

과 같이 값을 입력 받을 때 buf 변수가 아닌 변조된 buf_base 주소에 값을 써버린다.

특이사항

  • _flags 값은 보통 0xfbad208b를 쓴다.
  • buf_end는 당연히 buf_base보다 커야한다.

 

vtable 구조체

vtable 구조체라고 불리지만 사실은 _IO_jump_t 구조체가 맞다. 이의 모양은 아래와 같다.

struct _IO_jump_t
{
    JUMP_FIELD(size_t, __dummy);
    JUMP_FIELD(size_t, __dummy2);
    JUMP_FIELD(_IO_finish_t, __finish); // fclose()
    JUMP_FIELD(_IO_overflow_t, __overflow);
    JUMP_FIELD(_IO_underflow_t, __underflow);
    JUMP_FIELD(_IO_underflow_t, __uflow);
    JUMP_FIELD(_IO_pbackfail_t, __pbackfail);
    /* showmany */
    JUMP_FIELD(_IO_xsputn_t, __xsputn); // fwrite()
    JUMP_FIELD(_IO_xsgetn_t, __xsgetn); // fread()
    JUMP_FIELD(_IO_seekoff_t, __seekoff);
    JUMP_FIELD(_IO_seekpos_t, __seekpos);
    JUMP_FIELD(_IO_setbuf_t, __setbuf);
    JUMP_FIELD(_IO_sync_t, __sync);
    JUMP_FIELD(_IO_doallocate_t, __doallocate);
    JUMP_FIELD(_IO_read_t, __read);
    JUMP_FIELD(_IO_write_t, __write);
    JUMP_FIELD(_IO_seek_t, __seek);
    JUMP_FIELD(_IO_close_t, __close);
    JUMP_FIELD(_IO_stat_t, __stat);
    JUMP_FIELD(_IO_showmanyc_t, __showmanyc);
    JUMP_FIELD(_IO_imbue_t, __imbue);
};

그러므로 vtable이라는 것은 절대적인 명칭이 아니다.

예를 들면 _IO_str_jump, _IO_wstr_jump 등이 vtable 종류들이며 그 구조가 위와 같다.

vtable의 특이 사항이, 만일 vtable이 call 된다면, 해당 함수에 맞게 offset을 통해 함수가 실행된다.

 

vtable 값

기본사항

vtable의 값은 위에서 설명 했듯이 _IO_FILE_plus 내의 값이기에

_IO_FILE_plus 구조체에서 _IO_FILE_plus + 8 byte 위치에 있는 값이며,

_IO_FILE 구조체 기준으로는 _IO_FILE + 0xd8 위치의 값이다.

vtable의 값은 offset을 더하기 위한 기준 값이 된다.

유의사항

vtable 값은 호출할 함수의 주소를 담고 있는 주소여야 한다.

즉,

vtable 값 = system 함수의 주소를 값으로 가진 주소 - offset

여야 한다. offset은 아래를 참조.

 

_IO_finish_t & _IO_xsputn_t & _IO_xsgetn_t

아래와 같이 각각의 함수 실행 시 참조할 주소의 위치이다.

직접적으로 해당 값을 변조하여 사용되지는 않고 offset시에 활용된다고 생각하면 된다.

 

_IO_finish_t

fclose 함수 call 시 사용되는 값이며, 그 offset이 0x10 이다.

즉,

vtable 값 = system 함수의 주소를 값으로 가진 주소 - 0x10

 

_IO_xsputn_t

fprintf, fwrite 함수 call 시 사용되는 값이며, 그 offset이 0x38 이다.

즉,

vtable 값 = system 함수의 주소를 값으로 가진 주소 - 0x38

 

_IO_xsgetn_t

fread 함수 call 시 사용되는 값이며, 그 offset이 0x40 이다.

즉,

vtable 값 = system 함수의 주소를 값으로 가진 주소 - 0x40

 

libc 버전에 따른 문제.

libc 버전에 따라 공격 방법이 조금 다르다.

이유는 vtable을 검증하는 코드가 추가되었기 때문이다.

다만 우회 방법은 단순하게도 _IO_FILE 구조체의 값을 잘 조절해주면 된다.

자세한 내용은 아래 링크를 참조하자. (추후 여기로 가져올 예정)

https://wyv3rn.tistory.com/114

 

Bypass IO_validate_vtable

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

wyv3rn.tistory.com

 

728x90
반응형
저작자표시 비영리 변경금지

'Tips & theory' 카테고리의 다른 글

함수 호출 규약.  (0) 2022.09.05
system hacking을 register 기초  (0) 2022.09.05
FSOP - _IO_flush_all_lockp ()  (0) 2022.08.18
Bypass IO_validate_vtable  (0) 2022.08.17
_IO_FILE Arbitrary Address Write  (0) 2022.08.16
'Tips & theory' 카테고리의 다른 글
  • 함수 호출 규약.
  • system hacking을 register 기초
  • FSOP - _IO_flush_all_lockp ()
  • Bypass IO_validate_vtable
wyv3rn
wyv3rn
아저씨의 흔한 취미. wyv3rn#1249
  • wyv3rn
    think storage
    wyv3rn
  • 전체
    오늘
    어제
    • 분류 전체보기 (490) N
      • To do list (6)
        • Doing (0)
        • Complete (6)
      • Diary (35)
      • Tips & theory (77)
      • Kernel Exploit (22)
      • Wargame (310) N
        • pwn.college (34)
        • Dreamhack (145) N
        • pwnable.kr (15)
        • Lord of Sqlinjection (3)
        • Cryptohack (20)
        • Root me (27)
        • CodeEngn (4)
        • Exploit Education (22)
        • ROP Emporium (8)
        • H4C (10)
        • Hackerchool (22)
      • CTF (40) N
        • Solved (38) N
        • Unsolved (2)
      • Script (0)
  • 블로그 메뉴

    • 홈
    • 방명록
  • 링크

  • 공지사항

    • PWN wargame 모음 (및 느낀점)
    • 비공개 글들에 대해.
    • 뭐라도 하나 얻어가시길...
  • 인기 글

  • 태그

    heap
    dreamhack
    docker
    pwnable.kr
    exploit education
    rop
    vtable
    Me
    CANARY
    la ctf
    root-me
    32bit
    pwntools
    Buffer Overflow
    tcache
    RTL
    root
    FSB
    BOF
    cryptohack
    hackerschool
    libc
    lob
    ROOT ME
    _IO_FILE
    Format String Bug
    phoenix
    x86
    x64
    64bit
  • 최근 댓글

  • 최근 글

  • 250x250
    반응형
  • hELLO· Designed By정상우.v4.10.3
wyv3rn
_IO_FILE_plus의 모든 것.
상단으로

티스토리툴바