This post appeared originally in our sysadvent series and has been moved here following the discontinuation of the sysadvent microsite
A firewall activity plot
for showing port access. The temptation was
just a bit too great to ignore, so I chose to see it as a canvas for
artwork. All I should need to do is to convert a PNG image to series
of nmap
commands, easy right?
Plot size
First off, lets determine the actual size of the canvas – I mean plot. The graph area is 1040x417 pixels, but since the graph is logarithmic, the bottom part is not really usable, so I decide to limit the height to 237 pixels, which corresponds to port 80 and up. I need to find the logarithmic boundaries as well as the logarithmic value per vertical pixel, or “Y”:
Highest port available: log(65535) = 4.81647330376525
Lowest port I will use: log(80) = 1.90308998699194
Delta Y(port) = 65535-80 = 65455
Delta Y(log) = 4.81647330376525 - 1.90308998699194 = 2.91338331677331
Logarithmic value per pixel Y is: 2.91338331677331 / 65455 = 0.012292756610858
The coordinate system of a a PNG image starts at top left corner, so all port values have to be calculated from the top. A pixels Y value will therefor be calculated as:
Bottom margin (1.90308998699194) + ( height value (2.91338331677331) - ( pixel(Y) * 0.012292756610858 ) )
Use this as power to find the port: Port = 10^value
Although this may seem like high precision, the initial values are based on eyeballing, so we need to allow for some stretching in the final result.
It’s now easy to map each column in an image to ports, so the next step is to find the horizontal resolution. The plot is 1040 pixels wide, which spans exactly 24 hours, or 86400 seconds:
86400 sec / 1040 pixel = 83.0769230769231 sec/pixel
So I need to tickle the firewall every 83 seconds to get nice pixel values. The decimals can be ignored here, as the final script will introduce some delays anyway. After all, I’m drawing on a firewall, not trying to rescue Matt Damon from Mars…
Monochrome image
With the canvas in place, the next step is to prepare a monochrome PNG file from an image. The easiest type is an image with just 1 indexed colour. I created mine using Gimp, but I would think any decent image program would work.
Begin with creating a new image with the maximal usable size: 1040 x 237 pixels with transparent background. Now just draw what you want, using just one colour. Take care to use the top of the image as reference line. Then change the image mode to 1-bit “Indexed” (black and white). The transparent background should remain, and the single colour be white. Finally, crop the image to remove unneeded margins on the sides and bottom, but keep the top. Export as PNG.
Now, I used python to convert the image to a shell script. The code is not elegant, but it does the job.
#!/usr/bin/python
from PIL import Image
import math
inimage = "demo.png" # Hard coded filename
lowest = 1.90308998699194
deltay = 2.91338331677331
valuey = 0.012292756610858
target = "target.example.org"
im = Image.open(inimage) # Use im to find image size
pix = im.load() # Use pix to address individual pixels
print("#!/bin/bash")
for x in range(im.size[0]):
ports=[]
for y in range(im.size[1]):
if pix[x,y]==1:
ports.append(str(int(math.pow(10,(lowest+(deltay-(y*valuey)))))))
if ports:
print("nmap -4 -Pn -p {:s} {:s}".format(','.join(ports),target))
print("sleep 82") # nmap use around 1 second, so sleep the remaining 82.
Running the script
Now, run the python script and output to a shell script,
i.e. drawplot.sh
. Normally, nmap
needs to be run as root, so sudo
access is useful. Next to consider is when to run the script. I found
that on the target the plot is only updated once approx 20 minutes past every
hour. If the image is less than 40 pixels wide, it can fit within one hour,
and by starting it, say 22 minutes past the hour, the full image can appear
at once. Of course, if the image is wider, it will cover more than one hour,
and other start time concerns may be taken into account instead.
$ sudo at 16:22
at> drawplot.sh
All is left is to wait and see the results …
More colours
I know that IPv4 TCP-packets becomes green plots. The other colours are light blue for IPv4 UDP, red for IPv6 TCP, and white for IPv6 UDP. Not the greatest palette for artwork, and I’m no artist, but thought I would make a little something in the holiday spirit.
I’ll create a PNG image with four indexed colours on a transparent background,
making sure the colourmap is arranged correctly, and make a small addition
to the python script. One thing to remember is that each column will
consist of 0 to 4 nmap commands, so we cannot just sleep a constant
number of seconds between each. Adding a frequency variable, a column
counter, and calculating seconds using date
, should even out the
delays, averaging to one column every 83 seconds. Again, I’m not
trying to make the script elegant, it just has to work:
#!/usr/bin/python
from PIL import Image
import math
inimage = "xmastree.png" # Hard coded filename
lowest = 1.90308998699194
deltay = 2.91338331677331
valuey = 0.012292756610858
target = "target.example.org"
im = Image.open(inimage) # Use im to find image size
pix = im.load() # Use pix to address individual pixels
nmap_opts = [ None, "", "-sU", "-6", "-6 -sU" ]
print("#!/bin/bash")
print("FREQ=83")
print("START=$( date +%s )")
print("COLS=0")
for x in range(im.size[0]):
ports = [[],[],[],[],[]]
for y in range(im.size[1]):
port="{:d}".format(int(math.pow(10,(lowest+(deltay-(y*valuey))))))
colour = pix[x,y]
if colour >=1 and colour <=4:
ports[colour].append(port)
for colour in range(1,5):
if ports[colour]:
print("nmap {:s} -Pn -p {:s} {:s}".format(nmap_opts[colour],','.join(ports[colour]),target))
print("let COLS++")
print("sleep $(( ${START} + ${COLS} * ${FREQ} - $( date +%s ) ))")
As before, run the python script and output to shell script xmastree.sh
, and start that at a selected time…
Comparison of different compression tools
Working with various compressed files on a daily basis, I found I didn’t actually know how the different tools performed compared to each other. I know different compression will best fit different types of data, but I wanted to compare using a large generic file.
The setup
The file I chose was a 4194304000 byte (4.0 GB) Ubuntu installation disk image.
The machine tasked with doing of the bit-mashing was an Ubuntu with a AMD Ryzen 9 5900X 12-Core ... [continue reading]