水了2篇,开始干点正事吧。
在上一篇中,我提出怎么控制size_t _IO_default_xsputn (FILE *f, const void *data, size_t n)
这个函数的三个参数呢?
一般来说这是很难做到的,因为如果能够3个参数都能控制,能做的事情就太多了,getshell
简直是手到擒来。所以,house_of_魑魅魍魉
与其说是一种攻击链,不如说是一种攻击思路,当IO中存在以下条件都可以继续挖掘,本人利用_IO_helper_jumps
中的内容也只是攻击手段之一,不是绝对手段。
本篇文章介绍的攻击主要是利用_IO_helper_overflow
在执行_IO_sputn (target, s->_wide_data->_IO_write_base, used)
时,3个参数均能控制,然后利用memcpy、memmove
等函数实现house of 秦关汉月
,其中一条链如下。
一般来说一类跳表只有一个,但_IO_helper_jumps
比较特殊,通过下面可以看出,跳表会根据COMPILE_WPRINTF
值不同而生成不同的,但libc
在编译时会调用两次,分别是正常字符和宽字符,所以我们可以在内存中看到两个_IO_helper_jumps
,每种各一个。其中,COMPILE_WPRINTF==0
先生成,COMPILE_WPRINTF==1
后生成。
不同的COMPILE_WPRINTF
所对应的helper_file
也有所不同,区别在于是否需要伪造struct _IO_wide_data _wide_data;
。
这个函数在内存中也有2份。通过测试发现,如果使用COMPILE_WPRINTF==0
的情况,在攻击过程中s->_IO_write_base
会变成largebin->bk_size
指针,从而在largebin attack
时被强制修改从而无法控制。为了方便,我们使用COMPILE_WPRINTF==1
所生成的_IO_helper_overflow
。(第2个生成的)
通过上面函数可以清楚看出,在执行size_t written = _IO_sputn (target, s->_wide_data->_IO_write_base, used);
时
就达成了3个参数可控的要求,_IO_sputn
正是跳表中的_IO_default_xsputn
函数。
执行此函数内要绕过的内容较多。
需要绕过内容总结如下
执行此处需要绕过内容也比较多。
需要绕过内容总结如下
又到了喜闻乐见的抄板子时刻,此套攻击模板相对复杂很多,而且写入内容也比较长。
_IO_helper_overflow
/
/
FILE
*
target
=
((struct helper_file
*
) s)
-
>_put_stream;
int
used
=
s
-
>_wide_data
-
>_IO_write_ptr
-
s
-
>_wide_data
-
>_IO_write_base;
=
> _IO_sputn (target, s
-
>_wide_data
-
>_IO_write_base, used);
/
/
_IO_default_xsputn (
FILE
*
f, const void
*
data, size_t n)
/
/
s
-
>_wide_data
-
>_IO_write_base
=
=
s
=
> __mempcpy (f
-
>_IO_write_ptr, s, count);
/
/
f
-
>_IO_write_ptr
=
=
overflow 的地址,s 存储 onegadget
_IO_helper_overflow
/
/
FILE
*
target
=
((struct helper_file
*
) s)
-
>_put_stream;
int
used
=
s
-
>_wide_data
-
>_IO_write_ptr
-
s
-
>_wide_data
-
>_IO_write_base;
=
> _IO_sputn (target, s
-
>_wide_data
-
>_IO_write_base, used);
/
/
_IO_default_xsputn (
FILE
*
f, const void
*
data, size_t n)
/
/
s
-
>_wide_data
-
>_IO_write_base
=
=
s
=
> __mempcpy (f
-
>_IO_write_ptr, s, count);
/
/
f
-
>_IO_write_ptr
=
=
overflow 的地址,s 存储 onegadget
static const struct _IO_jump_t _IO_helper_jumps libio_vtable
=
{
JUMP_INIT_DUMMY,
JUMP_INIT (finish, _IO_wdefault_finish),
JUMP_INIT (overflow, _IO_helper_overflow),
JUMP_INIT (underflow, _IO_default_underflow),
JUMP_INIT (uflow, _IO_default_uflow),
JUMP_INIT (pbackfail, (_IO_pbackfail_t) _IO_wdefault_pbackfail),
JUMP_INIT (xsputn, _IO_wdefault_xsputn),
JUMP_INIT (xsgetn, _IO_wdefault_xsgetn),
JUMP_INIT (seekoff, _IO_default_seekoff),
JUMP_INIT (seekpos, _IO_default_seekpos),
JUMP_INIT (setbuf, _IO_default_setbuf),
JUMP_INIT (sync, _IO_default_sync),
JUMP_INIT (doallocate, _IO_wdefault_doallocate),
JUMP_INIT (read, _IO_default_read),
JUMP_INIT (write, _IO_default_write),
JUMP_INIT (seek, _IO_default_seek),
JUMP_INIT (close, _IO_default_close),
JUMP_INIT (stat, _IO_default_stat)
};
static const struct _IO_jump_t _IO_helper_jumps libio_vtable
=
{
JUMP_INIT_DUMMY,
JUMP_INIT (finish, _IO_default_finish),
JUMP_INIT (overflow, _IO_helper_overflow),
JUMP_INIT (underflow, _IO_default_underflow),
JUMP_INIT (uflow, _IO_default_uflow),
JUMP_INIT (pbackfail, _IO_default_pbackfail),
JUMP_INIT (xsputn, _IO_default_xsputn),
JUMP_INIT (xsgetn, _IO_default_xsgetn),
JUMP_INIT (seekoff, _IO_default_seekoff),
JUMP_INIT (seekpos, _IO_default_seekpos),
JUMP_INIT (setbuf, _IO_default_setbuf),
JUMP_INIT (sync, _IO_default_sync),
JUMP_INIT (doallocate, _IO_default_doallocate),
JUMP_INIT (read, _IO_default_read),
JUMP_INIT (write, _IO_default_write),
JUMP_INIT (seek, _IO_default_seek),
JUMP_INIT (close, _IO_default_close),
JUMP_INIT (stat, _IO_default_stat)
};
static const struct _IO_jump_t _IO_helper_jumps libio_vtable
=
{
JUMP_INIT_DUMMY,
JUMP_INIT (finish, _IO_wdefault_finish),
JUMP_INIT (overflow, _IO_helper_overflow),
JUMP_INIT (underflow, _IO_default_underflow),
JUMP_INIT (uflow, _IO_default_uflow),
JUMP_INIT (pbackfail, (_IO_pbackfail_t) _IO_wdefault_pbackfail),
JUMP_INIT (xsputn, _IO_wdefault_xsputn),
JUMP_INIT (xsgetn, _IO_wdefault_xsgetn),
JUMP_INIT (seekoff, _IO_default_seekoff),
JUMP_INIT (seekpos, _IO_default_seekpos),
JUMP_INIT (setbuf, _IO_default_setbuf),
JUMP_INIT (sync, _IO_default_sync),
JUMP_INIT (doallocate, _IO_wdefault_doallocate),
JUMP_INIT (read, _IO_default_read),
JUMP_INIT (write, _IO_default_write),
JUMP_INIT (seek, _IO_default_seek),
JUMP_INIT (close, _IO_default_close),
JUMP_INIT (stat, _IO_default_stat)
};
static const struct _IO_jump_t _IO_helper_jumps libio_vtable
=
{
JUMP_INIT_DUMMY,
JUMP_INIT (finish, _IO_default_finish),
JUMP_INIT (overflow, _IO_helper_overflow),
JUMP_INIT (underflow, _IO_default_underflow),
JUMP_INIT (uflow, _IO_default_uflow),
JUMP_INIT (pbackfail, _IO_default_pbackfail),
JUMP_INIT (xsputn, _IO_default_xsputn),
JUMP_INIT (xsgetn, _IO_default_xsgetn),
JUMP_INIT (seekoff, _IO_default_seekoff),
JUMP_INIT (seekpos, _IO_default_seekpos),
JUMP_INIT (setbuf, _IO_default_setbuf),
JUMP_INIT (sync, _IO_default_sync),
JUMP_INIT (doallocate, _IO_default_doallocate),
JUMP_INIT (read, _IO_default_read),
JUMP_INIT (write, _IO_default_write),
JUMP_INIT (seek, _IO_default_seek),
JUMP_INIT (close, _IO_default_close),
JUMP_INIT (stat, _IO_default_stat)
};
struct helper_file
{
struct _IO_FILE_plus _f;
struct _IO_wide_data _wide_data;
FILE
*
_put_stream;
_IO_lock_t lock;
};
struct helper_file
{
struct _IO_FILE_plus _f;
struct _IO_wide_data _wide_data;
FILE
*
_put_stream;
_IO_lock_t lock;
};
static
int
_IO_helper_overflow (
FILE
*
s,
int
c)
{
FILE
*
target
=
((struct helper_file
*
) s)
-
>_put_stream;
int
used
=
s
-
>_wide_data
-
>_IO_write_ptr
-
s
-
>_wide_data
-
>_IO_write_base;
if
(used)
{
/
/
利用这个链,显然这三个参数我们都可控。
size_t written
=
_IO_sputn (target, s
-
>_wide_data
-
>_IO_write_base, used);
if
(written
=
=
0
|| written
=
=
WEOF)
return
WEOF;
__wmemmove (s
-
>_wide_data
-
>_IO_write_base,
s
-
>_wide_data
-
>_IO_write_base
+
written,
used
-
written);
s
-
>_wide_data
-
>_IO_write_ptr
-
=
written;
}
/
/
如果使用这条链,_IO_write_ptr 将处于 largebin 的 bk_size 指针处
int
used
=
s
-
>_IO_write_ptr
-
s
-
>_IO_write_base;
if
(used)
{
size_t written
=
_IO_sputn (target, s
-
>_IO_write_base, used);
if
(written
=
=
0
|| written
=
=
EOF)
return
EOF;
memmove (s
-
>_IO_write_base, s
-
>_IO_write_base
+
written,
used
-
written);
s
-
>_IO_write_ptr
-
=
written;
}
return
PUTC (c, s);
}
static
int
_IO_helper_overflow (
FILE
*
s,
int
c)
{
FILE
*
target
=
((struct helper_file
*
) s)
-
>_put_stream;
int
used
=
s
-
>_wide_data
-
>_IO_write_ptr
-
s
-
>_wide_data
-
>_IO_write_base;
if
(used)
{
/
/
利用这个链,显然这三个参数我们都可控。
size_t written
=
_IO_sputn (target, s
-
>_wide_data
-
>_IO_write_base, used);
if
(written
=
=
0
|| written
=
=
WEOF)
return
WEOF;
__wmemmove (s
-
>_wide_data
-
>_IO_write_base,
s
-
>_wide_data
-
>_IO_write_base
+
written,
used
-
written);
s
-
>_wide_data
-
>_IO_write_ptr
-
=
written;
}
/
/
如果使用这条链,_IO_write_ptr 将处于 largebin 的 bk_size 指针处
int
used
=
s
-
>_IO_write_ptr
-
s
-
>_IO_write_base;
if
(used)
{
size_t written
=
_IO_sputn (target, s
-
>_IO_write_base, used);
if
(written
=
=
0
|| written
=
=
EOF)
return
EOF;
memmove (s
-
>_IO_write_base, s
-
>_IO_write_base
+
written,
used
-
written);
s
-
>_IO_write_ptr
-
=
written;
}
return
PUTC (c, s);
}
size_t
_IO_default_xsputn (
FILE
*
f, const void
*
data, size_t n)
{
const char
*
s
=
(char
*
) data;
size_t more
=
n;
if
(more <
=
0
)
return
0
;
for
(;;)
{
/
*
Space available.
*
/
if
(f
-
>_IO_write_ptr < f
-
>_IO_write_end)
{
size_t count
=
f
-
>_IO_write_end
-
f
-
>_IO_write_ptr;
/
/
要 more > count,能再次返回执行 __mempcpy
if
(count > more)
count
=
more;
/
/
要 count >
20
if
(count >
20
)
{
/
/
利用此处实现 house of 借刀杀人,
/
/
修改 memcpy 的内容为setcontext
/
/
再次返回的时候就能够实现 house of 一骑当千
f
-
>_IO_write_ptr
=
__mempcpy (f
-
>_IO_write_ptr, s, count);
s
+
=
count;
}
else
if
(count)
{
char
*
p
=
f
-
>_IO_write_ptr;
ssize_t i;
for
(i
=
count;
-
-
i >
=
0
; )
*
p
+
+
=
*
s
+
+
;
f
-
>_IO_write_ptr
=
p;
}
/
/
要 more > count,能再次返回执行 __mempcpy
more
-
=
count;
}
/
/
绕过下面这一行,再次执行
for
循环的内容
if
(more
=
=
0
|| _IO_OVERFLOW (f, (unsigned char)
*
s
+
+
)
=
=
EOF)
break
;
more
-
-
;
}
return
n
-
more;
}
libc_hidden_def (_IO_default_xsputn)
size_t
_IO_default_xsputn (
FILE
*
f, const void
*
data, size_t n)
{
const char
*
s
=
(char
*
) data;
size_t more
=
n;
if
(more <
=
0
)
return
0
;
for
(;;)
{
/
*
Space available.
*
/
if
(f
-
>_IO_write_ptr < f
-
>_IO_write_end)
{
size_t count
=
f
-
>_IO_write_end
-
f
-
>_IO_write_ptr;
/
/
要 more > count,能再次返回执行 __mempcpy
if
(count > more)
count
=
more;
/
/
要 count >
20
if
(count >
20
)
{
/
/
利用此处实现 house of 借刀杀人,
/
/
修改 memcpy 的内容为setcontext
/
/
再次返回的时候就能够实现 house of 一骑当千
f
-
>_IO_write_ptr
=
__mempcpy (f
-
>_IO_write_ptr, s, count);
s
+
=
count;
}
else
if
(count)
{
char
*
p
=
f
-
>_IO_write_ptr;
ssize_t i;
for
(i
=
count;
-
-
i >
=
0
; )
*
p
+
+
=
*
s
+
+
;
f
-
>_IO_write_ptr
=
p;
}
/
/
要 more > count,能再次返回执行 __mempcpy
more
-
=
count;
}
/
/
绕过下面这一行,再次执行
for
循环的内容
if
(more
=
=
0
|| _IO_OVERFLOW (f, (unsigned char)
*
s
+
+
)
=
=
EOF)
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
最后于 2023-3-24 08:53
被我超啊编辑
,原因: 错字