Sunday, June 23, 2013

Autosnort-CentOS progress -- SELinux, ROR, passenger, and Snorby all working in Harmony

I've been working pretty hard on getting The CentOS autosnort build up to par with the Debian and Ubuntu autosnort builds, and for the most part, I'm nearing the end of the road there.

Aside from work and my regular everyday life, I've been spending my weekends mostly working on getting Snorby to run on CentOS with SELinux enabled. I'm a firm believer that in this day and age you shouldn't have to turn off SELinux to make your application work.

According to Wikipedia, SELinux has been around since the year 2000 and mainlined into the 2.6 kernel since 2003. It's been close to over ten years since SELinux was rolled out. Turning it off isn't a solution. It's a work-around, and pardon my french, an incredibly shitty and lazy work-around at that.

Now, I've made it no secret that I do not like ROR at all. This could be for a number of reasons -- I'm a newb programmer, I haven't developed webapps, I don't know what I'm talking about -- take your pick. Do not take this as a personal attack if you love ROR for one reason or another. Ruby OTOH has given us pretty interesting things, such as the Metasploit Framework.

In troubleshooting this how to get Snorby and SELinux to behave I had to learn how to write SELinux policy modules. As a side note, I would like to thank whoever on github posted this gist:

The code that I am dropping below is HEAVILY based on this individual's work getting passenger to work under SELinux without turning it off. I don't know who you are, but I salute you.

Let me give you a bit of background. SELinux is incredibly modular, there are several different ways you can tell SELinux to allow an application to do certain things, access certain resources, etc. You can use chcon to tell SELinux to allow a process to access files (think of this as another layer on top of the file access controls that we all know and love with chmod/chown), there are booleans you can set that, almost windows registry-like tell SELinux to allow a process to be able to interact with a mysql database or connect over the network.

Then there is the ability to write your own modules via selinux development tools to load into SELinux and in turn load into the kernel. You would generally do this if the application is very complex and needs to get its hands into a lot of places.

The research I did on this over the weekend varied. Most places suggest just running the application over and over again -- each iteration, just running audit2allow to determine what it is that httpd wants access to and building a policy module out of it.

I kept doing this, and more and more things would be allowed, then of course, the next thing in the way would break. It felt like dependency hell all over again.

Eventually I found that block of code by someone who had apparently been here before and decided to iterate through audit2allow probably hundreds of times to develop a single policy for passenger. I took it, ran with it, and improved it. Over the last few evenings I expanded upon it, and finally got Snorby to a point to where it will run with 0 errors and full functionality with SELinux enforcing and in targeted mode.

Have a look; I'll be posting this code to github soon, but I wanted to copy it here just to give you an idea of what the hell this application has access to on your system:

### begin code ###
module passenger 1.0;

# Not an expert at SELinux module building, but this is similar to library declarations in C programming -- these are things that the module needs to be able to do and contexts the module needs to be able to understand/communicate with

require {
        type init_t;
        type initrc_t;
        type system_cronjob_t;
        type mysqld_t;
        type usr_t;
        type syslogd_t;
        type system_dbusd_t;
        type abrt_dump_oops_t;
        type dhcpc_t;
        type kernel_t;
        type auditd_t;
        type udev_t;
        type mysqld_safe_t;
        type postfix_pickup_t;
        type sshd_t;
        type crond_t;
        type getty_t;
        type anon_inodefs_t;
        type httpd_tmp_t;
        type devpts_t;
        type user_devpts_t;
        type httpd_sys_script_t;
        type security_t;
        type httpd_t;
        type unconfined_t;
        type selinux_config_t;
        type hi_reserved_port_t;
        type httpd_sys_content_t;
        type httpd_sys_rw_content_t;
        type var_t;
        type cert_t;
        type postfix_qmgr_t;
        type postfix_master_t;
        class file { getattr read create append write execute execute_no_trans open };
        class process { siginh signal noatsecure rlimitinh setpgid getsession };
        class unix_stream_socket { read write shutdown };
        class chr_file { read write append ioctl };
        class capability { setuid dac_override chown fsetid setgid fowner sys_nice sys_resource sys_ptrace kill };
        class fifo_file { setattr create getattr unlink };
        class sock_file { write getattr setattr create unlink };
        class lnk_file { read getattr };
        class udp_socket name_bind;
        class dir { write read search add_name getattr };

#This stuff below is more of an access control list -- these are things the contexts below are requesting to be able to do in order to run properly.
#============= httpd_sys_script_t ==============
allow httpd_sys_script_t abrt_dump_oops_t:dir { search getattr };
allow httpd_sys_script_t abrt_dump_oops_t:file { read open };
allow httpd_sys_script_t anon_inodefs_t:file { read write };
allow httpd_sys_script_t auditd_t:dir { search getattr };
allow httpd_sys_script_t auditd_t:file { read open };
allow httpd_sys_script_t cert_t:dir { search getattr };
allow httpd_sys_script_t cert_t:file { read getattr };
allow httpd_sys_script_t cert_t:lnk_file read;
allow httpd_sys_script_t crond_t:dir { search getattr };
allow httpd_sys_script_t crond_t:file { read open };
allow httpd_sys_script_t devpts_t:chr_file { read write };
allow httpd_sys_script_t dhcpc_t:dir { search getattr };
allow httpd_sys_script_t dhcpc_t:file { read open };
allow httpd_sys_script_t getty_t:dir { search getattr };
allow httpd_sys_script_t getty_t:file { read open };
allow httpd_sys_script_t httpd_sys_content_t:fifo_file setattr;
allow httpd_sys_script_t httpd_sys_content_t:sock_file { create unlink setattr };
allow httpd_sys_script_t httpd_sys_rw_content_t:file { execute execute_no_trans };
allow httpd_sys_script_t httpd_t:dir { search getattr };
allow httpd_sys_script_t httpd_t:file { read open };
allow httpd_sys_script_t httpd_t:unix_stream_socket { read write };
allow httpd_sys_script_t httpd_tmp_t:fifo_file setattr;
allow httpd_sys_script_t httpd_tmp_t:sock_file { write create unlink setattr };
allow httpd_sys_script_t init_t:dir { search getattr };
allow httpd_sys_script_t init_t:file { read open };
allow httpd_sys_script_t initrc_t:dir { search getattr };
allow httpd_sys_script_t initrc_t:file { read open };
allow httpd_sys_script_t kernel_t:dir { search getattr };
allow httpd_sys_script_t kernel_t:file { read open };
allow httpd_sys_script_t mysqld_safe_t:dir { search getattr };
allow httpd_sys_script_t mysqld_safe_t:file { read open };
allow httpd_sys_script_t mysqld_t:dir { search getattr };
allow httpd_sys_script_t mysqld_t:file { read open };
allow httpd_sys_script_t postfix_master_t:dir { search getattr };
allow httpd_sys_script_t postfix_master_t:file { read open };
allow httpd_sys_script_t postfix_pickup_t:dir { search getattr };
allow httpd_sys_script_t postfix_pickup_t:file { read open };
allow httpd_sys_script_t postfix_qmgr_t:dir { search getattr };
allow httpd_sys_script_t postfix_qmgr_t:file { read open };
allow httpd_sys_script_t self:capability { setuid chown fsetid setgid fowner dac_override sys_nice sys_resource sys_ptrace kill };
allow httpd_sys_script_t self:process { setpgid getsession };
allow httpd_sys_script_t sshd_t:dir { search getattr };
allow httpd_sys_script_t sshd_t:file { read open };
allow httpd_sys_script_t syslogd_t:dir { search getattr };
allow httpd_sys_script_t syslogd_t:file { read open };
allow httpd_sys_script_t system_cronjob_t:dir getattr;
allow httpd_sys_script_t system_dbusd_t:dir { search getattr };
allow httpd_sys_script_t system_dbusd_t:file { read open };
allow httpd_sys_script_t udev_t:dir { search getattr };
allow httpd_sys_script_t udev_t:file { read open };
allow httpd_sys_script_t unconfined_t:dir { search getattr };
allow httpd_sys_script_t unconfined_t:file { read open };
allow httpd_sys_script_t unconfined_t:process signal;
allow httpd_sys_script_t user_devpts_t:chr_file { read write append ioctl };
allow httpd_sys_script_t usr_t:file execute;
allow httpd_sys_script_t var_t:dir { write read add_name };
allow httpd_sys_script_t var_t:file { read getattr create append };
#============= httpd_t ==============
allow httpd_t hi_reserved_port_t:udp_socket name_bind;
allow httpd_t httpd_sys_content_t:fifo_file { create unlink getattr setattr };
allow httpd_t httpd_sys_content_t:sock_file { getattr unlink setattr };
allow httpd_t httpd_sys_script_t:process { siginh rlimitinh noatsecure };
allow httpd_t httpd_sys_script_t:unix_stream_socket { read write shutdown };
allow httpd_t httpd_tmp_t:fifo_file { create unlink getattr setattr };
allow httpd_t httpd_tmp_t:sock_file { getattr unlink setattr };
allow httpd_t security_t:dir search;
allow httpd_t self:capability { fowner fsetid };
allow httpd_t selinux_config_t:dir search;
allow httpd_t var_t:file { read getattr };
allow httpd_t var_t:lnk_file { read getattr };

### end code ###

Admittedly there are a number of things above that make sense that Snorby would need access to -- sockets, file execution, making its own fifos, managing its own files and process execution options, etc. but then there are other things that just made me go WTF. Why does the webapp need access to crond? to getty sessions? pts? sshd? cronjobs? files and directories under the unconstrained context? dhcp files? auditd files?

I could be blowing this entirely out of proportion, but I worked with snortreport, BASE and aaval, and there were a minimal number of things I had to enable to get each of those interfaces to work under SELinux. Maybe PHP is just better integrated into SELinux, or maybe SELinux knows that PHP is beyond hope and doesn't even try to constrain it. I don't know, but reading through the module and seeing what it has access to is kinda crazy to me.

Okay, so now that I'm off my soapbox, you're probably wondering when to expect a code push for CentOS.

The answer is: soon. I know that's not the answer you all want to hear, but it's the best I can give right now -- The rewrite of the main script is mostly done. At this point, I'm working on re-writing the child shell scripts, prettying them up, and also ensuring that Snorby plays nice.

I'm going to re-iterate again, that this isn't any sort of a personal attack on any developer of any web interface, or against any platform, just my (probably ill-informed) opinion based on my observations.

Until next time,


Addendum: I thought I would add a note stating that the I've posted the code above into an SELinux module that is available via autosnort's github under the CentOS autosnort directory, in a subdirectory called  "PolicyModules". the directory contains passenger.te as well as a PolicyModulesNotes.txt file that details how to actually compile the passenger.te file into an SELinux module. This is for those who may not necessary care to use autosnort, may not care to use Snorby, but may need some help trying to figure out what accesses Ruby, Rails, and Passenger want on SELinux enabled systems.

I hope that it is some help to the Linux community.

No comments:

Post a Comment