csaw 2022 quals writeups


This year, I participated in the CSAW Qualifiers. Here are my solutions to some of the challenges that I helped to solve.

DockREleakage (rev)

A breach occurred and some files have been leaked. One of the leaked files named
`dockREleakage.tar.gz` contains an image of one of the company's components. An anonymous hacker
has reached out to me and beware me that there is some serious mistake in my build image process.
The hacker implies that sensitive information should be handled carefully. However, I couldn't
find the mistake by myself. Please help me!

Upon downloading and extracting the challenge, we see a directory listing of various files related to the Docker build process:


I checked out the top-level acbb12...json and found some of the command history of the container:


It seems that the Dockerfile ran commands to add p-flag.txt, write some of its to a file, and tell the user to find the rest. The command prior wrote out some base64-encoded data to /dev/null, which decodes to flag{n3v3r_l34v3_53n5171v3_1nf0rm4710n_unpr0. I'm assuming at this point that the latter half of the data is in that tmp.txt (moved to flag.txt) file.

Navigating to some of the long hash-named directories and extracting their corresponding layer.tar files yielded a chal directory, some of which contained the flag.txt at different stages in command history. One version contained the second half of our flag, 73c73d_w17h1n_7h3_d0ck3rf1l3}.


Thus, the final flag is flag{n3v3r_l34v3_53n5171v3_1nf0rm4710n_unpr073c73d_w17h1n_7h3_d0ck3rf1l3}.

Anya Gacha (rev)

It is a Gacha game where the player spend coins to do lucky draw. If they can get the rare
character Anya, she will tell the player our flag!

Upon downloading the challenge, we're presented with what seems to be a Unity game. Upon running it, I'm shown what seems to be a gacha-styled game themed after Spy X Family.


Clicking the "Make a Wish" button yields no Anya though.


It seems that we'll probably need to make 1000 wishes in order to be able to yield Anya.

My first intuition was based on prior experience with interacting with primitive games -- using Cheat Engine. While I can't run this on Linux, There exists an alternative called Game Conqueror. After some quick attempts in trying to locate and modify the currency, I decided to try and reverse engineer the program.

I was aware that Unity games are written in C#, and that there exists tooling to decompile C#, so I gave that a shot. I grabbed the ILSpy plugin for VSCode and tossed in the AnyaGacha_Data/Managed/Assembly-CSharp.dll file, as this contains code specific to the game itself.


Reading through the decompiled code, I noticed two things:

Here is the function that handles wishes:

public void wish()
  int num = unmask_value(value);
  if (num < 10)
  num -= 10;
  value = mask_value(num);
  counter = mySHA256.ComputeHash(counter);
  loading.SetActive(value: true);

This checks if we have enough currency to perform a wish, and if so, it deducts 10, incremenets a counter (initially set to wakuwaku) by SHA-256 hashing it, and runs Upload().

Here is the Upload() function:

private IEnumerator Upload()
  WWWForm wWWForm = new WWWForm();
  string text = Convert.ToBase64String(counter);
  wWWForm.AddField("data", text);
  UnityWebRequest www = UnityWebRequest.Post(server, wWWForm);
  Debug.Log("Posted: " + text);
  yield return www.SendWebRequest();
  if (www.result != UnityWebRequest.Result.Success)
    yield break;
  loading.SetActive(value: false);
  string text2 = www.downloadHandler.text;
  if (text2 == "")

This sends a POST request to the challenge server with a field data being the base64-encoded value of counter.

Since we don't have enough currency initially to perform 1000 wishes, we can instead manually perform the actions necessary to submit a wish to the challenge server in order to check for a successful pull.

I wrote a Python script to help automate the process:

import requests
from hashlib import sha256
from base64 import b64encode

url = ""

counter = b"wakuwaku"

wish_count = 1

while True:
    counter = sha256(counter).digest()

    r =, data={"data": b64encode(counter)})
    if r.text != '':

    wish_count += 1

After 1000 wishes exactly, we end up with the flag:


Thus, flag{@nya_haha_1nakute_5amashii}

In hindsight, I probably should have tried the 1000th iteration from the start, but wasn't sure if there was a chance that some iteration between 1-1000 may have yielded the flag.

Not Too Taxing (crypto)

We intercepted some email communications between a tax consultant and his client that contained some
important tax documents. We were able to successfully extract two of the documents, but we can't
figure out the password to the file in order to extract the data. Attached are the two extracted
files, Tax_Ret_Form_Blank.pdf and, and a transcript of the emails we
found, SPBlock_Email.pdf.

Can you figure out the password so we can get this guy's info?

My teammate Allen had sent his thoughts on a potential solution path for this challenge, so I ended up giving it a shot.

We're given a blank tax return form, an encrypted zip containing a filled-out form, and an email transcript. Here's the relevant portions of the email conversation:


Reading through the email, it seems that there's heavy emphasis on the fact that the encryption algorithm is the default in Windows, and has been used since at least Windows 7.

A bit of research after solving the challenge shows that the algorithm is ZipCrypto, which is vulnerable to a known plaintext attack.

I was suggested to use a tool, pkcrypt, that would be able to break the encryption given an encrypted zip and plaintext file. After getting the encrypted PDF name from the zip listing via 7z l, I ran pkcrack -C -c Tax_Ret_Form_Nov_2021.pdf -p Tax_Ret_Form_Blank.pdf -d output.pdf -a to get a decrypted tax form:


Opening up the PDF in a viewer that supports viewing/editing these fields yields the flag: flag{1f_y0u_u53_z1pcryp70_4ny0n3_c4n_aud17_y0u}