AP Lab: English Language
Category: Reverse
Points: 100
Description:
The AP English Language activity will ask you to reverse a program about manipulating strings and arrays. Again, an output will be given where you have to reconstruct an input.
Author: AC
Given: EnglishLanguage.java & a pdf
Writeup
We can see right away that we have a .java file. I loaded up Eclipse and opened the .java file there.
Here’s what I found:
import java.util.Scanner;
public class EnglishLanguage
{
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String inp = sc.nextLine();
if (inp.length()!=23) {
System.out.println("Your input is incorrect.");
System.exit(0);
}
for (int i = 0; i<3; i++) {
inp=transpose(inp);
inp=xor(inp);
}
if (inp.equals("1dd3|y_3tttb5g`q]^dhn3j")) {
System.out.println("Correct. Your input is the flag.");
}
else {
System.out.println("Your input is incorrect.");
}
}
public static String transpose(String input) {
int[] transpose = {11,18,15,19,8,17,5,2,12,6,21,0,22,7,13,14,4,16,20,1,3,10,9};
String ret = "";
for (int i: transpose) {
ret+=input.charAt(i);
}
return ret;
}
public static String xor(String input) {
int[] xor = {4,1,3,1,2,1,3,0,1,4,3,1,2,0,1,4,1,2,3,2,1,0,3};
String ret = "";
for (int i = 0; i<input.length(); i++) {
ret+=(char)(input.charAt(i)^xor[i]) ;
}
return ret;
}
}
Doesn’t seem too bad. Looks like it runs the transpose function then the xor after the first one three total times. I guess we gotta put it in reverse.
For the xor, we know that if we XOR each char again, it will reverse that sequence.
For the transpose, it mixes the data up a little more. I took the index of the value of the index of my new array. For example, my first index for my new array is 0 and the index of 0 in the Java array was 11. For 1, the index was 19, for 2 it was 7, and so on…
You can find my script in this repo or right here:
def transpose(data):
trans = [11,19,7,20,16,6,9,13,4,22,21,0,8,14,15,2,17,5,1,3,18,10,12]
trans_new = []
for ind, val in enumerate(trans):
trans_new.append(data[val])
return ''.join(trans_new)
def xor(data):
xs = [4,1,3,1,2,1,3,0,1,4,3,1,2,0,1,4,1,2,3,2,1,0,3]
new_data = []
for i in range(len(data)):
new_data.append(chr(ord(data[i]) ^ xs[i]))
return ''.join(new_data)
if __name__ == '__main__':
text = "1dd3|y_3tttb5g`q]^dhn3j"
for i in range(3):
text = xor(text)
text = transpose(text)
print("FLAG: {}".format(text))
Flag
flag{n0t_t00_b4d_r1ght}
Ice Cream Bytes
Category: Reverse
Points: 100
Description:
Introducing the new Ice Cream Bytes machine! Here’s a free trial: IceCreamBytes.java Oh, and make sure to read the user manual: IceCreamManual.txt
Author: wooshi
Given: IceCreamManual.txt & IceCreamBytes.java
Writeup
We see right away that we have a Java program we can look at. I use Eclipse to open up the program and this is what I find:
import java.io.*;
import java.nio.file.*;
import java.util.Scanner;
public class IceCreamBytes {
public static void main(String[] args) throws IOException {
Path path = Paths.get("IceCreamManual.txt");
byte[] manualBytes = Files.readAllBytes(path);
Scanner keyboard = new Scanner(System.in);
System.out.print("Enter the password to the ice cream machine: ");
String userInput = keyboard.next();
String input = userInput.substring("flag{".length(), userInput.length()-1);
byte[] loadedBytes = toppings(chocolateShuffle(vanillaShuffle(strawberryShuffle(input.getBytes()))));
boolean correctPassword = true;
byte[] correctBytes = fillMachine(manualBytes);
for (int i = 0; i < correctBytes.length; i++) {
if (loadedBytes[i] != correctBytes[i]) {
correctPassword = false;
}
}
if (correctPassword) {
System.out.println("That's right! Enjoy your ice cream!");
} else {
System.out.println("Uhhh that's not right.");
}
keyboard.close();
}
public static byte[] fillMachine(byte[] inputIceCream) {
byte[] outputIceCream = new byte[34];
int[] intGredients = {27, 120, 79, 80, 147,
154, 97, 8, 13, 46, 31, 54, 15, 112, 3,
464, 116, 58, 87, 120, 139, 75, 6, 182,
9, 153, 53, 7, 42, 23, 24, 159, 41, 110};
for (int i = 0; i < outputIceCream.length; i++) {
outputIceCream[i] = inputIceCream[intGredients[i]];
}
return outputIceCream;
}
public static byte[] strawberryShuffle(byte[] inputIceCream) {
byte[] outputIceCream = new byte[inputIceCream.length];
for (int i = 0; i < outputIceCream.length; i++) {
outputIceCream[i] = inputIceCream[inputIceCream.length - i - 1];
}
return outputIceCream;
}
public static byte[] vanillaShuffle(byte[] inputIceCream) {
byte[] outputIceCream = new byte[inputIceCream.length];
for (int i = 0; i < outputIceCream.length; i++) {
if (i % 2 == 0) {
outputIceCream[i] = (byte)(inputIceCream[i] + 1);
} else {
outputIceCream[i] = (byte)(inputIceCream[i] - 1);
}
}
return outputIceCream;
}
public static byte[] chocolateShuffle(byte[] inputIceCream) {
byte[] outputIceCream = new byte[inputIceCream.length];
for (int i = 0; i < outputIceCream.length; i++) {
if (i % 2 == 0) {
if (i > 0) {
outputIceCream[i] = inputIceCream[i - 2];
} else {
outputIceCream[i] = inputIceCream[inputIceCream.length - 2];
}
} else {
if (i < outputIceCream.length - 2) {
outputIceCream[i] = inputIceCream[i + 2];
} else {
outputIceCream[i] = inputIceCream[1];
}
}
}
return outputIceCream;
}
public static byte[] toppings(byte[] inputIceCream) {
byte[] outputIceCream = new byte[inputIceCream.length];
byte[] toppings = {8, 61, -8, -7, 58, 55,
-8, 49, 20, 65, -7, 54, -8, 66, -9, 69,
20, -9, -12, -4, 20, 5, 62, 3, -13, 66,
8, 3, 56, 47, -5, 13, 1, -7,};
for (int i = 0; i < outputIceCream.length; i++) {
outputIceCream[i] = (byte)(inputIceCream[i] + toppings[i]);
}
return outputIceCream;
}
}
We can see above that we get our output text to be from the IceCreamManual.txt file given to us. That output text has to equal our input text (the flag) ran through the strawberryShuffle, vanillaShuffle, chocolateShuffle, and toppings functions.
To reverse this, we will need to write functions to reverse each of these functions. I wrote a script to help with that.
My script:
import sys
import binascii
def getCorrect():
ingredients = [27,120,79,80,147,154,97,8,13,46,31,54,15,112,3,464,116,
58,87,120,139,75,6,182,9,153,53,7,42,23,24,159,41,110]
with open("IceCreamManual.txt", "r") as f:
data = f.read()
arr = [c for c in data]
output_icecream = []
for val in ingredients:
output_icecream.append(ord(arr[val]))
output = [chr(x) for x in output_icecream]
print("Correct Bytes: {}".format(output))
f.close()
return output_icecream
def toppings(data):
toppings = [8,61,-8,-7,58,55,-8,49,20,65,-7,54,-8,66,-9,69,
20,-9,-12,-4,20,5,62,3,-13,66,8,3,56,47,-5,13,1,-7,]
output_icecream = []
for i in range(len(data)):
output_icecream.append(data[i] - toppings[i])
output = [chr(x) for x in output_icecream]
print("Before Toppings: {}".format(output))
return output_icecream
def chocolate(data):
output_icecream = []
for i in range(len(data)):
val = 0
if i % 2 == 0:
if i < (len(data) - 2):
val = data[i+2]
else:
val = data[0]
else:
if i > 1:
val = data[i-2]
else:
val = data[len(data) - 1]
output_icecream.append(val)
output = [chr(x) for x in output_icecream]
print("Before Chocolate: {}".format(output))
return output_icecream
def vanilla(data):
output_icecream = []
for i in range(len(data)):
if i % 2 == 0:
output_icecream.append(data[i] - 1)
else:
output_icecream.append(data[i] + 1)
output = [chr(x) for x in output_icecream]
print("Before Vanilla: {}".format(output))
return output_icecream
def strawberry(data):
output_icecream = data[::-1]
output = [chr(x) for x in output_icecream]
print("Before Strawberry: {}".format(output))
return output_icecream
if __name__ == '__main__':
input1 = getCorrect()
input2 = toppings(input1)
input3 = chocolate(input2)
input4 = vanilla(input3)
output = strawberry(input4)
output = ''.join([chr(x) for x in output])
print("Flag: flag{" + "{}".format(output) + "}")
My output:
Correct Bytes: ['l', 'o', 'l', 'l', 'o', 'o', 'k', 'a', 't', 't', 'h', 'i', 's', 't', 'e', 'x', 't', 'i', 'g', 'o', 't', 'f', 'r', 'o', 'm', 't', 'h', 'e', 'm', 'a', 'n', 'u', 'a', 'l']
Before Toppings: ['d', '2', 't', 's', '5', '8', 's', '0', '`', '3', 'o', '3', '{', '2', 'n', '3', '`', 'r', 's', 's', '`', 'a', '4', 'l', 'z', '2', '`', 'b', '5', '2', 's', 'h', '`', 's']
Before Chocolate: ['t', 's', '5', '2', 's', 's', '`', '8', 'o', '0', '{', '3', 'n', '3', '`', '2', 's', '3', '`', 'r', '4', 's', 'z', 'a', '`', 'l', '5', '2', 's', 'b', '`', '2', 'd', 'h']
Before Vanilla: ['s', 't', '4', '3', 'r', 't', '_', '9', 'n', '1', 'z', '4', 'm', '4', '_', '3', 'r', '4', '_', 's', '3', 't', 'y', 'b', '_', 'm', '4', '3', 'r', 'c', '_', '3', 'c', 'i']
Before Strawberry: ['i', 'c', '3', '_', 'c', 'r', '3', '4', 'm', '_', 'b', 'y', 't', '3', 's', '_', '4', 'r', '3', '_', '4', 'm', '4', 'z', '1', 'n', '9', '_', 't', 'r', '3', '4', 't', 's']
Flag: flag{ic3_cr34m_byt3s_4r3_4m4z1n9_tr34ts}
Flag
flag{ic3_cr34m_byt3s_4r3_4m4z1n9_tr34ts}