티스토리 뷰

Pwnable/CTF

0CTF 2015 [FlagGenerator]

err0rless313 2015. 4. 16. 01:27


0CTF 2015 Flagen [250pts]
https://github.com/ctfs/write-ups-2015/tree/master/0ctf-2015/exploit/flaggenerator

0CTF 2015 Quals CTF: FlagGenerator
Category: Exploit 
Points: 250 
Solves: 49 

Description:
Can you generate the correct flag?
flagen
libc.so.6
202.112.26.106:5149
202.112.28.115:5149
Notice: Ubuntu 14.04.2 LTS


DOWNLOAD

flagen


===================================================================================



checksec으로 보호기법을 확인해보면 NX + Canary를 찾을 수 있다.

물론 socket + fork로 돌아가는 환경이 아니기 때문에 ASLR도 유효하다.




간단하게 분석을 해보면 우리가 문자열을 입력하면 flag같이 생긴(?) 문자열로 만들어 준다.


1. Input Flag:

말 그대로 문자열을 입력해준다. userFlag를 malloc으로 256만큼 할당해서 

uRead함수로 값을 받는다.


2, 3번은 생략


4. Leetify:

뜻이 따로 있는줄 알고 보니 없음..

우리가 입력한 문자열을 진짜 flag같이 만들어 준다.

예를 들어 A -> 4, O -> 0 과 같이 우리가 흔히 볼 수 있는

알파벳을 숫자로 바꿔서 표기하는 표기법을 직접 제공한다.


5. Add Prefix:

단순하게 "0ctf{" + userFlag + "}" 와 같이 만들어 준다고 보면 된다.




Vuln


4. Leetify는 위에서 설명했듯 어떤 문자를 숫자(char형)으로 바꿔주는 역할을 한다.

그런데 여기서 h 혹은 H를 정말 H같이 생긴 "1-1"로 바꿔주는데 중요한건 H를 모두 

"1-1"로 바꿔주기 때문에 1바이트가 3바이트가 되는 현상을 볼 수 있다.


여기서 Overflow가 일어난다.



userFlag[x]   = "1"

userFlag[x+1] = "-"

userFlag[x+2] = "1"

와 같은 알고리즘을 사용했다고 보면 된다.

물론 덮어씌어지지 않게 pSrc가 v5 + 2를 가르키게 한다.



하지만 여기서 세그멘테이션 오류가 난다.

원래 정상적이라면 stack_chk_fail()함수가 실행 돼야 하지만 단순히 세그폴트가 떳다.

트레이싱을 해보자



gdb로 디버깅을 해보면 저 부분은 strcpy부분인 것을 알 수 있다.



물론 Leetify함수 마지막 부분에 있는 strcpy에서 나는 것이다.

그런데 이 부분에서 세그폴트가 뜨는 것은 &src가 아니라 aFlag부분이 변조 돼서 일어나는 오류다.



Leetify는 인자로 aFlag를 받아서 문자열을 바꿔준 후 strcpy로 aFlag에 다시 넣어준다.

여기서 세그폴트가 뜨는 것이고 이 부분에서 알 수 있는 것은 우리가 argv[1]을 변조할 수 있으며

변조한 주소에 &src를 복사 할 수 있다는 것이다.




PWNING



다른 문제를 풀 때 풀이에서 본 stack_chk_fail() 함수를 덮어쓰는 방법을 선택했다.

쉬울줄 알았지만 트레이싱과 디버깅이 굉장히 많이 필요했던 문제였다.


일단 stack_chk_fail을 printf나 다른 함수로 바꿔준다.

그러면 카나리를 우회할 수 있다. 그 후에는 ROP를 해 주면 된다.


주의해야 할 점은 stack_chk_fail을 printf@plt로 바꿔주면

그 후 printf를 사용하지 못한다는 것이다. 이건 상황마다 다른것 같기도 한데

나는 디버깅을 할 때 printf@plt가 완전히 다른 값으로 바뀌어 진 것을 확인해서

LIBC주소를 LEAK할 때 puts함수를 사용하였다. 이 부분에서 많이 해메었다.. 디버깅을 열심히 합시다.

-> stack_chk_fail@got를 printf@plt만 들어가는 것이 아니라 뒤에 있는 문자열까지 들어가서

   뒤에 있는 got함수들을 사용하지 못하는 거였습니다!


또한 read함수를 사용하여 system@libc의 인자가 될 문자열을 받으려 했으나

0x00이 들어가면 그 부분이 완전히 들어가지 않는 현상이 일어나서 uRead함수를 사용하였다.




read함수는 FD가 무조건 0x00이 돼야 하지만 uREAD는 BUf와 SIZE만 정해주면 되기 때문에 사용할 수 있다.


트레이싱을 해보면 printf@plt로 덮어쓴 stack_chk_fail()함수가 처음 실행 된 후

그 다음 실행되는 함수는 stack_chk_fail()함수가 위치하는 바로 전 4바이트 이다.


[*] 왜 그런지는 모르겠다.. 디버깅을 더 해봐야겠다.


주의해야 할 점이 너무 많지만 그 점만 감안하면 ROP자체는 매우 쉬운 편이다.

LIBC를 LEAK하고 SYSTEM함수의 주소를 구한 후 read로 받은 인자와 함께 실행시켜 주기만 하면 

Exploit에 성공 할 수 있다.







좀 어렵게 푼 감이 있다. 확실히 트레이싱과 디버깅이 중요하다는 것을 깨달았다.

공부가 많이 부족한 거 같다.. 조금 더 열심히 하도록 하자


조금 어려운 문제들은 대부분 ret를 직접 바꾸는 것이 없는 것 같다. 또한 기본적인 ROP를 방해하는

요소들도 곳곳에 숨어 있다. 조금 더 꼼꼼한 분석과 디버깅을 하자



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

CampCTF 2015 hacker_level exponly  (1) 2015.08.25
Inc0gnito 2015 anti-hexray exponly  (0) 2015.08.25
Plaid CTF 2014 [Kappa]  (2) 2015.04.06
CODEGATE 2015 JUNIOR [ SYSTEMSHOCK ]  (0) 2015.03.28
CODEGATE 2015 JUNIOR 예선 WRITE UP  (0) 2015.03.16
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2025/02   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28
글 보관함