[原创]无路远征——GLIBC2.37后时代的IO攻击之道(三)house_of_借刀杀人
2023-2-9 16:39:15 Author: bbs.pediy.com(查看原文) 阅读量:7 收藏

[原创]无路远征——GLIBC2.37后时代的IO攻击之道(三)house_of_借刀杀人

5天前 1564

[原创]无路远征——GLIBC2.37后时代的IO攻击之道(三)house_of_借刀杀人

为了说明下一个利用链,继续水一篇。

xctf 2021 final同名题目提出了一种利用方式,是在calloc的情况下,巧妙利用连续执行malloc、memcpy、free,将提前布置在tcache中的堆块申请出来,并赋值利用。关键代码如下。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

......   

    char *old_buf = fp->_IO_buf_base;

    size_t old_blen = _IO_blen (fp);

......

    new_buf = malloc (new_size);

      if (new_buf == NULL)

        {

          /*      __ferror(fp) = 1; */

          return EOF;

        }

      if (old_buf)

        {

          memcpy (new_buf, old_buf, old_blen); //赋值函数

          free (old_buf);

          /* Make sure _IO_setb won't try to delete _IO_buf_base. */

          fp->_IO_buf_base = NULL;

        }

......

可以看出,在memcpy (new_buf, old_buf, old_blen);过程中,old_bufold_blen都是可控的。那么理论上我们将tcache指向任意地址就可以实现任意地址写,但同时面临3个问题。

  1. 任意地址写之后如何控制执行流?在house_of_pig中,使用的是控制hook,2.34以后hook取消,又要如何控制执行流。
  2. 在不控制free_hook的情况下,因为要执行free (old_buf);,必须确保fp->_IO_buf_base能够被正常free。
  3. 控制执行流时如何控制参数?

在IO中,由于要处理宽字符的原因,有很多memcpy、memmove等内存函数覆写函数,但想利用好它们却非常困难。以_IO_default_xsputn为例,

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

size_t _IO_default_xsputn (FILE *f, const void *data, size_t n)

{

  const char *s = (char *) data;

  size_t more = n;

  if (more <= 0)

    return 0;

  for (;;)

    {

      /* Space available. */

      if (f->_IO_write_ptr < f->_IO_write_end)

    {

      size_t count = f->_IO_write_end - f->_IO_write_ptr;

          // count 在计算后还需要一个判断

      if (count > more)

        count = more;

      if (count > 20)

        {

          //此处为可以覆写的位置。

          // 困难1:执行后程序流无法控制。

          // 困难2:s 和 n 均不可控         

          f->_IO_write_ptr = __mempcpy (f->_IO_write_ptr, s, count);

          s += count;

        }

      else if (count)

        {

          char *p = f->_IO_write_ptr;

          ssize_t i;

          for (i = count; --i >= 0; )

        *p++ = *s++;

          f->_IO_write_ptr = p;

        }

      more -= count;

    }

      if (more == 0 || _IO_OVERFLOW (f, (unsigned char) *s++) == EOF)

    break;

      more--;

    }

  return n - more;

}

从上面代码中可以看出此处调用的memcpyhouse_of_pig中略有不同,在__mempcpy (f->_IO_write_ptr, s, count)中,目标地址可控,源地址不可控,count虽然是计算得来,但由于有需要判断,也是不可控。也就是说我能控制写入的地址,但无法控制写入什么。与house_of_pig相比,此种手段的优势在于不需要调用malloc,就可以指定要写入的地址。当然,要利用这个手段,我们还有2个问题需要解决。

  1. 对于执行流问题,这个比较简单,因为__mempcpy 也符合house_of_秦月汉关的攻击条件,我们可以将,重新返回执行__mempcpy (f->_IO_write_ptr, s, count);,也可以执行_IO_OVERFLOW (f, (unsigned char) *s++)中的相关路径。
  2. 关于参数控制的问题,因为我们在执行FSOP时传入参数中只有FILE *f可控,所以在f->_IO_write_ptr = __mempcpy (f->_IO_write_ptr, s, count);这个代码中,s是不可控的。也就是说只能修改任意地址,但不能控制写入的值。那么我们怎么控制size_t _IO_default_xsputn (FILE *f, const void *data, size_t n)这个函数的三个参数呢?

下一篇文章将介绍如何绕过和利用。

[2023春季班]《安卓高级研修班(网课)》月薪两万班招生中~


文章来源: https://bbs.pediy.com/thread-276039.htm
如有侵权请联系:admin#unsafe.sh