Grinchs website takendown with various other exploits

Disclosed: 2021-03-02 17:57:05 By archerl To h1-ctf
Critical
Vulnerability Details
# The HackyHolidays This is my first HackerOne CTF challenge writeup. Contents: (flag1): Day 1 (Check the files, robots.txt) (flag2): Day 2 (one more :) jquery.min.js) (flag3): Day 3 (People Rater) (flag4): Day 4 (Brute Force, Swag Shop) (flag5): Day 5 (Brute Force, Secure Login) (flag6): Day 6 (Brute Force, My Diary) (flag7): Day 7 (Brute Force, Hate Mail Generator) (flag8): Day 8 (Brute Force, Forum) (flag9): Day 9 (Brute Force, Evil Quiz) (flag10): Day 10 (Brute Force, Signup Manager) (flag11): Day 11 (Day 17th for me ;( ) (Brute Force, Follow the Link in Signup-Manager) Sheesh!!! (flag12): Day 12 (TAKE DOWN GRINCH! Follow the Link provided in 11) ## Flag 1 This was a fairly easy flag to find. As hacker instinct, the first place to look is the website's structure and that can be found in /robots.txt **Flag found**: [img](https://i.imgur.com/I87dIDS.png) {F1138714} ## Flag 2 This other flag is found in not so very traditional places. Like a good CTF player, I check for EXIF data in the images posted: `grinch-keepout` & `grinch-networks`, well nothing there. So I refreshed the page again and looked at one of the requests and saw one of the requests being made to `jquery.min.js`. To save time, typed `flag` as a keyword in the response tab in the burp suite to find it, nothing. So I thought of going for a manual scavenger hunt, this snippet caught my attention. ```javascript= , h1_0='la', h1_1='}', h1_2='', h1_3='f', h1_4='g', h1_5='{b7ebcb75', h1_6='8454-', h1_7='cfb9574459f7', h1_8='-9100-4f91-'; document.getElementById('alertbox').setAttribute('data-info', h1_2 + h1_3 + h1_0 + h1_4 + h1_2 + h1_5 + h1_8 + h1_6 + h1_7 + h1_1); document.getElementById('alertbox').setAttribute('next-page', '/ap'+ 'ps'); function b(e, t, n) { var r, i, o=(n=n||E).createElement("script"); if(o.text=e, t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r, i); n.head.appendChild(o).parentNode.removeChild(o) } ``` The flag is distributed in the variables, so if you have time you can manually patch the variables together to get the flag ```h1_2 + h1_3 + h1_0 + h1_4 + h1_2 + h1_5 + h1_8 + h1_6 + h1_7 + h1_1``` Or you can go a little smart and call the flag by its element from the console in dev tools. The call looks very difficult to understand but its nothing complicated, all you need to do is just call the flag with its elementId: `alert box`, like this: ```javascript= console.log(document.getElementById('alertbox')) ``` **Flag Found**: [img](https://i.imgur.com/EmnW37d.png) {F1138715} ## Flag 3 This one is also fairly easy. The new directory provided to look for `/apps` is the key. (In the source however there are mysterious blank spaces) One can only see how the people are rated by grinch in `people-rater`. There are names. But if you look closely in the responses for the `people-rater` you will notice that each person has an ID base64 encoded of course. First in the list "Tea Avery" happens to have an id `eyJpZCI6MH0=` which when decoded is `{id:"2"}`, I wonder who `id:"1"` is. **Flag Found**: [img](https://i.imgur.com/gPAS5sH.png) {F1138715} ## Flag 4 This flag is rather trivial if not difficult to find. `Try and find a way to pull the Grinch's personal details from the online shop.` As the hint gives away to find about grinch and bypass login. So the first thought is to look in the source code, nothing in there just some simple JQuery, with rather funny id names: `alert alert-danger` kind of throws me off the game, lol!. Anyhow the key here is an enumeration. Look at the API, so I guessed the `user` path `sawg-shop/api/user`. But it throws in the: ```json= { "error":"Missing required fields" } ``` So I tried guessing params, nothing worked. So I ran `Arjun` a tool by som3d3v, to find missing params, luckily the UUID was the param I was looking for, what next? I thought of doing API brute-forcing. Using one of the seclist's API lists I ran it to the endpoint.....waiting.... It found another 200 OK response on sessions `sawg-shop/api/sessions`. There are various `keys` along with it, but there is one which is the longest which when decoded gives: ```json= { "user":"C7DCCE-0E0DAB-B20226-FC92EA-1B9043", "cookie":"NDU0ODI5MmY3ZDY2MjRiMWE0MmY3NGQxMWE0ODMxMzg2MGE1YWRhMTc0YjhkYWE3MzU1MjZjNDg5MDQ2Y2JhYjY3YTFhY2Q3YjBmYTk4N2Q5ZWQ5MWQ5OWFkNWE2MjIyZmZjMzZjMDQ3ODk5ZmI4ZjZjOWU0OGJhMjIwNmVkMTY=" } ``` Here we have got our `UUID` param value. **Flag Found**: [img](https://i.imgur.com/uDHRBGR.png) {F1138719} ## Flag 5 I see another login page but this time the hint is very specific telling us to `Try and find a way past the login page to get to the secret area.`. As usual, I go on for looking at any `hidden` fields if any in the source code, nothing apart from yet another **element named** `alert alert-danger`. So another brute force? I mean the hint was very obvious since it was telling if the username is valid or not. Pulling down the longest username list, I start a brute force. Nothing found, actually, there was, I just forgot to put grep in place. So `user found: access` what about the pass, I try again with a small list this time. 207p-probable password list, and coincidently it worked. ``` user: access password: computer ``` What next, once logged in there is this message.: ``` No Files To Download ``` Looking around the page, nothing. Check the responses, I see a cookie, I attach the cookie and then take it to `s3cr3t-ar3a`, nothing. what's next? Took a closer look at the cookie, so I try to decode it: ```json= {"cookie":"1b5e5f2c9d58a30af4e16a71a45d0172","admin":falsZX0%3D ``` Ah, so we need to fix the cookie. Fixing it with setting ``"admin":true}`` and refreshing it, we see the file: ``` my_secure_files_not_for_you.zip ``` I see a Zip file. At first, I thought it was a polyglot, but it's a normal zip file that is password protected. Another brute force? why not. I download the fcrackzip program, to brute force the list. Seeing how the main concept of the CTF was to teach brute force and not to test our wordlists, I took a more conventional approach, `rockyou.txt` ```bash fcrackzip -u -D -p rockyou.txt my_secure_files_not_for_you.zip ``` **"hahahaha" it worked, I am the ultimate hacker**. No its the password `hahahaha`. It took like a second to break, so I was right the theme was to test brute force and not wordlist. **Flag found**: [img](https://i.imgur.com/Wfwz7J7.png) {F1138721} ## Flag 6 Day 6, flag 6. We need to find the missing todo in the calendar. The site seems very nice, of course, nothing **Grinch** worthy todo, lol. So following the lines of previous CTFs, the only thing that seemed **SUS**(among us) `/my-diary/?template=entries.html`. *So drop your crocks and grab your socs, we have another brute force in our hand, Ffuf to rescue. Nope..... nothing.....* So my traditional wordlist failed, how about dirsearch, so I copied the dirsearch wordlist, fixed it with -D flag for FFuf to use and voila, `__index` worked. Very sneaky. So the source finally reveals itself. ```php= <?php if( isset($_GET["template"]) ){ $page = $_GET["template"]; //remove non allowed characters $page = preg_replace('/([^a-zA-Z0-9.])/','',$page); //protect admin.php from being read $page = str_replace("admin.php","",$page); //I've changed the admin file to secretadmin.php for more security! $page = str_replace("secretadmin.php","",$page); //check file exists if( file_exists($page) ){ echo file_get_contents($page); }else{ //redirect to home header("Location: /my-diary/?template=entries.html"); exit(); } }else{ //redirect to home header("Location: /my-diary/?template=entries.html"); exit(); } ``` Very clever, so the admin.php is renamed to `secretadmin.php` and moreover they get filtered out from string replace method but the flaw is its not recursive, Ahh! a well-crafted payload. [img](https://i.imgur.com/RxP3NpN.png) {F1138722} So somehow, we need to come up with a file name, that when stripped out of these matching keyword `admin.php` and `secretadmin.php`. The payload would look like: **secretadmsecretadmadmin.phpin.phpin.php** secretadmsecretadmadmin.phpin.phpin.php => secretadmsecretadm~admin.php~in.phpin.php => secretadm~secretadmin.php~in.php => secretadmin.php **Flag found**: [img](https://i.imgur.com/I7oYV56.png) {F1138723} ## Flag 7 This was also one of the trickiest flags I came across (till now). We start with `hate-mail-generator`, so in this stage, we have two options we can either view the `Guess What` link or create a hate mail campaign of our own. Hmm ``{{name}} & {{template: }}`` almost reminded me of `Handlebars` (a way of making dynamic webpages, where you would feed the variable names to a webpage of .hbs extensions). I knew something has to be up with it. Also while reviewing the `Create New`, I noticed there were two furthermore possibilities, preview or create (this always showed, `Sorry but you've run out of credits`), and with preview the name was always set to Alice, because of one of the hidden input field: ```htmlembedded= <input type="hidden" name="preview_data" value='{"name":"Alice","email":"[email protected]"}'> ``` A usual directory brute force using 'dirseach' to rescue again. The directory found `/templates`, which just confirmed my suspicions of handlebars, usage. Now to solve the flag we need to include the admin header `38dhs_admins_only_header.html`. [img](https://i.imgur.com/DZharLs.png) {F1138725} seeing the `Guess what` param it was clear that we have two ways of including the flag (`name`, `template:`), it seems 3 but the footer/header.html flags are the same. ```json= {{template:cbdj3_grinch_header.html}} Hi {{name}}..... Guess what..... <strong>YOU SUCK!</strong>{{template:cbdj3_grinch_footer.html}} ``` using the way ``{{temaplte:38dhs_admins_only_header.html}}`` in `create new` via `preview feature`, nothing. The other variable name, which I changed from Alice, to ``{{temaplte:38dhs_admins_only_header.html}}`` which looked something like this and viola.. ```json= {"name":"{{template:38dhs_admins_only_header.html}}","email":"[email protected]"} ``` **Flag Found:** [img](https://i.imgur.com/U49TH38.png) {F1138726} ## Flag 8 Ohk, not gonna lie, this was something unexpected. I knew there were only two users, but the passwords, I didn't know. A simple directory brute force scan on the CTF link, reveals another login page `/phpmyadmin` apart from the one `/login`. Time for some brute force, I took the small password lists and tried them with the combination of, but all in vain. ```json= { user: grinch password: $checking$ } and { user: max, password: $checking$ } ``` [Github](https://github.com/Grinch-Networks) source code, took some time to find it, after some hints from team-mates. The code looks clean and fine, but with recent commits. Inspecting further in the code, one can find 4 commits, go through each one by one, `small fix` caught my attention. The code snippet [img](https://i.imgur.com/qYHxsQE.png) {F1138727} I don't know PHP but after seeing `DbConnect` and several minutes of googling later, I thought of them being creds, so I tried logging in `phpmyadmin` page and it worked. Navigating to the user's section, we can find both users and their passwords. But passwords are MD5 hash encrypted. No worries brute force to rescue. [img](https://i.imgur.com/V5wAEZJ.png) {F1138728} Now, time to go back to `/login` page and log into Grinch's account. **Flag found**: [img](https://i.imgur.com/Rp2Xuno.png) {F1138729} ## Flag 9 On day 9, we find ourselves being tested by Grinch, no like literally, welcome to the evil quiz. I begin my testing with directory brute-forcing, nothing of any particular interest actually. How about taking the evil quiz, doesn't allow a name less than 3 chars, also is sensitive to `'or;` since on any other responses it would respond as `There is 1 other player(s) with the same name as you!` but in this, it responded with **I am not evil** and also `There is 0 other player(s) with the same name as you!` lol, I see, SQLi it is. So, the name gets perfectly reflected in the quiz area, it's after the `302 Found ` redirect when it reflects any change. Interesting, so in order to get a reflection, we need to use both the requests, I see. So I bring out every hacker's fav SQLmap... with a very difficult query ``` sqlmap -u https://hackyholidays.h1ctf.com/evil-quiz --data "name=archerl" -p "name" --method POST --second-url "https://hackyholidays.h1ctf.com/evil-quiz/score" --cookie="session=<YourCookie>" -D quiz --dump ``` It took like forever to end though, but it ended. So we have the creds from the very long SQLmap run ``` admin:S3creT_p4ssw0rd-$ ``` **Flag found**: [](https://i.imgur.com/EFAeTG6.png) {F1138731} ## Flag 10 We have another login, ever since the secure-login, I check for each stage's source code on Github lol. So we look at the source code while simultaneously running the directory brute forcing on the web app. => nothing. so we check the page source, and it's easy to miss at first but we see the ```htmlembedded= <!-- See README.md for assistance --> ``` comment, very sneaky. So we download the README File. `https://hackyholidays.h1ctf.com/signup-manager/README.md` [img](https://i.imgur.com/zDqQZ4y.png) {F1138732} Reading the contents of the `README.md` file, a zip file is being mentioned, can we download a zip file? Yeah we can `https://hackyholidays.h1ctf.com/signup-manager/signupmanager.zip` [img](https://i.imgur.com/SZGXcQ0.png) {F1138733} So we have downloaded the zip file and let's see if we can see the contents of it. (Update: Adam, reuploaded the zip file, spent an hour questioning my abilities to read PHP code) anyhow the new zip file has more files now and particularly index.php caught my attention so to be admin, we need a special cookie and the fact that `user.php` is available on sever that means `admin.php` has to be too, but to access that page we need a special cookie. How to get that cookie? as mentioned in `README.md` on line `6) You can make anyone an admin by changing the last character in the users.txt file to a Y` and also in the code ```php= if( isset($_COOKIE["token"]) ){ foreach( $all_users as $u ){ if( $u["cookie"] === $_COOKIE["token"] ){ if( $u["admin"] ){ $page = 'admin.php'; }else{ $page = 'user.php'; } } } } ``` How to set the admin value in function `build users` as Y? ```php= function buildUsers(){ $users = array(); $users_txt = file_get_contents('users.txt'); foreach( explode(PHP_EOL,$users_txt) as $user_str ){ if( strlen($user_str) == 113 ) { $username = str_replace('#', '', substr($user_str, 0, 15)); $users[$username] = array( 'username' => $username, 'password' => str_replace('#', '', substr($user_str, 15, 32)), 'cookie' => str_replace('#', '', substr($user_str, 47, 32)), 'age' => intval(str_replace('#', '', substr($user_str, 79, 3))), 'firstname' => str_replace('#', '', substr($user_str, 82, 15)), 'lastname' => str_replace('#', '', substr($user_str, 97, 15)), 'admin' => ((substr($user_str, 112, 1) === 'Y') ? true : false) ); } } return $users; } ``` [img](https://i.imgur.com/uD0f1tY.png) {F1138734} The question was how? though...after a lot of brainstorming, I saw the `intval()` function. ```php= if (!is_numeric($_POST["age"])) { $errors[] = 'Age entered is invalid'; } if (strlen($_POST["age"]) > 3) { $errors[] = 'Age entered is too long'; } $age = intval($_POST["age"]); ``` How to overflow it though? I tried many values like 999, 1000 but it threw the `'Age entered is too long'` because of the string length check. After more brainStorming `1e5` so the input becomes something like this, ``` age=1e5 and lastname=YYYYYYYYYYYYYYYYYYYYYYYYYYYYY ``` so many Y's are there to ensure the value of admin is set to Y, in case of overflow. `1e5` is a scientific notation and blows up to 100000, thats the way to enlargen the user_string and push Y to 113 with last name. Intercept the request and change the value of age and signup with new creds. [img17](https://i.imgur.com/UpkZTbA.png) {F1138735} Voila!! [img18](https://i.imgur.com/6FQBQ6W.png) {F1138736} ## Flag 11 This one by far was the most difficult one. I had to spring up a discord bot to keep track of the brute force. So we go to the `/r3c0n_server_4fdk59` on day 11, (for me its 30th December lol), We see `/api` as one of the endpoints, and some images arranged based on their years. 1. So first thing first as every CTF player does, API enumeration (fuzzing) and ExifTool analysis on the images. => nothing The images had a funny way of being fetched, they were rather `base64` encrypted: ``` eyJpbWFnZSI6InIzYzBuX3NlcnZlcl80ZmRrNTlcL3VwbG9hZHNcL2RiNTA3YmRiMTg2ZDMzYTcxOWViMDQ1NjAzMDIwY2VjLmpwZyIsImF1dGgiOiJiYmYyOTVkNjg2YmQyYWYzNDZmY2Q4MGM1Mzk4ZGU5YSJ9 ``` once decrypted it looks something like this: ```json= {"image":"r3c0n_server_4fdk59\/uploads\/db507bdb186d33a719eb045603020cec.jpg","auth":"bbf295d686bd2af346fcd80c5398de9a"} ``` So maybe this works like an auth? I attached it to my request as a `cookie= token=<value>` nothing. ### API (part) Upon visiting it we can notice there are a set of response codes and their meanings respectively. There are two parameters we can try something on `hash` and `data`. I tried for XSS, and SSRF nothing. At last, I tied SQLi with SQLmap and it worked. ``` sqlmap -u "https://hackyholidays.h1ctf.com/r3c0n_server_4fdk59/album?hash=jdh34k" --risk 3 --level 3 ``` [img19](https://i.imgur.com/R540OUq.png) {F1138737} The dumps provide us with nothing new. Bummer!! What's next? I thought of using the payload in the browser. I found a **XSS** thought this might get something lol, nothing **STEP 0**: The SQli ` https://hackyholidays.h1ctf.com/r3c0n_server_4fdk59/album?hash=hash=-7611%27%20UNION+SELECT%20NULL,NULL,%27%3Cscript%3Ealert(1)%3C/script%3E%27--%20- ` After some hints in the server and Adam himself, it was clear that SQLi with an SQLi has to be used to get an auth token from the server, and then some more help from my fellow hacker in Hacker101 discord, it came down to brute-forcing the API but with new set of generated auths. In simple terms: (SQLi, within an SQLi) **URL**=` https://hackyholidays.h1ctf.com/r3c0n_server_4fdk59/album?hash=8291%27+UNION+SELECT+%22%27+union+select+1,2,%27../api/something%27%23%22,null,null%23 ` This link will generate a response that will have a nonexsisting image, which would look like this ```htmlembedded= <div class="col-md-4"> <img class="img-responsive" src="/r3c0n_server_4fdk59/picture?data=eyJpbWFnZSI6InIzYzBuX3NlcnZlcl80ZmRrNTlcL3VwbG9hZHNcLy4uXC9hcGlcL3NvbWV0aGluZyIsImF1dGgiOiJiNGQ4ZTEzOWNkMWY4N2U5YjRmY2QyNmM2MmUyNzQyZiJ9"> </div> ``` which when decoded is nothing but ```json= {"image":"r3c0n_server_4fdk59\/uploads\/..\/api\/something","auth":"b4d8e139cd1f87e9b4fcd26c62e2742f"} ``` So every time **URL** is sent one has to extract the token from this `img` tag and send that again to search query in this fashion. **STEP 1**: Take the fuzzed URL URL=` ...link...hash=8291%27+UNION+SELECT+%22%27+union+select+1,2,%27../api/`**FUZZ**`%27%23%22,null,null%23 ` **STEP2**: Send the request to the website, from the response fetch the value of data from the img tag (`src` value), and then send the request again to capture the response. **STEP3**: Check for the response, we get "Expected HTTP status 200, Received: 400" as the response for most of the keywords, so the if the condition would be like anything but `Expected HTTP status 200, Received: 404 ` [img20](https://i.imgur.com/RLAz4iH.png) {F1138738} Using this method, found out that there exists two paths, one `user` and other `sleep` which threw `Invalid content type detected` [img21](https://i.imgur.com/C7Uo3DO.png) {F1138739} So now we have a valid path, what's next? maybe there are more paths to it => Nothing How about params? so the same URL as in STEP 1, but slight change. **STEP 4**: Take the fuzzed URL URL=` ...link...hash=8291%27+UNION+SELECT+%22%27+union+select+1,2,%27../api/user?`**FUZZ**`%27%23%22,null,null%23 ` repeat **step 2 and 3**, with a change that we are now getting `Expected HTTP status 200, Received: 400`. Using this method, found out that there exists two paths, one `username` and other `password` and `sleep` which threw `Invalid content type detected` [img22](https://i.imgur.com/65MkG4o.png) {F1138740} well now we have found two valid params, so I am assuming we need to fuzz for them as well. As a basic instinct, I tried for an SQLi -> nothing. but the URL did seem to be funny for `'` & `%` so I enumerated more, and came back to this stage after 3 days lol. So the catch is to use the alphabet appended by `%` that way one can guess whether or not the given word is a substring of the valid user or password. like for any alphabet + `%` like a `...link...user?username=a%..` the response would be like `Expected HTTP status 200, Received: 204`, so as always we go for if condition where the response is anything but `Expected HTTP status 200, Received: 204` and we find `g%` to be one of it. hmmm very interesting. so the wordlist for this would go like? **STEP5** a,b,c.....**g**..............ga...........**gr**...**gri**..........**grinch**.....**grinchadmin**.......grinchadmina....grinchadminaa so we know the user name is grinch, very funny... How about password? I am assmuing this would involve numbers, this ran for like a so long, lol. The wordlist looked like **STEP6** a,b,c,d,e,..**s**...s1,s2,s3,**s4**....**s4t**.....you know it finally ended on **s4nt4sucks**, typical Grinch! ``` grinchadmin:s4nt4sucks ``` So finally we have the ID and password lets go to the login in `/attack-box`, took me 7 days to figure this one out. **Flag found**: [img23](https://i.imgur.com/S8ouhJN.png) {F1138741} ## Flag 12 And finally few hours before the final deadline for the report submission, I try the flag 12. We have the Santa's IP addresses, like previous flag this also has some wierd URL fetch as well. The `base64` encoded value, I wonder what it could be. hash: ``` eyJ0YXJnZXQiOiIyMDMuMC4xMTMuNTMiLCJoYXNoIjoiMjgxNGY5YzczMTFhODJmMWI4MjI1ODUwMzlmNjI2MDcifQ== ``` decoded looks like this: ``` {"target":"203.0.113.53","hash":"2814f9c7311a82f1b822585039f62607"} ``` Hmmm, now as per HackerOne's tweet the hint is hash and the salt! so after brief thinking and playing with the hash, I tried finding out the salt using the brute force methodology. Hashcat to the rescue! we know what the hashes are for (assuming IPs, since its the only logical thing) and the salted hash. Using the wordlist rockyou.txt, it was matter of seconds for the hash to break. [img24](https://i.imgur.com/LhbGiKD.png) {F1138742} `mrgrinch463` is the salt. what next? we need to DOS Grinch right? we are on Santa's side. We need to encrypt the 127.0.0.1 address with salt to destroy ourselves (grinch's server). using this [website](http://md5.my-addr.com/md5_salted_hash-md5_salt_hash_generator_tool.php) we get the slated hash value. [img25](https://i.imgur.com/nFjTaAU.png) {F1138743} Time to generate the payload. ``` {"target":"127.0.0.1","hash":"3e3f8df1658372edf0214e202acb460b"} ``` The Grinch's server identified it as the localhost and abandoned the attack... so lets try IPv6 versioning, "localhost" => nothing! After several hints later in the discord channel, someone recommended the YouTube video of [Watch owning the clout from Nahamsec and daeken](https://www.youtube.com/watch?v=o-tL9ULF0KI).... DNS rebinding it is, still little shaky on the concept and several more hints later, but I knew what to do. Something on the grounds of, like xcy.com redirects to `127.0.0.1` like so 127.0.0.1 is blocked ...but a random domain is not, so that passes the localhost check...but if the domain later redirects to localhost, it will attack it. [img26](https://i.imgur.com/GuBijAO.png) {F1138744} After generating the URL for attack and respective hash ``` {"target":"01020304.7f000001.rbndr.us","hash":"69c31cdcfad3ef1deb652f4aca52d2cc"} ``` encoded `base64` version ``` eyJ0YXJnZXQiOiIwMTAyMDMwNC43ZjAwMDAwMS5yYm5kci51cyIsImhhc2giOiI2OWMzMWNkY2ZhZDNlZjFkZWI2NTJmNGFjYTUyZDJjYyJ9 ``` It doesn't work the first time and second time it redirects to 1.2.3.4.... hmmm [img27](https://i.imgur.com/jihbfMs.png) {F1138745} Time to attack the Grinch again! but wait for 15 seconds...lol So the 4th time the payload works and voila! **Flag Found**: [img28](https://i.imgur.com/wUZDrYw.png) {F1138746} ## Conclusion The CTF was not very easy, specially the last ones, but it was a thrill ride! Learned many things, intreacted with many talented people. Kudos to Adam and Ben for such a creative CTF! hats off!! I would love to win the best report challenge but I am content with the h1-ctf badge as well :) ## Impact Holidays Saved!
Actions
View on HackerOne
Report Stats
  • Report ID: 1069034
  • State: Closed
  • Substate: resolved
  • Upvotes: 4
Share this report