_IO_FILE Arbitrary Address Read

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

문제와 함께 읽어야 이해가 쉽다.

https://wyv3rn.tistory.com/111

 

_IO_FILE Arbitrary Address Read

1. intro 2. code 및 분석 2.1 code // Name: iofile_aar // gcc -o iofile_aar iofile_aar.c -no-pie #include #include #include char flag_buf[1024]; FILE *fp; void init() { setvbuf(stdin, 0, 2, 0); setv..

wyv3rn.tistory.com

원리

여러개의 파일을 열지만 읽기 권한이 없는 경우, 예를 들어 관리자가 작성한 암호 파일과 유저가 작성한 파일을 열어 그 내용을 비교한다고 가정할 때 관리자 파일에 읽기 권한이 없는 경우 유저가 작성한 파일 내용이 임시 저장된 버퍼의 주소를 관리자 파일을 읽어온 버퍼의 주소로 변경한다면 해당 내용을 읽을 수 있을 것이다.

 

취약점

구조체

취약점은 파일을 열고 쓰기 위한 함수를 사용할때, _IO_FILE 구조체를 사용하는데, 이 구조체가 쓰기 권한이 있는 영역에 위치하기 때문에 이를 조작하면 다른 주소의 내용을 출력할 수 있다.

무엇보다 모든 파일 읽기 / 쓰기 함수가 이 구조체를 가지고 있다.

즉, 아래에서 보듯 read 함수만 사용하더라도 write 함수에서 사용될 값들도 가지고 있다는 것이다.

다만 구조체 내의 값들에 따라 읽고 쓰기가 가능한지 판단한다.

구조체의 전체 구조와 주요 포인터는 아래와 같은 내용을 담고 있다.

struct _IO_FILE_plus
{
  FILE file;
  const struct _IO_jump_t *vtable;
};
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
};
_flags 파일에 대한 읽기/쓰기/추가 권한을 의미. 0xfbad0000 값을 매직 값으로, 하위 2바이트는 비트 플래그로 사용됨.
_IO_read_ptr 파일 읽기 버퍼에 대한 포인터.
_IO_read_end 파일 읽기 버퍼 주소의 끝을 가리키는 포인터.
_IO_read_base 파일 읽기 버퍼 주소의 시작을 가리키는 포인터.
_IO_write_base 파일 쓰기 버퍼 주소의 시작을 가리키는 포인터.
_IO_write_ptr 쓰기 버퍼에 대한 포인터.
_IO_write_end 파일 쓰기 버퍼 주소의 끝을 가리키는 포인터.
_chain 프로세스의 _IO_FILE 구조체는 _chain 필드를 통해 링크드 리스트를 만드는데 링크드 리스트의 헤더는 라이브러리의 전역 변수인 _IO_list_all에 저장됨.
_fileno 파일 디스크립터의 값.
_IO_jump_ t *vtable 파일 관련 작업을 수행하는 가상 함수 테이블.

gdb로 보면 아래와 같은 값을 가지고 있다.

gef➤  p &_IO_list_all
$1 = (<data variable, no debug info> *) 0x7fcaee59d660 <_IO_list_all>
gef➤  p &_IO_file_jumps
$2 = (<data variable, no debug info> *) 0x7fcaee5992a0 <_IO_file_jumps>
gef➤  x/40gx 0x7fcaee59d660
0x7fcaee59d660 <_IO_list_all>:  0x00000000013ee260      0x0000000000000000
0x7fcaee59d670: 0x0000000000000000      0x0000000000000000
0x7fcaee59d680 <_IO_2_1_stderr_>:       0x00000000fbad2086      0x0000000000000000
0x7fcaee59d690 <_IO_2_1_stderr_+16>:    0x0000000000000000      0x0000000000000000
0x7fcaee59d6a0 <_IO_2_1_stderr_+32>:    0x0000000000000000      0x0000000000000000
0x7fcaee59d6b0 <_IO_2_1_stderr_+48>:    0x0000000000000000      0x0000000000000000
0x7fcaee59d6c0 <_IO_2_1_stderr_+64>:    0x0000000000000000      0x0000000000000000
0x7fcaee59d6d0 <_IO_2_1_stderr_+80>:    0x0000000000000000      0x0000000000000000
0x7fcaee59d6e0 <_IO_2_1_stderr_+96>:    0x0000000000000000      0x00007fcaee59d760
0x7fcaee59d6f0 <_IO_2_1_stderr_+112>:   0x0000000000000002      0xffffffffffffffff
0x7fcaee59d700 <_IO_2_1_stderr_+128>:   0x0000000000000000      0x00007fcaee59e8b0
0x7fcaee59d710 <_IO_2_1_stderr_+144>:   0xffffffffffffffff      0x0000000000000000
0x7fcaee59d720 <_IO_2_1_stderr_+160>:   0x00007fcaee59c780      0x0000000000000000
0x7fcaee59d730 <_IO_2_1_stderr_+176>:   0x0000000000000000      0x0000000000000000
0x7fcaee59d740 <_IO_2_1_stderr_+192>:   0x0000000000000000      0x0000000000000000
0x7fcaee59d750 <_IO_2_1_stderr_+208>:   0x0000000000000000      0x00007fcaee5992a0

 

_Flags

여기서 flags 값은 아래 값의 합으로 구성된다.

#define _IO_MAGIC         0xFBAD0000 /* Magic number */
#define _IO_MAGIC_MASK    0xFFFF0000
#define _IO_USER_BUF          0x0001 /* Don't deallocate buffer on close. */
#define _IO_UNBUFFERED        0x0002
#define _IO_NO_READS          0x0004 /* Reading not allowed.  */
#define _IO_NO_WRITES         0x0008 /* Writing not allowed.  */
#define _IO_EOF_SEEN          0x0010
#define _IO_ERR_SEEN          0x0020
#define _IO_DELETE_DONT_CLOSE 0x0040 /* Don't call close(_fileno) on close.  */
#define _IO_LINKED            0x0080 /* In the list of all open files.  */
#define _IO_IN_BACKUP         0x0100
#define _IO_LINE_BUF          0x0200
#define _IO_TIED_PUT_GET      0x0400 /* Put and get pointer move in unison.  */
#define _IO_CURRENTLY_PUTTING 0x0800
#define _IO_IS_APPENDING      0x1000
#define _IO_IS_FILEBUF        0x2000 /* 0x4000  No longer used, reserved for compat.  */
#define _IO_USER_LOCK         0x8000

예를 들어 flags 값이 fbad2c84라면

_IO_MAGIC
_IO_NO_READS
_IO_LINKED
_IO_TIED_PUT_GET
_IO_CURRENTLY_PUTTING
_IO_IS_FILEBUF

의 권한이 포함된 것이다.

 

fwrite 함수

함수 인자

어찌됐던 fopen은 권한 상 문제로 마음대로 할 수 없을테고, 이미 open된 파일 내용을 저장한 곳을 fwrite 또는 fputs로 표준 출력하거나 파일에 쓰는 것이 주 목적이 될 것이다.

fwrite 함수는 이런 저런 함수를 거쳐 결국 write system call을 통해 출력하며 그 구조는 아래와 같다.

write(f->_fileno, _IO_write_base, _IO_write_ptr - _IO_write_base);

각 인자의 주요점은 아래와 같다.

f->_fileno : 출력할 위치. 보통 표준 출력하면 되기에 1을 사용.
_IO_write_base : 출력을 시작할 주소
_IO_write_ptr : 출력을 종료할 주소

 

_flags 변수

추가로 위에서 이야기한 _flags 변수를 설정해줘야한다.

주요 사항은 _IO_MAGIC과 _IO_IS_APPENDING 비트를 포함해야하기에 변수 값은 0xfbad1000이어야 한다.

 

_IO_read_end

구조체에서 _IO_read_end는 값이 없으면 new_do_write 함수 내에서 lseek를 system call 한다.

그렇기에 여기에 적절한 값을 넣어줘야하며, 보통 _IO_write_base에 들어갈 값을 함께 넣어준다.

 

참고 - 각 값들의 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

 

728x90
반응형
저작자표시 비영리 변경금지 (새창열림)

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

Bypass IO_validate_vtable  (0) 2022.08.17
_IO_FILE Arbitrary Address Write  (0) 2022.08.16
SROP  (0) 2022.08.15
rtld_global  (0) 2022.08.15
seccomp 요약  (0) 2022.08.05
'Tips & theory' 카테고리의 다른 글
  • Bypass IO_validate_vtable
  • _IO_FILE Arbitrary Address Write
  • SROP
  • rtld_global
wyv3rn
wyv3rn
아저씨의 흔한 취미. wyv3rn#1249
  • wyv3rn
    think storage
    wyv3rn
  • 전체
    오늘
    어제
    • 분류 전체보기 (494) N
      • To do list (6)
        • Doing (0)
        • Complete (6)
      • Diary (35)
      • Tips & theory (77)
      • Kernel Exploit (23) N
        • Theory (15)
        • Exercise (1) N
      • Wargame (313)
        • pwn.college (34)
        • Dreamhack (148)
        • 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)
        • Solved (38)
        • Unsolved (2)
      • Script (0)
  • 블로그 메뉴

    • 홈
    • 방명록
  • 링크

  • 공지사항

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

  • 태그

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

  • 최근 글

  • 250x250
    반응형
  • hELLO· Designed By정상우.v4.10.3
wyv3rn
_IO_FILE Arbitrary Address Read
상단으로

티스토리툴바