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.