Cover Image

n00bzCTF 2023 - EZrev

Challenge Overview

In this challenge, we were given a downloadable Java class here .

To reverse engineer a Java class, we will need a Java decompiler. I decided to use jadx-gui.

Code Analysis

Initial Code Analysis

By analyzing the source code, we have the main() function which contains the following code:


package defpackage;

import java.util.Arrays;

/* renamed from: EZrev  reason: default package */
/* loaded from: EZrev.class */
public class EZrev {
    public static void main(String[] strArr) {
        if (strArr.length != 1) {
            System.out.println("L");
            return;
        }
        String str = strArr[0];
        if (str.length() != 31) {
            System.out.println("L");
            return;
        }
        int[] array = str.chars().toArray();
        for (int i = 0; i < array.length; i++) {
            if (i % 2 == 0) {
                array[i] = (char) (array[i] ^ 19);
            } else {
                array[i] = (char) (array[i] ^ 55);
            }
        }
        for (int i2 = 0; i2 < array.length / 2; i2++) {
            if (i2 % 2 == 0) {
                array[i2] = (char) (array[(array.length - 1) - i2] + 20);
                array[(array.length - 1) - i2] = (char) (array[i2] - 10);
            } else {
                array[i2] = (char) (array[i2] + 30);
            }
        }
        if (Arrays.equals(array, new int[]{130, 37, 70, 115, 64, 106, 143, 34, 54, 134, 96, 98, 125, 98, 138, 104, 25, 3, 66, 78, 24, 69, 91, 80, 87, 67, 95, 8, 25, 22, 115})) {
            System.out.println("W");
        } else {
            System.out.println("L");
        }
    }
}

Program Flow

This Java program accepts a single character string as a command-line argument and performs a series of manipulations and checks on this string. Here are the steps of its operation:

  1. Checks if a single argument is passed to the program. If the number of arguments is different from 1, it prints "L" and terminates execution.

  2. Checks if the length of the provided string is exactly 31 characters. If not, it prints "L" and terminates execution.

  3. Converts the character string into an array of integers, each integer representing the ASCII code of a character. For each character, if the character’s index is even, it performs an XOR (exclusive OR) operation with 19, otherwise, it performs an XOR operation with 55.

  4. Then, it modifies the array again. For each element of the array up to its half, if the index is even, it swaps the values between the current index and the symmetric index relative to the middle of the array, while adjusting the values with an addition or subtraction. If the index is odd, it simply adds 30 to the value at the current index.

  5. Finally, it compares the resulting array to a predefined array. If the two arrays are identical, it prints "W", otherwise, it prints "L".

Goal

The goal here is to find the character string that allows validating the condition and thus displaying "W".

Exploitation

Reverse Engineering Script

We need to perform all the reverse actions to recover the string, and here is the code that allows doing this:

public class Test {
    public static void main(String[] args) {
        int[] targetArray = {130, 37, 70, 115, 64, 106, 143, 34, 54, 134, 96, 98, 125, 98, 138, 104, 25, 3, 66, 78, 24, 69, 91, 80, 87, 67, 95, 8, 25, 22, 115};
        char[] result = new char[31];

        // Reverse the second part of the transformations
        for (int i = 0; i < 31 / 2; i++) {
            if (i % 2 == 0) {
                int tmp = targetArray[i];
                targetArray[i] = (char) (targetArray[30 - i] + 10);
                targetArray[30 - i] = (char) (tmp - 20);
            } else {
                targetArray[i] -= 30;
            }
        }

        // Reverse the first part of the transformations
        for (int i = 0; i < 31; i++) {
            if (i % 2 == 0) {
                result[i] = (char) (targetArray[i] ^ 19);
            } else {
                result[i] = (char) (targetArray[i] ^ 55);
            }
        }

        // Print the reversed string
        System.out.println(new String(result));
    }
}

Result

By executing the program, we get the following result:

$ javac Test.java; java Test
n00bz{r3v_1s_s0_e4zy_r1ght??!!}

Flag

The flag is therefore n00bz{r3v_1s_s0_e4zy_r1ght??!!}