Read the rules

Description

Please follow the rules for this CTF!

Connect here:
Read The Rules

Solution

All we have to do is view the source of the page and look for the flag.

<!-- Thank you for reading the rules! Your flag is: -->
<!--   flag{90bc54705794a62015369fd8e86e557b}       -->

Zip Zip

Description

My friend sent me this zip file… He is a prankster and compressed the file a LOT of times…
I don’t know how to make this go quickly and I don’t have the time… At least he told me the password is “pass”.
Can you please help?

Solution

Here we have a recursive zip file. So lets write a script to unzip each file.

#!/usr/bin/env python3

import zipfile

def unzip(file_name):
    with zipfile.ZipFile(file_name) as myzip:
        file = myzip.namelist()[0]
        password = b'pass'
        myzip.extractall('out', pwd=password)
        if '.zip' in file:
            print('Unzipping', file)
            unzip('out/' + file)
        else:
            print('No more zips found')

unzip('50.zip')

When all zip files are unzipped we get a flag.txt file.

[ blackarch ~/ctf/grimmctf/2020/warmups/Zip_Zip/out ]# ls
00.zip  06.zip  12.zip  18.zip  24.zip  30.zip  36.zip  42.zip  48.zip
01.zip  07.zip  13.zip  19.zip  25.zip  31.zip  37.zip  43.zip  49.zip
02.zip  08.zip  14.zip  20.zip  26.zip  32.zip  38.zip  44.zip  flag.txt
03.zip  09.zip  15.zip  21.zip  27.zip  33.zip  39.zip  45.zip
04.zip  10.zip  16.zip  22.zip  28.zip  34.zip  40.zip  46.zip
05.zip  11.zip  17.zip  23.zip  29.zip  35.zip  41.zip  47.zip
[ blackarch ~/ctf/grimmctf/2020/warmups/Zip_Zip/out ]# cat flag.txt 
flag{cf97382071cb149aac8d6ab8baeaa3ee}

Triple

Description

I was studying something called ASCII armor because I wanted to become better at encoding. I was having fun until I realized I couldn’t decode my message…

Ulc1amIyUnBibWNnWVNCdFpYTnpZV2RsSUdseklHRWdiRzkwSUc5bUlHWjFiaUIxYm5ScGJDQnBkQ0JwYzI0bmRDNGc= V20xNGFGb3pjM3BQVkd0M1RsZFJlVTFVVVRSYWFsSnRXa2RKTTFscVFYbE9WMDE1VFRKUk1rOUVVWGROUkU1cVdXNHdQUT09

Solution

Here we got two base64 encoded strings, lets decode them.

RW5jb2RpbmcgYSBtZXNzYWdlIGlzIGEgbG90IG9mIGZ1biB1bnRpbCBpdCBpc24ndC4gWm14aFozc3pPVGt3TldReU1UUTRaalJtWkdJM1lqQXlOV015TTJRMk9EUXdNRE5qWW4wPQ==

Seems like we have another base64 encoded string, lets check out the contents of this.

Encoding a message is a lot of fun until it isn't. ZmxhZ3szOTkwNWQyMTQ4ZjRmZGI3YjAyNWMyM2Q2ODQwMDNjYn0=

Ok, another one.

flag{39905d2148f4fdb7b025c23d684003cb}

Data dump

Description

Whew, this is a dumpster fire! Can you find anything interesting in here, like any cool passwords or anything? Dig through the dumpster quick, before the foxes and raccoons start eating at it!

Solution

For this challenge we got a compressed data dump. When we unpack it we get a lot of directoires. If we take a look in the home directory we can see a directory called challenge. In this directory we can find a .mozilla folder. Checking out the subfolders for firefox, we can locate a logins.json file containing a encrypted password.

{
  "nextId": 2,
  "logins": [
    {
      "id": 1,
      "hostname": "http://localhost:31337",
      "httpRealm": null,
      "formSubmitURL": "http://localhost:31337",
      "usernameField": "username",
      "passwordField": "password",
      "encryptedUsername": "MDIEEPgAAAAAAAAAAAAAAAAAAAEwFAYIKoZIhvcNAwcECPs50spbp6eyBAi0aCUHIntLPA==",
      "encryptedPassword": "MFIEEPgAAAAAAAAAAAAAAAAAAAEwFAYIKoZIhvcNAwcECEcjS+e6bXjFBCgCQ0p/1wCqPUmdgXdZWlohMXan4C3jD0bQgzsweyVEpAjJa+P9eOU4",
      "guid": "{9a363712-620c-499a-bb7d-999b8b2515dc}",
      "encType": 1,
      "timeCreated": 1604703907434,
      "timeLastUsed": 1604703907434,
      "timePasswordChanged": 1604703907434,
      "timesUsed": 1
    }
  ],
  "potentiallyVulnerablePasswords": [],
  "dismissedBreachAlertsByLoginGUID": {},
  "version": 3
}

So we should be able to use firepwd to decrypt this password. When we run firepwd with the logins.json file we get the decrypted password.

flag{35446041dc161cf5c9c325a3d28af3e3}

Memorandum

Description

I am so forgetful I have to write everything down.

Solution

For this challenge we get a binary blob. If we extract the strings from this we can find the flag.

strings -n 10 memorandum.bin | grep flag | tee grep.log

And in the grep.log file we can find the flag.

flag{e701f9290e2cd553be981461f8ea08e5}

Sentinel

Description

Only the password will grant access to the flag.

Solution

Here we have an Android app. Lets start by extracting the resources with apktool. In the file res\values\strings.xml we can find a encoded flag.

<string name="encrypted_flag">CVtQFwJcAFRFHAlUVRUdXQUHERgMVlMVSgoPUhUdDg4DRRpfAEw=</string>

If we base64 decode this we get the following in hex.

09 5b 50 17 02 5c 00 54 45 1c 09 54 55 15 1d 5d 05 07 11 18 0c 56 53 15 4a 0a 0f 52 15 1d 0e 0e 03 45 1a 5f 00 4c

Now it’s time to decompile the app with Bytecode Viewer to find out where the encrypted flag is used. When we have decompiled it we can see that it is obfuscated, but looking around the source we can find the following code.

package b.b.a.a;

import android.os.AsyncTask;
import android.util.Base64;
import com.congon4tor.sentinel.MainActivity;

public class a extends AsyncTask {
   public MainActivity a;

   public a(MainActivity var1) {
      this.a = var1;
   }

   public Object doInBackground(Object[] var1) {
      String[][] var2 = (String[][])var1;
      int var3 = 0;
      String var5 = var2[0][0];
      String var7 = var2[0][1];
      if (var7.length() != 5) {
         var5 = "Invalid password length";
      } else {
         byte[] var6 = Base64.decode(var5.getBytes(), 0);
         byte[] var8 = var7.getBytes();

         byte[] var4;
         for(var4 = new byte[var6.length]; var3 < var6.length; ++var3) {
            var4[var3] = (byte)((byte)(var6[var3] ^ var8[var3 % var8.length]));
         }

         var5 = new String(var4);
      }

      return var5;
   }

   public void onPostExecute(Object var1) {
      String var2 = (String)var1;
      super.onPostExecute(var2);
      this.a.p.setText(var2);
   }
}

It looks like the encrypted flag is being XOR:ed with a password with a length of five characters. Luckily for us, we know the first five characters of the plaintext. To get the password all we have to do is XOR flag{ with the first five bytes of the encrypted flag.

When we do this we get the password o71py. And using this to decrypt the complete flag we get the following.

flag{37e5efcded226aacabe3e8ceda925c07}

Axiom

Description

Things which are equal to the same thing are equal to one another.

Solution

This is another Android application. When we decompile this with Bytecode Viewer we can see that it is a React Native application. If we extract the resources with apktool we can find the JavaScript bundle in the assets directory.

Looking around in the bundle we can find an interesting function that has some strings mentioning the flag.

            function C() {
                var t;
                (0, u.default)(this, C);
                for (var n = arguments.length, l = new Array(n), s = 0; s < n; s++) l[s] = arguments[s];
                return (t = w.call.apply(w, [this].concat(l))).state = {
                    output: 'Insert the password to get the flag',
                    text: ''
                }, t.hash = 'c193e190062c69fb921332a8a5fc00317a3af35188c2a8f32a7c967d8a8f0d82', t.url = 'http://congon4tor.me:7777', t.token = '652W8NxdsHFTorqLXgo=', t.getFlag = function () {
                    return o.default.async(function (n) {
                        for (;;) switch (n.prev = n.next) {
                            case 0:
                                return n.prev = 0, n.next = 3, o.default.awrap(y.default.get(t.url + '/?token=' + t.token));
                            case 3:
                                response = n.sent, t.setState({
                                    output: response.data
                                }), n.next = 11;
                                break;
                            case 7:
                                n.prev = 7, n.t0 = n.catch(0), console.log(n.t0), t.setState({
                                    output: 'An error occurred getting the flag'
                                });
                            case 11:
                            case "end":
                                return n.stop()
                        }
                    }, null, null, [
                        [0, 7]
                    ], Promise)
                }, t.onChangeText = function (n) {
                    t.setState({
                        text: n
                    })
                }, t.onPress = function () {
                    t.hash === (0, x.sha256)(t.state.text) ? t.getFlag() : t.setState({
                        output: 'Invalid password'
                    })
                }, t
            }

From this we can see that the getFlag function calls the endpoint http://congon4tor.me:7777/?token=652W8NxdsHFTorqLXgo= and when we call this endpoint we get the flag.

flag{c62a673e0381ee32ec46282b94b2003a}

wannabeel33t

Description

We are chasing down a hacker, wannabeel33t and we watch to catch him red-handed. He keeps a low profile online, but he has to have some bad habits…

Solution

So we got the username. Lets use sherlock to find out on which social media platforms we might find him.

[*] Checking username wannabeel33t on:
[+] 500px: https://500px.com/p/wannabeel33t
[+] Badoo: https://badoo.com/profile/wannabeel33t
[+] Pling: https://www.pling.com/u/wannabeel33t/
[+] Realmeye: https://www.realmeye.com/player/wannabeel33t
[+] Reddit: https://www.reddit.com/user/wannabeel33t
[+] Travellerspoint: https://www.travellerspoint.com/users/wannabeel33t

We got some hits, but the most interesting of those are Reddit. Lets start there.

This looks like it might be the right place and the text looks like it’s URL encoded. Lets see what it says when we decode it.

flag{66b15347c58c91d1937f0b40e973d3f6}

Syringe

Description

Doctors love their databases! Here is a library of words and semantics relating to medical words, like “syringe”, or “x-ray”, or “injection”. Find whatever you need, just by searching for it!

Solution

For this challenge we got a web page with a single input field.

When we take a look at the source of the page we can find the following comment.

<!-- if ( isset($_GET["debug"])){ echo($sql_query); } -->

Lets add that to our URL. When we do this we can see the current SQL query for our search.

SELECT * FROM semantics WHERE name LIKE "%%";

Now we have to figure out a way to get the flag by SQLi. If we do a UNION SELECT from the table flag with the following search query f" UNION SELECT * FROM flag; # we get the flag.


fruitify

Description

Come grab a tasty freshly made juice, they are delicious

Solution

This challenge consists of a page with recipies for smoothies and juices.

Using Burp Suite we can see that there’s a request made to an endpoint called graphql when loading the page.

If we send this request to Repeater we can try to do some GraphQL introspection. If we change the request to {"operationName":"","variables":{},"query":"query {__schema{types{name,fields{name}}}}"} we get the following response.

{
  "data": {
    "__schema": {
      "types": [
        {
          "fields": [
            {
              "name": "id"
            },
            {
              "name": "image"
            },
            {
              "name": "ingredients"
            },
            {
              "name": "method"
            },
            {
              "name": "name"
            }
          ],
          "name": "Juice"
        },
        {
          "fields": null,
          "name": "String"
        },
        {
          "fields": [
            {
              "name": "defaultValue"
            },
            {
              "name": "description"
            },
            {
              "name": "name"
            },
            {
              "name": "type"
            }
          ],
          "name": "__InputValue"
        },
        {
          "fields": null,
          "name": "__TypeKind"
        },
        {
          "fields": [
            {
              "name": "flag"
            },
            {
              "name": "juice"
            },
            {
              "name": "juices"
            }
          ],
          "name": "Query"
        },
        {
          "fields": [
            {
              "name": "name"
            },
            {
              "name": "quantity"
            }
          ],
          "name": "Ingredient"
        },
        {
          "fields": null,
          "name": "__DirectiveLocation"
        },
        {
          "fields": [
            {
              "name": "deprecationReason"
            },
            {
              "name": "description"
            },
            {
              "name": "isDeprecated"
            },
            {
              "name": "name"
            }
          ],
          "name": "__EnumValue"
        },
        {
          "fields": [
            {
              "name": "args"
            },
            {
              "name": "deprecationReason"
            },
            {
              "name": "description"
            },
            {
              "name": "isDeprecated"
            },
            {
              "name": "name"
            },
            {
              "name": "type"
            }
          ],
          "name": "__Field"
        },
        {
          "fields": null,
          "name": "Int"
        },
        {
          "fields": [
            {
              "name": "directives"
            },
            {
              "name": "mutationType"
            },
            {
              "name": "queryType"
            },
            {
              "name": "subscriptionType"
            },
            {
              "name": "types"
            }
          ],
          "name": "__Schema"
        },
        {
          "fields": [
            {
              "name": "description"
            },
            {
              "name": "enumValues"
            },
            {
              "name": "fields"
            },
            {
              "name": "inputFields"
            },
            {
              "name": "interfaces"
            },
            {
              "name": "kind"
            },
            {
              "name": "name"
            },
            {
              "name": "ofType"
            },
            {
              "name": "possibleTypes"
            }
          ],
          "name": "__Type"
        },
        {
          "fields": null,
          "name": "Boolean"
        },
        {
          "fields": [
            {
              "name": "args"
            },
            {
              "name": "description"
            },
            {
              "name": "locations"
            },
            {
              "name": "name"
            }
          ],
          "name": "__Directive"
        }
      ]
    }
  }
}

Here we can see that there is a query called flag. Lets execute that query with this request {"operationName":"","variables":{},"query":"query flag {flag}"}, now we get the following response.

{"data":{"flag":"flag{5e4e716b08873b04ed7ee8c2d88a5a2e}"}}