首页
社区
课程
招聘
看雪CTF-ReeHY-main
发表于: 2017-6-8 20:36 7857

看雪CTF-ReeHY-main

BPG 活跃值
2
2017-6-8 20:36
7857

这题也是一般堆溢出的流程,主要有下面几个操作
1.创建
 

这一段代码比较多,但可以看到问题还是存在的,size和cun都是可以通过输入负数,接着通过强类型转换`unsigned int`来转换成很大的整数来整形溢出。

2.删除

可以看到这里也是存在问题的,删除之前没有判断块是否被删除了,所以应该可以构造`double-free`

3.编辑

这里就是正常的编辑,不过验证了块是否存在。

二、DOUBLE-FREE
一年前做过一道`double-free`之后就再也没碰过了,这里正好把相关知识点再温习一下。
堆结构如下,其中0,1,2,3表示一个单位长度。

正常`unlink`的函数主要代码如下:

如果能覆盖一个块的头部来达到控制其`bk`和`fd`的话,就能够成功修改任意地址的值了,但由于存在判断`FD->bk != P || BK->fd != P`,所以没法随便修改,这时就需要利用`double-free`了。
首先判断是需要通过的,所以可以有下面两个等
FD->bk = P   <=> FD+3 = P
BK->fd = P   <=> BK+2 =
接着就是构造一个堆头满足这两个等式了
pre_size     0
size         chunk_size + 1 //这两个条件表示堆仍在使用中
fd           p_addr - 3
bk           p_addr - 2

那么就能得到绕过判断后能实现的效果
FD->bk = BK => P = BK = P - 2
BK->fd = FD => P = FD = P - 3

所以最后实现的效果是`P=P-3`。

接着就是实现`double-free`的流程了,稍微盗一下图...
1.新建两个chunk分别为chunk0和chunk1

2.free掉这两个块,第一块作为稍后unlink的块,另一块作为free的块

3.新建一个块,这个块要能覆盖到chunk1的头部,从而伪造两个chunk的头,chunk0的头部之前已经说过了,而chunk1需要欺骗操作系统chunk0是已经被free了的,所以其头部应该如下
pre_size     chunk0_size
size         chunk1_size
然后整体实现如下:

4.那么新建这个块就相当于是两个块了,然后我们free chunk1,就能实现unlink chunk0从而使得chunk0的地址存放的值变成了P-0x18
5.接下来修改chunk0的值,修改的值为0x18个padding,然后就能修改chunk0的地址的值了,这时修改成free的GOT表地址
6.接下来再修改一次chunk0, 这次的值修改成system那么就会使得free的GOT表指向system,接下来free的时候传入/bin/sh就能获取shell了

三、 EXP
在调试EXP过程中出现了这样俩个问题,需要注意一下。
第一个是这里的P指的是指向堆地址的指针,也就是`0x6020e0`,不要误以为是堆的地址哦。
第二个在这里我是把`/bin/sh`写在第0个堆,而用2,3来进行`double-free`,主要原因是由于在调试的过程中发现把`/bin/sh`写后面会被系统发现`double-free`。
具体EXP:


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 1
支持
分享
最新回复 (7)
雪    币: 10914
活跃值: (3288)
能力值: (RANK:520 )
在线值:
发帖
回帖
粉丝
2

题目结束后 会移动到公开版

2017-6-8 21:07
0
雪    币: 822
活跃值: (290)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
咨询一下,第67和68行为什么要对2进行两次编辑呢?  我试着改成一行Edit(2,p64(puts_plt)+'1'*0x10  +  p64(free_got)  +  p64(1)  +  p64(atoi_got)+  "\n"),会报错
还有第71行atoi_addr  =  u64(p.recv(8))  &  0xffffffffffff  这里为什么要和12个f作与运算呢? 
多谢
2018-1-21 16:16
0
雪    币: 639
活跃值: (70)
能力值: ( LV12,RANK:219 )
在线值:
发帖
回帖
粉丝
4
lishua 咨询一下,第67和68行为什么要对2进行两次编辑呢? 我试着改成一行Edit(2,p64(puts_plt)+'1'*0x10 + p64(free_got) + p64(1) + p64(atoi_ ...
第一个问题  第一次修改是因为需要绕过unlink的判断  于是将指针指向p-0x18  第二次修改就能够任意地址写了
第二个好像是调试的时候发现这样获取的地址才是正确的,于是就这样写了
2018-2-1 17:12
0
雪    币: 822
活跃值: (290)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5

嗯,多谢 我再学习一下

2018-2-2 17:56
0
雪    币: 822
活跃值: (290)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6

回去想了一下,实在是想不通

我写了一个小程序,为了测试自己的想法

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

#include <string.h>
long int a[1];//保存待删除的指针的全局变量
long int d;//只是为了gcc编译时不报warning,d就是a[0]的地址
//下面就是unlink宏
#define unlink(P,BK,FD){\
/*FD = P->fd;\
BK = P->bk;\ */\
d=(long int)a;\
FD=(struct s*)(d-0x18);\
BK=(struct s*)(d-0x10);\
    if (__builtin_expect (FD->bk != P || BK->fd != P, 0))\
      printf ("corrupted double-linked list\n");\
    else {\
        FD->bk = BK;\
/**d=d-0x18;即a[0]=a-0x18 */\
        BK->fd = FD;\
}\
}

struct s
{
  long int b;
  long int c;
  struct s *fd;
  struct s *bk;
};
main ()
{
  struct s *FD;
  struct s *BK;
  struct s *p1 = malloc (sizeof (struct s));
  p1->b = 1;
  struct s *p2 = malloc (sizeof (struct s));
  p2->b = 2;
  struct s *p3 = malloc (sizeof (struct s));
  p3->b = 3;
  a[0] = (long int)p3;
  struct s *p4 = malloc (sizeof (struct s));
  p4->b = 4;
  struct s *p5 = malloc (sizeof (struct s));
  p5->b = 5;
  p1->fd = p2;
  p2->fd = p3;
  p3->fd = p4;
  p4->fd = p5;
  p5->bk = p4;
  p4->bk = p3;
  p3->bk = p2;
  p2->bk = p1;
  struct s *p;
  p = p1;
  while (p != NULL)
    {
      printf ("%d->", p->b);
      p = p->fd;
    }
  printf ("\n");
//输出unlink前全局变量的值
printf("[1]:%x\n",a[0]);
  unlink (p3, FD, BK);
//输出unlink后全局变量的值
printf("[2]:%x\n",a[0]);
printf("[3]:%x\n",p3);
//既然unlink执行后,*d=d-0x18,即*a=a-0x18,我们是不是就可以更改p3的值,从而更改a[0]的值? 此处是比划exp写的,其实并不理解
char m[]="AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHH";
memcpy(p3,m,32);
printf("[4]:%x\n",a[0]);
  p = p1;
  while (p != NULL)
    {
      printf ("%d->", p->b);
      p = p->fd;
    }
  free (p1);
  free (p2);
  free (p3);
  free (p4);
  free (p5);
}
运行结果如下:
[admin@bogon 4-ReeHY-main]$ ./3
1->2->3->4->5->
[1]:2210070
[2]:601058
[3]:2210070
[4]:601058
Segmentation fault (core dumped)
说明unlink后,a[0]的值确实变化了,但是我把p3的内容修改了,并没有覆盖到a[0],这是为什么呢?

2018-2-6 10:02
0
雪    币: 822
活跃值: (290)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
哎,脑子不太好用,我死记住了
2018-3-15 16:05
0
雪    币: 223
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
8
    free_got = elf.got['free']
    atoi_got = elf.got['atoi']
    puts_plt = elf.plt['puts']
您好,我想请问下,什么时候用plt地址什么时候用got地址呢?
2019-12-17 10:24
0
游客
登录 | 注册 方可回帖
返回
//