본문 바로가기
# write-up/- ctf

[Plaid CTF 2017] no_mo_flo

by ddddh 2017. 4. 27.

[Plaid CTF 2017] - no_mo_flo.


no_mo_flo


Plaid CTF 2017 에서 처음 나온 리버싱 문제다.

바이너리를 다운받고 file 명령어로 확인해 보면 64bit - elf 파일인 걸 확인할 수 있다.



ddddh@ubuntu:~/Desktop$ file no_mo_flo 

no_mo_flo: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=b9de9235c1a8c49096daba03ce36e334cf150c1c, stripped


실행 권한을 주고 직접 실행을 해 보면 입력을 기다린다.

우선은 아무 값이나 넣어보고 결과를 지켜본다.


ddddh@ubuntu:~/Desktop$ ./no_mo_flo 

ddddh_test     --------> 입력 값 

Short input     --------> 반환 값


입력 길이가 짧다는 문구를 띄우고 종료된다.


이제 리버서의 필수 툴이자 없어서는 안될 만능 IDA를 켜고 분석해 본다.



킹갓툴 IDA 답게 "no_mo_flo" 뚝배기를 으깨버렸다. 바로 main 함수를 보기 좋게 디스어셈 해주었다.

read함수를 사용해 input_ 변수에 32바이트를 입력받고 반환 값으로 32 bytes 인지 확인한다. ( read() 의 반환 값은 입력받은 bytes 수 )


즉, 32 bytes를 입력받지 못하면 "Shor input\n"이 출력되는 것이다.



띠0000용

0xf 만큼 반복문을 돌면서 값을 하나씩 넣고 있는게 보인다.

반복문이 끝나면 중요해 보이는 3개의 함수 호출이 보이고 2, 3번째 함수의 반환 값을 비교해 성공/실패 여부를 판단한다.


위를 python 코드로 바꿔주면 아마도(?) 다음과 같다 

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
import sys 
 
input_ = raw_input()[:32]
len_ = len(input_)
 
if len_ != 32:
    print "Short input"
    sys.exit(-1)
 
arr1 = []
arr2 = [] 
for x in range(0xf):
    arr1.append(input_[2*x])
    arr2.append(input_[2*x+1])
 
call1()
= call2(arr1)
= call3(arr2)
 
if (a & b) != 0:
    print "Good flow!!"
else
    print "You aint goin with the flow...."
 
sys.exit(0)
cs



c


call1 을 보면 sigemptyset(), sigaction() 시그널 셋 함수를 사용하여 sub_402b06 함수를 예외 처리로 등록해주는 것 같다. (확신x)


그리고 빠져나와 call2를 보면 굉장히 어마어마하다.




ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ......


그래프를 처음보고 엄청 더럽다고 생각했었다..


마음을 가다듬고 분석을 하니 다음과 같은 결론을 얻었다.



1. 에서 arr1 값을 하나씩 비교하고 결과에 따라 2. 에서 반환 값이 0으로 세팅되거나 1로 유지된다.

"Good Flow!!!"문자열을 띄우기 위해서는 반환 값이 1로 유지되어야 되기 때문에 1. 을 보고 값을 뽑아내면 다음과 같다.




그럼 이제 call3만 분석하면 끝이난다.




call3() 들어오자마자 값을 비교하는게 보인다.

그리고 밑에서 0을 나누는 순간에 이셉션을 일으키며 시그널 set으로 설정한 sub_402b06 함수를 실행해주며 다음 문자 비교로 넘어가게 된다.

(그래프 모드를 풀고 밑으로 쭉 내리면 비교 값을 다 찾을 수 있음)


call2, call3 에서 얻은 결과를 합치면 flag가 된다.


"PCTF{n0_fl0?_m0_like_ah_h3ll_n0}"


ddddh@ubuntu:~/Desktop$ ./no_mo_flo 

PCTF{n0_fl0?_m0_like_ah_h3ll_n0}

Good flow!!



'# write-up > - ctf' 카테고리의 다른 글

[DEFCON 2017] sorcery  (0) 2017.05.02
[DEFCON 2017] alchemy  (0) 2017.05.02
[ALEX CTF] RE5: packed movement  (0) 2017.02.07
[RC3 2016] 메모리 포렌식 - 500pt  (0) 2016.11.27
[RC3 2016] - Reversing 200pt  (0) 2016.11.21