OutDoorFrog의 리버싱 이야기
defcon crackme 2000 sorcery 본문
아는 지인분께 반드시 풀어보는 것이 좋다고 추천 받은 좋은 문제가 있습니다.
defcon-crackme 2000 시리즈에 속한 문제들입니다.
실로 문제 난이도가 어렵더군요;;;
이 바이너리를 어디서 다운 받을 수 있을까요..
sinfocol 님의 깃허브 에서 다운받을 수 있습니다.
제가 풀어볼 문제는 sorcery라는 문제입니다.
바이너리 구성
일단 샘플 상에 20여개의 바이너리가 존재합니다. (아래의 하나는 제가 ida로 분석한 거.. ㅎㅎ)
(근데 이거 라이트업 보니까 바이너리가 200개 존재하던데 왜 샘플에는 20개지)
아마 easy crack101 류의 풀이 형태가 비슷할 것 같습니다.
문제 분석
일단 바이너리 하나만 콕 찝어서 분석해봅시다 ㅎㅎ.
저는 0a4를 접두사로 가지고 있는 바이너리를 분석해보겠습니다.
분석의 시작은 실행부터 해야 제맛이죠.
"enter code:" 라고 떠서 고백을 했더니 차였습니다. (엉엉)
여기에서 우리는 중요한 몇 가지 사실을 알 수가 있습니다!
1. 이 바이너리에는 "enter code:"를 출력해주는 함수가 존재한다.
2. 이 바이너리에는 입력을 받는 함수가 존재한다.
3. 이 바이너리의 이름은 왜이리 길게 만들어졌을꼬??
(3번은 딱히 중요하지 않을 수도..?)
IDA로 열어봅시다!
base address가 없을 때 나오는 증상입니다.
저는 이런 base address가 없는 문제들을 angr로 풀 수 없는 문제라고 생각하고 있습니다.
문제가 쉽게 풀려주진 않을 것 같네요.
main 함수
음.. 그래프 개형만 보여드리겠습니다.
그래프의 개형이 복잡하고 문자열을 출력, 입력하는 함수가 보이진 않습니다.
우리가 분석을 시작해야되는 부분은 "enter code:"가 출력되는 부분이니까..
문자열 검색을 시도해보겠습니다.
문자열 검색에서도 "enter code:"가 안뜨는군요 ㅋㅋㅋㅋ
한 번 우리가 얻었던 정보를 돌이켜봅시다.
문자열을 출력해주는 함수와 입력해주는 함수를 이 바이너리에서는 반드시 사용을 할 것입니다.
그리고 "enter code:"라는 문자열을 찾아낼 수 없습니다.
즉 문자열 출력해주는 함수를 이용하여 찾는 방법은 우리가 분석을 시작해야할 부분을 찾는 데
관련이 없을 가능성이 크다고 판단할 수 있습니다.
그렇다면 입력하는 함수를 따로 찾아봐서 검색해봅시다.
_read, read 함수를 발견할 수 있었습니다.
_read 함수를 어느 주소에서 호출하는지 살펴봅시다.
sub_A6A0+28로 한 번 가봅시다.
read 함수를 호출하는 것을 확인할 수 있고, 또 어떤 함수에게서 호출당하네요. 추적해봅시다.
sub_30FC
main 함수에서 호출당하는 함수네요. 이제 조금 분석해야할 부분이 보이기 시작하는군요.
리버싱의 흐름
대부분 리버싱 문제의 흐름은 항상 이렇게 진행됩니다.
출력 -> 입력 -> 연산 -> 판단 -> 출력
여기에서는 입력하라고 출력하고, 입력받고, 플래그가 맞는지 판단하고
플래그가 맞다면 맞다고 출력하겠네요.
(저는 주로 연산은 주로 값을 한 번 더 꼬거나, 안티 리버싱 첨가된 부분을 연산이라고 칭합니다.
아직은 연산 부분이 있는지 없는지 알 수는 없습니다.)
입력하는 부분은 찾아냈으니 판단해주는 부분을 찾으면 되겠네요?
sub_30FC에서 sub_a6a0을 출력하는 부분부터 분석해봅시다.
sub_a6a0이라는 함수를 ReadCaller라는 함수로 리네임시켜줬습니다.
디컴파일 시켜서 한 번 슈도 코드를 확인해봅시다.
좋습니다. 판단이라고 생각해볼수 있는 부분을 찾아봅시다.
글자를 하나씩 받아서 플래그 인지 아닌지 확인하는 부분이라고 의심해볼만한 코드네요..
(딱 판단 부분이라고 포스가 흐르고 있습니다.)
dec -> hex로 한 후 그대로 hxd에 써넣어 보겠습니다.
뭔가 플래그 같은 느낌이 듭니다. 한 번 입력해봅시다.
오오오 다른 반응이 나오는군요?
다른 바이너리도 확인해봅시다.
0c5..로 시작하는 바이너리를 위와 같은 방법으로 리버싱하여 코드를 넣어봤습니다.
좋습니다. 어떻게 답을 구해야될지도 알겠다.. 우리에게 남은 문제가 있습니다.
어떻게 이 작업을 자동화 시킬까?
솔직히 바이너리 20개 정도야 금방 해낼 것 같습니다.
처음 분석하는데 시간이 오래 걸릴 뿐, 구하는 방법만 알아내면 그만큼 속도가 가속되니까요.
하지만 바이너리가 100, 200개라면? 혹은 그 이상의 바이너리를 조사해야될 경우라면?
참 난해해집니다. 30분 만에 끝낼 수 있는 걸 더 시간이 낭비되겠죠?
그래서 빠르게 답을 구해내려면 어떻게 이 작업을 자동화시킬지에 대해서 고민해봐야합니다.
일단 아래 사진을 보겠습니다.
저 사진은 한 글자식 비교하는 어셈블리 구문을 찍은 것입니다.
cmp cl, ?? 로 한글자씩 비교하는 구문이 일치합니다.
한 번 저런 형식의 명령어만 뽑도록 만들어봅시다.
objdump -d -M intel ./sorcery_dist/[파일이름] | grep 'cmp .cl'
이러면 cmp .cl, ?? 형태의 명령어만 뽑아줍니다.
하지만 안타깝께도 플래그를 전부 긁어내지 않더군요..
(왜냐하면 cmp al,?? 형식의 구문이 있는 것들도 몇몇 있으니까요)
이런형식의 명령어를 써볼까요?
objdump -d -M intel ./sorcery_dist/[파일이름] | grep 'cmp .l'
숫자를 파싱할 수 있게되었으니까.... 필요없는 정보들을 덜어내야겠죠?
특징을 살펴보니 플래그는 printable하고 플래그가 아닌 것들은 대부분 printable하지 않습니다.
그렇다면 printable 한것들만 흘려내고 printable하지 않은 것들부터는 싹 걸러내면 되겠네요.
python으로 코드를 한 번 만들어내봅시다.
실행시켜주시면 이런 결과가 뜹니다.
빡시네요. ㅎㅎ
ls 명령어 이용해서 파일 이름 긁으셔서 fileList 만들면 됩니당.
리다이렉션 이름은 왜 다르게 해줬냐면 cat a > a 이런식으로 리다이렉션하면 결과가 비더라구요;;
이상 소서리 풀이였습니다.
'공부 > CTF 문제 풀이' 카테고리의 다른 글
defcon crackme 2000 alchemy (불완전한 풀이) (1) | 2019.01.24 |
---|---|
LogCon 참여 후기 (0) | 2019.01.21 |
Welcome to Android를 통해 안드로이드 리버싱에 적응해보자. (0) | 2019.01.18 |
게싱 능력 상승 위해 easy_serial을 풀어보자. (2) | 2019.01.12 |
z3에 적응하기 위해 RedVelvet을 풀어보자. (0) | 2019.01.10 |