Back to Defense Log
Reverse EngineeringWASMPythonStatic Analysis

K17 CTF: Daily Re - WASM Static Analysis

2026-01-23rwx4m@vault

Daily Re - Writeup

Challenge Overview

"It's too easy to cheat at Wordle, so I fixed that! What are the words for the 72nd, 73rd, and 74th day?"

Objective: Menemukan tiga kata spesifik (urutan ke-72, 73, dan 74) yang tersembunyi di dalam file binary. Format jawaban: K17{<72nd>, <73rd>, <74th>}.

Artifacts:

  • words.wasm - File WebAssembly yang berisi logika permainan.

Initial Analysis

Observation

  1. File yang diberikan adalah WebAssembly (.wasm), yang biasanya dikompilasi dari C/C++ atau Rust untuk berjalan di browser.
  2. Karena tantangannya adalah menebak kata, kemungkinan besar daftar katanya disimpan sebagai hardcoded strings di dalam memori binary tersebut.

Hypothesis

Kita tidak perlu melakukan dekompilasi penuh. Cukup dengan mengekstrak string yang dapat dibaca (ASCII) menggunakan perintah strings, kita bisa melihat daftar katanya.


Solution & Exploitation

Step 1: String Extraction

Mengekstrak semua karakter yang bisa dibaca dari file .wasm.

strings words.wasm > output.txt

Output Analysis: Menemukan ribuan baris, tapi polanya terlihat jelas.

🔻 Klik untuk melihat Output Dump
memory
__wasm_call_ctors
get_word
fflush
_emscripten_tempret_set
_emscripten_tempret_get
emscripten_stack_init
emscripten_stack_get_free
emscripten_stack_get_base
emscripten_stack_get_end
_emscripten_stack_restore
_emscripten_stack_alloc
emscripten_stack_get_current
__indirect_function_table
jApq$
kApq"
8482423c95bf2f4a165f0c08ad27a800
might
43dc252ca71e1d9b502bc2c44bd3fb3e
joust
eb38ca52bed68ffc6e771cb904a76281
quaky
dfd13e0a7f17da5496a22cf4423fbd7a
unite
de271fa1d0777a3aea3a926280e42158
agile
980920de164c7f279b2dc8e4ccd6fbf9
valor
5dfd61c8ecae413bc851075388721e37
xenon
2bd5e35921f7682406c59e06e0bd5a73
latch
a7d955cc7bbe8de8bb70f772da29e262
image
508eb8634faba2eaaacda7194ff6ad10
orbit
072f9d124ccaa8426d453b179123087c
sleek
651a7234ff4100ed989795879163a5f6
vowel
9b37ddb0f7d92de5c73ecf4b1e0ab88b
brisk
17aa8695a3d0cdac566de5e3f2e9d594
whirl
afbbe4b3dd89ce9ff319649bfe90ab79
grape
337cab92d07605b1d1fc37d311b525a5
elbow
70e7726a9b8d5e65a6dbb19cf784ad5a
zonal
b3f61e6d07992d25a42114c7d50f5f69
loyal
67cb213109a49a3b9d3ca167c051dad9
zesty
37e55328fb18231f159ebb1d12b2c6a2
choke
68bf7179ac3257087966787f004543d5
haste
fc6521b9a1194a19de15ccd7e0975390
xenon
743fd28187df87b8e26e6c37ae50be1a
relay
c80f40e3c5250b243bd1ceceab2edf03
abyss
8522b961b71c5b6bbde930cd62bf36cb
march
13dcc16b15548672e0d308c1c2c67116
apron
d0229677b1c1734fd39aa96e895979c1
roast
8cc8f9f16e05dfeddad7aa7b847dbd4f
joint
102c63a00d6309b1a62f3552898bf5dc
vivid
654ce3959aadb4aa0cea8ab1f09719d7
drown
9b50e0517ec8a9fe31a6712cb239fc69
quack
a8b87cb7ca6c4cce8b6de91e55ff9c3e
gloom
6a1cc835e586a668e5de940eeb1fe364
tango
83bee0d3dce885bf1c51214c32f2f90a
quest
45b7698a8e92ce91b506d64fecba314a
nudge
f288bc4ee4dabb9ece63c60f9b9cb081
inbox
e612ca2c10c3a2790551a3153b725c71
zesty
10ebb501bc596fc0d68b77adc07885e5
glide
a0ae1102ed936a10f3c0a08a4eeb1d06
prank
d790b21bc90d2923cc3da0b07835f0a5
xerox
0b52b4ae038426e142173b550f6ff2d2
brave
80e68391801c921249e41756b42b3694
drive
01ccf3f1a516114b47e78b17c41d3068
opera
03bc4a9cf8c632bbeef7bbeae2b80cb2
trace
a1f6e432046a4d576491fb5977c04466
rover
a774822c8ece8c62548df1e0fd338beb
ultra
559886a46d4fc0334365207ffc10d366
spoil
dff54dc554b539b8a434bb5313e0a3ac
hairy
3e0965bc9c65bc987e30db9e0e803505
doubt
8b8f3419f95f982974bc3ea05897f089
koala
193436981ab2cd0c1c5fed476d1d2af8
juice
ef6b75ace2f1217dcc33a42911db7a6b
raise
e605d6861c75e572778ffb951cf231f7
flair
b7732452844d88e885de9bcccb5518b6
quilt
6b8f71356e819af1a2065cb2b2927490
pious
e177fbd897d6043ac26550b45690f304
inset
042df3ad75c3a98ffaba61723a87a7d1
uncle
0a96f95856f4aa17f91da3ec76be0b8b
obese
1f7d1fcdbf614b306caacc615ed44c33
barge
e68def0e199d4312a21bb63d2fe0b01d
kiosk
a15dd9f89f1ce0521d8d40924864f97f
yodel
1e83cd89d9be464fda5eb4a265fa665c
crane
cec5461ee8647e58534a7ddb9d7dd620
knock
c32213f4f34d1529824936ceb3863beb
plumb
5df4440ca30ced69e48da69ac48b2eb2
vague
3d273ba1e7a4d2060921a0b828879720
shove
4d24345d562516215d8e5dad1638c27b
wacky
48c649bc269ac8bb054bd6624ec47525
slide
354810314ddeaa675974e2fdaeb558d3
faint
3ed04769ba8857297b3d5019bdfde899
taunt
b0f88f4c8ef877ba8150f5d92d756c2c
trawl
dc99b25df638f6bc0eb9cdd44811f2dd
limbo
1ed5047bb0ada6ded5ab08fdb84a8875
urban
8748afe7a3214eaafc7380bf19a680f8
fiber
793ef7fbf6dff901a6606407cd5f0c8b
prism
fc520bf146aeb77fdea602e500e9845d
novel
ac1d6c3443cd2f849a9d18b851937839
mirth
6db5e56cec4d173744d5b458c0608c98
tribe
32a9af7f43ac5a8037a047b5e07a4d5d
drape
0c24f57036a5fe8518ef366f6265f9a4
charm
5aedfb770b7f3f2477051b22e281f548
karma
e9273a3bb44af43be051a5539f4fb66b
wrong
2fb6b2b917bbaa44cc74b28f2e2916f8
mound
f13d833cbfa67a79802051f44f48cd02
youth
0b17a8680c388a7caa02a4e296a34833
noise
8a810bfed10e6d76b5c18d633f0dfde1
blaze
6a3d227302a8f3ec34011b7f72845f1f
slink
b69f00361af11e7ae4ce9cf9a12dd6d0
liven
cfd92e74f1db5f11afab3835199d0d76
yacht
b72f533a3a90b1b7cb7cc84420252318
jolly
95ea1906cdc6fa71404e0dd1d5eb5975
squad
3c05527bcbb9f936cc2acd0666ef3e0a
ozone
6affd7f61fab8ddb3f18b4f499a665f1
flops
03a85ea2dac0e104d8d1012514c8c667
hasty
ac5cf869be0f98af893f3e57864f2449
eager
e022eaa87c84c719d445d465bc1d8d6e
gloat
e25903f490405fee417c76721a89bc39
crave
752a1f7b05895cb302c86478fc63cf98
notch
b20e698caa7d70d5351723c436f1aca9
evoke
5c5d906737c2edb0dc9c015ff4ca12c8
hatch

Step 2: Solver Script

Karena kita membutuhkan kata urutan ke-72, 73, dan 74, menghitung manual akan rentan salah (off-by-one error). Saya membuat script Python sederhana untuk melakukan parsing.

Logic:

  • Ambil output strings.
  • Pisahkan berdasarkan baris baru (\n).
  • Lakukan slicing [1::2] karena setiap kata diselingi oleh hash/id.
  • Ambil index ke-71, 72, dan 73 (karena array Python dimulai dari 0, maka elemen ke-72 adalah index 71).
🔻 Klik untuk melihat Solver Code
strings_data = """strings = """8482423c95bf2f4a165f0c08ad27a800
might
43dc252ca71e1d9b502bc2c44bd3fb3e
joust
eb38ca52bed68ffc6e771cb904a76281
quaky
dfd13e0a7f17da5496a22cf4423fbd7a
unite
de271fa1d0777a3aea3a926280e42158
agile
980920de164c7f279b2dc8e4ccd6fbf9
valor
5dfd61c8ecae413bc851075388721e37
xenon
2bd5e35921f7682406c59e06e0bd5a73
latch
a7d955cc7bbe8de8bb70f772da29e262
image
508eb8634faba2eaaacda7194ff6ad10
orbit
072f9d124ccaa8426d453b179123087c
sleek
651a7234ff4100ed989795879163a5f6
vowel
9b37ddb0f7d92de5c73ecf4b1e0ab88b
brisk
17aa8695a3d0cdac566de5e3f2e9d594
whirl
afbbe4b3dd89ce9ff319649bfe90ab79
grape
337cab92d07605b1d1fc37d311b525a5
elbow
70e7726a9b8d5e65a6dbb19cf784ad5a
zonal
b3f61e6d07992d25a42114c7d50f5f69
loyal
67cb213109a49a3b9d3ca167c051dad9
zesty
37e55328fb18231f159ebb1d12b2c6a2
choke
68bf7179ac3257087966787f004543d5
haste
fc6521b9a1194a19de15ccd7e0975390
xenon
743fd28187df87b8e26e6c37ae50be1a
relay
c80f40e3c5250b243bd1ceceab2edf03
abyss
8522b961b71c5b6bbde930cd62bf36cb
march
13dcc16b15548672e0d308c1c2c67116
apron
d0229677b1c1734fd39aa96e895979c1
roast
8cc8f9f16e05dfeddad7aa7b847dbd4f
joint
102c63a00d6309b1a62f3552898bf5dc
vivid
654ce3959aadb4aa0cea8ab1f09719d7
drown
9b50e0517ec8a9fe31a6712cb239fc69
quack
a8b87cb7ca6c4cce8b6de91e55ff9c3e
gloom
6a1cc835e586a668e5de940eeb1fe364
tango
83bee0d3dce885bf1c51214c32f2f90a
quest
45b7698a8e92ce91b506d64fecba314a
nudge
f288bc4ee4dabb9ece63c60f9b9cb081
inbox
e612ca2c10c3a2790551a3153b725c71
zesty
10ebb501bc596fc0d68b77adc07885e5
glide
a0ae1102ed936a10f3c0a08a4eeb1d06
prank
d790b21bc90d2923cc3da0b07835f0a5
xerox
0b52b4ae038426e142173b550f6ff2d2
brave
80e68391801c921249e41756b42b3694
drive
01ccf3f1a516114b47e78b17c41d3068
opera
03bc4a9cf8c632bbeef7bbeae2b80cb2
trace
a1f6e432046a4d576491fb5977c04466
rover
a774822c8ece8c62548df1e0fd338beb
ultra
559886a46d4fc0334365207ffc10d366
spoil
dff54dc554b539b8a434bb5313e0a3ac
hairy
3e0965bc9c65bc987e30db9e0e803505
doubt
8b8f3419f95f982974bc3ea05897f089
koala
193436981ab2cd0c1c5fed476d1d2af8
juice
ef6b75ace2f1217dcc33a42911db7a6b
raise
e605d6861c75e572778ffb951cf231f7
flair
b7732452844d88e885de9bcccb5518b6
quilt
6b8f71356e819af1a2065cb2b2927490
pious
e177fbd897d6043ac26550b45690f304
inset
042df3ad75c3a98ffaba61723a87a7d1
uncle
0a96f95856f4aa17f91da3ec76be0b8b
obese
1f7d1fcdbf614b306caacc615ed44c33
barge
e68def0e199d4312a21bb63d2fe0b01d
kiosk
a15dd9f89f1ce0521d8d40924864f97f
yodel
1e83cd89d9be464fda5eb4a265fa665c
crane
cec5461ee8647e58534a7ddb9d7dd620
knock
c32213f4f34d1529824936ceb3863beb
plumb
5df4440ca30ced69e48da69ac48b2eb2
vague
3d273ba1e7a4d2060921a0b828879720
shove
4d24345d562516215d8e5dad1638c27b
wacky
48c649bc269ac8bb054bd6624ec47525
slide
354810314ddeaa675974e2fdaeb558d3
faint
3ed04769ba8857297b3d5019bdfde899
taunt
b0f88f4c8ef877ba8150f5d92d756c2c
trawl
dc99b25df638f6bc0eb9cdd44811f2dd
limbo
1ed5047bb0ada6ded5ab08fdb84a8875
urban
8748afe7a3214eaafc7380bf19a680f8
fiber
793ef7fbf6dff901a6606407cd5f0c8b
prism
fc520bf146aeb77fdea602e500e9845d
novel
ac1d6c3443cd2f849a9d18b851937839
mirth
6db5e56cec4d173744d5b458c0608c98
tribe
32a9af7f43ac5a8037a047b5e07a4d5d
drape
0c24f57036a5fe8518ef366f6265f9a4
charm
5aedfb770b7f3f2477051b22e281f548
karma
e9273a3bb44af43be051a5539f4fb66b
wrong
2fb6b2b917bbaa44cc74b28f2e2916f8
mound
f13d833cbfa67a79802051f44f48cd02
youth
0b17a8680c388a7caa02a4e296a34833
noise
8a810bfed10e6d76b5c18d633f0dfde1
blaze
6a3d227302a8f3ec34011b7f72845f1f
slink
b69f00361af11e7ae4ce9cf9a12dd6d0
liven
cfd92e74f1db5f11afab3835199d0d76
yacht
b72f533a3a90b1b7cb7cc84420252318
jolly
95ea1906cdc6fa71404e0dd1d5eb5975
squad
3c05527bcbb9f936cc2acd0666ef3e0a
ozone
6affd7f61fab8ddb3f18b4f499a665f1
flops
03a85ea2dac0e104d8d1012514c8c667
hasty
ac5cf869be0f98af893f3e57864f2449
eager
e022eaa87c84c719d445d465bc1d8d6e
gloat
e25903f490405fee417c76721a89bc39
crave
752a1f7b05895cb302c86478fc63cf98
notch
b20e698caa7d70d5351723c436f1aca9
evoke
5c5d906737c2edb0dc9c015ff4ca12c8
hatch
"""

words = strings.split("\n")[1::2]
print(words[71], words[72], words[73])

Parsing: Ambil elemen ganjil saja

words = strings_data.strip().split["\n"](1::2)

Print target: index 71, index 72, index 73

print(f"Result: {words[71]}, {words[72]}, {words[73]}")

Execution Output:

limbo urban fiber

Get Final Flag

K17{xxxxx, xxxxx, xxxxx}

Lessons Learned

Static Analysis First: Jangan langsung membuka disassembler (Ghidra/IDA) jika hanya mencari data statis. Perintah strings seringkali cukup.

Indexing: Hati-hati dengan urutan (1-based vs 0-based indexing) saat menyelesaikan soal urutan array.