카테고리 없음

_IO_FILE AAW

Kon4 2023. 2. 18. 19:20

파일의 내용을 읽기 위한 함수는 대표적으로 fread, fgets 함수 가 존재한다.

해당 함수는 라이브러리 내부에서 _IO_file_xsgetsn 함수를 호출한다.

_IO_new_file_xsgetn code

_IO_size_t
_IO_file_xsgetn (_IO_FILE *fp, void *data, _IO_size_t n)
{
  _IO_size_t want, have;
  _IO_ssize_t count;
  _char *s = data;
  want = n;
    ...
	  /* If we now want less than a buffer, underflow and repeat
	     the copy.  Otherwise, _IO_SYSREAD directly to
	     the user buffer. */
	  if (fp->_IO_buf_base
	      && want < (size_t) (fp->_IO_buf_end - fp->_IO_buf_base))
	    {
	      if (__underflow (fp) == EOF)
		break;
	      continue;
	    }
	...
}

want 변수 즉 인자 n 값이 (fp->_IO_buf_end - fp->_IO_buf_base) 의 값, 즉 length 의 크기 보다 작은지를 검사하고 __underflow(fp) 를 호출한다.

_underflow(fp) —> _IO_new_file_underflow(fp)

_IO_new_file_underflow code

int _IO_new_file_underflow (FILE *fp)
{
  ssize_t count;
  if (fp->_flags & _IO_NO_READS)           
    {
      fp->_flags |= _IO_ERR_SEEN;
      __set_errno (EBADF);
      return EOF;
    }
   ...
   count = _IO_SYSREAD (fp, fp->_IO_buf_base,     
	fp->_IO_buf_end - fp->_IO_buf_base);
}

_IO_new_file_underflow 함수는 내부에서 flags 값에 Read 권한이 부여 되어있는지 확인하고 _IO_SYSREAD(fp, fp→_IO_buf_base, fp→_IO_buf_end - fp→_IO_buf_base) 함수를 호출한다.

#define _IO_SYSREAD(FP, DATA, LEN) JUMP2 (__read, FP, DATA, LEN)

_IO_SYSREAD 함수는 위 매크로처럼 vtable의 _IO_file_read 함수이다.

_IO_file_read code

_IO_ssize_t
_IO_file_read (_IO_FILE *fp, void *buf, _IO_ssize_t size)
{
  return (__builtin_expect (fp->_flags2 & _IO_FLAGS2_NOTCANCEL, 0)
	  ? __read_nocancel (fp->_fileno, buf, size)
	  : __read (fp->_fileno, buf, size));
}

_IO_file_read 함수 내부에서 read 시스템 콜을 사용해 파일의 데이터를 읽는다 . 시스템 콜의 인자로 파일 구조체의 파일 디스크립터를 나타내는 _fileno, _IO_buf_base, _IO_buf_end - _IO_buf_base 를 전달하는 것을 알 수 있다.

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

익스 시나리오

#include <stdio.h>
#include <unistd.h>
#include <string.h>
char account_buf[1024];
int overwrite_me;
void init() {
  setvbuf(stdin, 0, 2, 0);
  setvbuf(stdout, 0, 2, 0);
}
int read_account() {
	FILE *fp;
	fp = fopen("/etc/passwd", "r");
	fread(account_buf, sizeof(char), sizeof(account_buf), fp);
	write(1, account_buf, sizeof(account_buf));
	fclose(fp);
}
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_account();
  fclose(fp);
}

익스시 주의 사항.

_IO_new_file_underflow 함수 안에 보면 조건문 중에 _IO_buf_end - _IO_buf_base 값이 fread함수의 인자로 전달된 읽을 값(sizeof(file_buf)-1) 보다 크기가 커야하는 조건이 있음.

  1. 파일 구조체 조작
    1. 먼저 AAW를 하기 위해서 _IO_buf_end 와 _IO_buf_base를 조작해야 한다.
    _IO_buf_base = overwrite_me addr _IO_buf_end = overwrite_me + sizeof(overwrite_me) +n // n is over 1 2. 그리고 정상적으로 입력하기 위해 파일 구조체의 파일 디스크립터를 stdin, 즉 0으로 덮어쓴다.
    read(f->_fileno, _IO_buf_base, _IO_buf_end - _IO_buf_base);
    
    번외... 전역변수를 자세히 보아야 하는 이유. code
int __cdecl main(int argc, const char **argv, const char **envp)
{
  char s[520]; // [rsp+10h] [rbp-220h] BYREF
  void *src; // [rsp+218h] [rbp-18h]
  void *dest; // [rsp+220h] [rbp-10h]
  int v7; // [rsp+22Ch] [rbp-4h]

  v7 = 0;
  dest = 0LL;
  src = 0LL;
  memset(s, 0, 0x1FFuLL);
  initialize(s);
  while ( 1 )
  {
    while ( 1 )
    {
      while ( 1 )
      {
        while ( 1 )
        {
          printf("# ");
          read_command(s);
          if ( strcmp(s, "read") )
            break;
          read_str();
        }
        if ( strcmp(s, "help") )
          break;
        help();
      }
      if ( strncmp(s, "printf", 6uLL) )
        break;
      if ( strtok(s, " ") )
      {
        src = strtok(0LL, " ");
        dest = stdin;
        if ( src )
          memcpy(dest, src, 0x40uLL);
      }
    }
    if ( !strcmp(s, "exit") )
      break;
    printf("%s: command not found\n", s);
  }
  return 0;
}
.data:0000000000602000 ; ===========================================================================
.data:0000000000602000
.data:0000000000602000 ; Segment type: Pure data
.data:0000000000602000 ; Segment permissions: Read/Write
.data:0000000000602000 _data           segment qword public 'DATA' use64
.data:0000000000602000                 assume cs:_data
.data:0000000000602000                 ;org 602000h
.data:0000000000602000                 public __data_start ; weak
.data:0000000000602000 __data_start    db    0                 ; Alternative name is '__data_start'
.data:0000000000602000                                         ; data_start
.data:0000000000602001                 db    0
.data:0000000000602002                 db    0
.data:0000000000602003                 db    0
.data:0000000000602004                 db    0
.data:0000000000602005                 db    0
.data:0000000000602006                 db    0
.data:0000000000602007                 db    0
.data:0000000000602008                 public __dso_handle
.data:0000000000602008 __dso_handle    db    0
.data:0000000000602009                 db    0
.data:000000000060200A                 db    0
.data:000000000060200B                 db    0
.data:000000000060200C                 db    0
.data:000000000060200D                 db    0
.data:000000000060200E                 db    0
.data:000000000060200F                 db    0
.data:0000000000602010                 public size
.data:0000000000602010 size            dd 200h                 ; DATA XREF: read_command+C↑r
.data:0000000000602010 _data           ends
.data:0000000000602010
LOAD:0000000000602014 ; ===========================================================================
LOAD:0000000000602014
LOAD:0000000000602014 ; Segment type: Pure data
LOAD:0000000000602014 ; Segment permissions: Read/Write
LOAD:0000000000602014 LOAD            segment byte public 'DATA' use64
LOAD:0000000000602014                 assume cs:LOAD
LOAD:0000000000602014                 ;org 602014h
LOAD:0000000000602014                 public __bss_start
LOAD:0000000000602014 __bss_start     db    ? ;               ; Alternative name is '__bss_start'
LOAD:0000000000602014                                         ; _edata
LOAD:0000000000602015                 db    ? ;
LOAD:0000000000602016                 db    ? ;
LOAD:0000000000602017                 db    ? ;
LOAD:0000000000602018                 public __TMC_END__
LOAD:0000000000602018 __TMC_END__     db    ? ;               ; DATA XREF: deregister_tm_clones+6↑o
LOAD:0000000000602018                                         ; deregister_tm_clones+20↑o ...
LOAD:0000000000602019                 db    ? ;
LOAD:000000000060201A                 db    ? ;
LOAD:000000000060201B                 db    ? ;
LOAD:000000000060201C                 db    ? ;
LOAD:000000000060201D                 db    ? ;
LOAD:000000000060201E                 db    ? ;
LOAD:000000000060201F unk_60201F      db    ? ;               ; DATA XREF: deregister_tm_clones↑o
LOAD:000000000060201F LOAD            ends
LOAD:000000000060201F
.bss:0000000000602020 ; ===========================================================================
.bss:0000000000602020
.bss:0000000000602020 ; Segment type: Uninitialized
.bss:0000000000602020 ; Segment permissions: Read/Write
.bss:0000000000602020 _bss            segment align_32 public 'BSS' use64
.bss:0000000000602020                 assume cs:_bss
.bss:0000000000602020                 ;org 602020h
.bss:0000000000602020                 assume es:nothing, ss:nothing, ds:_data, fs:nothing, gs:nothing
.bss:0000000000602020                 public stdout@@GLIBC_2_2_5
.bss:0000000000602020 ; FILE *stdout
.bss:0000000000602020 stdout@@GLIBC_2_2_5 dq ?                ; DATA XREF: LOAD:00000000004004F0↑o
.bss:0000000000602020                                         ; initialize+22↑r
.bss:0000000000602020                                         ; Alternative name is 'stdout'
.bss:0000000000602020                                         ; Copy of shared data
.bss:0000000000602028                 align 10h
.bss:0000000000602030                 public stdin@@GLIBC_2_2_5
.bss:0000000000602030 ; FILE *stdin
.bss:0000000000602030 stdin@@GLIBC_2_2_5 dq ?                 ; DATA XREF: LOAD:0000000000400478↑o
.bss:0000000000602030                                         ; initialize+4↑r ...
.bss:0000000000602030                                         ; Alternative name is 'stdin'
.bss:0000000000602030                                         ; Copy of shared data
.bss:0000000000602038 completed_7594  db ?                    ; DATA XREF: __do_global_dtors_aux↑r
.bss:0000000000602038                                         ; __do_global_dtors_aux+13↑w
.bss:0000000000602039                 align 20h
.bss:0000000000602040                 public buf
.bss:0000000000602040 ; char buf[80]
.bss:0000000000602040 buf             db 50h dup(?)           ; DATA XREF: read_str+13↑o
.bss:0000000000602040 _bss            ends
.bss:0000000000602040
.prgend:0000000000602090 ; ===========================================================================

전역변수에 buf가 허걱 ㄷㄷ