CTF/리버싱

[HouseplantCTF] Bendy - 리버싱 / Java

SecurityMan 2022. 6. 11. 11:00


Java 리버싱 최종단계 문제

확실히 이전 두 문제(Fragile, Breakable) 보다 더 어렵다.

막 기술적으로 어렵다기보다 계산을 복잡하게 해서 머리가 아파진다.

Fragile : https://hackingstudypad.tistory.com/163
Breakable : https://hackingstudypad.tistory.com/164

반응형


이번에도 역시 java 파일이 주어진다.

import java.util.*;

public class bendy
{
    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 = "r34l_g4m3rs_eXclus1v3";
        String theflag = "";
        int i = 0;
        if(input.length() != flag.length()){
            return false;
        }
        for(i = 0; i < flag.length()-14; i++){
            theflag += (char)((int)(flag.charAt(i)) + (int)(input.charAt(i+8)));
        }
        for(i = 10; i < flag.length()-6; i++){
            theflag += (char)((int)(flag.charAt(i)) + (int)(input.charAt(i-8)));
        }
        for(; i < flag.length(); i++){
            theflag += (char)((int)(flag.charAt(i-3)) + (int)(input.charAt(i)));
        }
        //Ғdݾ¤¤¾ÙàåГcÝƐ¥ÌÈáÏܦaã
        String[] flags = theflag.split("");
        for(i=0; i < (int)((flags.length)/2); i++){
            flags[i] = Character.toString((char)((int)(flags[i].charAt(0)) + 20));
        }
        theflag = theflag.substring(flags.length/2);
        for(int k = 0; k < ((flags.length)/2); k++){
            theflag += flags[k];
        }
        return theflag.equals("ÄѓӿÂÒêáøz§è§ñy÷¦");
    }
}


bendy.java 파일을 열어보면 위와 같은 내용이 있다.

이전 문제들 보다 일단 길이부터 확실히 차이나게 길어졌다.

for 문이 5개 있는거 부터 참 피곤하게 느껴진다.

main 함수는 이전 두 문제처럼 사용자 입력을 정제해서 input 변수에 저장하는 게 똑같다.

flag 변수에는 r34l_g4m3rs_eXclus1v3 라는 값이 저장되어 있고

theflag 변수는 비어있다.


가장 먼저 위에 있는 3개의 for문 부터 살펴본다.

참고로 for문에 있는 flag.length() 는r34l_g4m3rs_eXclus1v3의 글자수인 21이다.

첫번째 for문은

flag 변수의 0번째부터 6번째까지 글자

input 변수의 8번째부터 14번째까지 글자를 더해서 theflag 변수에 저장

두번째 for문은

flag 변수의 10번째부터 14번째까지 글자

input 변수의 2번째부터 6번째까지 글자를 더해서 theflag 변수에 이어서 저장

세번째 for문은

flag 변수의 12번째부터 17번째까지 글자

input 변수의 15번째부터 20번째까지 글자를 더해서 theflag 변수에 이어서 저장해준다.

여기까지 하면 theflag 변수에 18글자(7+5+6)가 저장된다.


그다음 flags 배열에 theflag 변수에 저장된 값을 한글자식 잘라서 순서대로 집어넣고,


네번째 for문에서 flags 배열의 절반 길이만큼(9)

다시말해 flags 배열의 0번째부터 8번째까지는 저장되어있던 값에 20을 더해서 저장해주고


theflag 변수에 저장되있던 값중 0번째부터 8번째까지의 값을 잘라내 버린 뒤에(substring)


flag 변수의 0번째부터 8번째까지의 값을 theflag 변수에 이어붙여준다.(아까 +20한 값)

그리고 나서 마지막으로

theflag에 저장된 값이 ÄѓӿÂÒêáøz§è§ñy÷¦ 인지 검증하고 있다.

아주 토나오게 복잡하다..

문제 풀다가 머리로는 도지히 안되겠어서 그림을 그려가면서 풀었다..

하지만 그래봤다 더하고 자르고 이어붙이는 작업이기 때문에

차근차근히 역으로 계산해주면 input 값을 구할 수 있다.


java 파일은 eclipse를 이용해서 컴파일 해볼 수 있다.

이렇게 코드가 주어지면 컴파일 해보면서 푸는게 가장 편하다.


이클립스를 이용해 새로운 자바 프로젝트를 하나 만들어 주고


새로만든 프로젝트 아래에 패키지를 하나 만들어서 거기 bendy.java 파일을 넣어주면 된다.


코드를 이렇게 실행시켜보면

Enter flag: 라는 문자열이 나오고 사용자 입력을 받는다.

1을 입력해봤더니 역시나 Access denied! 가 나온다.

이제 소스코드를 수정해보자.

package test;
import java.util.*;

public class bendy
{
    public static void main(String args[]) {
        String flag = "r34l_g4m3rs_eXclus1v3";
        String theflag = "";
        String hiddenflag_1 = "";
        String hiddenflag_2 = "";
        String hiddenflag_3 = "";
        String flags = "ÄѓӿÂÒêáøz§è§ñy÷¦";
        String flags_Array [] = flags.split("");
        
        for(int k = 9; k < 18; k++) {
        	flags_Array[k] = Character.toString((char)((int)(flags_Array[k].charAt(0)) - 20));
        }
        for(int k = 9; k < (flags_Array.length); k++) {
        	theflag += flags_Array[k];
        }
        for(int k = 0; k < ((flags_Array.length)/2); k++) {
        	theflag += flags_Array[k];
        }
        
        int i = 0;

        for(i = 0; i < 7; i++) {
            hiddenflag_1 += (char)((int)(theflag.charAt(i)) - (int)(flag.charAt(i)));
        }
        for(i = 7; i < 12; i++) {
            hiddenflag_2 += (char)((int)(theflag.charAt(i)) - (int)(flag.charAt(i+3)));
        }
        for(; i < 18; i++) {
            hiddenflag_3 += (char)((int)(theflag.charAt(i)) - (int)(flag.charAt(i)));
        }

        System.out.println(hiddenflag_1);
        System.out.println(hiddenflag_2);
        System.out.println(hiddenflag_3);
    }
}


역시나 필요없는 부분을 과감하게 지워버렸다.(그래도 길다)

main 함수에서 입력받는 부분을 몽땅 지우고

check 함수를 main 쪽으로 옮겨서 작성했다.


가장 먼저 flags 변수를 되돌려 줬다.

flag 변수에서 +20을 해줬던 부분을 다시 -20을 해주고,

9글자씩 끊어서 순서를 바꿔주는 작업을 했다.

그리고 그렇게 만든 값을 theflag 변수에 저장해준다.


그다음은 Fragile, Breakable 문제에서 했던것과 똑같다.

hiddenflag 변수를 만들어서 역으로 계산해주면 된다.


코드를 실행시켜 보면 이렇게 문자열이 3개 나오는걸 볼 수 있다.

첫번째는 input의 8번째부터 14번째글자

두번째는 input의 2번째부터 6번째글자

세번째는 input의 15번째부터 20번째 글자이다.

합쳐서 써보면

??p3_yo?r3_h4v1ng_fun 이런 문장이 나오는데

보이는것처럼 0, 1, 7번째 글자가 누락되어있는걸 볼 수 있다.

이건 그냥 guessing(추측) 해서 때려맞췄는데

영어 문장이기 때문에 빈 칸에 적절한 단어를 넣어줬다.


hope youre having fun 이 이번문제의 플래그였다.

반응형