개념
: Unsorted Bin Attack 의 업그레이드 버전.. 매우 복잡
>> 조건
: Top Chunk 를 덮어쓸 수 있도록 힙 오버플로우가 일어나야 함 (경계 검사 X)
>> _IO_list_all 변수
struct _IO_FILE_plus *_IO_list_all = &_IO_2_1_stderr_;
>> _IO_FILE_plus 구조체
struct _IO_FILE_plus
{
FILE file;
const struct _IO_jump_t *vtable;
};
>> FILE = _IO_FILE 구조체
typedef struct _IO_FILE FILE;
struct _IO_FILE
{
int _flags; /* High-order word is _IO_MAGIC; rest is flags. */
/* The following pointers correspond to the C++ streambuf protocol. */
/* Note: Tk uses the _IO_read_ptr and _IO_read_end fields directly. */
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;
_IO_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_jump_t 구조체
#define JUMP_FIELD(TYPE, NAME) TYPE NAME
struct _IO_jump_t
{
JUMP_INIT_DUMMY,
JUMP_INIT(finish, _IO_file_finish),
JUMP_INIT(overflow, _IO_file_overflow),
JUMP_INIT(underflow, _IO_file_underflow),
JUMP_INIT(uflow, _IO_default_uflow),
JUMP_INIT(pbackfail, _IO_default_pbackfail),
JUMP_INIT(xsputn, _IO_file_xsputn),
JUMP_INIT(xsgetn, _IO_file_xsgetn),
JUMP_INIT(seekoff, _IO_new_file_seekoff),
JUMP_INIT(seekpos, _IO_default_seekpos),
JUMP_INIT(setbuf, _IO_new_file_setbuf),
JUMP_INIT(sync, _IO_new_file_sync),
JUMP_INIT(doallocate, _IO_file_doallocate),
JUMP_INIT(read, _IO_file_read),
JUMP_INIT(write, _IO_new_file_write),
JUMP_INIT(seek, _IO_file_seek),
JUMP_INIT(close, _IO_file_close),
JUMP_INIT(stat, _IO_file_stat),
JUMP_INIT(showmanyc, _IO_default_showmanyc),
JUMP_INIT(imbue, _IO_default_imbue)
};
전체 과정
- 힙 오버플로우로 Top Chunk 크기를 변조 * 반드시 페이지 단위를 맞출 것 *
- 변조된 크기보다 큰 크기를 할당 (Top Chunk becomes Free Chunk)
- freed Top Chunk 변조
- prev size = "/bin/sh\x00" (딱 8바이트)
- size of chunk = small_bin[4] 에 들어가는 90~98 바이트
- bk = &_IO_list_all - 0x10 영역으로 수정
- 나머지 영역은 freed Top Chunk 의 시작주소를 기준으로 _IO_FILE_plus 구조체로 만듬
- 오프셋 계산해서 ptr of vtable = ptr of _IO_jump_t 위치만 이동할 주소로 수정
- _IO_jump_t 구조체는 별도 영역에 생성하지 않고 freed Top Chunk 에 있는 _IO_FILE_plus 구조체를 덮어써도 됨
- _IO_jump_t 구조체에서 0x18 위치에 _IO_overflow_t 대신 이동할 주소를 씀 (보통 system())
- _IO_FILE 에서 몇몇 필드는 _IO_wide_data 구조체로 덮어씌워짐 (아래 내용 참고)
_IO_flush_all_lockp() 함수에서 사용하지 않는 "fp"변수의 "_freeres_list", "_freeres_buf" 영역 다음과 같이 활용합니다.
fp→_wide_data 변수에 fp→_offset의 주소 값을 저장합니다.
fp→_freeres_list = _wide_data->_IO_write_ptr
fp→_freeres_buf = _wide_data->_IO_write_base
- 새로운 힙 영역 할당
- 아래의 함수 호출 순서를 따라 _IO_overflow_t 영역의 함수 (변조한 주소)로 이동한다.
- _int_malloc() → malloc_printerr() → __libc_message → __FI_abort() → _IO_flush_all_lockp()
Proof Of Concept
Reference
https://www.lazenca.net/display/TEC/House+of+Orange
hitctf 2016 : http://4ngelboy.blogspot.com/2016/10/hitcon-ctf-qual-2016-house-of-orange.html
'Security > System' 카테고리의 다른 글
CTF Summary (0) | 2020.02.07 |
---|---|
linux system call table (0) | 2019.07.03 |
[Linux] Lazy Binding (0) | 2019.06.30 |
ROP Gadget Dictionary (0) | 2019.06.30 |
BROP (Blind Return Oriented Programming) (0) | 2019.06.26 |