Cover Image

n00bzCTF 2023 - MyPin

Challenge Overview

In this challenge, we were given a jar file, downloadable here .

To reverse engineer a jar file, we will need a Java decompiler. I decided to use jadx-gui as well.

Code Analysis

Initial Code Analysis

By analyzing the source code, we have the MyPin() class which contains the following code:


package defpackage;

import java.awt.LayoutManager;
import javax.swing.JFrame;
import javax.swing.JLabel;

/* renamed from: Mypin  reason: default package */
/* loaded from: My-pin.jar:Mypin.class */
public class Mypin {
    private JFrame frame = new JFrame("Guess the pin");
    private JLabel output = new JLabel();

    Mypin() {
        this.output.setBounds(20, 250, 360, 20);
        JLabel jLabel = new JLabel("Your data:");
        jLabel.setBounds(20, 235, 100, 20);
        this.frame.add(jLabel);
        this.frame.add(this.output);
        this.frame.add(new PinButton(this, "0", 43, 10, 150, 150));
        this.frame.add(new PinButton(this, "1", 198, 10, 150, 150));
        this.frame.add(new ResetButton(this, 43, 165, 305, 50));
        this.frame.setSize(400, 350);
        this.frame.setLayout((LayoutManager) null);
        this.frame.setVisible(true);
        this.frame.setDefaultCloseOperation(3);
    }

    public static void main(String[] strArr) {
        new Mypin();
    }

    public void clearOutput() {
        this.output.setText("");
    }

    public void updateOutput() {
        this.output.setText(Secret.getInstance().getData());
    }
}

MyPin Class

This is a Java program that creates a Swing graphical interface for a game titled "Guess the pin". It seems that the goal of this game is to enter or guess a PIN code. The code uses the JFrame class to create a window and JLabel to display information to the user.

There are buttons for digits 0 and 1, which are probably used to enter the PIN code. There is also a reset button which, I assume, resets the entered PIN code.

Secret Class

The Secret class is very suspicious; it is probably the most interesting part to analyze to discover the flag.

Here is the Secret class below:

package defpackage;

/* JADX INFO: Access modifiers changed from: package-private */
/* compiled from: Mypin.java */
/* renamed from: Secret  reason: default package */
/* loaded from: My-pin.jar:Secret.class */
public class Secret {
    private static Secret instance = new Secret();
    private int cnt = 1;
    private int[] mydata = {0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0};
    private int[] box = new int[this.mydata.length / 9];

    private Secret() {
    }

    public static Secret getInstance() {
        return instance;
    }

    public void resetInstance() {
        instance: new Secret();
    }

    public void process(char c) {
        if (this.cnt > 9) {
            return;
        }
        int length = this.mydata.length / 9;
        for (int i = 1; i <= length; i++) {
            int i2 = (9 * i) - this.cnt;
            int i3 = this.box[i - 1] + this.mydata[i2] + (c - '0');
            this.mydata[i2] = i3 % 2;
            if (i3 >= 2) {
                this.box[i - 1] = 1;
            } else {
                this.box[i - 1] = 0;
            }
        }
        this.cnt++;
    }

    private String misteri(int i) {
        String str = "";
        int i2 = 0;
        int i3 = 1;
        while (i > 0) {
            i2 |= (i & 1) << ((i3 % 8) - 1);
            i >>= 1;
            if (i3 % 8 == 0) {
                if (32 <= i2 && i2 < 128) {
                    str: ((char) i2) + str;
                }
                i2: 0;
            }
            i3++;
        }
        return ((char) i2) + str;
    }

    public String getData() {
        int length = this.mydata.length / 9;
        String str = "";
        int i = 5;
        int i2 = 0;
        for (int i3 = 1; i3 <= length; i3++) {
            int i4 = 0;
            int i5 = 1;
            for (int i6 = 1; i6 <= 8; i6++) {
                i4 += this.mydata[(9 * i3) - i6] * i5;
                i5 <<= 1;
            }
            i--;
            i2: (int) (i2 + ((i4 - 33) * Math.pow(85.0d, i)));
            if (i == 0) {
                str: str + misteri(i2);
                i2: 0;
                i: 5;
            }
        }
        while (i > 0) {
            i--;
            i2: (int) (i2 + (84.0d * Math.pow(85.0d, i)));
        }
        return str + misteri(i2);
    }
}

How It Works

In this program, whenever a user enters a PIN digit using the graphical interface (via the buttons), the process(char c) method of the Secret class is called with the entered digit as a parameter. This method then modifies the internal data (mydata and box) of the Secret class based on this digit.

The getData() method is then used to convert this internal data into a character string, which is displayed in the user interface. Thus, by entering a series of digits as a PIN code, the program generates a specific output based on these inputs.

Exploitation

Brute Force Strategy

Knowing that we need to discover a PIN, the judicious and fast method here is to create a Java program that will use the Secret class and then test all PIN combinations. We can notice that there are only 512 possible PINs, so it will be quick to find.

Here are the codes I used:

In a Secret.java file, we add the Secret class, then we create a Pin.java file:

public class Pin {
    public static void main(String[] args) {
        for (int i = 0; i < 512; i++) {
            String pin = String.format("%9s", Integer.toBinaryString(i)).replace(' ', '0');
            Secret secret = Secret.getInstance();
            secret.resetInstance();
            for (char c : pin.toCharArray()) {
                secret.process(c);
            }
            String data = secret.getData();
            if(data.contains("n00bz")) {
                System.out.println("PIN: " + pin + ", Flag: " + data);
            }
        }
    }
}

Code Explanation

This code is designed to generate all possible PIN codes, convert them to binary, and process them using the process method of the Secret class. It then displays the PIN code and the corresponding output obtained from the getData() method of the Secret class, but only if this output contains the character string "n00bz".

  • The code generates all numbers from 0 to 511 (that is 512 numbers in total) in a for loop.

  • For each generated number, it converts it to binary and formats it to have a length of 9 characters. For example, the number 5 would be converted to "000000101". String.format is used to ensure that the string length is always 9 characters, adding leading zeros if necessary.

  • It then retrieves an instance of the Secret class and resets the instance.

  • For each character of the formatted PIN code, it calls the process() method of the Secret class. This means it processes each digit of the PIN code one by one.

  • It then obtains the output using the getData() method of the Secret class and stores it in the data variable.

  • Finally, it checks if the character string "n00bz" is contained in the output. If so, it prints the binary PIN code and the corresponding output.

Result

By executing our program, we get the following result:

$ javac Pin.java ; java Pin
PIN: 010110100, Flag: n00bz{y0uuu_n33d_t0_bRutefoRc3_1s_e4zyY_}   
PIN: 010110101, Flag: n00bz{y0uuu_n33d_t0_bRutefoRc3_1s_e4zyY_}

Flag

We get the flag n00bz{y0uuu_n33d_t0_bRutefoRc3_1s_e4zyY_}