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

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
    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
    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 -E header=y | sort | uniq --count | sort --numeric --reverse
    285       lab.securitynik.local
      1 ip.src    

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
    285       Mozilla/5.0 (compatible; Nmap Scripting Engine;
    1   ip.src          http.user_agent

Looks like the device at 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
    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
    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
    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
      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
      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 -E header=y
ip.src      tcp.srcport     ip.dst     tcp.dstport  80         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,, | more  80

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

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='))"

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  == && (http.request.method == POST) && (http.request.uri == http.request.uri == "/lab/webapp/basicauth"))' -t ad | more
   28 2020-05-30 21:23:57.541751 → HTTP 265 POST /lab/w
ebapp/basicauth HTTP/1.1 
   50 2020-05-30 21:23:57.715894 → HTTP 300 POST /lab/w
ebapp/basicauth HTTP/1.1 
   52 2020-05-30 21:23:57.716791 → HTTP 304 POST /lab/w
ebapp/basicauth HTTP/1.1 
   54 2020-05-30 21:23:57.717297 → HTTP 304 POST /lab/w
ebapp/basicauth HTTP/1.1 
   56 2020-05-30 21:23:57.717872 → HTTP 304 POST /lab/w
ebapp/basicauth HTTP/1.1 
   58 2020-05-30 21:23:57.719344 → HTTP 304 POST /lab/w
ebapp/basicauth HTTP/1.1 
 3097 2020-05-30 21:24:02.422018 → HTTP 304 POST /lab/w
ebapp/basicauth HTTP/1.1 
 3098 2020-05-30 21:24:02.422234 → HTTP 304 POST /lab/w
ebapp/basicauth HTTP/1.1 
 3099 2020-05-30 21:24:02.422609 → HTTP 304 POST /lab/w
ebapp/basicauth HTTP/1.1 
 3100 2020-05-30 21:24:02.422823 → HTTP 304 POST /lab/w
ebapp/basicauth HTTP/1.1 
 3101 2020-05-30 21:24:02.423343 → HTTP 304 POST /lab/w
ebapp/basicauth HTTP/1.1 
 3102 2020-05-30 21:24:02.423554 → 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 == && (http.response.code == 200))' -t ad
  741 2020-05-30 21:23:58.779688 →    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. 


No comments:

Post a Comment