高版本libc FILE_IO的vtable合法性检查分析

前言

在glibc-2.24之后FILE_IO的vtable加入了合法性检查,导致原本的fsop无法使用,不过我们依然可以在合法的vtable中找到合适的gadget。

分析

这里以glibc-2.35为例。
首先我们从IO_OVERFLOW开始分析,可以看到它调用了宏JUMP1

#define _IO_OVERFLOW(FP, CH) JUMP1(__overflow, FP, CH)

在宏JUMP1又调用了_IO_JUMPS_FUNC

#define JUMP1(FUNC, THIS, X1) (_IO_JUMPS_FUNC(THIS)->FUNC)(THIS, X1)

_IO_JUMPS_FUNC中,将FILE_IO的vtable传入一个叫做IO_validate_vtable的函数,从函数名可以看出这个应该就是检查vtable合法性的函数。

#define _IO_JUMPS_FUNC(THIS) (IO_validate_vtable(*(struct _IO_jump_t **)((void *)&_IO_JUMPS_FILE_plus(THIS) + (THIS)->_vtable_offset)))

接着看IO_validate_vtable函数,可以看出最基本的检查是检查vtable是否在libc中连续的vtable范围中。如果不符合,还会调用_IO_vtable_check()函数。

static inline const struct _IO_jump_t *IO_validate_vtable(const struct _IO_jump_t *vtable) {
    /* Fast path: The vtable pointer is within the __libc_IO_vtables
       section.  */
    uintptr_t section_length = __stop___libc_IO_vtables - __start___libc_IO_vtables;
    uintptr_t ptr            = (uintptr_t)vtable;
    uintptr_t offset         = ptr - (uintptr_t)__start___libc_IO_vtables;
    if (__glibc_unlikely(offset >= section_length))
        /* The vtable pointer is not in the expected section.  Use the
           slow path, which will terminate the process if necessary.  */
        _IO_vtable_check();
    return vtable;
}

最后看_IO_vtable_check,进入该函数意味着目前的vtable不是glibc中的vtable,因此_IO_vtable_check判断程序是否使用了外部合法的vtable(重构或是动态链接库中的vtable),如果不是则报错。

void attribute_hidden _IO_vtable_check(void) {
#ifdef SHARED
    /* Honor the compatibility flag.  */
    void (*flag)(void) = atomic_load_relaxed(&IO_accept_foreign_vtables);
#    ifdef PTR_DEMANGLE
    PTR_DEMANGLE(flag);
#    endif
    if (flag == &_IO_vtable_check)
        return;

    /* In case this libc copy is in a non-default namespace, we always
       need to accept foreign vtables because there is always a
       possibility that FILE * objects are passed across the linking
       boundary.  */
    {
        Dl_info di;
        struct link_map *l;
        if (!rtld_active() ||
            (_dl_addr(_IO_vtable_check, &di, &l, NULL) != 0 && l->l_ns != LM_ID_BASE))
            return;
    }

#else /* !SHARED */
    /* We cannot perform vtable validation in the static dlopen case
       because FILE * handles might be passed back and forth across the
       boundary.  Therefore, we disable checking in this case.  */
    if (__dlopen != NULL)
        return;
#endif

    __libc_fatal("Fatal error: glibc detected an invalid stdio handle\n");
}

不过vtable范围内不只有FILE_IO的vtable,还有其他的vtable,比如libioP.h就还声明了以下几个全局vtable,可以在这几个表中找到合适的函数作为gadget加以利用。

extern const struct _IO_jump_t _IO_file_jumps;
libc_hidden_proto(_IO_file_jumps) extern const
    struct _IO_jump_t _IO_file_jumps_mmap attribute_hidden;
extern const struct _IO_jump_t _IO_file_jumps_maybe_mmap attribute_hidden;
extern const struct _IO_jump_t _IO_wfile_jumps;
libc_hidden_proto(_IO_wfile_jumps) extern const
    struct _IO_jump_t _IO_wfile_jumps_mmap attribute_hidden;
extern const struct _IO_jump_t _IO_wfile_jumps_maybe_mmap attribute_hidden;
extern const struct _IO_jump_t _IO_old_file_jumps attribute_hidden;
extern const struct _IO_jump_t _IO_streambuf_jumps;
extern const struct _IO_jump_t _IO_old_proc_jumps attribute_hidden;
extern const struct _IO_jump_t _IO_str_jumps attribute_hidden;
extern const struct _IO_jump_t _IO_wstr_jumps attribute_hidden;
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇