1.攻防世界 level3
2.buu babyrop
3.buu ciscn_2019_c_1
@TOC
1.攻防世界 level3
把文件放到kali里面发现是一个压缩包(放入exeinfo里面也可以发现是压缩包),解压缩得到level3和libc.so文件
file checksec
ida32
进入漏洞函数vunl(),发现有栈溢出漏洞
没有system函数和/bin/sh
题目提示了用libc。
libc.so是一个函数库(类似于C语言#include<iostream>的iostream库),与level3文件共享函数,也就是level3可以使用libc.so里面包装好的函数
因此我们可以栈溢出后使用libc.so中的system函数和/bin/sh来得到权限,但是ret返回的是一个地址,我们必须知道libc.so中的system函数以及/bin/sh字符串的地址才可以实现getshell
plt表与got表:主函数在调用libc.so中的函数时,有一个延迟绑定机制(由于libc.so中有很多函数,而在程序中只会调用很少一部分函数,因此只有在用到的时候才找libc中的该函数地址,这样可以节省编译时间),调用libc中函数时先让plt表(指向got表)找got表(有函数在libc中的真实地址)中的地址,但是由于延迟绑定,got表中还没有写入地址,就让plt表去找libc中的函数地址,找到后写在got表中,之后再找该函数时就可以找plt表-->got表直接找到函数在libc中的地址,就可以直接使用了
又因为在程序加载时,libc中的地址不固定,但libc中函数的相对位置固定,即地址差值是固定的,所以我们可以通过泄露got表中的某函数(已经调用过的libc中的函数在程序中的真实地址)进行差值计算,而我们可以找到libc中的函数地址,根据差值就可以得到system和/bin/sh在程序中的真实地址了
x86,32位程序调用函数所使用的参数都在栈中,栈中从高地址到低地址顺序是“调用的函数地址,返回的函数地址,调用函数的参数1,参数2,参数3.....
回到本题,在栈溢出之前调用了write()函数,并且write()可以写出我们想要的数据(puts函数,printf等函数都可以利用来泄露地址),所以可以利用write()将write_addr写出来,求出地址差值,计算出system_addr,binsh_addr,同时在用write函数泄露地址时返回到main函数,进行第二次read栈溢出,此时将重新构造的get_shell_payload,发送过去,得到权限。
脚本
1 | #!/usr/bin/env python3 |
write函数有三个参数,用法可自行百度
2.buu babyrop
file checksec
ida32
进入到sub_804871F中,发现虽然有read函数,但无法溢出
返回主函数,进入sub_80487D0
进入buf发现栈大小0xE7,0xC8无法溢出,但如果a1!=127,那么我们就可以用a1控制输入多少,回主函数看a1=v2,v2又是sub_804871F函数中的v5,点进v5发现就在buf下面,我们在输入buf时可以控制v5的大小,但在输入buf后有一个判断函数,比较buf与s如果不相等直接退出,而s被写入了a1,a1是主函数中的buf,从/dev/urandom文件中读入,random意味着是随机数,所以我们只能绕过判断。
stcncmp是对字符串进行比较,strlen作为比较的长度,strlen计算长度截止到/0,所以我们可以用\x00作为payload开头,直接绕过strncmp的比较,把v5覆盖为0xff,就可以栈溢出了,用write函数泄露read函数在程序中的地址,构造payload即可。
脚本
1 | #!/usr/bin/env python3 |
脚本中有使用LibcSearcher工具,但使用时老是找不到合适的libc文件,就直接在buu libc文件库中下载对应版本的libc文件来使用了。
输入函数名称和泄露出来的最后三位地址(原因应该是x64中段地址的改变不影响末尾的4位地址)(x86不影响末尾2位)(推测)就可以找相应的libc文件中的其他函数地址。
3.buu ciscn_2019_c_1
file checksec
ida64
进入主函数后初步判断发现只能输入1,否则程序结束
进入encrypt(“%d”, &v4);加密函数
发现有gets栈溢出漏洞,依然是泄露函数地址,这次可以使用puts函数泄露
要注意的是在x64,64位系统中rdi,rsi,rdx,rcx,r8,r9作为调用函数的前6个参数,如果参数多于6个,其余参数放入栈中
所以我们要将我们写入栈中的数据先pop进寄存器中,这也导致了64位系统题目中的payload有所区别
我们可以用ROPgadget工具查找pop对应的地址(注意参数顺序与寄存器顺序相对应)
1 | ROPgadget --binary ciscn_2019_c_1 --only 'pop|ret' |
脚本
1 | #!/usr/bin/env python3 |
对了,getshell_payload中多加了一个ret,好像是为了栈对齐,这个。。。还不太了解。反正加上就行了。。。
以上的ret2libc的原理以及思路都只是个人学习过程中的理解,可能不全面,甚至可能有错误,希望大家可以指出不当的地方。
-------------本文结束感谢您的阅读-------------