Final exam: Problems

Due: Thursday, Dec 15 12:00PM

Introduction

TickTock Global Platforms, Inc. is under attack! An elite hacker going by the moniker fr3ddy has broken into TickTock’s servers and encrypted all of our files. He sent us a message to tell us he won’t give us back our files unless we pay a ransom.

We don't know who this mysterious hacker is or what he wants, but rest assured, we will find him!

We need you once again to help us recover from this attack, and to protect us from getting attacked in the future!

Problem selection

You only need to do two of the problems on this final! You should clearly indicate which two problems you wish to have graded.

There is no additional credit for answering more than two problems. If you answer more than two problems and don’t indicate which problems should be graded, then the first two problems you selected will be graded.

Instructions

You should read the following section before you start working on the problems.

For this exam, you will need to answer two of the following four problems. Make sure that it’s clear which of the problems you selected!

When you are finished, you should submit a writeup with your answers to the problems via Collab. You may submit your writeup under the “Final” assignment listed there; you can resubmit it as many times as you like before time runs out.

Question components: each problem contains an interactive component as well as a written component. The interactive component should be solved in Virginia Cyber Range; you can select one of the provided VMs to test your solutions to the problems. The written component can be solved without the use of VCR.

Your answers to the interactive component should clearly outline your methodology and any steps you took. For both parts of the problem, you should answer thoroughly and outline all necessary details using clear and concise language.

warning
The VMs that are available in Virginia Cyber Range for the final are all identical. I recommend using a different VM for each problem, so that a broken configuration on one machine doesn’t impact your ability to complete the other problem you’ve selected.

Partial answers: If you are unable to completely finish a problem in time, you should still write down whatever work you completed towards that problem. Partial credit will be given for incomplete solutions that make a lot of progress towards the correct answer.


Problem 1: Cryptography

The attacker encrypted all of our files with his ransomware. We didn’t feel like backing up our data (who wants to pay to store their data twice? Cloud storage is expensive 🤷), so we need you to figure out another way to get our data back.

Question 1.1 (4 points)

The attacker sent all of TickTock’s files over to http://crypto.fr3ddy.lab:1337 (accessible in Virginia Cyber Range). This host takes files uploaded from TickTock’s servers, and sends back encrypted versions to overwrite the originals.

By looking at similar attacks that this hacker has performed, we’ve deduced that they’re using the following code to encrypt our files. The encrypt function (shown below) gets called every time a file is sent to crypto.fr3ddy.lab:

import os
from base64 import b64encode
from cryptography.hazmat.primitives.ciphers.aead import ChaCha20Poly1305
from cryptography.hazmat.primitives.hashes import SHA256
from cryptography.hazmat.primitives.kdf.hkdf import HKDF

ikm = os.environ["CRYPTO_IKM"].encode("utf-8")
if len(ikm) < 32:
    raise RuntimeError("Input key material must be at least 32 bytes")

hkdf = HKDF(SHA256(), length=32, salt=b"", info=b"Encrypt")
CHACHA_KEY: bytes = hkdf.derive(ikm)

hkdf = HKDF(SHA256(), length=32, salt=b"", info=b"GenerateNonce")
NONCE_KEY: bytes = hkdf.derive(ikm)


def encrypt(filename: str, contents: bytes):
    cipher = ChaCha20Poly1305(CHACHA_KEY)
    filename_as_bytes = filename.encode("utf-8")
    hkdf = HKDF(SHA256(), length=12, salt=b"", info=filename_as_bytes)
    nonce = hkdf.derive(NONCE_KEY)
    ciphertext = cipher.encrypt(nonce, contents, filename_as_bytes)

    # Poly1305 tag is stored in the last 16 bytes of the
    # ChaCha20Poly1305 output
    ct, tag = ciphertext[:-16], ciphertext[-16:]
    return {"ciphertext": b64encode(ct), "tag": b64encode(tag), "filename": filename}

We’ve given you a file that was encrypted using this code; it is stored in

/usr/local/share/cs3710/encrypted_manifesto.txt.json

Identify a flaw in the way the attacker is performing encryption, and use it to decrypt the encrypted_manifesto.txt.json file. You should submit the decrypted file contents, and detail the steps you used to decrypt the file.

running tests
You can try encrypting files on fr3ddy’s encryption server by going to http://crypto.fr3ddy.lab:1337/docs, clicking the /crypto/encrypt tab, and then pressing Try it out. This will allow you to upload a file to the server and get back an encrypted version of it.

Question 1.2 (3 points)

What is the vulnerability in the code snippet above? As a defender, what would you do differently to protect against this vulnerability?

Hints

  • You can use the b64decode function to convert Base64-encoded data back into raw bytes, e.g.:
>>> from base64 import b64decode
>>> b64encoded_msg = "aGVsbG8sIHdvcmxkIQ=="
>>> b64encoded_msg_as_bytes = b64encode_msg.encode("utf-8")
>>> b64decode(b64encoded_msg_as_bytes)
b'hello, world!'
  • There is a Jupyter Notebook available (link) for you to play around with this code in your browser (note that CRYPTO_IKM is set differently from what the webserver uses, so encryptions generated in the notebook will be different from encryptions generated by the server).

Problem 2: Networking

Before we can bring our servers back online, we need to set up a firewall so that vulnerable services aren’t exposed to the outside world.

Question 2.1 (4 points)

TickTock runs a few different services to keep its site up and running. These include the TickTock web server, written in Python; a PostgreSQL database to store posts and user data; a MinIO server for static files and media; and a reverse proxy to log traffic and direct it to the create service. For this problem, we will write some firewall rules that allow other machines to connect to our web services and our Postgres database.

Create an nftables firewall that meets the following requirements:

  • Allow loopback connections: you should allow all traffic going from your machine back to itself.
  • Allow inbound HTTP(S): you should allow all HTTP and HTTPS traffic going from external hosts to your machine, so that they can access your webserver.
  • Allow inbound connections to PostgreSQL from the internal network: other hosts on TickTock’s internal network need to connect to the PostgreSQL database on your machine, which communicates on TCP port 5432. You should allow all traffic to the database that comes from an internal IP address in the range 10.0.0.0/8.
  • Allow outbound DNS and HTTP(S): the web server should still be allowed to send out DNS and HTTP/HTTPS requests.
  • Log dropped packets: you should log any packets that are dropped by your firewall.

You may structure your rules in any way you like, but all packets that are accepted must match one of the above conditions. You should build off of the base rules provided in

/usr/local/share/cs3710/base.nft

in your Virginia Cyber Range VMs.

warning
  • Do not run nft flush ruleset to delete existing firewall rules, or delete the filter table.

  • Do not delete any of the rules that are in the original version of base.nft that you are given.

Doing either of these may risk either locking you out of the VM or making it impossible to route traffic to the webserver. If you need to reset your firewall to its initial state, reboot your VM. You can find a copy of the original base.nft in the /usr/local/share/cs3710/backup directory.

Question 2.2 (3 points)

After setting up your firewall, things seem to go alright for a while. Suddenly, we notice a huge burst packets, most of which are being dropped. These are the logs that these packets are generating:

Dec 15 10:40:37 desktop.example.com kernel: input.drop: IN=eth0 OUT= MAC=0e:b7:1d:ef:04:fd:0e:09:d3:6b:95:97:08:00 SRC=10.1.56.72 DST=10.1.52.67 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=32433 DF PROTO=TCP SPT=44466 DPT=5900 WINDOW=62727 RES=0x00 SYN URGP=0 
Dec 15 10:40:37 desktop.example.com kernel: input.drop: IN=eth0 OUT= MAC=0e:b7:1d:ef:04:fd:0e:09:d3:6b:95:97:08:00 SRC=10.1.56.72 DST=10.1.52.67 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=23073 DF PROTO=TCP SPT=42770 DPT=1720 WINDOW=62727 RES=0x00 SYN URGP=0 
Dec 15 10:40:37 desktop.example.com kernel: input.drop: IN=eth0 OUT= MAC=0e:b7:1d:ef:04:fd:0e:09:d3:6b:95:97:08:00 SRC=10.1.56.72 DST=10.1.52.67 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=37492 DF PROTO=TCP SPT=38036 DPT=110 WINDOW=62727 RES=0x00 SYN URGP=0 
Dec 15 10:40:37 desktop.example.com kernel: input.drop: IN=eth0 OUT= MAC=0e:b7:1d:ef:04:fd:0e:09:d3:6b:95:97:08:00 SRC=10.1.56.72 DST=10.1.52.67 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=37897 DF PROTO=TCP SPT=56482 DPT=113 WINDOW=62727 RES=0x00 SYN URGP=0 
Dec 15 10:40:37 desktop.example.com kernel: input.accept: IN=eth0 OUT= MAC=0e:b7:1d:ef:04:fd:0e:09:d3:6b:95:97:08:00 SRC=10.1.56.72 DST=10.1.52.67 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=4962 DF PROTO=TCP SPT=40068 DPT=80 WINDOW=62727 RES=0x00 SYN URGP=0 
Dec 15 10:40:38 desktop.example.com kernel: input.drop: IN=eth0 OUT= MAC=0e:b7:1d:ef:04:fd:0e:09:d3:6b:95:97:08:00 SRC=10.1.56.72 DST=10.1.52.67 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=34695 DF PROTO=TCP SPT=56698 DPT=3306 WINDOW=62727 RES=0x00 SYN URGP=0 
Dec 15 10:40:38 desktop.example.com kernel: input.drop: IN=eth0 OUT= MAC=0e:b7:1d:ef:04:fd:0e:09:d3:6b:95:97:08:00 SRC=10.1.56.72 DST=10.1.52.67 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=26883 DF PROTO=TCP SPT=57852 DPT=139 WINDOW=62727 RES=0x00 SYN URGP=0 
Dec 15 10:40:38 desktop.example.com kernel: input.drop: IN=eth0 OUT= MAC=0e:b7:1d:ef:04:fd:0e:09:d3:6b:95:97:08:00 SRC=10.1.56.72 DST=10.1.52.67 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=37898 DF PROTO=TCP SPT=56482 DPT=113 WINDOW=62727 RES=0x00 SYN URGP=0 
Dec 15 10:40:38 desktop.example.com kernel: input.drop: IN=eth0 OUT= MAC=0e:b7:1d:ef:04:fd:0e:09:d3:6b:95:97:08:00 SRC=10.1.56.72 DST=10.1.52.67 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=26535 DF PROTO=TCP SPT=41658 DPT=995 WINDOW=62727 RES=0x00 SYN URGP=0 
Dec 15 10:40:38 desktop.example.com kernel: input.drop: IN=eth0 OUT= MAC=0e:b7:1d:ef:04:fd:0e:09:d3:6b:95:97:08:00 SRC=10.1.56.72 DST=10.1.52.67 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=37493 DF PROTO=TCP SPT=38036 DPT=110 WINDOW=62727 RES=0x00 SYN URGP=0 
Dec 15 10:40:38 desktop.example.com kernel: input.accept: IN=eth0 OUT= MAC=0e:b7:1d:ef:04:fd:0e:09:d3:6b:95:97:08:00 SRC=10.1.56.72 DST=10.1.52.67 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=56456 DF PROTO=TCP SPT=57046 DPT=443 WINDOW=62727 RES=0x00 SYN URGP=0 
Dec 15 10:40:39 desktop.example.com kernel: input.drop: IN=eth0 OUT= MAC=0e:b7:1d:ef:04:fd:0e:09:d3:6b:95:97:08:00 SRC=10.1.56.72 DST=10.1.52.67 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=14821 DF PROTO=TCP SPT=40286 DPT=2105 WINDOW=62727 RES=0x00 SYN URGP=0 
Dec 15 10:40:39 desktop.example.com kernel: input.drop: IN=eth0 OUT= MAC=0e:b7:1d:ef:04:fd:0e:09:d3:6b:95:97:08:00 SRC=10.1.56.72 DST=10.1.52.67 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=4226 DF PROTO=TCP SPT=46608 DPT=2107 WINDOW=62727 RES=0x00 SYN URGP=0 
Dec 15 10:40:39 desktop.example.com kernel: input.drop: IN=eth0 OUT= MAC=0e:b7:1d:ef:04:fd:0e:09:d3:6b:95:97:08:00 SRC=10.1.56.72 DST=10.1.52.67 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=1887 DF PROTO=TCP SPT=57414 DPT=3077 WINDOW=62727 RES=0x00 SYN URGP=0 
Dec 15 10:40:39 desktop.example.com kernel: input.drop: IN=eth0 OUT= MAC=0e:b7:1d:ef:04:fd:0e:09:d3:6b:95:97:08:00 SRC=10.1.56.72 DST=10.1.52.67 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=19133 DF PROTO=TCP SPT=35684 DPT=1 WINDOW=62727 RES=0x00 SYN URGP=0 
Dec 15 10:40:39 desktop.example.com kernel: input.drop: IN=eth0 OUT= MAC=0e:b7:1d:ef:04:fd:0e:09:d3:6b:95:97:08:00 SRC=10.1.56.72 DST=10.1.52.67 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=59201 DF PROTO=TCP SPT=42922 DPT=3878 WINDOW=62727 RES=0x00 SYN URGP=0 
Dec 15 10:40:40 desktop.example.com kernel: input.drop: IN=eth0 OUT= MAC=0e:b7:1d:ef:04:fd:0e:09:d3:6b:95:97:08:00 SRC=10.1.56.72 DST=10.1.52.67 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=60063 DF PROTO=TCP SPT=56580 DPT=1048 WINDOW=62727 RES=0x00 SYN URGP=0 
Dec 15 10:40:40 desktop.example.com kernel: input.accept: IN=eth0 OUT= MAC=0e:b7:1d:ef:04:fd:0e:09:d3:6b:95:97:08:00 SRC=10.1.56.72 DST=10.1.52.67 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=12335 DF PROTO=TCP SPT=40076 DPT=80 WINDOW=62727 RES=0x00 SYN URGP=0 
Dec 15 10:40:40 desktop.example.com kernel: input.drop: IN=eth0 OUT= MAC=0e:b7:1d:ef:04:fd:0e:09:d3:6b:95:97:08:00 SRC=10.1.56.72 DST=10.1.52.67 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=4532 DF PROTO=TCP SPT=50260 DPT=1455 WINDOW=62727 RES=0x00 SYN URGP=0 
Dec 15 10:40:40 desktop.example.com kernel: input.drop: IN=eth0 OUT= MAC=0e:b7:1d:ef:04:fd:0e:09:d3:6b:95:97:08:00 SRC=10.1.56.72 DST=10.1.52.67 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=48623 DF PROTO=TCP SPT=43640 DPT=4848 WINDOW=62727 RES=0x00 SYN URGP=0 
Dec 15 10:40:40 desktop.example.com kernel: input.drop: IN=eth0 OUT= MAC=0e:b7:1d:ef:04:fd:0e:09:d3:6b:95:97:08:00 SRC=10.1.56.72 DST=10.1.52.67 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=10400 DF PROTO=TCP SPT=41208 DPT=2009 WINDOW=62727 RES=0x00 SYN URGP=0 
Dec 15 10:40:40 desktop.example.com kernel: input.drop: IN=eth0 OUT= MAC=0e:b7:1d:ef:04:fd:0e:09:d3:6b:95:97:08:00 SRC=10.1.56.72 DST=10.1.52.67 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=16723 DF PROTO=TCP SPT=36528 DPT=9200 WINDOW=62727 RES=0x00 SYN URGP=0 
Dec 15 10:40:41 desktop.example.com kernel: input.drop: IN=eth0 OUT= MAC=0e:b7:1d:ef:04:fd:0e:09:d3:6b:95:97:08:00 SRC=10.1.56.72 DST=10.1.52.67 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=39799 DF PROTO=TCP SPT=60980 DPT=5033 WINDOW=62727 RES=0x00 SYN URGP=0

Assuming we didn’t do anything wrong or make any other changes, what could be causing this sudden activity? Does this behavior indicate that we’ve been compromised?

Your answer should explain in detail what could be triggering this kind of behavior. You should also justify whether or not you believe it could be indicative of a compromise, or otherwise concerning from a security perspective.


Problem 3: Access control

We can’t keep our servers down forever! Time is money. And for TickTock, a multinational conglomerate cornering the global timekeeping and time-related social media market, that’s a lot of money.

Question 3.1 (4 points)

Write an AppArmor profile to help sandbox the TickTock web servers.

There is an base AppArmor profile1 you can work off of in /etc/apparmor.d/ticktock.profile. The ticktock-web profile listed in this file automatically gets applied to the TickTock web server when it starts up.

If you want to try stopping and restarting the services used to run TickTock, you can run the following commands:

server start up
The TickTock web server may take 20 or so seconds before it’s completely started up.
cd /usr/local/share/cs3710

# Stop the servers
docker compose down

# Start the webservers
docker compose up -d

You should browse the TickTock website, which is running inside the Virginia Cyber Range machines at http://localhost, and thoroughly test its functionality. and thoroughly test its functionality. Your profile should include any permissions needed by the webserver and no others.

profile length restrictions
For this problem, it is possible (but extremely unnecessary) to generate a profile that is tens of thousands of lines long. In order to make it feasible to grade this problem, any AppArmor profile with more than 300 rules will not be accepted.

Hints

The web server that you are writing an AppArmor profile for is the same one that appeared all the way back in Labs 2 and 3. It is a Python-based web server running Gunicorn, which may help you a bit in figuring out what files it needs to access.

Question 3.2 (3 points)

TickTock is setting up its enterprise file sharing service, TUFF (TickTock’s Unbelievably Fast Files). Everyone who signs up will be assigned to a user on a Linux server, as well as a group that defines the “friends group” for that user. In addition, they will be given three directories:

  • /srv/<user>/public: files uploaded by the user that anybody should be allowed to see.
  • /srv/<user>/private: files uploaded by the user that only they should be able to see.
  • /srv/<user>/friends: files uploaded by the user that they and the people in their friends group should be able to see, but that nobody else has access to.

In all cases, only the owner of the files should be allowed to upload them to any of these directories.

For instance, suppose Alice is given the username alice, and her friends group is called alice-friends. Then she would be given three directories, /srv/alice/public, /srv/alice/private, and /srv/alice/friends. In terms of Linux access controls, each of these directories would be owned by alice and assigned to the group alice-friends:

$ tree -ug /srv
/srv
└── [alice alice-friends]  alice
    ├── [alice alice-friends]  friends
    ├── [alice alice-friends]  private
    └── [alice alice-friends]  public

How should the permissions be set on each of these directories (/srv/alice and its three subdirectories), as well as files under these directories, in order for TUFF to provide these access controls? Explain in detail.


Problem 4: Detection

We’ve analyzed the attack and identified some logs that were generated by our reverse proxy before and after it. We need you to help us detect this attacker the next time he infects our systems!

Question 4.1 (4 points)

We have a reverse proxy, Caddy, that we put in front of our webserver to log and redirect traffic. We’ve saved some of Caddy’s logs from before and during the attack to two directories:

  • /usr/local/share/cs3710/goodlog/: logs generated by standard, non-malicious web traffic before the attack.
  • /usr/local/share/cs3710/badlog/: logs generated by the attacker’s tools during the attack.

Each log file contains a record of traffic sent to the webserver. For instance, here’s the first log recorded in goodlog/normal.log.1:

$ head -n1 goodlog/normal.log.1
{"level":"info","ts":1671095313.9216814,"logger":"http.log.access","msg":"handled request","request":{"remote_ip":"172.25.1.1","remote_port":"47680","proto":"HTTP/1.1","method":"GET","host":"localhost","uri":"/","headers":{"Sec-Fetch-User":["?1"],"Accept-Language":["en-US,en;q=0.9"],"Cookie":[],"Sec-Ch-Ua":["\"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"108\", \"Google Chrome\";v=\"108\""],"Sec-Ch-Ua-Mobile":["?0"],"Upgrade-Insecure-Requests":["1"],"Accept":["text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9"],"Sec-Fetch-Site":["same-origin"],"Sec-Ch-Ua-Platform":["\"Linux\""],"Referer":["http://localhost/search?query=%27+or+1%3D1%3B+--"],"User-Agent":["Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36"],"Sec-Fetch-Mode":["navigate"],"Connection":["keep-alive"],"Sec-Fetch-Dest":["document"],"Accept-Encoding":["gzip, deflate, br"]}},"user_id":"","duration":0.036822772,"size":2259,"status":200,"resp_headers":{"Content-Type":["text/html; charset=utf-8"],"Content-Length":["2259"],"Vary":["Cookie"],"Date":["Thu, 15 Dec 2022 09:08:33 GMT"],"Server":["Caddy","gunicorn"]}}

… and a slightly prettier version of it, via the jq command:

$ head -n1 goodlog/normal.log.1 | jq -C
{
  "level": "info",
  "ts": 1671095804.031732,
  "logger": "http.log.access",
  "msg": "handled request",
  "request": {
    "remote_ip": "172.25.1.1",
    "remote_port": "58402",
    "proto": "HTTP/1.1",
    "method": "GET",
    "host": "localhost",
    "uri": "/",
    "headers": {
      "Sec-Ch-Ua": [
        "\"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"108\", \"Google Chrome\";v=\"108\""
      ],
      ... (cut out for space) ...
    }
  },
  "user_id": "",
  "duration": 0.004653378,
  "size": 2259,
  "status": 200,
  "resp_headers": {
    "Server": [
      "Caddy",
      "gunicorn"
    ],
    ... (cut out for space) ...
  }
}

As you can see, each log contains information about an HTTP request received by the webserver, including the IP address that sent the request, the HTTP method they used, the headers they sent, and so on. The log also contains information about HTTP data sent in the response.

Write one or more YARA rules to detect log files containing the malicious activity. Your rule(s) should only flag logfiles containing malicious activity, i.e. logfiles in badlog/, while ignoring log files with normal activity (those in goodlog/).

# Your rules should flag all of the files in this directory
yara -r rules.yar /usr/local/share/cs3710/badlog/

# None of the files in this directory should be flagged
yara -r rules.yar /usr/local/share/cs3710/goodlog/

Be sure to explain how you came up with the YARA rules that you wrote, and why you think they will be effective in detecting the attacker’s tools in the future. Your rules will be graded on their ability to accurately flag malicious activity while ignoring benign web traffic, as well as their applicability to future attempts to repeat this attack.

Question 4.2 (3 points)

important note
Instructor’s note: my apologies; your VMs do not have YARA installed on them by default. You can run sudo apt install -y yara to fix this.

The good news is that we’ve found all of fr3ddy’s malware on our systems and managed to remove it completely. The bad news is that we’ve figured out their command-and-control (C2) channel: TickTock’s own website!

I don't know about you, but something about this post seems a little off (and it isn't just my poor CSS).

It looks like the attackers were exfiltrating data from their implants by encrypting it in chunks, Base64-encoding those chunks, and then posting them on our website. That way, they could get data back to the operator while making it look like “normal” web traffic – because it was going back to our own web servers! Sneaky stuff.

How would you detect this kind of malware communication? You should consider various properties of these communications and how they differ from the normal messages that appear on TickTock’s website (which you can find by going to http://localhost in your Virginia Cyber Range machine). You should also consider the advantages and drawbacks of your method, such as whether somebody could (intentionally or unintentionally) trigger a false positive with it.

Your proposal will be graded on the basis of its accuracy in correctly flagging malicious communications while avoiding false positives; its technical feasibility; and on your ability to give a detailed and accurate assessment of its advantages and disadvantages.


  1. You can also find a read-only copy of this AppArmor profile in /usr/local/share/cs3710/backups/ticktock.profile, if you need to revert back to the original profile. ↩︎