vault-door-5 - Points 300
In the last challenge, you mastered octal (base 8), decimal (base 10), and hexadecimal (base 16) numbers, but this vault door uses a different change of base as well as URL encoding! The source code for this vault is here:
import java.net.URLDecoder; import java.util.*; class VaultDoor5 { public static void main(String args[]) { VaultDoor5 vaultDoor = new VaultDoor5(); Scanner scanner = new Scanner(System.in); System.out.print("Enter vault password: "); String userInput = scanner.next(); String input = userInput.substring("picoCTF{".length(),userInput.length()-1); if (vaultDoor.checkPassword(input)) { System.out.println("Access granted."); } else { System.out.println("Access denied!"); } } // Minion #7781 used base 8 and base 16, but this is base 64, which is // like... eight times stronger, right? Riiigghtt? Well that's what my twin // brother Minion #2415 says, anyway. // // -Minion #2414 public String base64Encode(byte[] input) { return Base64.getEncoder().encodeToString(input); } // URL encoding is meant for web pages, so any double agent spies who steal // our source code will think this is a web site or something, defintely not // vault door! Oh wait, should I have not said that in a source code // comment? // // -Minion #2415 public String urlEncode(byte[] input) { StringBuffer buf = new StringBuffer(); for (int i=0; i<input.length; i++) { // 0xg33k - three % is to get one single % to the buf buf.append(String.format("%%%2x", input[i])); } // 0xg33k - sends back UTF-8 encoded string return buf.toString(); } public boolean checkPassword(String password) { String urlEncoded = urlEncode(password.getBytes()); // 0xg33k - urlEncode returns c0nv3rt1ng_fr0m_ba5e_64_db6946ba String base64Encoded = base64Encode(urlEncoded.getBytes()); // 0xg33k - base64Encode returns %63%30%6e%76%33%72%74%31%6e%67%5f%66%72%30%6d%5f%62%61%35%65%5f%36%34%5f%64%62%36%39%34%36%62%61 String expected = "JTYzJTMwJTZlJTc2JTMzJTcyJTc0JTMxJTZlJTY3JTVm" + "JTY2JTcyJTMwJTZkJTVmJTYyJTYxJTM1JTY1JTVmJTM2" + "JTM0JTVmJTY0JTYyJTM2JTM5JTM0JTM2JTYyJTYx"; return base64Encoded.equals(expected); } }
Solution
This is the Fifth vault door and as mentioned in the problem statement it doesn't uses basic encoding it first encodes to URL encoding and then it encodes to base64.
To decode this, first we need to know what the checkPassword method does,
public String base64Encode(byte[] input) { return Base64.getEncoder().encodeToString(input); } public String urlEncode(byte[] input) { StringBuffer buf = new StringBuffer(); for (int i=0; i<input.length; i++) { buf.append(String.format("%%%2x", input[i])); } return buf.toString(); } public boolean checkPassword(String password) { String urlEncoded = urlEncode(password.getBytes()); String base64Encoded = base64Encode(urlEncoded.getBytes()); String expected = "JTYzJTMwJTZlJTc2JTMzJTcyJTc0JTMxJTZlJTY3JTVm" + "JTY2JTcyJTMwJTZkJTVmJTYyJTYxJTM1JTY1JTVmJTM2" + "JTM0JTVmJTY0JTYyJTM2JTM5JTM0JTM2JTYyJTYx"; return base64Encoded.equals(expected); }
First it encodes the characters to ASCII encoded bytes and passes them as the argument to the urlEncode Method in that method there is a StringBuffer and each of the ASCII encoded is converted as HexaDecimal and also append them with % symbol and when the loop is done the method sends back the StringBuffer as String.
you can print the urlEncoded Variable if you want, after that this variable is sent to base64Encode Method to get a Base64 encoded String and it is done with a inbuilt Base64 Class methods.
This is how the encoding is done in this program, so to Decode and get the Flag you can just reverse this process, I leave that part for you figure out, because I want you to understand how it is done, incase if you just want to know the Flag here it is,
picoCTF{c0nv3rt1ng_fr0m_ba5e_64_db6946ba}
Reference Links,