Blog 2019

Linux Smart Enumeration 1.15


In the past days, there were a lot of improvements in the Linux Smart Enumeration script. Some of them were related to stability but most of them addressed some performance issues in certain scenarios.

Thanks to an issue opened last week (thanks @exploide) I started to investigate a serious performance problem that occurs when the user executing the script has thousands of writable files outside its home directory. In this case, LSE could take hours to finish do to how several checks were performed.

After some testing, I found some good alternatives to write the problematic tests and I ended up shorting the time (in my environment) from hours to 8 minutes.

In addition, I implemented a new option that allows the user to exclude paths from the tests. So if you know that the machine you are testing has a ton of files under, lets say, /mnt/backups, now you can use -e /mnt/backups so tests will skip that path. You can also specify several paths in a comma separated list: -e '/mnt/backups,/var/lib/mysql'.

After using this option in my environment, I improved the timing from the past 8 minutes to just 2 minutes while excluding a path with thousands of writable files for the user.

Of course, using the -e option will give less complete results, so use it with care.

A bit more about the problem

Several tests use the files found in test fst000 (writable files outside home directory) to find interesting files. For that they iterate over these writable files.

The problem was that in each iteration, the tests made some basic checks like, before doing anything, confirm that the file exists with [ -f "$w_file" ]. This apparently innocent call worked just fine in systems with a few hundreds of writable files found, but when several thousands are found, then this call hits really hard, performance wise.

The solution was to work only with the path strings until we have a positive match for the specific test and only then check if the file exists. Now it seems pretty obvious :).

Happy Hacking!

Fri, 20 Dec 2019 12:31

Drupal Security


The last couple of years have been hard for the Drupal team, with several highly critical vulnerabilities in the Drupal Core. First it came SA-CORE-2018-002 in March 2018, which was commonly known as drupalgeddon2. Not even a month later we had another round with SA-CORE-2018-4. After some other critical vulnerabilities we found another highly critical at the begining of this year: SA-CORE-2019-003.

Yesterday, we had a batch of critical and moderately critical updates that you should patch as soon as you can. It is in these cases where you are glad to be running some sort of WAF that creates an additional layer of protection against attacks.

Drupal vs Wordpress security

One might think that after seeing these Drupal vulnerabilities published it would be better off using Wordpress. After all, you don't see any security advisory from Wordpress. How is that possible? Because Wordpress does not any kind of differentiation between regular and security updates. That means that you don't know if the next update is "highly critical" or just a "minor fix" so you cannot plan accordingly. Updating software always risks to break something so many follow the rule: if it works, don't touch it. However, this rule falls appart when the security of your site and users is at stake, so you better know if it works safely.

Besides that, Wordpress does not have a security advisory page where to publish the security updates like Drupal has. Drupal even has one for its contributed projects. For Wordpress you have to rely on a third party service like wpvulndb that, althought it is awesome, it is a shame that a basic service like this is not offered by Wordpress itself.

Thanks to this control over updates and security, the Drupal admin panel will show the user when security updates are pending and it will let you know very clear that they should be applied as soon as possible.

So if you hear more about Drupal than Wordpress security problems is, in part, because the Drupal team has way more control over their security. For this reason I think Drupal is better at securing their software than Wordpress is.

Thu, 19 Dec 2019 12:37

Nginx Cache Purge


For a while I've been looking for a proper solution to purge the cache of one or several entries in my nginx servers.

The solutions I found were either the commercial ones or some lua modules that didn't look very solid and actually had some security vulnerabilities.

I know that there are projects like ngx_cache_purge, which is even packaged for the official debian repositories, but it does not allow the use of wild cards to purge cache entries.

I already had my own solution using some trickery with cache_bypass to be able to clear the cache of a single URL, but I wanted more.

As I already had some experience with ngx_lua from my nginx_waf module, I decided to create my own lua module to purge caches that allows me to purge both single and multiple entries. It is also easy to deploy and very versatile in the ways you can set it up.

It can work very similar to the commercial solution but of course the performance will be a bit worse and it is for sure not as elegant.

Performance shouldn't be a big issue when clearing caches, but I did the best I could to improve response times in balance with setup easiness and versatility.

In any case it gets the job done with a reasonable performance and security.

Please check it up here:

Wed, 11 Dec 2019 17:46

Quick temporal VPN


Sometimes I need to access an internal network or server where a customer hosts their services. This internal network is usually behind some firewall that allows generally unrestricted outgoing traffic but blocks incoming connections or lacks of any NAT configuration.

It would look something like this.

INTERNET           ║             LAN
                ╭──╨───╮      ╭───────╮
                ╰──╥───╯    │ ╰───────╯
                   ║        │
                   ║        │ ╭───────╮
                   ║        ├─┤server2│
                   ║        │ ╰───────╯
                   ║        │
                   ║        │ ╭───────╮
                   ║        ╰─┤server3│
                   ║          ╰───────╯

In these cases, you need some setup that allows you to connect to these servers and that is simple, mostly on the customer side. Ideally allowing a non-technical person on the client side to follow just a couple of easy steps.


You need a server with a public IP. If you already have one you can even have a permanent setup. If not you hire an inexpensive VPS in many hosting providers for $5/month or even less. Let's call this host myhost.

This server needs to have a user account that allows Port Forwarding via SSH, which is allowed by default in most distributions. To secure the account you can assign to it the /bin/true shell, so it can login but not execute commands. In this example, the user will be called tunnel.

root@myhost:~# adduser --no-create-home --shell /bin/true  --gecos '' tunnel

Now you ask a person with access to any server in the internal network to execute the following command and provide him or her with the password for the tunnel user.

user@server2:~$ ssh tunnel@myhost -N -R 1080

This command will not provide any output and will stay there as if nothing happens. However, in the background it is using SSH to create a remote SOCKS proxy in your server, listening in localhost and port 1080

INTERNET           ║             LAN
                ╭──╨───╮      ╭───────╮
   │            ╰──╥───╯    │ ╰───────╯
   ▼               ║        │
╭──────╮           ║        │ ╭───────╮
│myhost│           ║        ├─┤server2│
╰──────╯           ║        │ ╰───────╯
                   ║        │
                   ║        │ ╭───────╮
                   ║        ╰─┤server3│
                   ║          ╰───────╯

Now in your server you can access the internal network using localhost:1080 as a SOCKS proxy.

The easiest way to do this is to install tsocks.

root@myhost:~# apt install tsocks

Once installed, edit /etc/tsocks.conf like this:

# Remove any "local =" or other "local" variable lines
server = localhost
server_type = 5
server_port = 1080

Now you can enable the access to the internal network in one of your server shells with.

root@myhost:~# . tsocks -on

After this command, you will be able to access any server in the internal network just like if you were inside the network.

root@myhost:~# ssh root@server3
root@server3:~# exit
root@myhost:~# ssh root@server1

I hope you find this trick useful. Keep in mind that once you have this setup in your end, the other end only needs to execute one command.

Fri, 06 Dec 2019 16:46

Checking Access Log Files


From time to time you need to check the access log of some of your servers right? Sometimes you want to find if or why something is wrong and sometimes you just want to gather some data (to understand if or why something is wrong).

Here are some neat tools and commands I use to check the access log files of my servers.


I love console based and pretty looking tools and for sure goaccess is one of those.

This tool allows you to see what is going on in your website giving you some stats and some information about your visitors. There you can see what are the most requested urls, the amount of visitors per day, the hours where you get more traffic, referrers, etc.

You can run it with

goaccess -f /var/log/nginx/access.log

And it basically looks like this:


However it also provides an HTML interface so you can periodically generate a static HTML page to check the stats in an more graphical format.


The name says it all: it is a top command for apache. However, as it requires an access.log file as input, you can also use it with nginx as long as you keep the common log format.

One of the features that I like about this command is that it will show the current rate of requests per second, averaging both since the command started and in an specified interval (default 30s). It will also show the most requested urls and other stats.

You can run it with

apachetop -f /var/log/nginx/access.log

And it looks like this:



Yes... grep and friends help me a lot to find useful information and stats.

Let me show you some examples.

$ zgrep -Poh '" \d{3} ' access.log* | sort | uniq -c | sort -rn

196071 " 200
 30397 " 302
  3928 " 404
   590 " 301
   339 " 304
    48 " 502
    38 " 470
    32 " 499
    27 " 504
    24 " 500
    18 " 400
     9 " 418
     4 " 405
     2 " 206
     1 " 403
$ zgrep -Poh '\d{2}/Nov/2019' access.log* | sort | uniq -c
[ ... ]
1601 21/Nov/2019
1603 22/Nov/2019
1552 23/Nov/2019
1517 24/Nov/2019
1601 25/Nov/2019
1545 26/Nov/2019
1624 27/Nov/2019
1615 28/Nov/2019
1542 29/Nov/2019
1527 30/Nov/2019
$ zgrep -Poh '03/Dec/2019:\d{2}' access.log* | cut -d' ' -f1 | sort | uniq -c
  63 03/Dec/2019:00
  66 03/Dec/2019:01
  61 03/Dec/2019:02
  64 03/Dec/2019:03
  62 03/Dec/2019:04
  65 03/Dec/2019:05
  61 03/Dec/2019:06
  60 03/Dec/2019:07
  73 03/Dec/2019:08
  73 03/Dec/2019:09
  73 03/Dec/2019:10
  64 03/Dec/2019:11
 164 03/Dec/2019:12
 137 03/Dec/2019:13
 135 03/Dec/2019:14
  93 03/Dec/2019:15
 103 03/Dec/2019:16
 195 03/Dec/2019:17
 145 03/Dec/2019:18
 139 03/Dec/2019:19
  94 03/Dec/2019:20
 114 03/Dec/2019:21
 109 03/Dec/2019:22
 106 03/Dec/2019:23
$ zgrep -Poh '.* \[03/Dec/2019.*\] "HEAD ' access.log* | cut -d' ' -f1 | sort | uniq -c | sort -rn

I know what you are thinking: "This guy has no traffic at all" ... and you are right. This server has almost not traffic.

Jokes aside, I hope you can see that you can make different combinations of the above commands, or change some parameters to obtain the information you are looking for in a very easy way.

ansible -o -m shell -a "zgrep -h  '\"GET /public/awesome_85.03.img' /var/log/nginx/public.access.log* | egrep 'ROUTERCOM' | grep '\" 200' | egrep '/Nov/2019' | awk '{ print \$1\" \"\$9 }' | sort | uniq | wc -l" 'frontends:!TRASH' | awk '{sum += $8} END {print sum}'

This is based in a real case. It looks in all the frontends servers defined in the Ansible inventory (that are not in the TRASH group) for successfull downloads (code 200) using the user agent "ROUTERCOM" during November 2019 of the firmware awesome_85.03.img and then gets the output from ansible and sums all the values, returning single number of downloads: 217.

Wed, 04 Dec 2019 18:48

NGINX Web Application Firewall


For a long time I looked for a WAF (Web Application Firewall) for my nginx installations. As a systems administrator that installs web applications from developer teams with very different degrees of attention to security, a WAF is a must in every installation.

Why to use a WAF?

Installing a WAF helps to frustrate attack attempts. It will prevent the exploitation of some vulnerabilities present in the underlying web application and also discourage some lazy attackers who will prefer to switch to an easier target. You might even save some bandwidth from deterring these attacks.

However, a WAF is not a fix for web vulnerabilties so if you know your web application has security issues, you must fix them. Installing a WAF will certainly obstruct the exploitation, but in the long run your website will be compromised.


There are several options for securing our nginx.

We can use naxsi, however it requires some "training" to find the rules that we must whitelist and this might be a long process and it is very specific to each installation. I prefer an easy configurable WAF that it just works after it is installed.

We can also use mod_securty for nginx, but we would need to compile it specifically for our installations and take care of its maintenance each time we update nginx so it is not very practical.

There are some other custom options using ngx_lua but none of them was exactly what I wanted. However, I was inspired by them and I ended up writing my own WAF.

I wanted it to be configurable and have options to whitelist rules and IPs. I also wanted it to be fast, so ngx_lua looked like a great option.

This is why I created nginx_waf:

I've been using it for more than a year now and it has certainly blocked a ton of attacks, which can be seeing in its log file. I am very happy with the results and I plan to continue to improve it.

Please, feel free to use it and sent questions or requests via the GitHub issue tracker. All the information regarding how to use it and install it is in the repository.

Tue, 03 Dec 2019 13:12

Linux Smart Enumeration


I've been learing a lot about cyber security during the last couple of years. Reading some books, testing stuff, practicing in platforms like vulnhub or hackthebox, etc. One of the problems I found during the privilege escalation phase, when I gained a shell into a linux machine, is the lack of a tool that finds important security problems that I can exploit to gain further access.

One of the tools I use for local enumeration in linux is LinEnum, which is great and shows a lot of information about the system you are in. However, for me, the feature that I missed was some kind of filtering about the information. A way to see clearly if there is something specially vulnerable or poorly configured in a system. In other words, I wanted some information filtering and blinking arrows pointing towards critical exploitable vulnerabilities.

For this reason I started to see if I could contribute to the LinEnum project adding this feature, but eventually I realized that it was too complex to change LinEnum as it required a heavy code refactoring to add different levels of verbosity. For that reason I ended up coding linux-smart-enumeration, or lse.

With lse, you have several verbosity levels. In the default level (level 0), you basically see the most important information that you can use in a privilege escalation. It will use nice coloring so it is easy to see the different vulnerabilities.

In case you dont see anything important in level 0 verbosity, you can switch to level 1. Here you will see the "important stuff" that might not have been automatically detected in level 0.

Finally you have level 2, that basically dumps everything about the system that this tool gathers.

You can also select exactly what tests to execute, individually or by sections.

Please, check the lse github for more information.

Here is a video of the tool in action so you can see a bit of what it does and how it looks.

Fri, 22 Nov 2019 00:46