Snowing [Ekoparty 2023]
Challenge Description
So, because we wrote this writeup kinda late, we don’t have the original description anymore. But, the original description was heavily hinting that some text is hidden in the Phrack articles hosted on EKONET (which was some online file server you could access through Gopher). This actually is some continuation of the protect.exe
challenge. We recommend you take a look at that writeup as well.
Intuition
So, since the title of the challenge is Snowing
and the tag for it is steganography, it heavily hints at Snow
, the program we just showcased in Protect
, that hides messages in the whitespaces of text. The initial idea was to write a crawler for EKONET and download all Phrack articles there, then to grep them for (weird amounts of) whitespaces.
Solution
A quick crawler script that mixes some shell calls here and there is listed below:
#!/usr/bin/env python3
import os
import subprocess
issues = subprocess.check_output(["curl", f"gopher://go.ctf.site:10070/1/DOCS/phrack/issues"]).split(b'\n')
no_issues = []
for line in issues: # parse all issues available first
line = line.split(b'\t')
if len(line) > 1:
no_issues.append(int(line[1].split(b'/')[-1]))
print(no_issues)
i = 0
for x in sorted(no_issues): # iterate through each issue
pages = subprocess.check_output(["curl", f"gopher://go.ctf.site:10070/1/DOCS/phrack/issues/{x}"]).split(b'\n') # get all available pages
no_pages = []
for line in pages:
line = line.split(b'\t')
if len(line) > 1:
no_pages.append(int(line[1].split(b'/')[-1].rstrip(b".txt")))
for p in sorted(no_pages): # download each page in sorted order
while os.waitstatus_to_exitcode(os.system(f"curl gopher://go.ctf.site:10070/1/DOCS/phrack/issues/{x}/{p}.txt > {i}.txt")):
continue
i += 1
After grepping en-masse through them we can find multiple Phrack articles that end with multiple whitespaces. Snow always hides the messages at the end of the lines. To have a more reliable search, we construct a diff script that also crawls and scrapes the original Phrack articles. Before you ask, yes, I do refuse to complicate shell interaction with the various wrappers provided by Python.
#!/usr/bin/env python3
import os
import subprocess
count = 0
for i in range(1, 71):
os.system(f"wget http://phrack.org/archives/tgz/phrack{i}.tar.gz")
os.system(f"tar xvfz phrack{i}.tar.gz")
files = subprocess.check_output(["ls"]).split(b"\n")
pages = []
for f in files:
if b".txt" in f:
pages.append(f.rstrip(b".txt"))
pages = list(map(int, pages))
for p in sorted(pages):
try:
# this is the part where we diff
# I keep the EKONET sources at "../phracker/{NUM}.txt"
# that's the path you see below
diff = subprocess.check_output(["diff", f"{p}.txt", f"../phracker/{count}.txt"])
except subprocess.CalledProcessError as e:
print(f"Original Phrack Issue: {i},{p}, phracker: {count}")
#print(e.output)
pass
count += 1
os.system(f"rm phrack{i}.tar.gz")
os.system(f"rm *.txt")
The only differences we find are in 880.txt
, or Phrack #64 file 6
. This is where the secret message resides. However, any attempt at using Snow
to decode and decrypt ultimately fail and result in complete garbage. It is obvious that we have to guess some password. After trying numerous ones, including building a wordlist and bruteforcer, we give up.
After the CTF we find out that the solution was to use the password phrack
, which we did try. However, guessing the password was not enough. We also had to recompile an original version of Snow
. Remember the flag found in Protect
, in the ICE sbox? Apparently the solution is to rewrite the sbox with that modified one and try to decrypt the message. Let’s try it. We rewrite the sbox found in ice.c
in the Snow source files:
[...]
/* WE MODIFIED THIS TABLE BELOW */
/* XOR values for the S-boxes */
static const int ice_sxor[4][4] = {
{0x45, 0x4b, 0x4f, 0x7b},
{0x72, 0x34, 0x6e, 0x64},
{0x30, 0x6d, 0x5f, 0x73},
{0x62, 0x30, 0x78, 0x7d}};
[...]
We recompile and use it now, with the password phrack
and we get the following:
$ ./snow -C -p "phrack" secret.txt
???? JFIF ? ? ?? C /&&;+;\66\vZIZvmZZZZm?}}}}}??????????????????????????????????????? C1;;LBLZ99Z?ZLZ???ee????B}????????????????????????????????????????? ? ? ?? ?? < !1AQa?"2Rbq??#$B?????r???3CS4???? ?? ?? ? ??i?n?'Y9S?? ?|?v恠!% ??4 @?)@^(9(PN(8?M????sSë{?? ??.?R@? ??@????s?=?KF?{O';??
C?P3A?6?1At?????k?
?wxA?iWgD0x ??vx}?ӵ??(??<P????@???????????=?tZ?<>?j??@{Wg??????????Z?<TZ?<????@??????ZB??ct ܉Px??6??ų??O??Ct???A???u?ZD5????3?}}%??<???D-AR?????z?j????s??2?fr@?gk???{e?Pmjf?s(4?F???u???????cz?Q?PTgD??'??[?w Pu???0A c%6[S??5s??A?zV?EA?PX<???'?drY+w?kv??h???'