srdnlen2026 quals started
This commit is contained in:
140
2026/srdnlen_quals/forensic/chapter1/fc.wcm
Normal file
140
2026/srdnlen_quals/forensic/chapter1/fc.wcm
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
Application (WP; "WordPerfect"; Default; "EN")
|
||||||
|
|
||||||
|
v0 := 0
|
||||||
|
v1 := 1
|
||||||
|
v3 := 128
|
||||||
|
v4 := 7
|
||||||
|
v5 := 13
|
||||||
|
|
||||||
|
k1 := v3 - v4 - 51
|
||||||
|
k2 := k1 - v5 + v4 + v1
|
||||||
|
k3 := k1 + v4 - 2
|
||||||
|
k4 := k2 + v4 - 3
|
||||||
|
|
||||||
|
doclen := 38
|
||||||
|
docbodyLen := 38
|
||||||
|
Declare docbody[38]
|
||||||
|
docbody[1] := 206
|
||||||
|
docbody[2] := 56
|
||||||
|
docbody[3] := 8
|
||||||
|
docbody[4] := 128
|
||||||
|
docbody[5] := 209
|
||||||
|
docbody[6] := 47
|
||||||
|
docbody[7] := 2
|
||||||
|
docbody[8] := 149
|
||||||
|
docbody[9] := 202
|
||||||
|
docbody[10] := 34
|
||||||
|
docbody[11] := 95
|
||||||
|
docbody[12] := 128
|
||||||
|
docbody[13] := 226
|
||||||
|
docbody[14] := 41
|
||||||
|
docbody[15] := 92
|
||||||
|
docbody[16] := 156
|
||||||
|
docbody[17] := 142
|
||||||
|
docbody[18] := 38
|
||||||
|
docbody[19] := 51
|
||||||
|
docbody[20] := 153
|
||||||
|
docbody[21] := 137
|
||||||
|
docbody[22] := 57
|
||||||
|
docbody[23] := 51
|
||||||
|
docbody[24] := 218
|
||||||
|
docbody[25] := 211
|
||||||
|
docbody[26] := 21
|
||||||
|
docbody[27] := 88
|
||||||
|
docbody[28] := 130
|
||||||
|
docbody[29] := 201
|
||||||
|
docbody[30] := 121
|
||||||
|
docbody[31] := 30
|
||||||
|
docbody[32] := 128
|
||||||
|
docbody[33] := 137
|
||||||
|
docbody[34] := 62
|
||||||
|
docbody[35] := 93
|
||||||
|
docbody[36] := 152
|
||||||
|
docbody[37] := 142
|
||||||
|
docbody[38] := 55
|
||||||
|
|
||||||
|
rhLen := 24
|
||||||
|
Declare rh[24]
|
||||||
|
rh[1] := 80
|
||||||
|
rh[2] := 113
|
||||||
|
rh[3] := 171
|
||||||
|
rh[4] := 195
|
||||||
|
rh[5] := 17
|
||||||
|
rh[6] := 89
|
||||||
|
rh[7] := 222
|
||||||
|
rh[8] := 175
|
||||||
|
rh[9] := 32
|
||||||
|
rh[10] := 97
|
||||||
|
rh[11] := 153
|
||||||
|
rh[12] := 187
|
||||||
|
rh[13] := 68
|
||||||
|
rh[14] := 2
|
||||||
|
rh[15] := 204
|
||||||
|
rh[16] := 127
|
||||||
|
rh[17] := 136
|
||||||
|
rh[18] := 19
|
||||||
|
rh[19] := 85
|
||||||
|
rh[20] := 224
|
||||||
|
rh[21] := 250
|
||||||
|
rh[22] := 60
|
||||||
|
rh[23] := 109
|
||||||
|
rh[24] := 144
|
||||||
|
|
||||||
|
doB64 := v0
|
||||||
|
If (doB64 = v1)
|
||||||
|
Type (NToC(k3 + v5 + v4 + v1 + v1))
|
||||||
|
Type (NToC(v3 - v4))
|
||||||
|
Type (NToC(v3 - v5 - v4))
|
||||||
|
Type (NToC(v3 - v5 - v4 - v1))
|
||||||
|
Type (NToC(v3 - v5 - v4))
|
||||||
|
Type (NToC(v3 - v5 - v5 + v1 + v1))
|
||||||
|
Type (NToC(v3 - v5 - v5 + v1 + v1))
|
||||||
|
Type (NToC(v5 + v5 + v4 - v1))
|
||||||
|
EndIf
|
||||||
|
|
||||||
|
Declare kArr[4]
|
||||||
|
kArr[1] := k1
|
||||||
|
kArr[2] := k2
|
||||||
|
kArr[3] := k3
|
||||||
|
kArr[4] := k4
|
||||||
|
|
||||||
|
Type (NToC(k1 + v5 + v1))
|
||||||
|
Type (NToC(v3 - v5 - v5 + v1 + v1))
|
||||||
|
Type (NToC(v3 - v5 - v4 - v4))
|
||||||
|
Type (NToC(v5 + v5 + v4 - v1))
|
||||||
|
Type (NToC(v3 - v5 - v4 - v1))
|
||||||
|
Type (NToC(v3 - v5 - v4 - v4))
|
||||||
|
Type (NToC(v3 - v4))
|
||||||
|
Type (NToC(v5 + v5 + v4 - v1))
|
||||||
|
Type (NToC(k2 + k2 - v5 - v5 + v1))
|
||||||
|
Type (NToC(v3 - v5))
|
||||||
|
Type (NToC(v5 + v5 + v4 - v1))
|
||||||
|
Type (NToC(k2 + k2 - v5 - v5 + v1))
|
||||||
|
Type (NToC(v3 - v5 - v4 + v1 + v1))
|
||||||
|
Type (NToC(v5 + v5 + v4 - v1))
|
||||||
|
Type (NToC(v3 - v4 - v1 - v1))
|
||||||
|
Type (NToC(v3 - v5 - v5 + v1 + v1))
|
||||||
|
Type (NToC(k3 + v5 + v4 + v1 + v1))
|
||||||
|
Type (NToC(v3 - v5 + v1))
|
||||||
|
Type (NToC(v5 + v5 + v4 - v1))
|
||||||
|
Type (NToC(k2 + k2 - v5 - v5 + v1))
|
||||||
|
Type (NToC(v3 - v5))
|
||||||
|
Type (NToC(v5 + v5 + v4 - v1))
|
||||||
|
Type (NToC(v3 - v5 - v4))
|
||||||
|
Type (NToC(v3 - v5 - v4 - v4))
|
||||||
|
Type (NToC(k1 + v5 + v5 + v4 - v1))
|
||||||
|
Type (NToC(v3 - v5 + v1))
|
||||||
|
Type (NToC(13))
|
||||||
|
|
||||||
|
ForNext (ii; v1; doclen; v1)
|
||||||
|
bb := docbody[ii]
|
||||||
|
kb := kArr[(ii - v1) % 4 + v1]
|
||||||
|
Type (NToC((bb + kb) - 2 * (bb & kb)))
|
||||||
|
EndFor
|
||||||
|
|
||||||
|
buf := ""
|
||||||
|
ForNext (jj; v1; rhLen; v1)
|
||||||
|
kb := kArr[(jj - v1) % 4 + v1]
|
||||||
|
rb := rh[jj]
|
||||||
|
buf := buf + NToC((rb + kb) - 2 * (rb & kb))
|
||||||
|
EndFor
|
||||||
BIN
2026/srdnlen_quals/forensic/chapter1/img.qcow
(Stored with Git LFS)
Normal file
BIN
2026/srdnlen_quals/forensic/chapter1/img.qcow
(Stored with Git LFS)
Normal file
Binary file not shown.
18
2026/srdnlen_quals/forensic/chapter1/solve.py
Normal file
18
2026/srdnlen_quals/forensic/chapter1/solve.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
docbody = [206,56,8,128,209,47,2,149,202,34,95,128,226,41,92,156,
|
||||||
|
142,38,51,153,137,57,51,218,211,21,88,130,201,121,30,128,
|
||||||
|
137,62,93,152,142,55]
|
||||||
|
|
||||||
|
# Known prefix "srdnlen{"
|
||||||
|
prefix = "srdnlen{"
|
||||||
|
|
||||||
|
# Derive key bytes from known prefix
|
||||||
|
key = []
|
||||||
|
for i, c in enumerate(prefix):
|
||||||
|
key.append(docbody[i] ^ ord(c))
|
||||||
|
|
||||||
|
print(f"Derived key bytes: {key}")
|
||||||
|
print(f"Derived key chars: {''.join(chr(k) for k in key)}")
|
||||||
|
|
||||||
|
# Decode full docbody with cycling key
|
||||||
|
result = ''.join(chr(docbody[i] ^ key[i % len(key)]) for i in range(len(docbody)))
|
||||||
|
print(f"\nDecoded flag: {result}")
|
||||||
212
2026/srdnlen_quals/forensic/chapter1/writeup.md
Normal file
212
2026/srdnlen_quals/forensic/chapter1/writeup.md
Normal file
@@ -0,0 +1,212 @@
|
|||||||
|
I mounted the filesytem via:
|
||||||
|
```bash
|
||||||
|
sudo qemu-nbd --connect=/dev/nbd1 img.qcow
|
||||||
|
sudo mount /dev/nbd1 /mnt/chall1
|
||||||
|
```
|
||||||
|
|
||||||
|
Then I tried to look for interesting stuff.
|
||||||
|
|
||||||
|
|
||||||
|
```
|
||||||
|
total 140K
|
||||||
|
drwxr-xr-x 20 root root 4,0K 27. Feb 04:11 .
|
||||||
|
drwxr-xr-x 6 root root 4,0K 28. Feb 19:34 ..
|
||||||
|
drwxr-xr-x 3 root root 4,0K 27. Feb 04:11 bin
|
||||||
|
drwxr-xr-x 2 root root 4,0K 27. Feb 04:10 boot
|
||||||
|
drwxr-xr-x 4 root root 4,0K 26. Feb 20:07 .cdl_amnt
|
||||||
|
drwxr-xr-x 5 root root 20K 27. Feb 05:20 dev
|
||||||
|
drwxr-xr-x 2 root root 4,0K 26. Feb 20:06 disks
|
||||||
|
drwxr-xr-x 56 root root 4,0K 27. Feb 05:20 etc
|
||||||
|
drwxr-sr-x 3 root games 4,0K 26. Feb 20:07 home
|
||||||
|
drwxr-xr-x 2 root root 4,0K 26. Feb 20:06 initrd
|
||||||
|
drwxr-xr-x 5 root root 4,0K 27. Feb 04:11 lib
|
||||||
|
drwxr-xr-x 2 root root 48K 26. Feb 20:05 lost+found
|
||||||
|
drwxr-xr-x 6 root root 4,0K 27. Feb 05:19 mnt
|
||||||
|
drwxr-xr-x 3 500 500 4,0K 27. Feb 04:11 opt
|
||||||
|
drwxr-xr-x 2 root root 4,0K 26. Feb 20:06 proc
|
||||||
|
drwx---r-x 4 root root 4,0K 27. Feb 05:19 root
|
||||||
|
drwxr-xr-x 3 root root 4,0K 27. Feb 04:11 sbin
|
||||||
|
drwxrwxrwt 5 root root 4,0K 27. Feb 05:20 tmp
|
||||||
|
drwxr-xr-x 16 root root 4,0K 26. Feb 20:06 usr
|
||||||
|
drwxr-xr-x 15 root root 4,0K 27. Feb 04:10 var
|
||||||
|
lrwxrwxrwx 1 root root 20 26. Feb 20:06 vmlinuz -> /boot/vmlinuz-2.2.16
|
||||||
|
lrwxrwxrwx 1 root root 19 26. Feb 20:06 vmlinuz-debug -> boot/vmlinuz-2.2.16
|
||||||
|
```
|
||||||
|
In the initial phase I tried the easy stuff
|
||||||
|
- checking etc/passwd, etc/issue, the home directory of user davezero
|
||||||
|
- running `fd flag` hoping for an easy win
|
||||||
|
- tried strings img.qcow | rg srdnl
|
||||||
|
- reading bash_history of `root` and `davezero` with no special findings
|
||||||
|
|
||||||
|
Then I turned to log analysis
|
||||||
|
- syslog files
|
||||||
|
- auth files
|
||||||
|
- apache logs
|
||||||
|
I found out that only root ever logged in. This explains the empty bash_history of davezero
|
||||||
|
|
||||||
|
I found nothing interesting in the log files so I snooped around the file system.
|
||||||
|
The challenge stated that the hacker hid their secrets in old systems. I looked for anything that I did not recognize in modern Linux.
|
||||||
|
- `.cdl_amnt/` is a directory special to corel but had nothing interesting in it
|
||||||
|
- `/opt/smartmove` is a program special to corel to migrate settings from windows but seemed untouched
|
||||||
|
- I found `/var/lib/dwww/quickfind.dat` which seemed interesting but i then found out that this is standard debian stuff for manuals
|
||||||
|
- The `var/www` directory also did not have anything special
|
||||||
|
The rest of the filesystem looked pretty normal to me.
|
||||||
|
|
||||||
|
At this point I was a bit confused what to do. I returned to the log files to see if I missed anything.
|
||||||
|
|
||||||
|
Here I discovered the key to the challenge. I found the file /var/log/fc.wcm.
|
||||||
|
I thought of this as strange since `.wcm` is not a file ending i recognize.
|
||||||
|
|
||||||
|
Opening the file revealed this:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
❯ cat fc.wcm
|
||||||
|
Application (WP; "WordPerfect"; Default; "EN")
|
||||||
|
|
||||||
|
v0 := 0
|
||||||
|
v1 := 1
|
||||||
|
v3 := 128
|
||||||
|
v4 := 7
|
||||||
|
v5 := 13
|
||||||
|
|
||||||
|
k1 := v3 - v4 - 51
|
||||||
|
k2 := k1 - v5 + v4 + v1
|
||||||
|
k3 := k1 + v4 - 2
|
||||||
|
k4 := k2 + v4 - 3
|
||||||
|
|
||||||
|
doclen := 38
|
||||||
|
docbodyLen := 38
|
||||||
|
Declare docbody[38]
|
||||||
|
docbody[1] := 206
|
||||||
|
docbody[2] := 56
|
||||||
|
docbody[3] := 8
|
||||||
|
docbody[4] := 128
|
||||||
|
docbody[5] := 209
|
||||||
|
docbody[6] := 47
|
||||||
|
docbody[7] := 2
|
||||||
|
docbody[8] := 149
|
||||||
|
docbody[9] := 202
|
||||||
|
docbody[10] := 34
|
||||||
|
docbody[11] := 95
|
||||||
|
docbody[12] := 128
|
||||||
|
docbody[13] := 226
|
||||||
|
docbody[14] := 41
|
||||||
|
docbody[15] := 92
|
||||||
|
docbody[16] := 156
|
||||||
|
docbody[17] := 142
|
||||||
|
docbody[18] := 38
|
||||||
|
docbody[19] := 51
|
||||||
|
docbody[20] := 153
|
||||||
|
docbody[21] := 137
|
||||||
|
docbody[22] := 57
|
||||||
|
docbody[23] := 51
|
||||||
|
docbody[24] := 218
|
||||||
|
docbody[25] := 211
|
||||||
|
docbody[26] := 21
|
||||||
|
docbody[27] := 88
|
||||||
|
docbody[28] := 130
|
||||||
|
docbody[29] := 201
|
||||||
|
docbody[30] := 121
|
||||||
|
docbody[31] := 30
|
||||||
|
docbody[32] := 128
|
||||||
|
docbody[33] := 137
|
||||||
|
docbody[34] := 62
|
||||||
|
docbody[35] := 93
|
||||||
|
docbody[36] := 152
|
||||||
|
docbody[37] := 142
|
||||||
|
docbody[38] := 55
|
||||||
|
|
||||||
|
rhLen := 24
|
||||||
|
Declare rh[24]
|
||||||
|
rh[1] := 80
|
||||||
|
rh[2] := 113
|
||||||
|
rh[3] := 171
|
||||||
|
rh[4] := 195
|
||||||
|
rh[5] := 17
|
||||||
|
rh[6] := 89
|
||||||
|
rh[7] := 222
|
||||||
|
rh[8] := 175
|
||||||
|
rh[9] := 32
|
||||||
|
rh[10] := 97
|
||||||
|
rh[11] := 153
|
||||||
|
rh[12] := 187
|
||||||
|
rh[13] := 68
|
||||||
|
rh[14] := 2
|
||||||
|
rh[15] := 204
|
||||||
|
rh[16] := 127
|
||||||
|
rh[17] := 136
|
||||||
|
rh[18] := 19
|
||||||
|
rh[19] := 85
|
||||||
|
rh[20] := 224
|
||||||
|
rh[21] := 250
|
||||||
|
rh[22] := 60
|
||||||
|
rh[23] := 109
|
||||||
|
rh[24] := 144
|
||||||
|
|
||||||
|
doB64 := v0
|
||||||
|
If (doB64 = v1)
|
||||||
|
Type (NToC(k3 + v5 + v4 + v1 + v1))
|
||||||
|
Type (NToC(v3 - v4))
|
||||||
|
Type (NToC(v3 - v5 - v4))
|
||||||
|
Type (NToC(v3 - v5 - v4 - v1))
|
||||||
|
Type (NToC(v3 - v5 - v4))
|
||||||
|
Type (NToC(v3 - v5 - v5 + v1 + v1))
|
||||||
|
Type (NToC(v3 - v5 - v5 + v1 + v1))
|
||||||
|
Type (NToC(v5 + v5 + v4 - v1))
|
||||||
|
EndIf
|
||||||
|
|
||||||
|
Declare kArr[4]
|
||||||
|
kArr[1] := k1
|
||||||
|
kArr[2] := k2
|
||||||
|
kArr[3] := k3
|
||||||
|
kArr[4] := k4
|
||||||
|
|
||||||
|
Type (NToC(k1 + v5 + v1))
|
||||||
|
Type (NToC(v3 - v5 - v5 + v1 + v1))
|
||||||
|
Type (NToC(v3 - v5 - v4 - v4))
|
||||||
|
Type (NToC(v5 + v5 + v4 - v1))
|
||||||
|
Type (NToC(v3 - v5 - v4 - v1))
|
||||||
|
Type (NToC(v3 - v5 - v4 - v4))
|
||||||
|
Type (NToC(v3 - v4))
|
||||||
|
Type (NToC(v5 + v5 + v4 - v1))
|
||||||
|
Type (NToC(k2 + k2 - v5 - v5 + v1))
|
||||||
|
Type (NToC(v3 - v5))
|
||||||
|
Type (NToC(v5 + v5 + v4 - v1))
|
||||||
|
Type (NToC(k2 + k2 - v5 - v5 + v1))
|
||||||
|
Type (NToC(v3 - v5 - v4 + v1 + v1))
|
||||||
|
Type (NToC(v5 + v5 + v4 - v1))
|
||||||
|
Type (NToC(v3 - v4 - v1 - v1))
|
||||||
|
Type (NToC(v3 - v5 - v5 + v1 + v1))
|
||||||
|
Type (NToC(k3 + v5 + v4 + v1 + v1))
|
||||||
|
Type (NToC(v3 - v5 + v1))
|
||||||
|
Type (NToC(v5 + v5 + v4 - v1))
|
||||||
|
Type (NToC(k2 + k2 - v5 - v5 + v1))
|
||||||
|
Type (NToC(v3 - v5))
|
||||||
|
Type (NToC(v5 + v5 + v4 - v1))
|
||||||
|
Type (NToC(v3 - v5 - v4))
|
||||||
|
Type (NToC(v3 - v5 - v4 - v4))
|
||||||
|
Type (NToC(k1 + v5 + v5 + v4 - v1))
|
||||||
|
Type (NToC(v3 - v5 + v1))
|
||||||
|
Type (NToC(13))
|
||||||
|
|
||||||
|
ForNext (ii; v1; doclen; v1)
|
||||||
|
bb := docbody[ii]
|
||||||
|
kb := kArr[(ii - v1) % 4 + v1]
|
||||||
|
Type (NToC((bb + kb) - 2 * (bb & kb)))
|
||||||
|
EndFor
|
||||||
|
|
||||||
|
buf := ""
|
||||||
|
ForNext (jj; v1; rhLen; v1)
|
||||||
|
kb := kArr[(jj - v1) % 4 + v1]
|
||||||
|
rb := rh[jj]
|
||||||
|
buf := buf + NToC((rb + kb) - 2 * (rb & kb))
|
||||||
|
EndFor
|
||||||
|
```
|
||||||
|
|
||||||
|
This looks incredibly suspicious. To get started with things I chucked the file into Claude and asked it if it can decode it.
|
||||||
|
Prompt: `I found this strange looking file in a forensics CTF. Can you decode its contents? The flag format is srdnlen{*}`
|
||||||
|
Sadly Claude solved it in one go generating a simple script that bruteforces the key from the known `srdnlen{` flag prefix.
|
||||||
|
|
||||||
|
Flag: `srdnlen{wh3n_c0r3l_w4s_4n_4lt3rn4t1v3}`
|
||||||
|
|
||||||
|
Using AI in CTFs is a double edged sword because it can save you a lot of time but can take out the fun out of solving puzzles and hinders learning.
|
||||||
Reference in New Issue
Block a user