두번째 리버싱 문제
어제 포스팅한 Fragile 문제보다 조금 더 어렵게 진화한 문제이다.
Fragile : https://hackingstudypad.tistory.com/163
이번에도 역시 java 파일이 주어진다.
import java.util.*;
public class breakable
{
public static void main(String args[]) {
Scanner scanner = new Scanner(System.in);
System.out.print("Enter flag: ");
String userInput = scanner.next();
String input = userInput.substring("rtcp{".length(),userInput.length()-1);
if (check(input)) {
System.out.println("Access granted.");
} else {
System.out.println("Access denied!");
}
}
public static boolean check(String input){
boolean h = false;
String flag = "k33p_1t_in_pl41n";
String theflag = "";
int i = 0;
if(input.length() != flag.length()){
return false;
}
for(i = 0; i < flag.length()-2; i++){
theflag += (char)((int)(flag.charAt(i)) + (int)(input.charAt(i+2)));
}
for(i = 2; i < flag.length(); i++){
theflag += (char)((int)(flag.charAt(i)) + (int)(input.charAt(i-2)));
}
String[] flags = theflag.split("");
for(; i < (int)((flags.length)/2); i++){
flags[i] = Character.toString((char)((int)(flags[i].charAt(0)) + 20));
}
return theflag.equals("Òdݾ¤¤¾ÙàåÐcÝÆ¥ÌÈáÏܦaã");
}
}
breakable.java 파일을 열어보면 이런 내용이 있다.
딱 봐도 이전 fragile 문제보다 복잡하게 생겼다.
앞부분은 사용자 입력을 정제해서 input 변수에 저장하는게 fragile 문제와 똑같다.
이번엔 flag 변수에 k33p_1t_in_pl41n 이라는 값이 저장되어 있고
theflag 변수는 비어있다.
문제는 check 함수 아래쪽에 있는 이 부분이다.
for 문이 3개가 보이는데 첫번째거 부터 살펴보자
참고로 for문에 있는 flag.length() 는 k33p_1t_in_pl41n의 글자수인 16이다.
첫번째 for문은
flag 변수의 0번째부터 13번째까지 글자와
input 변수의 2번째부터 15번째까지 글자를 더해서 theflag 변수에 저장해주고,
두번째 for문은
flag 변수의 2번째부터 15번째까지 글자와
input 변수의 0번째부터 13번째까지 글자를 더해서 theflag 변수에 이어서 저장해준다.
마지막 for문은 그냥 더한 값들을 문자열로 변환해주는 함수이고
최종적으로 theflag 변수에 저장된 값이 Òdݾ¤¤¾ÙàåÐcÝÆ¥ÌÈáÏܦaã 인지 검증하고 있다.
조금 계산이 복잡하긴 하지만
역으로 하나씩 계산해주면 input 값을 구할 수 있다.
java 파일은 eclipse를 이용해서 컴파일 해볼 수 있다.
이렇게 코드가 주어지면 컴파일 해보면서 푸는게 가장 편하다.
조만간 eclipse 설치 방법에 관한 내용도 포스팅을 해봐야겠다.
이클립스를 이용해 새로운 자바 프로젝트를 하나 만들어 주고
새로만든 프로젝트 아래에 패키지를 하나 만들어서 거기 breakable.java 파일을 넣어주면 된다.
코드를 이렇게 실행시켜보면
Enter flag: 라는 문자열이 나오고 사용자 입력을 받는다.
1을 입력해봤더니 역시나 Access denied! 가 나온다.
이제 소스코드를 수정해보자.
package test;
import java.util.*;
public class breakable
{
public static void main(String args[]) {
String flag = "k33p_1t_in_pl41n";
String theflag_1 = "Òdݾ¤¤¾ÙàåÐ";
String theflag_2 = "cÝÆ¥ÌÈáÏܦaã";
String hiddenflag_1 = "";
String hiddenflag_2 = "";
int i = 0;
for(i = 0; i < theflag_1.length(); i++){
hiddenflag_1 += (char)((int)(theflag_1.charAt(i)) - (int)(flag.charAt(i)));
}
for(i = 0; i < theflag_2.length(); i++){
hiddenflag_2 += (char)((int)(theflag_2.charAt(i)) - (int)(flag.charAt(i+2)));
}
System.out.println(hiddenflag_1);
System.out.println(hiddenflag_2);
}
}
필요없는 부분은 과감하게 지웠다.
Fragile 문제를 풀때는 사용자 입력을 받는 main 함수와 검증하는 check 함수를 거의 그대로 살려뒀는데
굳이 그럴 필요는 없을거 같아서 check 함수를 날려버리고 main 함수에서 모든 작업을 수행했다.
가장 먼저 theflag 변수에 저장된 Òdݾ¤¤¾ÙàåÐcÝÆ¥ÌÈáÏܦaã 를 두 부분으로 쪼갰다.
총 28글자인데, 14글자씩 쪼개서 theflag_1, theflag_2 변수에 저장해줬다.
그다음 hiddenflag_1, hiddenflag_2 변수를 선언하고
for 문을 이용해 theflag_1 - flag 한 값을 hiddenflag_1 변수에 저장,
theflag_2 - flag(i+2) 한 값을 hiddenflag_2 변수에 저장한 뒤 출력시켜줬다.
어려운거 없이 원래 소스코드를 거꾸로 계산한 것 뿐이다.
코드를 컴파일하면 0mg_1m_s0_pr0ud_ 라고 플래그가 출력되는걸 볼 수 있다.
'CTF > 리버싱' 카테고리의 다른 글
[HouseplantCTF] Bendy - 리버싱 / Java (57) | 2022.06.11 |
---|---|
[HouseplantCTF] EZ - 리버싱 / Python / 주석 (58) | 2022.06.10 |
[HouseplantCTF] Fragile - 리버싱 / Java (54) | 2022.06.06 |
[UMDCTF] Twilight Zone - 리버싱 / dnSpy (65) | 2022.05.11 |
[UMDCTF] Santa Mysterious Box - 리버싱 / IDA (62) | 2022.05.03 |