栈溢出之Return2libc

参考文章:https://zhuanlan.zhihu.com/p/25816426

我们利用函数调用来实现攻击,核心目的是用攻击指令的地址来覆盖返回地址

通常用的有以下四种方法:

修改返回地址,让其指向溢出数据中的一段指令(shellcode)
修改返回地址,让其指向内存中已有的某个函数(return2libc)
修改返回地址,让其指向内存中已有的一段指令(ROP)
修改某个被调用函数的地址,让其指向另一个函数(hijack GOT)

上次我们讲解了一下shellcode,其适合于NX和PIE都不开启的情况下,但是这种情况几乎是遇不到的,所以这次我们来了解一下Return2libc

从上面的描述我们知道,要完成的任务包括:在内存中确定某个函数的地址,并用其覆盖掉返回地址

由于 libc 动态链接库中的函数被广泛使用,所以有很大概率可以在内存中找到该动态库。同时由于该库包含了一些系统级的函数(例如 system() 等),所以通常使用这些系统级函数来获得当前进程的控制权。

鉴于要执行的函数可能需要参数,比如调用 system() 函数打开 shell 的完整形式为 system(“/bin/sh”) ,所以溢出数据也要包括必要的参数。

上图即为return2libc 所用溢出数据的构造。

padding1处的数据可以随意填充(注意不要包含 “\x00” ,否则向程序传入溢出数据时会造成截断),长度应该刚好覆盖函数的基地址。其长度的确定可以通过跟shellcode一样的,在运行程序时用不断增加输入长度的方法来试探。

address of system() 是 system() 在内存中的地址,用来覆盖返回地址。该地址如何确定呢?我们可能需要了解一下动态链接库的知识:
当函数被动态链接至程序中,程序在运行时首先确定动态链接库在内存的起始地址,再加上函数在动态库中的相对偏移量,最终得到函数在内存的绝对地址。

但是如果操作系统打开了 ASLR(内存布局随机化),程序每次运行时动态库的起始地址都会变化,也就无从确定库内函数的绝对地址。在 ASLR 被关闭的前提下,我们可以通过调试工具在运行程序过程中直接查看 system() 的地址,也可以查看动态库在内存的起始地址,再在动态库内查看函数的相对偏移位置,通过计算得到函数的绝对地址。

padding2处的数据长度为4(32位机),对应调用 system() 时的返回地址。因为我们在这里只需要打开 shell 就可以,并不关心从 shell 退出之后的行为,所以 padding2 的内容可以随意填充。

address of “/bin/sh”是字符串 “/bin/sh” 在内存中的地址,作为传给 system() 的参数。

关于ROP和hijack GOT我就不当文字的搬运工了,大家看这里吧:
长亭科技牛逼!好想加入啊~加油加油加油~

猜你喜欢

转载自blog.csdn.net/qq_37414405/article/details/84928128