Address
304 North Cardinal St.
Dorchester Center, MA 02124
Work Hours
Monday to Friday: 7AM - 7PM
Weekend: 10AM - 5PM
Address
304 North Cardinal St.
Dorchester Center, MA 02124
Work Hours
Monday to Friday: 7AM - 7PM
Weekend: 10AM - 5PM
I tried to compete in the FaradaySec CTF recently and wanted to share the one flag that I captured.
FaradaySec hosted a CTF before the ekoparty conference.
The scoreboard and challenges were located here but are no longer active.
I heard about this CTF from this Tweet, and you can follow their Twitter account here.
The one challenge that I solved was a JavaScript encryption challenge, which you can still find here.
In case the link dies, you can find the entire source of the challenge below.
<!doctype html>
<html class="no-js" lang="">
<head>
<meta charset="utf-8">
<title></title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="manifest" href="site.webmanifest">
<link rel="apple-touch-icon" href="icon.png">
<!-- Place favicon.ico in the root directory -->
<link rel="stylesheet" href="css/normalize.css">
<link rel="stylesheet" href="css/main.css">
<meta name="theme-color" content="#fafafa">
</head>
<body>
<!-- Add your site or application content here -->
Enter 72bit hex-encoded key: <input id="key-input" type="text" placeholder="example: DEADBEEFCAFE1234AB" size="30">
<input type="submit" id="submit-key">
<p id="flag-ok" style="display:none">
Correct <img src="img/happy-emoji.png" height="30" width="30"> The flag is <b><code id="flag"></code></b>
</p>
<p id="flag-invalid" style="display:none">
Incorrect <img src="img/sad-emoji.png" height="30" width="30">
</p>
<script src="js/vendor/modernizr-3.7.1.min.js" type="text/javascript"></script>
<script src="https://code.jquery.com/jquery-3.4.1.min.js" type="text/javascript" integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"></script>
<script>window.jQuery || document.write('<script src="js/vendor/jquery-3.4.1.min.js"><\/script>')</script>
<!--[if IE]>
<p class="browserupgrade">You are using an <strong>outdated</strong> browser. Please <a href="https://browsehappy.com/">upgrade your browser</a> to improve your experience and security.</p>
<![endif]-->
<script src="text/javascript">
// Copyright (C) 2019 Infobyte LLC (http://www.infobytesec.com/)
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
function parseHexString(str) {
// Taken from https://stackoverflow.com/questions/14603205/how-to-convert-hex-string-into-a-bytes-array-and-a-bytes-array-in-the-hex-strin
var result = [];
while (str.length >= 2) {
result.push(parseInt(str.substring(0, 2), 16));
str = str.substring(2, str.length);
}
return result;
}
function decrypt(ciphertext, key){
var k = parseHexString(key);
var result = "";
for(var i=0; i<ciphertext.length; i++){
result = result + String.fromCharCode(ciphertext[i] ^ k[i % k.length]);
}
return result;
}
$(document).ready(function(){
$("#submit-key").click(function(){
var key = $('#key-input').val();
var ct = [0x9a, 0x1e, 0x19, 0x9c, 0xe1, 0x77, 0xf5, 0x3e, 0x55, 0xb5, 0x3b, 0x2e, 0xb4, 0x92, 0x54, 0xc9, 0x26, 0x0c, 0xaf, 0x37, 0x24, 0xb2, 0xd2, 0x5f, 0xc9, 0x0f, 0x47];
var decoded = decrypt(ct, key);
$("#flag-invalid").hide(function(){
if(decoded.startsWith("FARADAY{") && decoded.endsWith("}")){
$("#flag").text(decoded);
$("#flag-ok").show();
}else{
// Random data decoded, invalid key
$("#flag-invalid").show();
}
});
});
});
</script>
<!-- Google Analytics: change UA-XXXXX-Y to be your site's ID. -->
<!-- <script> -->
<!-- window.ga = function () { ga.q.push(arguments) }; ga.q = []; ga.l = +new Date; -->
<!-- ga('create', 'UA-XXXXX-Y', 'auto'); ga('set','transport','beacon'); ga('send', 'pageview') -->
<!-- </script> -->
<script src="https://www.google-analytics.com/analytics.js" async></script>
</body>
</html>
Taking a quick look at the source code, only two functions really stood out to me.
It looked like this application took a key, and a cipher-text, and then performed a XOR operation with the entire cipher-text.
function parseHexString(str) {
// Taken from https://stackoverflow.com/questions/14603205/how-to-convert-hex-string-into-a-bytes-array-and-a-bytes-array-in-the-hex-strin
var result = [];
while (str.length >= 2) {
result.push(parseInt(str.substring(0, 2), 16));
str = str.substring(2, str.length);
}
return result;
}
function decrypt(ciphertext, key){
var k = parseHexString(key);
var result = "";
for(var i=0; i<ciphertext.length; i++){
result = result + String.fromCharCode(ciphertext[i] ^ k[i % k.length]);
}
return result;
}
Since the decrypt method goes through the entire length of the cipher-text, I needed to provide a key that was the same length.
Using my trusty CyberChef, I generated a key with the provided CT and a flag in the valid format.
I grabbed the ct variable from the $(document).ready function and just removed the spaces and commas.
To verify that the key was correct, I used the Javascript console in the browser.
> var ct = [0x9a, 0x1e, 0x19, 0x9c, 0xe1, 0x77, 0xf5, 0x3e, 0x55, 0xb5, 0x3b, 0x2e, 0xb4, 0x92, 0x54, 0xc9, 0x26, 0x0c, 0xaf, 0x37, 0x24, 0xb2, 0xd2, 0x5f, 0xc9, 0x0f, 0x47];
undefined
> var key = "dc5f4bdda536ac456584091d80a762fe1e359f061681e66aff383a"
undefined
> var decoded = decrypt(ct, key);
undefined
> decoded
"FARADAY{012345678901234567}"
> decoded.startsWith("FARADAY{") && decoded.endsWith("}")
true
Unfortunately, the application was rejecting this flag, even though the console output looked correct.
I also tried a shorter key, and, as expected, this had some gibberish on the end of the decoded string.
> var key = "dc5f4bdda536ac4528"
undefined
> var decoded = decrypt(ct, key);
undefined
> decoded
"FARADAY{}idei7bec$shoowieJo"
I was unable to figure out why my solution was working, when everything was correct.
After looking at the debugging window, I noticed a file called text/javascript.
When I opened this file, I noticed that it was almost the same, except for a different ct variable.
var ct = [0x63, 0xe0, 0x26, 0x89, 0x57, 0x13, 0x57, 0x58, 0xc8, 0x4c, 0x91, 0x11, 0x82, 0x76, 0x3b, 0x77, 0x1a, 0xe6, 0x4a, 0xc9, 0x11, 0xa1, 0x27, 0x22, 0x67, 0x46, 0xd4];
Taking another look at the original source, I noticed the ingenious line that caused this to happen.
<script src="text/javascript">
This line of code meant that the application was loading the FILE at text/javascript, and the rest of the tag was being ignored. This was a wonderfully dirty trick, and something that I may need to reuse for a CTF challenge.
Using this correct cipher-text value, I generated a new key using CyberChef.
Using this new key value, I was able to correctly solve the challenge!
I also used Python to quickly verify that my solution decoded correctly.
>>> print '{:x}'.format(int("63e0268957135758c84c911182763b771ae64ac911a127226746d4", 16) ^ int("25a174c813520e23f87da322b6430d4022df7af8239213175171a9", 16)).decode("hex")
FARADAY{012345678901234567}
As a fun bonus, I decided to generate a flag with a shout-out to EverSec CTF.
And, like before, I verified this newly generated key using Python.
>>> print '{:x}'.format(int("63e0268957135758c84c911182763b771ae64ac911a127226746d4", 16) ^ int("25a174c813520e238d3af463d113583175942fbf74d306034677a9", 16)).decode("hex")
FARADAY{EverSecForever!!!1}
This was a fun JavaScript CTF challenge, with a great twist.
After solving this one, I realized that any flag of the correct length should work, unless the scoreboard wanted the encoded key.
I’ve got plenty more CTF write-ups planned but let me know if there is any that I should attempt to solve.
Ray Doyle is an avid pentester/security enthusiast/beer connoisseur who has worked in IT for almost 16 years now. From building machines and the software on them, to breaking into them and tearing it all down; he’s done it all. To show for it, he has obtained an OSCE, OSCP, eCPPT, GXPN, eWPT, eWPTX, SLAE, eMAPT, Security+, ICAgile CP, ITIL v3 Foundation, and even a sabermetrics certification!
He currently serves as a Senior Staff Adversarial Engineer for Avalara, and his previous position was a Principal Penetration Testing Consultant for Secureworks.
This page contains links to products that I may receive compensation from at no additional cost to you. View my Affiliate Disclosure page here. As an Amazon Associate, I earn from qualifying purchases.