©Jing0107 | Powered by LOFTER

Toddler's Bottle-passcde

GOT和PLT:

GOT表:

概念:每一个外部定义的符号在全局偏移表(Global offset Table )中有相应的条目,GOT位于ELF的数据段中,叫做GOT段。

作用:把位置无关的地址计算重定位到一个绝对地址。程序首次调用某个库函数时,运行时连接编辑器(rtld)找到相应的符号,并将它重定位到GOT之后每次调用这个函数都会将控制权直接转向那个位置,而不再调用rtld。


PLT:过程连接表,一个PLT条目对应一个GOT条目

当main函数开始,会请求plt中这个函数的对应GOT地址,如果第一次调用那么GOT会重定位到plt,并向栈中压入一个偏移,程序的执行回到_init()函数,rtld得以调用就可以定位printf的符号地址,第二次运行程序再次调用这个函数时程序跳入plt,对应的GOT入口点就是真实的函数入口地址。

动态连接器并不会把动态库函数在编译的时候就包含到ELF文件中,仅仅是在这个ELF被加载的时候,才会把那些动态函库数代码加载进来,之前系统只会在ELF文件中的GOT中保留一个调用地址.

http://www.programlife.net/linux-got-plt.html

http://blog.csdn.net/lmh12506/article/details/6801630

这里面有详细的介绍linux的got和plt

got覆写技术

原理:由于got表是可写的,把其中的函数地址覆盖为我们shellcode地址,在程序进行调用这个函数时就会执行shellcode。


实例:

http://pwnable.kr/play.php 中Toddler's Bottle的passcode


用 file 命令查看一下,可以看到是一个32位的 ELF 可执行文件,拖到 Ubuntu 中进行调试。

ssh passcode@pwnable.kr -p2222 (pw:guest)



从程序中可以看到scanf()函数中第二个参数没有加&符,传递的是值而不是地址,可以产生内存写入漏洞,可以利用got表覆写技术


简单运行发现程序需要我们输入:用户名name、password1、password2


查看程序的保护方式(DEP、 GS)



IDA先进行静态分析:


welcome函数:



login函数:



输入的用户名 name 位于 ebp-0x70,password1 位于 ebp-0x10,password2 位于 ebp-0xc

本来我觉得这么说是不对的,我开始理解的是这是两个子函数中的参数,其位置不应该这样表示,然后用gdb调试了一下看看,两个函数中ebp的地址是一样的都是0xbffff308,


welcome函数



login函数:



数据并没有写入passcode1,passcode2,写入passcode1和passcode2的内容是没有初始化所存储的内容,即name,gdb调试发现welcome函数中的name变量最后4字节刚好可以覆盖到passcode1,即可以通过控制最后四个字节进行构造地址,如果可以直接改写EIP就可以直接跳到system(“/bin/cat flag”);但是EIP是不可以直接控制的,所以这里就用到了GOT表。

修改GOT表,直接把下一个要执行的函数地址改成输出flag的代码的起始地址。


用查看got表命令查看一下:

IDA查看system

我们通过更改 printf() 函数的 GOT 来让我们输入完 password1 后的 printf() 函数调用流程转到 system("/bin/cat flag"); 处。

printf 地址: 0804a0000

system地址:080485E3

name 与 password1 相差 (0x70-0x10)96 bytes


所以构造payload

Congratulations!enter passcode1 : Now I can safely trust you that you have credential :)


参考:http://drops.wooyun.org/binary/6521




标签:pwn
热度: 1
评论
热度(1)

一天一天 在这里留下成长的脚印。。。