Write-up

[RITSEC 2018] Gimme sum fud write up

ch4rli3kop 2018. 11. 22. 11:38
반응형
해당 바이너리를 보면 go 언어로 작성된 64-bit elf 파일임을 알 수 있다. go 언어는 main 함수가 컴파일 시 main_main으로 변하므로 그 부분을 보면 다음과 같다.


go 언어라 좀 복잡하지만, 중점적으로 봐야 할 루틴은 다음 네 가지정도로 정리할 수 있겠다.
main.main -> io/ioutil.ReadFile
main.main -> main.main.func1 -> main._Cfunc_CBytes
main.main -> main.Cfunc_myGets -> runtime.cgocall -> main._cgo_22ceff77f670_Cfunc_myGets -> read
main.main -> main.Cfunc_myPrint -> runtime.cgocall -> main._cgo_22ceff77f670_Cfunc_myPrint -> printf


첫 번째 루틴과 두 번째 루틴은 간단하게 요약하면 바이너리와 같은 디렉토리에 존재하는 flag.txt 파일을 읽어 해당 데이터를 heap에 저장한다.

io/ioutil.ReadFile을 자세히 보면, syscall을 통해 flag 파일을 읽어들이는 것을 확인할 수 있다.

heap영역에 flag를 저장하는 main._Cfunc_CBytes 함수는 다음과 같다. malloc을 통해 공간을 새로 할당받은 뒤, runtime_memmove를 통해 앞서 읽어왔던 flag를 해당 공간에 저장한다.


다음과 같이 chunk가 새로 생성되고 flag가 저장된 것을 확인할 수 있다.




다음은 입력루틴이다. 
main.main -> main.Cfunc_myGets -> runtime.cgocall -> main._cgo_22ceff77f670_Cfunc_myGets -> read

먼저, 사용자의 입력을 받을 곳은 아래의 코드에서 runtime.cgocall을 부르기 직전, rax에 들어있는 포인터의 값에 저장되어 있다.(*RAX  0xc42005bf20 —▸ 0x563400 ◂— 0x0) 해당 포인터를 스택에 저장하면서 이 후의 루틴에서 해당 포인터를 사용한다. 


이 후에 사용자의 입력을 받는 루틴이 동작하게 되는데, 여기서 read 함수로 0x1337만큼 입력을 받게되어 overflow 취약점이 발생한다.



해당 입력이 들어가는 곳은 heap 영역에서 플래그가 저장된 chunk로 부터 0x90만큼 앞 쪽이다.



마지막 루틴인 출력 루틴에서는 다음과 같이 사용자의 입력을 출력하기 때문에, flag까지 입력을 주어 사용자의 입력과 flag 사이에 null을 없애면, flag 까지 출력된다. 해당 취약점을 통해 flag를 얻을 수 있다.
int __fastcall cgo_22ceff77f670_Cfunc_myPrint(_QWORD *a1)
{
  return printf("%s", *a1);
}



Leak
from pwn import *


r = process('./pwn3')
#r = remote('fun.ritsec.club',1338)

r.recvuntil("Gimme some bytes, I'm hangry...")
pause()
r.sendline("A"*0x10*9)
r.interactive()



반응형

'Write-up' 카테고리의 다른 글

[pwnable.tw] start  (0) 2019.01.07
[X-MAS CTF 2018] writeup  (0) 2018.12.29
[RITSEC 2018] write up  (0) 2018.11.19
[InCTF 2018] Lost writeup  (0) 2018.11.06
[InCTF 2018] Yawn writeup  (0) 2018.10.30