Points: 200
Tags: picoCTF 2022, Reverse Engineering, Java
Author: LT 'SYREAL' JONES
Description:
Can you get the flag?
Reverse engineer this Java program.
Hints:
1. Use a decompiler for Java!
Challenge link: https://play.picoctf.org/practice/challenge/271
The given file is a compiled Java file
┌──(kali㉿kali)-[/mnt/…/picoCTF/picoCTF_2022/Reverse_Engineering/Fresh_Java]
└─$ file KeygenMe.class
KeygenMe.class: compiled Java class data, version 55.0 (Java SE 11)
To get the source code we need to decompile it.
This can be done in Linux with jadx-gui
. Install with sudo apt install jadx
if needed.
Start jadx-gui
and open the KeygenMe.class
file.
Then navigate to main
in the hierarchy to the left. It should look something like this:
The full source code looks like this
package defpackage;
import java.util.Scanner;
/* renamed from: KeygenMe reason: default package */
/* loaded from: KeygenMe.class */
public class KeygenMe {
public static void main(String[] strArr) {
Scanner scanner = new Scanner(System.in);
System.out.println("Enter key:");
String nextLine = scanner.nextLine();
if (nextLine.length() != 34) {
System.out.println("Invalid key");
} else if (nextLine.charAt(33) != '}') {
System.out.println("Invalid key");
} else if (nextLine.charAt(32) != '9') {
System.out.println("Invalid key");
} else if (nextLine.charAt(31) != '8') {
System.out.println("Invalid key");
} else if (nextLine.charAt(30) != 'c') {
System.out.println("Invalid key");
} else if (nextLine.charAt(29) != 'a') {
System.out.println("Invalid key");
} else if (nextLine.charAt(28) != 'c') {
System.out.println("Invalid key");
} else if (nextLine.charAt(27) != '8') {
System.out.println("Invalid key");
} else if (nextLine.charAt(26) != '3') {
System.out.println("Invalid key");
} else if (nextLine.charAt(25) != '7') {
System.out.println("Invalid key");
} else if (nextLine.charAt(24) != '_') {
System.out.println("Invalid key");
} else if (nextLine.charAt(23) != 'd') {
System.out.println("Invalid key");
} else if (nextLine.charAt(22) != '3') {
System.out.println("Invalid key");
} else if (nextLine.charAt(21) != 'r') {
System.out.println("Invalid key");
} else if (nextLine.charAt(20) != '1') {
System.out.println("Invalid key");
} else if (nextLine.charAt(19) != 'u') {
System.out.println("Invalid key");
} else if (nextLine.charAt(18) != 'q') {
System.out.println("Invalid key");
} else if (nextLine.charAt(17) != '3') {
System.out.println("Invalid key");
} else if (nextLine.charAt(16) != 'r') {
System.out.println("Invalid key");
} else if (nextLine.charAt(15) != '_') {
System.out.println("Invalid key");
} else if (nextLine.charAt(14) != 'g') {
System.out.println("Invalid key");
} else if (nextLine.charAt(13) != 'n') {
System.out.println("Invalid key");
} else if (nextLine.charAt(12) != '1') {
System.out.println("Invalid key");
} else if (nextLine.charAt(11) != 'l') {
System.out.println("Invalid key");
} else if (nextLine.charAt(10) != '0') {
System.out.println("Invalid key");
} else if (nextLine.charAt(9) != '0') {
System.out.println("Invalid key");
} else if (nextLine.charAt(8) != '7') {
System.out.println("Invalid key");
} else if (nextLine.charAt(7) != '{') {
System.out.println("Invalid key");
} else if (nextLine.charAt(6) != 'F') {
System.out.println("Invalid key");
} else if (nextLine.charAt(5) != 'T') {
System.out.println("Invalid key");
} else if (nextLine.charAt(4) != 'C') {
System.out.println("Invalid key");
} else if (nextLine.charAt(3) != 'o') {
System.out.println("Invalid key");
} else if (nextLine.charAt(2) != 'c') {
System.out.println("Invalid key");
} else if (nextLine.charAt(1) != 'i') {
System.out.println("Invalid key");
} else if (nextLine.charAt(0) != 'p') {
System.out.println("Invalid key");
} else {
System.out.println("Valid key");
}
}
}
We can see that the program checks the key character by character in reverse order (from the end to the beginning).
We can rather easily create the flag manually but let's not do that.
Instead we will use builtin commandline tools like grep
, sort
and cut
to extract the flag for us.
Start by copying the source to a file named KeygenMe_main.java
.
Then we extract the involved lines with grep
┌──(kali㉿kali)-[/mnt/…/picoCTF/picoCTF_2022/Reverse_Engineering/Fresh_Java]
└─$ grep charAt KeygenMe_main.java
if(s.charAt(33) != '}')
if(s.charAt(32) != 'e')
if(s.charAt(31) != 'b')
if(s.charAt(30) != '6')
if(s.charAt(29) != 'a')
if(s.charAt(28) != '2')
if(s.charAt(27) != '3')
if(s.charAt(26) != '3')
if(s.charAt(25) != '9')
if(s.charAt(24) != '_')
if(s.charAt(23) != 'd')
if(s.charAt(22) != '3')
if(s.charAt(21) != 'r')
if(s.charAt(20) != '1')
if(s.charAt(19) != 'u')
if(s.charAt(18) != 'q')
if(s.charAt(17) != '3')
if(s.charAt(16) != 'r')
if(s.charAt(15) != '_')
if(s.charAt(14) != 'g')
if(s.charAt(13) != 'n')
if(s.charAt(12) != '1')
if(s.charAt(11) != 'l')
if(s.charAt(10) != '0')
if(s.charAt(9) != '0')
if(s.charAt(8) != '7')
if(s.charAt(7) != '{')
if(s.charAt(6) != 'F')
if(s.charAt(5) != 'T')
if(s.charAt(4) != 'C')
if(s.charAt(3) != 'o')
if(s.charAt(2) != 'c')
if(s.charAt(1) != 'i')
if(s.charAt(0) != 'p')
Next we remove all characters until the numbers with cut
┌──(kali㉿kali)-[/mnt/…/picoCTF/picoCTF_2022/Reverse_Engineering/Fresh_Java]
└─$ grep charAt KeygenMe_main.java | cut -d '(' -f3
33) != '}')
32) != 'e')
31) != 'b')
30) != '6')
29) != 'a')
28) != '2')
27) != '3')
26) != '3')
25) != '9')
24) != '_')
23) != 'd')
22) != '3')
21) != 'r')
20) != '1')
19) != 'u')
18) != 'q')
17) != '3')
16) != 'r')
15) != '_')
14) != 'g')
13) != 'n')
12) != '1')
11) != 'l')
10) != '0')
9) != '0')
8) != '7')
7) != '{')
6) != 'F')
5) != 'T')
4) != 'C')
3) != 'o')
2) != 'c')
1) != 'i')
0) != 'p')
Then we sort
numerically (-n)
┌──(kali㉿kali)-[/mnt/…/picoCTF/picoCTF_2022/Reverse_Engineering/Fresh_Java]
└─$ grep charAt KeygenMe_main.java | cut -d '(' -f3 | sort -n
0) != 'p')
1) != 'i')
2) != 'c')
3) != 'o')
4) != 'C')
5) != 'T')
6) != 'F')
7) != '{')
8) != '7')
9) != '0')
10) != '0')
11) != 'l')
12) != '1')
13) != 'n')
14) != 'g')
15) != '_')
16) != 'r')
17) != '3')
18) != 'q')
19) != 'u')
20) != '1')
21) != 'r')
22) != '3')
23) != 'd')
24) != '_')
25) != '9')
26) != '3')
27) != '3')
28) != '2')
29) != 'a')
30) != '6')
31) != 'b')
32) != 'e')
33) != '}')
Next we extract the flag characters with cut
┌──(kali㉿kali)-[/mnt/…/picoCTF/picoCTF_2022/Reverse_Engineering/Fresh_Java]
└─$ grep charAt KeygenMe_main.java | cut -d '(' -f3 | sort -n | cut -d"'" -f2
p
i
c
o
C
T
F
{
7
0
0
l
1
n
g
_
r
3
q
u
1
r
3
d
_
9
3
3
2
a
6
b
e
}
Finally, we remove newlines with tr
to get the flag
┌──(kali㉿kali)-[/mnt/…/picoCTF/picoCTF_2022/Reverse_Engineering/Fresh_Java]
└─$ grep charAt KeygenMe_main.java | cut -d '(' -f3 | sort -n | cut -d"'" -f2 | tr -d '\n'
picoCTF{<REDACTED>}
If you need more information, please see the references below.