Sunday, November 17, 2024

SANS: Holiday Hack 2024: Act 1: Unshredding Shredded Document & Hardware Hacking 1

The next part is important for the next terminal, Hardware Hacking 1.

Unshredding Shredded Document

Talk to Morcel again after completing the Frosty Keypad.  Click on the green icon in the dock again.  There will be a bag of shredded paper.  In the badge, under hints, Morcel also gives a clue how to piece the shredded pieces back together.  It's a python script.

Most Linux distributions already have python or python3 or both installed.  Sometimes numpy is not included.  In my case, I had to install both pip3 and numpy.  Open a Terminal.

sudo apt install python3-pip
pip3 install numpy
unzip shreds.zip

Note, the new folder after shreds is unzipped is called "slices".

python3 heuristic_edge_detection.py slices

Once that is done, an assembled image pops out.



That looks kind of weird.

Looks like each of the images: The left side image and the right-side image needs to be flipped horizontally individually and connected back together.

I couldn't read every single character, but having dealt with serial communications before, I had an idea.

BAUD: 115200
PARITY: even
DATA: 7 BITS
STOP BITS: 1 BIT
FLOW CONTROL: RTS

Even if that is not known, in the Hardware Hacking 1 challenge, powering on the device and looking at the settings can assist with figuring this out.

Alternatively, print it out, cut it and tape it back together, or use your favorite photo editing software like GIMP to fix it.  I left STOPPITS in the image below because it looks like what was reassembled by the python script. 😁.  It is supposed to be STOP BITS.



Hardware Hacking Part 1:

This Terminal is near Jewel Loggins.

Silver Medal:

This can be done by trial and error, however, looking in the source code for the site is another valid solution, as well as understanding why each cable is a different color, and how to properly wire it, and the correct voltage to use.

Search and Learn Method:


The voltage matters.  In this case 3V are needed, so the tiny switch needs to be switched from 5 V to 3 V.  If this isn't correct, a pretty puff of blue smoke comes out of the device. Thankfully if the voltage is switched, it's fine.  This is hard to see, but in the manual that is shown to begin with, it has a picture with 3V.  This is how this is known.  The voltage is at 5V by default, so the tiny orange button needs to be clicked on the bridge at the bottom.  It's difficult to see but matches what is in the manual.

Identifying the wires by Googling may not be easy. Each of the cables have positive and negative charges.  If they're wired wrong, they can fry the board.  The game seems to start from a new state when the Terminal is opened again, so this can be brute-forced without much penalty that I'm aware of.  Santa's magic, I guess.  Don't know if there's a penalty on the scoreboard - have no idea how that functions in the background.

The device is on the left side - the bridge is on the bottom right side.  The PDA is at the top right side.

An important fact to remember is that the post for transmitting (TX) on the device is cabled to the receiving (RX) post of the bridge.  This also means that the post for receiving (RX) on the device is cabled to the transmitting (TX) post of the bridge.  That means the cables are crossed.  For the voltage (VCC) and ground (GND), the voltage post on the device goes to the voltage post of the bridge.  The ground post on the device goes to the ground post on the bridge.

For each of these, the left side of the cable goes to the device post.  The right side of the cable goes to the bridge post.  

The red cable is for the voltage (VCC).
The orange cable is for transmitting (TX).
The green cable is for receiving (RX)
The black cable is for the ground (GND).

It didn't seem to matter if the black and red cables were switched - ie black for voltage and red for ground.  Note: not crossed, I mean using one cable instead of the other.  A chart for usb I found by doing a Google-search notes the above though.  This could be different for different cables and pinouts.  It's best to consult documentation regarding the specific cables and devices being used.

Connect the wires.

The USB needs to be plugged into the bridge by clicking on the USB.

Make sure the V on the bride is set to 3V (The tiny orange square will be on the right-side of the tiny white rectangle with either 5V or 3V in it.)

Next click the power button (P) on the device.  Settings can be selected by clicking the up/down arrow buttons on screen.  To change the settings, click the left or right arrow buttons on screen.  Modify them according to the settings in the reassembled shreds.

BAUD: 115200
PARITY: even
DATA: 7 BITS
STOP BITS: 1 BIT
FLOW CONTROL: RTS

Click the Serial button (S) to start a serial connection.  Silver Medal awarded.

Source Code Method:


The colors for the cables and where they correspond to are defined in the connectPins() Method:

    const targetPins = [
      { pin: this.children.getByName('gnd'), dest: this.children.getByName('uGnd'), color: 0x000000 },
      { pin: this.children.getByName('tx'), dest: this.children.getByName('uRx'), color: 0x1bff00 },
      { pin: this.children.getByName('rx'), dest: this.children.getByName('uTx'), color: 0xff8700 },
      { pin: this.children.getByName('v3'), dest: this.children.getByName('uVcc'), color: 0xff0000 }
    ];

VCC = 0xff0000 = red
GND = 0x00000 = black
RX = 0x1bff00 = lime green
TX = 0xff8700 = dark orange

In that same method - connectPins(), there is a loop checking to see if the wires are wired.

    targetPins.forEach((targetPin) => {
      let connectionFound = false;

      jumperWires.forEach((wire) => {
        if (
          wire.female &&
          Phaser.Geom.Intersects.RectangleToRectangle(wire.female.getBounds(), targetPin.dest.getBounds()) &&
          wire.male &&
          Phaser.Geom.Intersects.RectangleToRectangle(wire.male.getBounds(), targetPin.pin.getBounds())
        ) {
          console.log(`Connected ${targetPin.pin.name} (${targetPin.dest.name}) with ${wire.female.name} and ${wire.male.name}`);
          allPinnedUp++;
          connectionFound = true;
          // You can add more logic here for when the connection is made
        }
      });

      if (!connectionFound) {
        console.warn(`No connection found for ${targetPin.pin.name} (${targetPin.dest.name})`);
      }
    });

When the pins are correct it states "All pinned up in the console."

    if (allPinnedUp === targetPins.length) {
      console.log("All pinned up!");
      this.allConnectedUp = true;
    } else {
      this.allConnectedUp = false;
    }
  }

Now we know how to tell if the wires are correctly wired.  We know the colors.  The left side part of the wire goes to the device, and the right side of the wire goes to the bridge.  Once the console says "All pinned up!" we know the wires are ready to go.

In a method called checkConditions(), there are voltage checks.

We can tell 5 volts is incorrect, because if it's 5 volts, all the pins are connected, and the usb has been moved, there is smoke coming out of the device, which is not preferable.  That smell of ozone is very memorable if you've ever fried a board in real life.

      if (this.uV === 5 && this.allConnectedUp && !this.usbIsAtOriginalPosition) {
        const smoked = this.children.getByName('smoked');
        smoked.start();
        this.playAudioForDuration(this.smokey, 3000);
        this.time.delayedCall(3000, () => smoked.stop(), [], this);
      }

If it's 3 volts, there is a check to see if all the serial connection settings are correct.  Then it brings up the serial connection and states to talk to Jewel Loggins.  This is the condition necessary to reach for the silver medal.

    if (this.uV === 3 && this.allConnectedUp && !this.usbIsAtOriginalPosition || this.dev) {
      // console.log("PARTY TIME");
      let checkIt = await checkit([this.currentPortIndex, this.currentBaudIndex, this.currentParityIndex, this.currentDataIndex, this.currentStopBitsIndex, this.currentFlowControlIndex], this.uV)
      if (checkIt) {
        this.popup("success! loading bootloader...\nGo speak with Jewel Loggins for the next step!");
        this.yippee.play();
      } else {
        this.merp.play();
        this.popup("Serial connection couldn't be established...\nPlease check your settings and try again.");
      }

Looking through the code, the settings for the console connection (USB), baud rate, parity, data, stop bites, and flow control index don't seem to be in the code.  It shows the potential settings, but not which ones are correct.  Could be I missed them?

Under the function showHelpScreen(), the settings for the PDA are set (the device on the top right-hand side that does the serial connection.

    const baudRates = [300, 1200, 2400, 4800, 9600, 14400, 19200, 38400, 57600, 115200];
    const dataBits = [5, 6, 7, 8];
    const parityOptions = ["None", "odd", "even"];
    const stopBits = [1, 2];
    const flowControlOptions = ["None", "RTS/CTS", "Xon/Xoff", "RTS"];
    const ports = ["COM1", "COM2", "COM3", "USB0"];

Seems like the information is sent to https://hhc24-hardwarehacking.holidayhackchallenge.com/api/v2/complete according to the checkIt() function.  So it looks like it's checked server-side.  This can still be brute forced by trying options though or finding the shredded papers and unscrambling them.

Note something interesting in that checkConditions() function.  (If(Voltage=3, all the wires are connected, and usb is moved from its original condition) OR (this.dev)).  When something is by itself like that without a condition, it means OR this.dev must be true.  What's dev?  Where is it?

At the beginning of the code it states:

this.dev = false;

What happens if that's changed to true?

this.dev = true

And uncomment the PARTY TIME line in the checkConditions() function.

Press the P button (for power).  Pressing the P button, it powers on without the usb being plugged in, and without a Voltage.

It seems to get past the first check, as evidenced the PARTY TIME being shown in the console, however, the settings have to be set to pass the next check to pop the serial connection.

Change if(checkit) to if(!checkit)

Press S (for serial).  Success!  It doesn't give gold though because this is an unintended solution. :(  Not sure if it works for silver.  I didn't test.

Gold Medal

The key to this one is the dev=true and checkIt() function found earlier.

this.dev earlier in the code needs to be set to true to bypass the first if statement in the checkConditions() function.

The following is the checkIt() function.

async function checkit(serial, uV) {
  // Retrieve the request ID from the URL query parameters
  const requestID = getResourceID(); // Replace 'paramName' with the actual parameter name you want to retrieve

  if (!requestID) {
    requestID = "00000000-0000-0000-0000-000000000000";
  }

  // Build the URL with the request ID as a query parameter
  // Word on the wire is that some resourceful elves managed to brute-force their way in through the v1 API.
  // We have since updated the API to v2 and v1 "should" be removed by now.
  // const url = new URL(`${window.location.protocol}//${window.location.hostname}:${window.location.port}/api/v1/complete`);
  const url = new URL(`${window.location.protocol}//${window.location.hostname}:${window.location.port}/api/v2/complete`);

  try {
    // Make the request to the server
    const response = await fetch(url, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({ requestID: requestID, serial: serial, voltage: uV })
    });

    // Check if the request was successful
    if (!response.ok) {
      throw new Error('Network response was not ok: ' + response.statusText);
    }

    const data = await response.json();
    console.log("Data", data)
    // Return true if the response is true
    return data === true;
  } catch (error) {
    console.error('There has been a problem with your fetch operation:', error);
    return false;
  }
}

Notice there's a commented line about changing from v1 to v2 in the checkIt() function because some resourceful elves brute forced their way through v1 and that v1 SHOULD not be active now?

uncomment v1 by removing the // near  // const url = new URL(`${window.location.protocol}//${window.location.hostname}:${window.location.port}/api/v1/complete`);

Add a comment for v2.  By placing // next to  const url = new URL(`${window.location.protocol}//${window.location.hostname}:${window.location.port}/api/v2/complete`);

The try block under the checkIt() function is just looking for the requestID, serial, and voltage.

The game should get the requestID when you load the Terminal in Holiday Hack 2024.  The serial is an array containing [3,9,2,2,0,3]. and the voltage should be 3.  These settings can be seen in the Network tab in Chrome if the silver medal is done near the same time as the gold medal.  I think it's possible the requestID changes over time - like it times out.  I don't know for sure.  The serial and voltage will be the same at least.

The checkIt() function is called by the checkConditions() function.  checkIt() is passed the following values according to the checkconditions() function:

checkit([this.currentPortIndex, this.currentBaudIndex, this.currentParityIndex, this.currentDataIndex, this.currentStopBitsIndex, this.currentFlowControlIndex], this.uV)

None of these values matter because we are going to manually adjust them in the checkIt() function.

All of those, except for the voltage are settings for the serial connection.  They should look familiar: Port for Serial Port, Baud, Parity, Data, Stop Bits, and Flow Control.  When it's passed in, those settings are renamed to "serial" and placed in an array.  If the serial value passed in is confusing it soon won't be.  

Under the function showHelpScreen(), the settings for the PDA are set (the device on the top right-hand side that does the serial connection.

    const baudRates = [300, 1200, 2400, 4800, 9600, 14400, 19200, 38400, 57600, 115200];
    const dataBits = [5, 6, 7, 8];
    const parityOptions = ["None", "odd", "even"];
    const stopBits = [1, 2];
    const flowControlOptions = ["None", "RTS/CTS", "Xon/Xoff", "RTS"];
    const ports = ["COM1", "COM2", "COM3", "USB0"];

The first number (3) is the serial port index.  Remember computers count from 0.  The options are COM1, COM2, COM3, and USB0.  COM1=0, COM2=1, COM3=2, and USB0=3.  The next number is the BAUD.  Position 9 matches with the 115200 setting it needs to be.  The next option is the PARITY.  Position 2 is even.  The next setting passed is the DATA.  Position 2 is 7.  The next option passed is the STOP BITS.  Position 0 is 1.  The last option passed is the flow Control.  Position 3 is RTS.

The voltage is set to 3 like it says in the source code.  Knowing this info, a POST request can be sent to https://hhc24-hardwarehacking.holidayhackchallenge.com/api/v1/complete with the json formatted data after the v1 line is changed so that it is not commented, and the v2 line is commented out as described above.

The data looks like this in json:

{"requestID":"YOUR ID","serial":[3,9,2,2,0,3],"voltage":3}

This can be changed in the checkIt() function in the try block:

  try {
    // Make the request to the server
    const response = await fetch(url, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({ requestID: requestID, serial: serial, voltage: uV })
    });

After the changes described are made, and the S button is pressed, a serial connection screen should appear and the gold for HWH1 should be awarded.

There's another place to visit on that site shown in the source code:

Check out function dad. Lolz

https://hhc24-hardwarehacking.holidayhackchallenge.com/joke


No comments:

Post a Comment