HackCTF/Reversing

[HackCTF] keygen Write-up

magarets 2021. 12. 6. 22:31

이번에 풀 문제는 keygen 문제입니다.

 

무려 200점 짜리 문제네요??

 

얼마나 어려울지.. 

 

거두절미하고 바로 풀어보겠습니다.

 

 

IDA로 열고 main 함수를 디컴파일하면 위와같은 코드가 나옵니다.

 

여기서 눈여겨볼 함수는 check_key 인데요

 

check_key 함수를 if문에서 비교해서 true 일시 플래그를 뿌려주는것 같습니다.

 

 

check_key 함수에 들어왔습니다.

 

해석을 해보면 a1 (input string) 의 길이를 우선 비교하는데요

 

10 <= a1 <= 64 사이에 있다고 합니다.

 

만약 이 조건이 틀릴 시 프로그램은 종료되구요.

 

ai 길이가 위 크기안에 있다면 다음으로는 encoding() 함수에 인자값을 a1으로 넘겨줍니다.

 

그리고나서 return 값을 s2에 저장하고, 해당값을 "OO]oUU2U<sU2UsUsK" 와 비교하네요.

 

그럼 다시 encoding 함수에 들어가보도록 하죠.

 

 

a1을 인자값으로 받은 encoding 함수입니다.

 

뭔가 상당히 조잡해 보이는데요

 

해석을 또! 해보자면

 

우선 v4 = strlen(a1) 으로 문자열의 길이가 들어가게됩니다.

 

그리고 for 문으로 a1의 문자열의 길이만큼 반복하는데요

 

((a1[i] + 12) * v2 + 17) % 70 + 48 을 연산을 해서

 

해당 결과값을 v5[i]에 저장합니다.

 

그리고 나서 여기가 제일 중요한데요

 

v5[i]에 저장한 값을 또 다시 v2에 저장합니다.

 

눈치 채셨나요?

 

여기서 v2는 앞서 연산하는 식에 사용되기때문에 결과론적으론 앞서 연산한 결과가 다음 결과에 영향을 미친다.

 

라고 할 수 있겠습니다.

 

역 연산을 하기엔 키 값을 모르기에 brute-force 정공법으로 풀어야 되는 것 같네요

 

첫 글자는 72가 들어갑니다.

 

이 글자는 'H' 에 해당하는데요

 

느낌이 딱 오죠? 저 문자열을 복호화하면 flag가 나올것 같네요

 

(소스 첨부했습니다!)

더보기
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int v5[64] = {0};
int chk_Arr[64] = {0};
int cnt;

int chkPasswd(char chkword, int v2)
{
int num;

for(int i=33; i<=126; ++i){
num = ((i + 12) * v2 + 17) % 70 + 48;
if(chkword == num) {
chk_Arr[cnt++] = i;
return num;
}
}
return num;
}

int main()
{
char string[] = "OO]oUU2U<sU2UsUsK";
int num = 72;
int i;

for(i = 0; i < strlen(string); ++i)
     num = chkPasswd(string[i], num);

for(i = 0; i < 17; ++i) printf("%c", chk_Arr[i]);
return 0;
}

 

패스워드를 복호화하는 스크립트를 작성했습니다.

 

동작원리를 설명해드릴게요

 

먼저 main 함수의 chkPasswd 함수에 인자값을 두개 주는데요

 

첫번째 인자는 문제에서 주어진 문자열을 한글자씩 떼어서 넣어줍니다

 

그리고 두번째 인자는 num 값인데요. 이 값이 IDA 에서본 v2 값에 해당합니다.

 

즉 함수의 리턴값을 num 값에 넣어주고, 다음 연산시에 다시 인자값으로 넘겨주는 것이죠.

 

그리고 chkPasswd 함수는 아스키코드 33 부터 126까지 전수조사를 해서

 

문제에서 주어진 식을 연산했을때 인자로 넘겨준 문자값 (문제에서 주어진 문자열을 한글자 뗀것) 이 나올때까지 찾아줍니다.

 

찾았다면 해당값을 chk_Arr에 넣어주면서 return해줍니다.

 

이걸 반복하면 키 값이 나오게 됩니다.

 

A,d<&$+$''.+$&.&&

 

이제 이걸 서버에다 넘겨주면??

 

 

전 원래 제가 확실히 생각했던 방식이 안되면 당황을 하는(?) 편인데

 

흠.. 솔직히 여기서 조금 헤맸습니다.

 

분명 맞는데 어디가 잘못된거지....?? 하다가 조금 야매로 풀었습니다.

 

끝에 한글자를 지우고 입력하니 flag가 나오더라구요

 

 

이게 맞는건 아닐거라 생각하고 다른분들의 풀이를 조금 참고했더니 단번에 이해되더라구요

 

fgets가 \n 까지 입력을 받기때문에 끝에 하나를 없앤다고 하네요.

 

보고나니까 어렴풋이 기억납니다..

 

아직 전 부족한가 봅니다.