欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

pwnable中的passcode题目以及GOT表和PLT表初识

程序员文章站 2024-01-20 13:40:40
...

首先解释一下GOT表和PLT表

GOT表是全局函数表(动态函数表,全局函数偏移量表)而PLT表则是局部函数表,GOT表中具有这个程序或者进程引用的所有的数据(包括函数和全局变量),PLT表中则是局部函数的表目,PLT表与GOT表是一一对应的,即PLT表中存储的是GOT表中的相对位置,而GOT表中存储的是函数的真正地址。在程序加载的时候,动态链接器会重定位GOT表中函数得到地址,即达到动态加载的过程。

PLT表与GOT表通过延时绑定,即将过程地址的绑定推迟到第一次调用该函数的时候,为了实现延时绑定,GOT表中的三个位置是特殊的:GOT[0]包含.dynamic段的地址,.dynamic段包含了动态链接器用来绑定过程地址的信息,比如符号的位置和重定位信息;GOT[1]包含动态链接器的标识;GOT[2]包含动态链接器的延迟绑定代码的入口点。GOT的其他表目为本模块要引用的一个全局变量或函数的地址。同样PLT表中有一个位置是特殊的,PLT[0]中保存的是相当于一个函数的一串代码,他跳到动态链接库中执行。每一个数据的PLT表目中的数据是由三部分组成的:第一条指令是跳转到相应的GOT存储的地址值中.第二条指令把函数相应的ID压入栈中,第三条指令跳转到PLT[O]中调用动态链接器解析函数地址,并把函数真正地址存入相应的GOT表目中。GOT表的初始化函数地址是PLT表中的第二条指令的地址,在函数被调用一次之后,GOT表中的函数地址的值就会变为真正的函数地址的值,在下一次调用函数的时候,只会花费一条指令和一个间接的存储器引用。

下面是具体的函数第一次调用的过程

首先是跳转到相应的PLT表中,此时该PLT表中的指令为

0x000001 jmp GOT
0x000002 push id
0x000003 jmp PLT[0]

GOT表中的内容

id:
0x000002

首先是程序执行到jmp GOT  进入GOT表中之后又跳转到0x000002位置即push id处将函数的id压入栈中,接着跳转到jmp PLT[0]的位置执行相应的动态链接库中查找该函数的真实地址的操作,并且把真实地址写入到GOT表中,在下一次调用函数的时候直接就进入GOT表中的相应位置,这是跳转的地址就直接到了真是函数地址的入口处,开始执行相应的代码

 

pwnable中的passcode题目以及GOT表和PLT表初识

在执行完6之后GOT表中的id为3的函数的地址就变为函数的真实入口地址

 

再看这个题目

pwnable中的passcode题目以及GOT表和PLT表初识

 

查看源代码发现漏洞很明显,scanf函数后面没有加 &所产生的漏洞原理

pwnable中的passcode题目以及GOT表和PLT表初识

输入scanf(“%d”,&passcode)时读取的是passcode的地址0x70707070

当输入scanf(“%d”,passcode)时读取的是passcode这个地址的存储内容即0x80808080

如果我们可以控制0x80808080这个内容,那我们就可以利用这个漏洞进行GOT表的覆写

首先是检查一下有没有加壳,发现没有加壳
然后查看是32位的程序

pwnable中的passcode题目以及GOT表和PLT表初识

用gdb调试一下程序在各个函数入口处下一个断点运行

pwnable中的passcode题目以及GOT表和PLT表初识

我们写入数据存储的地方是0xffffd268   地址为edp-0x70  此时ebp的地址为

pwnable中的passcode题目以及GOT表和PLT表初识

其中红色标识的部分是启用了栈溢出保护措施,再继续向下执行

进入到login函数中,发现两者的ebp相同

pwnable中的passcode题目以及GOT表和PLT表初识

继续向下看,反编译一下login函数

pwnable中的passcode题目以及GOT表和PLT表初识

发现scanf要读取的地址就是ebp-0x10(前面的两个参数从右向左依次压栈),两者ebp地址又相同,也就是scanf要写入的地址会从输入的name变量中读取,这就给了我们控制写入地址的机会

在IDA反编译中也可以看到passcode1的地址

pwnable中的passcode题目以及GOT表和PLT表初识

 

 

两者的距离为0x60 即96个字节,最后的四个字节恰好是要写入的地址,那么我们怎么知道哪些地址可以写入呢,答案就是GOT表可以写入,我们可以将scanf后面的函数在GOT表中的真实函数地址写为我们想要执行的函数地址如(system)就可以获得相应的权限或者直接拿到flag

看到后面运行了fflush函数  puts函数  exit函数

这三个函数都可以,我们的目的是通过覆写GOT表在执行完scanf后直接执行system函数

我们看一下函数的地址

pwnable中的passcode题目以及GOT表和PLT表初识

选这三个函数都可以,因为都在login中调用,我们选择最近的fflush函数,他的地址为0x0804a004

也就是说我们输入的name字段的最后四位是这个地址

我们再来查找system函数的地址,我们的目的是获取flag,因此要执行的是验证成功之后的system('/bin/bash cat flag')而不是单纯的system函数,他是有参数的于是我们选择地址0x80485e3,参数地址0x80487af
pwnable中的passcode题目以及GOT表和PLT表初识

这样playload就出来了
由于scanf输入passcode1时是\d因此我们要先把地址转换为十进制

'a'*96 + '\x00\xa0\x04\x08'+ '\n'+'134514147\n'

连上服务器

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

成功拿到flag