_IO_FILE_plus의 모든 것.

2022. 8. 21. 17:16·File Structure
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
반응형
저작자표시 비영리 변경금지 (새창열림)

'File Structure' 카테고리의 다른 글

file structure __lll_lock_wait_private 우회  (0) 2023.09.06
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
_IO_FILE Arbitrary Address Read  (0) 2022.08.16
'File Structure' 카테고리의 다른 글
  • file structure __lll_lock_wait_private 우회
  • FSOP - _IO_flush_all_lockp ()
  • Bypass IO_validate_vtable
  • _IO_FILE Arbitrary Address Write
wyv3rn
wyv3rn
아저씨의 흔한 취미. wyv3rn#1249
  • wyv3rn
    think storage
    wyv3rn
  • 전체
    오늘
    어제
    • 분류 전체보기 (559)
      • To do list (0)
        • Doing (1)
        • Complete (6)
      • Diary (37)
      • Tips & theory (77)
      • Kernel Exploit (28)
        • Theory (16)
        • Exercise (5)
      • File Structure (6)
      • Wargame (352)
        • Dreamhack (183)
        • pwn.college (37)
        • pwnable.tw (0)
        • pwnable.kr (15)
        • Lord of Sqlinjection (4)
        • Cryptohack (20)
        • Root me (27)
        • CodeEngn (4)
        • Exploit Education (22)
        • ROP Emporium (8)
        • H4C (10)
        • Hackerchool (22)
      • CTF (50)
        • Solved (48)
        • Unsolved (2)
      • Script (0)
      • RubiyaLap (0)
  • 블로그 메뉴

    • 홈
    • 방명록
  • 링크

  • 공지사항

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

  • 태그

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

  • 최근 글

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

티스토리툴바