这是从原来的博客搬过来的,之前刚开始接触pwn学的,现在已经转战web,留作纪念。一下题目均来自攻防世界pwn新手区
level2:
连接题目,发现一个输入口
检查保护措施
打开ida,观察主函数,主函数很简单,调用vulnerable_function后输出Hello,World
进入函数vulnerable_function,buf最大字节长度0x88,比0x100小,存在溢出
观察函数列表,没有发现可以执行shellcode的函数
根据题目信息,需要用到ROP,猜测需要构建函数栈帧。缺少变量,shift+F12查看一下字符串,发现了我们需要的东西
思路:将buf溢出,覆盖read函数的返回地址为_system函数。然后用/bin/sh构建一个栈帧,执行shellcode
_system = 0x08048320
shell = 0x0804A024
payload:’a’*0x88 + p32(1) + p32(_system) + p32(1) + p32(shell) + P32(1)
exp:
1 | from pwn import* |
when_did_you_born:
链接题目,输入口有2个,分别输入出生日期和姓名
查看防御措施,存在Canary,无法构造栈帧
进入ida查看主函数,发现意图明显。第一次输入的Birth不能为1926,当变量V5为1926的时候输出flag。那么推测第二次输入姓名存在溢出,将V5变量覆盖为1926,输出flag
验证猜想正确var_20对应V4变量,var18对应V5变量
构造payload:’A’*8 + p32(1926)
exp:
1 | from pwn import* |
get flag!
Level3
链接题目,看一下大致内容
将level3用ida打开查看,进入主函数,内容非常简单
进而进入vulnerable_function查看,发现read函数存在溢出点
观察函数列表,未发现system函数,打开字符串查找未发现/bin/sh字样字符串。题目压缩包附带了一个libc文件,考虑到本题用到ret2libc分析。从libc中载入system函数和/bin/sh字符串,从而达到获取权限目的。
使用ida打开附件libc_32.so.6
搜索到system函数,函数地址为0x3A940
通过命令 strings -a -t x libc | grep “/bin/sh” 查找到/bin/sh在libc中的偏移为15902b
现在我们只需要知道libc的地址,从而计算出system和/bin/sh的地址即可,要想得到libc地址,则需要通过得到write函数的真实地址,用write函数的真实地址减去write函数在libc中的地址便可得到libc的地址。
如何得到write函数的真实地址?用ida打开level3我们发现,write函数的地址属于plt部分,这个并不是write函数的真实地址
而我们知道,动态链接库加载函数的时候,如果是第一次加载这个函数,便会通过plt表中对应位置的代码调用连接器来解析write函数在外部的地址,并且将这个真实地址(write函数的)返回填写到write_got.plt中。而我们需要做的就是通过溢出,首先执行plt中对应的关于write函数的代码,这个时候就会调用连接器查找write函数,并且把write函数真实地址已经存放进了got.plt这个表对应write函数的位置中了。当这个过程结束后,我们再次返回到vulnerable_function这个函数中,再次调用write函数,将参数传入write函数使他输出write函数的真实地址(在got.plt表中对应的位置)这样便获得了write函数的真实地址。
通过ida查找,可以发现:
write_plt = 0x08048340 write函数plt地址
write_got.plt = 0x0804A018 write函数got.plt地址
vulnerable_function = 0x0804844B write函数父函数地址
第一次溢出payload:
payload = ‘A’*0x88 + p32(1) + p32(write_plt) + p32( vulnerable_function) + p32(1) + p32(write_got.plt) + p32(0x4)
‘A’*0X88:填充字符串buf
P32(1):劫持EIP
P32(write_plt):函数返回到此处调用连接器,将write函数真实地址覆盖到got.plt表中
p32( vulnerable_function):函数返回write函数父函数
p32(1) 传入参数1
p32(write_got.plt)传入参数2
p32(0x4)传入参数3
接下来获取write函数的真实地址
write_got_addr = u32(sh.recv())
计算出libc地址:libc_addr = write_got_addr – libc.symbols[‘write’]
计算出system真实地址:sys_addr = libc_addr + libc.symbols[‘system’]
计算bin字符串真实地址:bin_sh_addr = libc_addr + 0x15902b
第二次payload:payload2 = ‘A’*0x88 + p32(1) + p32(sys_addr) + p32(1) + p32(bin_sh_addr) 简单的溢出,劫持eip,覆盖返回地址,返回地址,传参
完整exp:
1 | from pwn import * |
本题感谢N0p3的大力支持!!!!
CGfsb
老规矩,连接题目,实现类似于留言板的小程序
查看保护措施存在栈溢出保护,DEP保护
ida查看,可以发现,将pwnme变量赋值为8即可获得flag。pwnme上面的一行代码引起了我们的主意。程序直接将printf函数的参数控制权限交给了我们,也就是说这里存在格式化字符串漏洞。我们需要利用这一漏洞将pwnme变为8
想要修改pwnme的值首先就要知道pwnme的地址以及他在栈中的偏移,简单的测试一下。我通过print函数输入了字符串“bbbb-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x”它有什么用?首先,根据printf函数的特性,bbbb被入栈用于输出,而后面的%x由于没有对应的数据输出,那么将会输出栈中每个字节的数据。我们根据输出结果不难发现,首先输出的是bbbb,这是正常printf函数该做的事情,然后连续输出栈中数据,直到我们发现了62626262,这是我们输出的数据bbbb的十六进制。那么数一下就不难发现,我们向printf函数中输入的字符串是存储在栈中第10个字节处,那么我们就可以将pwnme变量的地址保存在第十个字节处,在利用%n写入数据8达到修改pwnme数据的目的。
ida查找到pwnme变量的地址为0x0804A068
pwnme_addr = 0x0804A068
payload:p32(pwnme_addr) + ‘a’*4 + ‘%10$n’
p32(pwnme_addr)首先保存在栈中偏移10个字节的地方,然后用4个a补充4个字节,那么p32(pwnme_addr) + a*4便拥有8个字节 %10$n的意思就是将他前面字符串的字节个数赋值到第10位的地方也就是pwnme地址所在的位置。那么这样pwnme便完成了数字8的赋值。
完整exp:
1 | from pwn import* |
get flag!