Tuesday Apr 25, 2006

I see you! snoop(1M)'ing in non-global zones!

Dear diary... It has been quite a while since my last posting...

While I have not posted very much to my blog lately, I have been quite busy writing. In fact, since February, the following Sun BluePrints articles have been published:

Today's article talks about how to enable snoop(1M) in a non-global (or local) zone. In Solaris 10 today, the ability to use the snoop(1M) command or any other packet sniffer for that matter is restricted to the global zone. There is no way to snoop traffic from within a zone. Enter the Configurable Privileges for Zones project which integrated into Nevada build 37 and of course is available in OpenSolaris today.

Using this project and a little device manipulation, you can today get snoop working in a non-global zone, and here is how to do it... But first, a few warnings:

WARNING #1: This approach will allow the local zone to see all of the network traffic associated with the device that is added. Unless you use separate network interfaces for the global zone and other non-global zones, this means that following these instructions will allow a zone to see traffic intended for or exchanged with another zone.

WARNING #2: This approach is likely not generally recommended. This is meant only as an illustration of what can be done and may serve as a useful workaround in some environments until a more recommended, secure and supportable solution is available.

With that out of the way, let's give it a try!

First, you must configure your zone to include the net_rawaccess privilege. This is done using a new zonecfg(1M) parameter, limitpriv. In the following example, we will assume that we have previously created and installed a non-global zone, called test. To add the new net_rawaccess privilege, simply use the following command:

# zonecfg -z test
zonecfg:test> set limitpriv=default,net_rawaccess
zonecfg:test> exit
Next, let's boot up the zone and check that the privilege has been successfully added:

# zoneadm -z test boot
# zlogin test
[Connected to zone 'test' pts/5]
Last login: Mon Apr 24 23:49:15 on pts/5
Sun Microsystems Inc.   SunOS 5.11      snv_38  October 2007
# ppriv $$
4547:   -sh
flags = 
        E: basic,contract_event,contract_observer,file_chown,file_chown_self,file_dac_execute,
           file_dac_read,file_dac_search,file_dac_write,file_owner,file_setid,ipc_dac_read,
           ipc_dac_write,ipc_owner,net_bindmlp,net_icmpaccess,net_mac_aware,net_privaddr,
           net_rawaccess,proc_audit,proc_chroot,proc_owner,proc_setid,proc_taskid,sys_acct,
           sys_admin,sys_audit,sys_mount,sys_nfs,sys_resource
        I: basic
        P: basic,contract_event,contract_observer,file_chown,file_chown_self,file_dac_execute,
           file_dac_read,file_dac_search,file_dac_write,file_owner,file_setid,ipc_dac_read,
           ipc_dac_write,ipc_owner,net_bindmlp,net_icmpaccess,net_mac_aware,net_privaddr,
           net_rawaccess,proc_audit,proc_chroot,proc_owner,proc_setid,proc_taskid,sys_acct,
           sys_admin,sys_audit,sys_mount,sys_nfs,sys_resource
        L: basic,contract_event,contract_observer,file_chown,file_chown_self,file_dac_execute,
           file_dac_read,file_dac_search,file_dac_write,file_owner,file_setid,ipc_dac_read,
           ipc_dac_write,ipc_owner,net_bindmlp,net_icmpaccess,net_mac_aware,net_privaddr,
           net_rawaccess,proc_audit,proc_chroot,proc_owner,proc_setid,proc_taskid,sys_acct,
           sys_admin,sys_audit,sys_mount,sys_nfs,sys_resource
Technically speaking what comes next is likely not recommended, but it does work and can help you out in a pinch if you need to get this functionality working in a non-global zone until a more recommended method becomes available.

In order to get snoop working in a non-global zone, you must also introduce the network devices into the zone. The following commands must be executed from the global zone and are representative only (based on my system's configuration). The actual command you should use will vary (based on the actual interface name and the major/minor numbers of the device.

On my system, the network interface name is nge0. My first goal is to determine the major and minor device number associated with the network interface:

# ls -l /dev/nge0
lrwxrwxrwx   1 root     root          38 Apr 21 10:02 /dev/nge0 -> ../devices/pci@0,0/pci108e,5347@a:nge0
# ls -l /devices/pci@0,0/pci108e,5347@a:nge0
crw-rw-rw-   1 root     root      96,  1 Apr 22 10:46 /devices/pci@0,0/pci108e,5347@a:nge0
With this information, we can now create the network device in the non-global zone:
# zonecfg -z test info zonepath
zonepath: /my/zones/test
# cd /my/zones/test/dev
# mknod nge0 c 96 1
# ls -l nge0
crw-r--r--   1 root     root      96,  1 Apr 25 13:00 nge0
All the hard work is now done. With the privilege and device added to the zone, you can now use snoop!

# snoop -d nge0
Using device /dev/nge0 (promiscuous mode)
192.168.1.11 -> test         TCP D=22 S=62991 Syn Seq=2109859625 Len=0 Win=49640 Options=
      test   -> 192.168.1.11 TCP D=62991 S=22 Syn Ack=2109859626 Seq=377273646 Len=0 Win=49640 Options=
192.168.1.11 -> test         TCP D=22 S=62991 Ack=377273647 Seq=2109859626 Len=0 Win=49640
      test   -> 192.168.1.11 TCP D=62991 S=22 Push Ack=2109859626 Seq=377273647 Len=20 Win=49640
Voila! Piece of cake! Just use this tip with caution as you do not inadvertantly want to expose yourself. Peek-a-boo! I'll see you (later!)

Take care,

g

Technorati Tag:

Wednesday Feb 15, 2006

CIS Solaris 10 Security Benchmark Support

On Tuesday, Sun issued a press release titled, "Sun Announces Plan for Trusted Extensions for Solaris 10, the Most Secure Operating System on the Planet". Hidden somewhat discretely within this release (for reasons not entirely clear to me) was the following:

Support for CIS Benchmark

Sun has also extended support services for Solaris 10 OS deployments that adhere
to the Center for Internet Security (CIS) Benchmark. Named "best benchmarking 
effort" by Information Security Magazine, CIS Benchmarks are developed through 
a global consensus process involving hundreds of security professionals to 
determine best-practice security configurations. The CIS Level-I Benchmark for
the Solaris 10 OS is a compilation of security configuration actions and settings
introduced in March 2005. As a result of a close partnership between Sun and the
members of CIS, Solaris 10 Service Plan customers who now implement the CIS
security recommendations will have Sun support for their resulting configurations.
Complementing Sun's freely available Solaris Security Toolkit, CIS will also
introduce a Scoring Tool for the Solaris 10 OS later this month, giving users a
quick and easy way to evaluate systems and compare their security configuration
against the CIS Benchmark criteria. 

This is actually quite an important announcement!

A number of us have been working with the Center for Internet Security, or CIS, for years in an effort to promote more consistent and complete Solaris security recommendations and to better align their Solaris Security Benchmarks with our recommendations. In fact, the CIS Solaris 10 Security Benchark represents the highest level of collaboration and sharing to date. Together, we were able to develop and publish the updated Benchmark document before the GA of Solaris 10 (last year).

This announcement takes our relationship one step further by ensuring customers who implement the Solaris 10 Security Benchmark from CIS can receive support from Sun (under the Solaris 10 Service Plan). This is the first time that Sun has publically announced support for Solaris security recommendations (other than those documented in the Sun BluePrints program). Certainly this is a natural step that stems from our work over the last few years.

I believe that this is another great example of collaboration between vendors (Sun in this case) and members of academia, industry and government. We have all come together for the sole purpose of developing and sharing recommended security practices. By working together in this fashion, we have been able to generate more complete, consistent and supportable advice that will benefit Solaris users and administrators around the world.

This is participation and sharing in action!

Technorati Tag:

Saturday Feb 11, 2006

Try it for yourself: Solaris 10 Privilege Debugging

Just this month, Darren Moffat and I have published a Sun BluePrint article and opened a OpenSolaris Security Project on privilege debugging which includes a cool, new tool, called privdebug.

Together these resources can help you quickly and easily determine which privileges are used by any process, service or application. With this information, you can configure SMF to limit the privileges granted to it using the approach described here.

Everything is freely available. So why not give it a try! We would love to hear what you think!

Take care,

Glenn

Technorati Tag:

Updated Solaris 10 Security TOI

While I am at it, how about an update to the Solaris 10 Technical TOI that I had posted a while back. This new version of the TOI includes support for Solaris 10 Update 1 as well as a bunch of other new additions and examples.

I would love to hear what you think about this new version. Remeber, if you would be interested in having someone from Sun come out and talk to you and your organization on this topic, please let us know. We have been giving this (or similar) Solaris 10 Security deep dive talks to customers for some time now, and there has always been a lot of great interaction, discussion and Q&A. Honestly, they are always a lot of fun.

Take care!

Glenn

Technorati Tag:

Tuesday Sep 20, 2005

Sun announces Solaris 10 3/05 Entering Common Criteria Evaluation

Good news, good news! Hot off the presses!


 Sun Microsystems, Inc. is pleased to announce that the Solaris 10 3/05 
 Operating System has entered into evaluation for Common Criteria evaluation.
 This announcement demonstrates Sun's commitment and leadership in the field
 of independent security certification of operating systems and acts as a 
 catalyst for many world wide government customers wanting to develop and 
 deploy on Solaris 10.

 Common Criteria evaluation represents and agreed upon standard for independent
 certification of various security claims for IT products. The Protection 
 Profiles and Evaluation Assurance Levels are mutually understood, agreed upon
 and accepted by over 22 different countries around the world as being required
 for deploying technology into sensitive scenarios. An example of a recognition
 body includes the National Information Assurance Program Common Criteria 
 Evaluation and Validation Scheme (NIAP CCEVS) in the United States and the 
 Canadian Common Criteria Evaluation and Certification Scheme (CCS) in Canada.

 Stepping above what is normal for the competition, Solaris 10 will be evaluated
 against the Controlled Access Protection Profile (CAPP) and Role Based Access
 Control Protection Profile (RBACPP) at Evaluation Assurance Level 4+ (EAL 4+).

 The Common Criteria testing is being conducted by CGI Information Systems and
 Management Consultants, Inc. in Ottawa, Ontario, Canada, who also conducted 
 the testing of the Solaris 9 Operating System. Actual time to complete the 
 evaluation is under investigation.

 The Communications Security Establishment (CSE) is the Canadian recognition 
 body that will be accepting the evaluation. Formal notice of the evaluation 
 status of Solaris 10 will be posted on CSE's Web site shortly and is available
 at :http://www.cse.dnd.ca/en/services/common_criteria/ongoing_evals.html

Technorati Tag:

Wednesday Jun 15, 2005

Solaris 10 Query Appreciation Day

Occasionally, I look through the referer logs to see how people happen to come across my little patch of cyberspace. It is often very interesting to see what people are actually searching for when they are directed to this blog. Today, I would like to give back to those who have taken the time to visit and look around this site after being directed to it by a search engine. To that end, I will list some of the search queries that were in the referer listing today along with answers to questions or pointers that people can use for more information.

So without further ado...

The first search query reference comes from our friends at Yahoo from someone looking for more information on locked accounts in Solaris.

This topic has been covered previously. There is a little more information that can be found in the Solaris 10 What's New document as well as the passwd(1) manual page as well.

The next query comes from our friends at Google from someone looking for steps on how to disable the telnet service in Solaris 10.

The answer to this is very straightforward:

# svcadm disable telnet

That is all there is to it. Keep in mind that if you do not want the telnet service at all on your system you can also simply remove the SUNWtnetd and SUNWtnetr packages using the command:

# pkgrm SUNWtnetd SUNWtnetr

Further, if you want to simply use TCP Wrappers to control access to telnet in Solaris 10, check out this entry.

Another Google query was looking for information on minimal Solaris 10 configurations. This is a great topic. In Solaris 10, a new software installation cluster called the Reduced Networking Meta Cluster is available and should be leveraged when building minimal configurations. You can read about it here. Further, for a great read check out Eric Boutilier's seven part series on building a UNIX OE platform from scratch.

Well, that's enough for today. I would like to occassionally do more entries like this where we can provide more directed feedback based on what people are actually searching for. While it may be too late in some cases for them, it may help people down the road who have similar questions or concerns.

I am off to finalize a presentation on Solaris recommended practices for the NY State Cyber Security Conference. If you will be at the conference tomorrow, please drop by and say hello!

Take care!

Technorati Tag:

Tuesday Jun 14, 2005

Privilege Enabling Set-ID Programs: Part 2

Previously, we talked about how the ping program was modified in Solaris 10 to be privilege aware.  During that discussion, it was noted that the functions used in the ping program were private to the OpenSolaris ON (OS and Networking) consolidation.  While this is fine for programs like ping that reside in that consolidation, it does not offer a solution to programs in other consolidations or for those developed external to OpenSolaris.  As a companion to that article, let's now discuss how we can adapt ping.c to use the public privilege manipulation functions yet still accomplish the same result - making the program privilege-aware and implementing bracketing around privileged operations.

Without further ado, let's just dive into the code.  By way of convention, I will be showing only the changes that need be implemented to covert the original ping.c program to use the new public functions.

The first thing that you will notice is that a different header file is used.  If you want to use the public interfaces, then you should be sure to include priv.h and not priv_utils.h:

72c72
< #include <priv_utils.h>
---
> #include <priv.h>

Next, we move to the section of the code that configured the privilege sets at the start of the program.  This was done in order to drop any privileges that were not needed and disable those that were left (and not needed right now).  This was originally accomplished using the __init_suid_priv function which provided a convenient wrapper for the functionality described below.  Rather than a single line, we need to do a little more work.  To make the code easier to follow, a new function, setup_privs, was created to do the initial privilege operations.  This handles the majority of the work originally done by __init_suid_priv.  This code is fairly well documented, so I will not go into too much detail as to what it does.

225a226
> static priv_set_t \*setup_privs(void);
227a229,298
>  \* setup_privs()
>  \*/
> priv_set_t \*
> setup_privs(void)
> {
>     priv_set_t \*pPrivSet = NULL;
>     priv_set_t \*lPrivSet = NULL;
>
>     /\*
>      \* Start with the 'basic' privilege set and then remove any
>      \* of the 'basic' privileges that will not be needed by this
>      \* process.  The 'net_icmpaccess' privilege will be added
>      \* since we know that we will need it for the permitted set.
>      \*/
>
>     if ((pPrivSet = priv_str_to_set("basic", ",", NULL)) == NULL) {
>             perror("priv_str_to_set");
>             return (NULL);
>     }
>
>     /\*
>      \* Let's clear all of the privileges we know we will not
>      \* need from the 'basic' set.
>      \*/
>
>     (void) priv_delset(pPrivSet, PRIV_FILE_LINK_ANY);
>     (void) priv_delset(pPrivSet, PRIV_PROC_EXEC);
>     (void) priv_delset(pPrivSet, PRIV_PROC_FORK);
>     (void) priv_delset(pPrivSet, PRIV_PROC_INFO);
>     (void) priv_delset(pPrivSet, PRIV_PROC_SESSION);
>
>     /\* Next add the known required privilege, 'net_icmpaccess' \*/
>
>     (void) priv_addset(pPrivSet, PRIV_NET_ICMPACCESS);
>
>     /\* Set the permitted privilege set. \*/
>
>     if (setppriv(PRIV_SET, PRIV_PERMITTED, pPrivSet) != 0) {
>             perror("setppriv(PRIV_SET, PRIV_PERMITTED)");
>             return (NULL);
>     }
>
>     /\* Ensure that the 'net_icmpaccess' privilege is off by default. \*/
>
>     if (priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_NET_ICMPACCESS,
>             NULL) != 0) {
>             perror("priv_set(PRIV_OFF, PRIV_EFFECTIVE)");
>             return (NULL);
>     }
>
>     /\* Clear the limit set. \*/
>
>     if ((lPrivSet = priv_allocset()) == NULL) {
>             perror("priv_allocset");
>             return (NULL);
>     }
>
>     priv_emptyset(lPrivSet);
>
>     if (setppriv(PRIV_SET, PRIV_LIMIT, lPrivSet) != 0) {
>             perror("setppriv(PRIV_SET, PRIV_LIMIT)");
>             return (NULL);
>     }
>
>     priv_freeset(lPrivSet);
>
>     return (pPrivSet);
> }
>
> /\*

So, why do we go through the process of starting with the basic set of privileges and removing them all?  Why not just start out with no privileges and simply the code?  The answer lies in the fact that the basic privilege set is not intended to be static.  Over time additional non-administrative privileges may be added.  If you started with simply no privileges, then you may find that your code will fail as it will need a privilege for an operation that previously did not require one.  In essence, this is a way of future-proofing your code so that it can better adapt to changes in Solaris down the road.

So at this point, we have defined a function that will help minic most of the behavior that had been done by __init_suid_priv.  Let's take a look at how this function is used:

243a315
>     priv_set_t \*privSet = NULL;
252,253d323
<     (void) __init_suid_priv(PU_CLEARLIMITSET, PRIV_NET_ICMPACCESS,
<         (char \*)NULL);
254a325,337
>     if ((privSet = setup_privs()) == NULL) {
>             exit(EXIT_FAILURE);
>     }
>
>     /\*
>      \* Reset the real and effective UIDs for this process.
>      \*/
>
>     if (setreuid(getuid(), getuid()) != 0) {
>             perror("setreuid");
>             exit(EXIT_FAILURE);
>     }
>

As you can see, the __init_suid_priv call has been replaced by calls to both setup_privs and setreuid(2) functions.  This is a fairly simple replacement since all of the "hard work" was done in the setup_privs function.  We capture the privilege set parameter, privSet, as we will need it later in the code when it comes time to relinquish our privileges.  Let's continue sequentially down the code to see where other replacements are needed.  Frankly, the hard part is over.  The rest of the changes needed to complete the conversion from private to public privilege manipulation functions are trivial.  Let's take a look at the next replacement:

602c685,687
<     __priv_relinquish();
---
>     /\*
>      \* Clear the permitted set of the 'net_icmpaccess' privilege.
>      \*/
603a689,696
>     (void) priv_delset(privSet, PRIV_NET_ICMPACCESS);
>
>     if (setppriv(PRIV_SET, PRIV_PERMITTED, privSet) != 0) {
>             perror("setppriv(PRIV_PERMITTED)");
>             exit(EXIT_FAILURE);
>     }
>     priv_freeset(privSet);
>

In this case, we are replacing the __priv_relinquish function with a call to setppriv(2).  Before we can do this however, we need to remove the net_icmpaccess privilege from privSet using the priv_delset function.  Remember that privSet (returned to us from setup_privs earlier in the code) contains the privileges from the basic set that we had not already dropped as well as the net_icmpaccess privilege.  By removing the net_icmpaccess privilege, setppriv will set to the process' permitted privilege set to the non-dropped basic privileges (which in this particular case is none although as Solaris continues to evolve and new non-administrative privileges are added, this may change).

Moving along to the next section of replacement code, we come to where the bracketing of the net_icmpaccess privilege is enforced.  In thiscase, the call to __priv_bracket is replaced with a call to priv_set(3C) function.  priv_set is called with the PRIV_ON parameter which enables the net_icmpaccess privilege for the process' effective privilege set.

1197c1290,1293
<     (void) __priv_bracket(PRIV_ON);
---
>     if (priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_NET_ICMPACCESS, NULL) != 0) {
>             perror("priv_set(PRIV_ON, PRIV_EFFECTIVE)");
>             exit(EXIT_FAILURE);
>     }

Similarly, the companion instance of __priv_bracket is replaced with another call to priv_set once the privileged operations are complete to remove the net_icmpaccess privilege (from the process' effective privilege set) - therefore completing the bracketing of privilege.

1208c1304,1308
<     (void) __priv_bracket(PRIV_OFF);
---
>     if (priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_NET_ICMPACCESS,
>             NULL) != 0) {
>             perror("priv_set(PRIV_OFF, PRIV_EFFECTIVE)");
>             exit(EXIT_FAILURE);
>     }

That is all there is to it.  As you can tell, there is a bit more work in the initial setup of a process' privilege sets, but once that is complete, the use of the public privilege manipulation functions is straightforward.  I know that this helps to illustrate how you can privilege enable your code whether you choose to use ON specific functions or the public ones defined in the Solaris product documentation.  For those who just can't get enough, check out Joep Vesseur's discussion of several developer-focused security enhancements in Solaris 10 (and OpenSolaris).

Last, but certainly not least, I would like to offer my sincere thanks to Casper, Joep and Darren for their help with this article.  You guys are the best!

Take care and have fun!

Technorati Tag:

Privilege Enabling Set-ID Programs

There have been quite a few posts, articles,and resources made available discussing the new process privilege model introduced the Solaris 10 operating system. The majority of them have focused on describing what this new privilege model is, why it is useful and how it can be used through mechanisms such as Solaris RBAC, SMF, and ppriv(1). Today, with the launch of OpenSolaris, I feel the urge to discuss privileges from the view of a software developer (not that I am one anymore, but please indulge me a bit).  If you are interested in this kind of thing, you can find more information about this in the Solaris 10 product documentation.

Today, let's look at a how a developer could develop a program to be privilege aware. In particular, for our example, let's take a set-id program and configure it such that it:

  1. drops any privileges that it will never need;
  2. enables the remaining privileges exactly when it needs them;
  3. relinquishes the use of privileges when they are no longer needed

Sounds pretty straight forward, right? Essentially, we just want to ensure that a program is only running with those privileges that it needs, and it activates those privileges only when it needs them. To illustrate this concept, let's take a look at ping.c. This program was converted to use Solaris privileges by Casper Dik way back in 2003. I chose to use it for this example because:

  1. the ping(1M) source code is simple and straightforward to read and understand, and
  2. all of the changes needed to make it privilege aware were contained in one file

There is nothing special about ping with respect to privileges and the same techniques described below could be applied to other programs whether they are set-id or not.

So, let's begin this tale back in February of 2003 before the ping command was made privilege aware. In those days, ping was a set-uid root program that controlled its use of privilege using seteuid(2). When the program started as root, it quickly set its effective UID to the UID of the calling user to run with less privilege. When it came time to execute a privileged operation, the code issued another seteuid call that reset its EUID to root so that the privileged operation could succeed.

With the introduction of process privileges in Solaris 10, this model was no longer needed. Rather than executing code as EUID 0, specific privileges are used to define the types of privileged operations that are be permitted. This is a huge step forward as privilege aware programs will now run only with the privileges that they need (exactly when they need them). So, enough of the fluff, let's get to the code! Note that all of the following code examples were taken from ping.c.

The first thing that you will notice that if you want to configure a program to be privilege aware, you will need to include a new header that will declare functions and define constants used by the privilege functions described below:

     72    #include <priv_utils.h>

With the header out of the way, we move into main where the first thing that we do is drop all of the privileges that we do not need:

    247         /\*
    248          \* This program needs the net_icmpaccess privileges.  We'll fail
    249          \* on the socket call and report the error there when we have
    250          \* insufficient privileges.
    251          \*/
    252         (void) __init_suid_priv(PU_CLEARLIMITSET, PRIV_NET_ICMPACCESS,
    253             (char \*)NULL);

Remember that ping is still set-uid root. This means that when it is started, it will have the privileges that have been assigned to root which by default is all. The purpose of the __init_suid_priv function is to do the following (described in priv_utils.h):

     48 /\*
     49  \* Should be run at the start of a set-uid root program;
     50  \* if the effective uid == 0 and the real uid != 0,
     51  \* the specified privileges X are assigned as follows:
     52  \*
     53  \* P = I + X + B (B added insofar allowable from L)
     54  \* E = I
     55  \* (i.e., the requested privileges are dormant, not active)
     56  \* Then resets all uids to the invoking uid; no-op if euid == uid == 0.
     57  \*
     58  \* flags: PU_LIMITPRIVS, PU_CLEARLIMITSET, PU_CLEARINHERITABLE
     59  \*
     60  \* Caches the required privileges for use by __priv_bracket().
     61  \*
     62  \*/

So this function (as used in the ping.c code) will reset the real and effective UID of the process to that of the calling user so that it is no longer running as root.  Further, it will clear the limit set of the process which means that any children spawned by this process will themselves have no privileges.  Lastly, this function will also add the net_icmpaccess privilege to the process' permitted set so that it can be enabled and used when necessary.  The process' four privilege sets (effective, inheritable, permitted and limit) will look like this:

# ppriv -S `pgrep ping`
14527: ping localhost
flags = PRIV_AWARE
E: basic
I: basic
P: basic,net_icmpaccess
L: none

According to ppriv, the net_icmpaccess privilege is used to allow a process to send and receive ICMP packets:

$ ppriv -lv net_icmpaccess
net_icmpaccess
Allows a process to send and receive ICMP packets.

So rather than having the potential to access all of root's power, a ping process will now run as the calling user's UID with a single (non-basic) privilege that allows the sending or receiving ICMP packets.  Sounds great, but we are not done yet!  In priv_utils.h, you will find more instruction as to how to proceed:

     65 /\*
     66  \* After calling __init_suid_priv we can __priv_bracket(PRIV_ON) and
     67  \* __priv_bracket(PRIV_OFF) and __priv_relinquish to get rid of the
     68  \* privileges forever.
     69  \*/

Recall that before ping was made privilege aware, it used seteuid to control when its privileges were in effect. This was necessary for the program to only run in a privileged capacity when it needs to execute privileged operations. In the new model, the process leverages a capability called privilege bracketing which controls when a privilege (defined in the process' permitted set) is made effective. To see this capability in action, take a look at the following code which appears in the setup_socket function:

   1196         /\* now we need the net_icmpaccess privilege \*/
   1197         (void) __priv_bracket(PRIV_ON);
   1198
   1199         recv_sock = socket(family, SOCK_RAW,
   1200             (family == AF_INET) ? IPPROTO_ICMP : IPPROTO_ICMPV6);
   1201
   1202         if (recv_sock < 0) {
   1203                 Fprintf(stderr, "%s: socket %s\\n", progname, strerror(errno));
   1204                 exit(EXIT_FAILURE);
   1205         }
   1206
   1207         /\* revert to non-privileged user after opening sockets \*/
   1208         (void) __priv_bracket(PRIV_OFF);

As you can see, the __priv_bracket function is used around the privileged operation (in this case the socket(2) call) to control whether or not the instructions are executed with privilege. This is one form of privilege bracketing that enables and disables all of the privileges cached by the __init_suid_priv function called earlier in the program (and described above). There are other privilege manipulation functions available to allow more fine grained control if needed.

Our final step is to relinquish the privileges when we are sure that we will no longer need them:

    602         __priv_relinquish();

The __priv_relinquish function is called after the setup_socket function has completed in main. Since the program will no longer need the net_raw_icmpaccess privilege (the only non-basic privilege available to the process), it can now be safely dropped. The __priv_relinquish function is used for just this purpose. Note that once a privilege is relinquished, it is gone. If you think that you may need the privilege later in the program, you should simply disable its use (removing it from the process' effective set) until you need it again.

That's all there is to it.  Pretty cool, eh?

One thing that I should mention, however.  In the development of this article, I was reminded by Darren Moffat that the privilege functions and header file described above are private to Solaris (and more specifically the ON [OS and Networking] consolidation).  So, the approach described above will work just fine if you are modifying set-id programs in ON such as atq, atrm, traceroute, lpstat, and the like.  If you want to make other programs privilege aware, you can do this using a set of privilege manipulation functions described in the Solaris 10 product documentation. Regardless of the method you use, however, there should be nothing to stop you from improving your code by making your programs privilege aware and bracketing privileged operations.

Take care and have fun!

Technorati Tag:

Wednesday Apr 20, 2005

Enforcing a Two Man Rule Using Solaris 10 RBAC

The "two man rule" (also sometimes called the "four eyes rule") has its origins in military protocol although for quite some time it has been welcomed into the stockpile of IT security controls used by organizations around the world. The "two man rule" specifies that there must be two individuals that must act in concert in order to perform some action. Further, each individual should have comparable knowledge and skill in order to detect attempts of subversion initiated by the other. One can certainly see why this is essential for tasks such as safeguarding a country's nuclear arsenal. One would not want all of that authority to rest in the hands of one individual.

The "two man rule" is also useful for IT security. Whether you are talking about physical or logical access controls, the "two man rule" has been applied to help secure IT assets for quite some time. Whether you want to protect access to key data sets or restrict who may perform sensitive or high impact operations on a system, using the "two man rule" may be an option. That said, in many circumstances, more traditional IT security controls are likely appropriate. Using the "two man rule" is most often reserved for restricting the most sensitive IT security operations performed within an organization. Whether and where you could apply the "two man rule" to your organization will depend on your policy, architecture, processes and requirements.

Let's assume that you are interested in applying the "two man rule" on a given system. For our example, we will focus on implementing the "two man rule" on the Solaris 10 operating system. It should be noted that the same techniques apply to both Solaris 8 and 9 since all three versions of the operating system included the Solaris Role-based Access Control ("RBAC") facility. We will make use of this facility to implement the "two man rule" as described above.

The content and examples below will include references to both normal users and roles. In the Solaris OS, roles are similar to normal user accounts with two important differences. First, a role cannot be accessed directly over the network or from the console. You can only use the su(1M) command (or smc(1M)) to assume a role. In either case, a user must first authenticate to the system as himself before attempting to access a role. Secondly, a role can only be assumed by authorized users. That is, before a given user can assume a role, an administrator must assign that role to the user otherwise attempts to access the role will fail. Both of these restrictions are important for preserving accountability and will factor quite heavily in our implementation of the two man rule in Solaris 10.

So let's begin. For our example, we will implement the "two man rule" for our hypothetical IT security administrators, joe and john. From here, there are several ways that we can go:

  • Configure both joe and john with normal accounts on the system, each able to assume an individual Solaris role. Neither joe nor john will know the password for the role that they are permitted to assume. For example, joe is permitted to assume the role roleA but is unable to do so since only john knows the password for that role. This option creates two roles (one for each user) each able to perform a restricted operation. This approach has the benefit of either user being able to assume the role (i.e., it does not require that one user be the initiator of the action). Further by permitting both users to be on the system they have more opportunity to monitor the actions of the other (e.g., Solaris auditing, syslog, etc.).

  • Configure only one user on the system with permission to assume one role. In this example, one user would know the initial password while the other user would know the second (i.e., role) password. This case is similar to the first although it only requires one user and one role account on the system. It suffers from the disadvantage of not permitting the second user to log directly into the system thereby potentially missing critical monitoring opportunities. Further, it requires that joe must be first logged into the system before john can assume roleA.

  • Configure both joe and john as in example one but only give them access to the same shared role. In this case, neither user would have the password to authenticate to that role. In order to obtain the authenticator for that role, both users would be required to work together to obtain the password from an external source such as a physical safe. This option has the benefit of greater protection since access to the safe could be placed in an area that requires additional physical controls and provides greater opportunities for monitoring. Further, the authenticator could be monitored and changed by a third party who has no relationship to either joe or john. This approach also preserves the benefits of the first approach where both joe and john can easily monitor the activities of the other.

For our example, I will choose the first option. This option will allow me to showcase the capabilities of Solaris RBAC to implement the "two man rule" without depending on external factors such as those described in the third option above. The actual choice that you make will depend on your policy and requirements. Additional security controls (physical and logical) beyond those described in this article may also be required depending on the level of assurance that you need for your situation.

First, let's verify our users - joe and john:

# getent passwd joe john
joe:x:105:1::/export/home/joe:/bin/pfsh
john:x:106:1::/export/home/john:/bin/pfsh

You will note that these users have been configured with profile shells. This is only done to simplify some of the commands that follow. If you did want want to use a profile shell, you could prefix your commands with pfexec(1) when you wanted them to be evaluated by Solaris RBAC to run with privilege.

We can verify that these account do not have any special privileges (beyond those available to any regular Solaris user) by running the following commands:

# roles joe john
joe : No roles
john : No roles

# profiles -l joe john

      All:
          \*

      All:
          \*

# auths joe john
joe : solaris.device.cdrw,solaris.profmgr.read,solaris.jobs.users,solaris.mail.mailq,solaris.admin.usermgr.read,
solaris.admin.logsvc.read,solaris.admin.fsmgr.read,solaris.admin.serialmgr.read,solaris.admin.diskmgr.read,
solaris.admin.procmgr.user,solaris.compsys.read,solaris.admin.printer.read,solaris.admin.prodreg.read,
solaris.admin.dcmgr.read,solaris.snmp.read,solaris.project.read,solaris.admin.patchmgr.read,
solaris.network.hosts.read,solaris.admin.volmgr.read
john : solaris.device.cdrw,solaris.profmgr.read,solaris.jobs.users,solaris.mail.mailq,solaris.admin.usermgr.read,
solaris.admin.logsvc.read,solaris.admin.fsmgr.read,solaris.admin.serialmgr.read,solaris.admin.diskmgr.read,
solaris.admin.procmgr.user,solaris.compsys.read,solaris.admin.printer.read,solaris.admin.prodreg.read,
solaris.admin.dcmgr.read,solaris.snmp.read,solaris.project.read,solaris.admin.patchmgr.read,
solaris.network.hosts.read,solaris.admin.volmgr.read

As you can see, neither joe nor john have been granted access to any roles, rights profiles or authorizations (beyond those available to any normal Solaris user). You will notice several authorizations that are available to them. They have been granted by default using the AUTHS_GRANTED and PROFS_GRANTED parameters in the /etc/security/policy.conf file.

To each of these users we will grant the rights profile Audit Review. This will allow both joe and john to review Solaris audit records so that each can monitor the activities of the other. This step is not necessary for the "two man rule" if you have an external third party who is able to monitor the activities of the two users.

# usermod -P "Audit Review" joe
# usermod -P "Audit Review" john

Let's verify that this change has taken effect:

# profiles -l joe john

      Audit Review:
          /usr/sbin/praudit    euid=0
          /usr/sbin/auditreduce    euid=0
          /usr/sbin/auditstat    euid=0
      All:
          \*

      Audit Review:
          /usr/sbin/praudit    euid=0
          /usr/sbin/auditreduce    euid=0
          /usr/sbin/auditstat    euid=0
      All:
          \*

Now that we have verified the accounts have been configured as expected, we will create two roles: roleA and roleB. roleA will be assigned to joe, and roleB will be assigned to john. To these roles, our restricted operations will be assigned.

# roleadd -d /export/home/roleA -m roleA
64 blocks

# passwd roleA
New Password:
Re-enter new Password:
passwd: password successfully changed for roleA

# roleadd -d /export/home/roleB -m roleB
64 blocks

# passwd roleB
New Password:
Re-enter new Password:
passwd: password successfully changed for roleB

# usermod -R roleA joe
# usermod -R roleB john
Now, let's verify that the roles have been created and assigned as we expected:

# getent passwd roleA roleB
roleA:x:107:1::/export/home/roleA:/bin/pfsh
roleB:x:108:1::/export/home/roleB:/bin/pfsh

# roles joe john
joe : roleA
john : roleB

Great. Our last step is to assign the restricted operations to the roles so that joe and john can perform them after they have jointly assumed either roleA or roleB. For our example, we will assign the Crypto Management rights profile to both roleA and roleB. This will allow either of those roles to execute cryptographic administration functions such as those provided by cryptoadm(1M):

# rolemod -P "Crypto Management" roleA
# rolemod -P "Crypto Management" roleB

To see what privileged commands are now available to these roles, use the following command:

# profiles -l roleA roleB

      Crypto Management:
          /usr/sbin/cryptoadm    euid=0
          /usr/sfw/bin/CA.pl    euid=0
          /usr/sfw/bin/openssl    euid=0
      All:
          \*

      Crypto Management:
          /usr/sbin/cryptoadm    euid=0
          /usr/sfw/bin/CA.pl    euid=0
          /usr/sfw/bin/openssl    euid=0
      All:
          \*

Great! We are all set. At this point, we have two users (joe and john). joe is permitted to assume roleA, and john is permitted to assume roleB. joe does not know the password for roleA (although john does), and similarly john does not know the password for roleB (although joe does). Both of the users have been assigned the Audit Review rights profile allowing them to monitor each other's activities. Both of the roles have been assigned the Crypto Management rights profile allowing them to perform cryptographic management operations on the system.

Let's verify that this all actually works... For my example, all of the users and roles were created within a zone called "blue". The first thing that I will do to test is log into the zone as joe:

# zlogin -l joe blue
[Connected to zone 'blue' pts/2]
Last login: Tue Apr 12 07:20:19 on pts/2
joe$ id -a
uid=105(joe) gid=1(other) groups=1(other)
joe$ auths
solaris.audit.read,solaris.device.cdrw,solaris.profmgr.read,solaris.jobs.users,solaris.mail.mailq,
solaris.admin.usermgr.read,solaris.admin.logsvc.read,solaris.admin.fsmgr.read,solaris.admin.serialmgr.read,
solaris.admin.diskmgr.read,solaris.admin.procmgr.user,solaris.compsys.read,solaris.admin.printer.read,
solaris.admin.prodreg.read,solaris.admin.dcmgr.read,solaris.snmp.read,solaris.project.read,
solaris.admin.patchmgr.read,solaris.network.hosts.read,solaris.admin.volmgr.read
joe$ profiles -l

      Audit Review:
          /usr/sbin/praudit    euid=0
          /usr/sbin/auditreduce    euid=0
          /usr/sbin/auditstat    euid=0
      All:
          \*
joe$ roles
roleA

First, since joe does know the password for roleB, let's see if we can assume that role:

joe$ su roleB
Password:
Roles can only be assumed by authorized users
su: Sorry

Even with a valid password, joe is not permitted to assume roleB. Next, let's try to guess the password for roleA:

joe$ su roleA
Password:
su: Sorry
joe$ su roleA
Password:
su: Sorry
joe$ su roleA
Password:
su: Sorry

No luck. In order to prevent brute force password attempts, you could also configure account lockout so that an account will be administratively locked after n consecutive failed authentication attempts, where n is the value defined by the RETRIES parameter in /etc/default/login.

Next, let's see what user john would see in the audit trails after joe executed the above commands. Since john has been granted the Audit Review rights profile, he is able to look at the Solaris audit records. If you wanted to further limit what john could see in the audit trail, you could develop a small wrapper script to call praudit(1M) and auditreduce(1M) to filter out unwanted records. So, let's pick up our example with john logging into the "blue" zone:

# zlogin -l john blue
[Connected to zone 'blue' pts/2]
john$ id -a
uid=106(john) gid=1(other) groups=1(other)
john$ auths
solaris.audit.read,solaris.device.cdrw,solaris.profmgr.read,solaris.jobs.users,solaris.mail.mailq,
solaris.admin.usermgr.read,solaris.admin.logsvc.read,solaris.admin.fsmgr.read,solaris.admin.serialmgr.read,
solaris.admin.diskmgr.read,solaris.admin.procmgr.user,solaris.compsys.read,solaris.admin.printer.read,
solaris.admin.prodreg.read,solaris.admin.dcmgr.read,solaris.snmp.read,solaris.project.read,
solaris.admin.patchmgr.read,solaris.network.hosts.read,solaris.admin.volmgr.read
john$ profiles -l

      Audit Review:
          /usr/sbin/praudit    euid=0
          /usr/sbin/auditreduce    euid=0
          /usr/sbin/auditstat    euid=0
      All:
          \*
john$ roles
roleB

Next, john uses the praudit and auditreduce commands to look at any attmepts to su taken by joe:

john$ auditreduce -m AUE_su -r joe | praudit -s
file,2005-04-12 07:25:06.000 -04:00,
header,97,2,AUE_su,,10.8.31.9,2005-04-12 07:28:30.220 -04:00
subject,gmb,root,other,joe,other,1834,3097759606,12114 22 129.150.66.247
text,bad auth. for user roleB
return,failure,2
header,97,2,AUE_su,,10.8.31.9,2005-04-12 07:28:40.043 -04:00
subject,gmb,root,other,joe,other,1835,3097759606,12114 22 129.150.66.247
text,bad auth. for user roleA
return,failure,2
header,97,2,AUE_su,,10.8.31.9,2005-04-12 07:28:49.940 -04:00
subject,gmb,root,other,joe,other,1836,3097759606,12114 22 129.150.66.247
text,bad auth. for user roleA
return,failure,2
header,97,2,AUE_su,,10.8.31.9,2005-04-12 07:28:59.683 -04:00
subject,gmb,root,other,joe,other,1837,3097759606,12114 22 129.150.66.247
text,bad auth. for user roleA
return,failure,2
file,2005-04-12 07:28:59.000 -04:00,

From this audit trail, you can see that user joe attempted to assume both roleA and roleB. In fact, joe attempted to assume roleB three times with each attempt ending in failure. For more information on the audit logs, their format and options for configuring them, see auditd(1M). For the purposes of this example, Solaris auditing was configured with the following policies:

# auditconfig -getpolicy
audit policies = argv,cnt,perzone

Further, the users and roles defined in this example were audited as follows:

# cat /etc/security/audit_user
#
# Copyright (c) 1988 by Sun Microsystems, Inc.
#
# ident "@(#)audit_user.txt     1.6     00/07/17 SMI"
#
#
# User Level Audit User File
#
# File Format
#
#       username:always:never
#
root:lo:no
joe:lo,ad,ex:
john:lo,ad,ex:
roleA:lo,ad,ex:
roleB:lo,ad,ex:

These settings effectively audited login and logout events, administrative actions and command execution (exec(2) calls). You should configure Solaris auditing to comply with your local auditing requirements and policies. The configuration presented serves only as an example to illustrate the type of information that can be collected.

By now, you can see that joe cannot access the Cryto Management rights profile on his own. Let's see what would happen if joe attempted to simply perform a restricted cryptographic operation on his own:

joe$ cryptoadm stop
cryptoadm: failed to stop cryptographic framework daemon - Not owner.

Still no luck. In order to perform those restricted operations, he will need john to help him assume roleA. In the final example below, we illustrate that working in concert, joe and john together can successfully assume roleA.

joe$ su roleA
Password:
roleA$ id -a
uid=107(roleA) gid=1(other) groups=1(other)
roleA$ profiles -l

      Crypto Management:
          /usr/sbin/cryptoadm    euid=0
          /usr/sfw/bin/CA.pl    euid=0
          /usr/sfw/bin/openssl    euid=0
      All:
          \*

With these privileges, joe and john can perform operations such as starting and stopping the Solaris cryptographic framework:

roleA$ echo "foo" | digest -a md5
d3b07384d113edec49eaa6238ad5ff00
roleA$ cryptoadm stop
roleA$ echo "foo" | digest -a md5
digest: failed to initialize PKCS #11 framework: CKR_GENERAL_ERROR
roleA$ cryptoadm start
roleA$ echo "foo" | digest -a md5
d3b07384d113edec49eaa6238ad5ff00

Clearly, you can see that the "two man rule" is enforced since neither joe nor john can perform any cryptographic management operations on the system without knowledge and support of the other. Further, should either user attempt to access their assigned role, the other user can be alerted through the presence of a Solaris audit record (that neither user can modify). Very cool.

Finally, I would like to thank both Collin Sampson and Scott Rotondo for their careful review and feedback provided on this article.

As always, I am interested in your feedback and thoughts. Please let me know if you have any questions. Take care!

Technorati Tag:

Friday Apr 15, 2005

CIS Solaris 10 Security Benchmark Published

It is with great pleasure that I can announce the public availability of the Solaris 10 Security Benchmark published by the Center for Internet Security.

For those who are not aware, for more than two years, Sun has been working quite closely with CIS to refine the Solaris Benchmark and to better align that document with Sun's BluePrints and tools. Frankly, both parties have benefited from this collaboration and has led to the addition or tuning of many recommendations and the filing of several RFEs that will in turn improve the overall quality and security of Solaris. It is great to see and be a part of such a collaborative effort, and this release marks the greatest level of Sun participation yet!

So - congratulations to CIS and the Unix Benchmark team on a job well done.

Technorati Tag:

Friday Apr 08, 2005

New Sun BluePrints Security Cookbook

As I alluded to in a previous article, another one of my blog articles was recently reworked and published as a Sun BluePrints Cookbook. Integrating BART and the Solaris Fingerprint Database in the Solaris 10 Operating System was published this month. This article does feature quite a bit of cleanup and some new content in addition to what you may have already seen. This will be my last BART article for a little bit as I have turned by focus on the Service Management Framework. Look for some new Sun BluePrints Security Cookbooks focusing on SMF in the next few months!

As always, I am very interested in any feedback that you may have...

Take care!

Technorati Tag:

Wednesday Apr 06, 2005

Enabling TCP Wrappers on Solaris 10

Tip of the Month: Enabling TCP Wrappers in Solaris 10

Before answering this question, let's first provide a little background. TCP Wrappers has been around for many, many years. It is used to restrict access to TCP services based on host name, IP address, network address, etc. For more detailed on what TCP Wrappers is and how you can use it, see tcpd(1M). TCP Wrappers was integrated into Solaris starting in Solaris 9 where both Solaris Secure Shell and inetd-based (streams, nowait) services were wrapped. Bonus points are awarded to anyone who knows why UDP services are not wrapped by default.

TCP Wrappers support in Secure Shell was always enabled since Secure Shell always called the TCP Wrapper function host_access(3) to determine if a connection attempt should proceed. If TCP Wrappers was not configured on that system, access, by default, would be granted. Otherwise, the rules as defined in the hosts.allow and hosts.deny files would apply. For more information on these files, see hosts_access(4). Note that this and all of the TCP Wrappers manual pages a stored under /usr/sfw/man in Solaris 10. To view this manual page, you can use the following command:

$ man -M /usr/sfw/man -s 4 hosts_access

inetd-based services use TCP Wrappers in a different way. In Solaris 9, to enable TCP Wrappers for inetd-based services, you must edit the /etc/default/inetd file and set the ENABLE_TCPWRAPPERSparameter to YES. By default, TCP Wrappers was not enabled for inetd.

In Solaris 10, two new services were wrapped: sendmail and rpcbind. sendmail works in a way similar to Secure Shell. It always calls the host_access function and therefore TCP Wrappers support is always enabled. Nothing else needs to be done to enable TCP Wrappers support for that service. On the other hand, TCP Wrappers support for rpcbind must be enabled manually using the new Service Management Framework ("SMF"). Similarly, inetd was modified to use a SMF property to control whether TCP Wrappers is enabled for inetd-based services.

Let's look at how to enable TCP Wrappers for inetd and rpcbind...

To enable TCP Wrappers support for inetd-based services, you can simply use the following commands:

# inetadm -M tcp_wrappers=true
# svcadm refresh inetd

This will enable TCP Wrappers for inetd-based (streams, nowait) services like telnet, rlogin, and ftp (for example):

# inetadm -l telnet | grep tcp_wrappers
default  tcp_wrappers=TRUE

You can see that this setting has taken effect for inetd by running the following command:

# svcprop -p defaults inetd
defaults/tcp_wrappers boolean true

Note that you can also use the svccfg(1M) command to enable TCP Wrappers for inetd-based services.

# svccfg -s inetd setprop defaults/tcp_wrappers=true
# svcadm refresh inetd

Whether you use inetadm(1M) or svccfg is really a matter of preference. Note that you can also use inetadm or svccfg to enable TCP Wrappers on a per-service basis. For example, let's say that we wanted to enable TCP Wrappers for telnet but not for ftp. By default, both the global and per-service settings for TCP Wrappers are disabled:

# inetadm -p | grep tcp_wrappers
tcp_wrappers=FALSE

# inetadm -l telnet | grep tcp_wrappers
default  tcp_wrappers=FALSE

# inetadm -l ftp | grep tcp_wrappers
default  tcp_wrappers=FALSE

To enable TCP Wrappers for telnet, use the following command:

# inetadm -m telnet tcp_wrappers=TRUE

Let's check out settings again:

# inetadm -p | grep tcp_wrappers
tcp_wrappers=FALSE

# inetadm -l telnet | grep tcp_wrappers
         tcp_wrappers=TRUE

# inetadm -l ftp | grep tcp_wrappers
default  tcp_wrappers=FALSE

As you can see, TCP Wrappers has been enabled for telnet but none of the other inetd-based services. Pretty cool, eh?

You can enable TCP Wrappers support for rpcbind by running the following command:

# svccfg -s rpc/bind setprop config/enable_tcpwrappers=true
# svcadm refresh rpc/bind

This change can be verified by running:

# svcprop -p config/enable_tcpwrappers rpc/bind
true

That is all that there is to it! Quick, easy and painless! As always, let me know what you think!

Take care!

Technorati Tag:

Solaris 10 Security Technical TOI

In a recent posting, I talked about a presentation that I gave on Solaris 10 at a set of "boot camps" in Somerset, NJ and New York City. The presentation was a deep dive into Solaris 10 security that talked about a variety of capabilities in depth and covered many other features and enhancements that you may not have heard about. The version of this talk that I gave at the boot camp has been posted if you are interested. I would love to hear what you think.

If you would be interested in having Sun come out and deliver this presentations to your and your organizations, please let us know. We have been giving this (or similar) Solaris 10 Security deep dive talks to customers for some time now, and there has always been a lot of great interaction, discussion and Q&A focused on how this great technology can be applied to solve problems facing their organizations.

Take care!

Technorati Tag:

Thursday Oct 28, 2004

Integrating Solaris 10 BART and the Solaris Fingerprint Database

In a previous entry, I discussed on how you could automate the collection of file integrity information using the Solaris 10 Basic Auditing and Reporting Tool (or "BART"), Process Privileges, Role-based Access-Control and Secure Shell. Today, I would like to talk about how you can quickly and easily validate BART manifests for file integrity against the Solaris Fingerprint Database (or the "sfpDB").

Before jumping into the details, I would first like to talk about BART and the sfpDB including what they are, how they differ and how they can be used to complement one another. These are important considerations that must be understand in order to be able to use these technologies effectively.

The Basic Auditing and Reporting Tool is used to collect and compare attributes of filesystem objects installed on a system. BART collects filesystem object attributes including name, size, permissions, access control lists, UID, GID, etc. The exact attributes collected are depend on the type of object being evaluated. For a more detailed description of the attributes collected, see bart(1M).

You can run BART as many times as you like. In fact, each run of BART captures point in time information about the filesystem. Any two independent BART runs can be compared to determine if there have been any changes made to the objects being assessed. This is a great capability for detecting change. For example, with BART, you can quickly and easily answer the question: "has this file changed since yesterday"? In fact, since you can compare any two BART runs, you can select the time duration based on your individual requirements.

Regardless of the time intervals that you select, however, BART is still not able to answer the question: "is this a genuine object that Sun shipped?" This is because you need to manually perform your data collection using BART after the system has been installed. There is always the possibility (however slight) that someone or something could have changed a Sun-provided file from its default before you performed your first BART snapshot. As a result, it is important to be able to determine if the files contained in your BART manifest are genuine.

Luckily, there is another tool that you can use to help solve this problem. It is called the Solaris Fingerprint Database or sfpDB for short. The Solaris Fingerprint Database is a free SunSolve Online service that enables users to verify the integrity of files distributed with the Solaris Operating Environment. You can read more about the Solaris Fingerprint Database in the Sun BluePrints article The Solaris Fingerprint Database - A Security Tool for Solaris Operating Environment Files.

In a nutshell, the Solaris Fingerprint Database takes as input a list of MD5 file fingerprints and returns information about any fingerprints that match known files shipped by Sun. This is precisely where BART comes into play since BART collects MD5 signatures of the files that it processes. You can extract these fingerprints from the BART manifest and with some minor manipulation prepare them for submission to the Solaris Fingerprint Database, either directly using the web site interface or using the Solaris Fingerprint Database Companion tool. The Solaris Fingerprint Database Companion is a small Perl script that automates the submission process.

So, why would you want to do this? Great question! Leveraging the Solaris Fingerprint Database is very useful when you build your first BART manifest. Since this could have been done at system installation or perhaps days, weeks or months later, it is important for your to determine if you are creating a baseline from known good and genuine files. Further, this same technique can be re-applied to help resolve any conflicts that may arise from the installation of patches, for example. That way, you will know if a conflict was generated as a result of a new, genuine Sun file being installed versus some other type of change.

So, let's look at how you can implement this tip. We will use a very simple BART rules file to collect file signatures for items in the /usr/lib/nis directory. This directory was chosen arbitrarily for its relatively small size (making it more useful as an example). Any directory or set of directories could have been used here. To instruct BART to create a manifest for the files in /usr/lib/nis, we use the following command:

# find /usr/lib/nis | bart create -I
! Version 1.0
! Tuesday, October 26, 2004 (03:50:42)
# Format:
#fname D size mode acl dirmtime uid gid
#fname P size mode acl mtime uid gid
#fname S size mode acl mtime uid gid
#fname F size mode acl mtime uid gid contents
#fname L size mode acl lnmtime uid gid dest
#fname B size mode acl mtime uid gid devnode
#fname C size mode acl mtime uid gid devnode
/usr/lib/nis D 512 40755 user::rwx,group::r-x,mask:r-x,other:r-x 4166bb19 0 2
/usr/lib/nis/nisaddent F 63668 100555 user::r-x,group::r-x,mask:r-x,other:r-x 415cec73 0 2 ba94af26a1fa9dbb26ba0e2a07d888ec
/usr/lib/nis/nisauthconf F 10104 100555 user::r-x,group::r-x,mask:r-x,other:r-x 415cec73 0 2 08f50f2555553710f9eb3225ebc7a04e
/usr/lib/nis/nisclient F 38374 100755 user::rwx,group::r-x,mask:r-x,other:r-x 415cec8c 0 2 1bf5c90088933a61c0b1e9138d52b841
/usr/lib/nis/nisctl F 9816 100555 user::r-x,group::r-x,mask:r-x,other:r-x 415cec8b 0 2 fb4cade13611fb4904f06f26cc51ad8b
/usr/lib/nis/nisopaccess F 5545 100755 user::rwx,group::r-x,mask:r-x,other:r-x 415cec8d 0 2 00f19fcd403283f0510efadeafac2e66
/usr/lib/nis/nisping F 9904 100555 user::r-x,group::r-x,mask:r-x,other:r-x 415cec8b 0 2 dd928cf7778e19749b28334dfaf503b2
/usr/lib/nis/nispopulate F 33943 100755 user::rwx,group::r-x,mask:r-x,other:r-x 415cec8d 0 2 5af2053863e687464285d4892bcc4b11
/usr/lib/nis/nisserver F 38443 100755 user::rwx,group::r-x,mask:r-x,other:r-x 415cec8c 0 2 87e05dc59fd5e25f117313a3160c2c33
/usr/lib/nis/nissetup F 10927 100755 user::rwx,group::r-x,mask:r-x,other:r-x 415cec8c 0 2 8bdc76f327b86edee2c1dcafef289cb6
/usr/lib/nis/nisshowcache F 9656 100555 user::r-x,group::r-x,mask:r-x,other:r-x 415cec8b 0 2 a3d06fea784afe9ce6974cfa87dbe1d6
/usr/lib/nis/nisstat F 11056 100555 user::r-x,group::r-x,mask:r-x,other:r-x 415cec8a 0 2 63be71e1fb14121e20e95e1369d1485b
/usr/lib/nis/nisupdkeys F 18172 100555 user::r-x,group::r-x,mask:r-x,other:r-x 415cec8b 0 2 8f0fd3abbefd1ae1ef31083a18d59c18

What you will notice about this output is that the very last field is an MD5 fingerprint when the object type (column 2) is a file (type F). With this information, it is then easy to construct a command that will create a list of MD5 fingerprints that can be passed to the Solaris Fingerprint Database in a format that it will be able to recognize. Basically, we just need to select any type F (file) records and capture each corresponding fingerprint value. This can be accomplished using the simple command:

# find /usr/lib/nis | bart create -I | grep -v "\^#" | awk '$2 == "F" { print $NF }'
ba94af26a1fa9dbb26ba0e2a07d888ec
08f50f2555553710f9eb3225ebc7a04e
1bf5c90088933a61c0b1e9138d52b841
fb4cade13611fb4904f06f26cc51ad8b
00f19fcd403283f0510efadeafac2e66
dd928cf7778e19749b28334dfaf503b2
5af2053863e687464285d4892bcc4b11
87e05dc59fd5e25f117313a3160c2c33
8bdc76f327b86edee2c1dcafef289cb6
a3d06fea784afe9ce6974cfa87dbe1d6
63be71e1fb14121e20e95e1369d1485b
8f0fd3abbefd1ae1ef31083a18d59c18

Now that you have a list of MD5 fingerprints, you are ready to submit them to the Solaris Fingerprint Database. The sfpDB will only accept a total of 256 individual fingerprints at a time. In this case, it is not an issue since we only generated 12. If we had generated more than 256, which is likely for a real BART run, then we could use the Solaris Fingerprint Database Companion to process them since this tool will automatically break up the list of fingerprints into chunks of 256 and process each chunk in turn until all of the fingerprints have been processed.

So, let's see what happens when these fingerprints are submitted to the database. For the sake of simplicity, for this example, I used the sfpDB web interface which produced the following result:

Results of Last Search

ba94af26a1fa9dbb26ba0e2a07d888ec - - 0 match(es)
    Not found in this database.

08f50f2555553710f9eb3225ebc7a04e - - 0 match(es)
    Not found in this database.

1bf5c90088933a61c0b1e9138d52b841 - - 0 match(es)
    Not found in this database.

fb4cade13611fb4904f06f26cc51ad8b - - 0 match(es)
    Not found in this database.

00f19fcd403283f0510efadeafac2e66 - - 9 match(es)

        \* canonical-path: /usr/lib/nis/nisopaccess
        \* package: SUNWnisu
        \* version: 11.8.0,REV=2000.01.08.18.17
        \* architecture: i386
        \* source: Solaris 8/x86

        \* canonical-path: /usr/lib/nis/nisopaccess
        \* package: SUNWnisu
        \* version: 11.8.0,REV=2000.10.28.19.07
        \* architecture: i386
        \* source: Trusted Solaris 8/x86

        \* canonical-path: /usr/lib/nis/nisopaccess
        \* package: SUNWnisu
        \* version: 11.8.0,REV=2003.04.03.19.26
        \* architecture: i386
        \* source: Trusted Solaris 8/x86

        \* canonical-path: /usr/lib/nis/nisopaccess
        \* package: SUNWnisu
        \* version: 11.9.0,REV=2002.11.04.02.51
        \* architecture: i386
        \* source: Solaris 9/x86


        \* canonical-path: /usr/lib/nis/nisopaccess
        \* package: SUNWnisu
        \* version: 11.8.0,REV=2000.01.08.18.12
        \* architecture: sparc
        \* source: Solaris 8/SPARC

        \* canonical-path: /usr/lib/nis/nisopaccess
        \* package: SUNWnisu
        \* version: 11.8.0,REV=2000.10.30.04.48
        \* architecture: sparc
        \* source: Trusted Solaris 8/SPARC

        \* canonical-path: /usr/lib/nis/nisopaccess
        \* package: SUNWnisu
        \* version: 11.8.0,REV=2001.09.25.00.12
        \* architecture: sparc
        \* source: Trusted Solaris 8 4/01

        \* canonical-path: /usr/lib/nis/nisopaccess
        \* package: SUNWnisu
        \* version: 11.8.0,REV=2003.04.03.21.27
        \* architecture: sparc
        \* source: Trusted Solaris 8/SPARC

        \* canonical-path: /usr/lib/nis/nisopaccess
        \* package: SUNWnisu
        \* version: 11.9.0,REV=2002.04.06.15.27
        \* architecture: sparc
        \* source: Solaris 9/SPARC

dd928cf7778e19749b28334dfaf503b2 - - 0 match(es)
    Not found in this database.

5af2053863e687464285d4892bcc4b11 - - 2 match(es)

        \* canonical-path: /usr/lib/nis/nispopulate
        \* package: SUNWnisu
        \* version: 11.9.0,REV=2002.11.04.02.51
        \* architecture: i386

        \* source: Solaris 9/x86

        \* canonical-path: /usr/lib/nis/nispopulate
        \* package: SUNWnisu
        \* version: 11.9.0,REV=2002.04.06.15.27
        \* architecture: sparc
        \* source: Solaris 9/SPARC

87e05dc59fd5e25f117313a3160c2c33 - - 0 match(es)
    Not found in this database.

8bdc76f327b86edee2c1dcafef289cb6 - - 0 match(es)
    Not found in this database.

a3d06fea784afe9ce6974cfa87dbe1d6 - - 0 match(es)
    Not found in this database.

63be71e1fb14121e20e95e1369d1485b - - 0 match(es)
    Not found in this database.

8f0fd3abbefd1ae1ef31083a18d59c18 - - 0 match(es)
    Not found in this database.

You will note that a number of files show no matches in the database. Have no fear - this is due to the fact that the tests are being run on a pre-release version of Solaris 10. Once Solaris 10 officially ships, all of the fingerprints will be recorded and should show up here. You will also note that for the positive matches, the source showed up as Solaris 9/SPARC, Solaris 9/x86, Trusted Solaris 8/SPARC, etc. This is because the file is the same on each of those versions of (Trusted) Solaris including Solaris 10. Just to make things interesting, the following example shows how you can automate this using the Solaris Fingerprint Database Companion. In the following example, I will only look for files that do not match any of the records in the database:

# find /usr/lib/nis | bart create -I | grep -v "\^#" | awk '$2 == "F" { print $NF }' > ./md5.list

# cat ./md5.list
ba94af26a1fa9dbb26ba0e2a07d888ec
08f50f2555553710f9eb3225ebc7a04e
1bf5c90088933a61c0b1e9138d52b841
fb4cade13611fb4904f06f26cc51ad8b
00f19fcd403283f0510efadeafac2e66
dd928cf7778e19749b28334dfaf503b2
5af2053863e687464285d4892bcc4b11
87e05dc59fd5e25f117313a3160c2c33
8bdc76f327b86edee2c1dcafef289cb6
a3d06fea784afe9ce6974cfa87dbe1d6
63be71e1fb14121e20e95e1369d1485b
8f0fd3abbefd1ae1ef31083a18d59c18

# sfpC.pl ./md5.list | grep -- "- 0 match"
 ba94af26a1fa9dbb26ba0e2a07d888ec -  - 0 match(es)
 08f50f2555553710f9eb3225ebc7a04e -  - 0 match(es)
 1bf5c90088933a61c0b1e9138d52b841 -  - 0 match(es)
 fb4cade13611fb4904f06f26cc51ad8b -  - 0 match(es)
 dd928cf7778e19749b28334dfaf503b2 -  - 0 match(es)
 87e05dc59fd5e25f117313a3160c2c33 -  - 0 match(es)
 8bdc76f327b86edee2c1dcafef289cb6 -  - 0 match(es)
 a3d06fea784afe9ce6974cfa87dbe1d6 -  - 0 match(es)
 63be71e1fb14121e20e95e1369d1485b -  - 0 match(es)
 8f0fd3abbefd1ae1ef31083a18d59c18 -  - 0 match(es)

While this is a quick and easy way to find files that were not shipped by Sun, it would be nice to have the filename listed in addition to just the fingerprint so that we do not have to manually correlate them later. You can do this very easily by constructing the MD5 fingerprints in a slight different way (which is also readable by the Solaris Fingerprint Database):

# find /usr/lib/nis | bart create -I |\\
awk '$1 ~ /\^\\// && $2 == "F" { printf "MD5 (%s) = %s\\n", $1, $NF; }' > md5.list

# cat ./md5.list
MD5 (/usr/lib/nis/nisaddent) = ba94af26a1fa9dbb26ba0e2a07d888ec
MD5 (/usr/lib/nis/nisauthconf) = 08f50f2555553710f9eb3225ebc7a04e
MD5 (/usr/lib/nis/nisclient) = 1bf5c90088933a61c0b1e9138d52b841
MD5 (/usr/lib/nis/nisctl) = fb4cade13611fb4904f06f26cc51ad8b
MD5 (/usr/lib/nis/nisopaccess) = 00f19fcd403283f0510efadeafac2e66
MD5 (/usr/lib/nis/nisping) = dd928cf7778e19749b28334dfaf503b2
MD5 (/usr/lib/nis/nispopulate) = 5af2053863e687464285d4892bcc4b11
MD5 (/usr/lib/nis/nisserver) = 87e05dc59fd5e25f117313a3160c2c33
MD5 (/usr/lib/nis/nissetup) = 8bdc76f327b86edee2c1dcafef289cb6
MD5 (/usr/lib/nis/nisshowcache) = a3d06fea784afe9ce6974cfa87dbe1d6
MD5 (/usr/lib/nis/nisstat) = 63be71e1fb14121e20e95e1369d1485b
MD5 (/usr/lib/nis/nisupdkeys) = 8f0fd3abbefd1ae1ef31083a18d59c18

# sfpC.pl ./md5.list | grep -- "- 0 match"
 ba94af26a1fa9dbb26ba0e2a07d888ec - (/usr/lib/nis/nisaddent) - 0 match(es)
 08f50f2555553710f9eb3225ebc7a04e - (/usr/lib/nis/nisauthconf) - 0 match(es)
 1bf5c90088933a61c0b1e9138d52b841 - (/usr/lib/nis/nisclient) - 0 match(es)
 fb4cade13611fb4904f06f26cc51ad8b - (/usr/lib/nis/nisctl) - 0 match(es)
 dd928cf7778e19749b28334dfaf503b2 - (/usr/lib/nis/nisping) - 0 match(es)
 87e05dc59fd5e25f117313a3160c2c33 - (/usr/lib/nis/nisserver) - 0 match(es)
 8bdc76f327b86edee2c1dcafef289cb6 - (/usr/lib/nis/nissetup) - 0 match(es)
 a3d06fea784afe9ce6974cfa87dbe1d6 - (/usr/lib/nis/nisshowcache) - 0 match(es)
 63be71e1fb14121e20e95e1369d1485b - (/usr/lib/nis/nisstat) - 0 match(es)
 8f0fd3abbefd1ae1ef31083a18d59c18 - (/usr/lib/nis/nisupdkeys) - 0 match(es)

Using the different MD5 fingerprint format, you can now easily see those files for which a record was not found in the Solaris Fingerprint Database.

Before I stop, I did want to express one note of caution. BART can be used to tell you if a file changed between two sets of snapshots. The Solaris Fingerprint Database can tell you if a file was shipped by Sun. There is still a problem that exists and of which you must be made aware. It is possible for an attacker to replace a valid Solaris binary or library with another from an older (or unpatched) version of the operating system. While the Solaris Fingerprint Database will tell you that this is a genuine Sun binary, it may still not be a binary appropriate for the system. Due to Solaris binary compatibility guarantees, it is possible for an attacker to replace a binary with one from a previous version of the OS that may have been vulnerable in some way.

Another potential issue is that an attacker could have replaced a valid Sun binary with another. In this case, the name reported by the Solaris Fingerprint Database "canonical-path" field will differ from that passed via the MD5 fingerprint.

Both of these issues should raise a big red flag. So what should you do? When you do detect file conflicts using BART and check them out using the Solaris Fingerprint Database, be sure to take a look at the canonical path, package, version and other fields to ensure that they are appropriate for your system. You can also always take a look at the fingerprints associated with any patches you applied. Either way, you should not just let these conflicts slide as they could be an indication of a security incident or at least a change control problem.

Well, it is about time to draw this article to a close. As always, I hope you enjoyed this article and will be able to apply the tips contained within to your environment. Please let me know if you have any suggestions for any future articles. Thank you for allowing me to share this with you. Until next time, take care!

Technorati Tag:

Friday Oct 01, 2004

Automating Solaris 10 File Integrity Checks

Well, after a short hiatus, I am back with what I hope is a very interesting and useful tip for our Solaris 10 user community. Today's tip talks about how you can automate the collection of file integrity information using Solaris Secure Shell, Role-based Access Control, Process Privileges and the new Solaris 10 Basic Auditing and Reporting Tool. This sounds like quite a bit of work, but I can assure that it is simple. Allow me to demonstrate...

New to the Solaris 10 OS is a feature called the Basic Auditing and Reporting Tool or just "BART" for short. BART is intended to provide you with a quick and easy way to collect information on filesystem objects and their attributes so that at a later point in time you can determine if there have been any changes.

BART has two primary modes of operation: create and compare. When run in create mode, BART will collect filesystem object information from a system. You can just collect everything on the system, everything under a specified root directory, just a subset of files or you can specify a more granular policy in what is called a rules file) that can be customized to meet your organization's requirements. What's more is that you can specify the rules to be read from a file or from standard input. The output of a BART run is called a manifest and it is directed to standard output (at which you can redirect it to a file, another program, etc.) The ability to read rules from standard input and produce a manifest on standard output are important points as they factor heavily in the tip that I describe below.

To use BART in compare mode, you need two BART manifests and optionally a rules file that will be used to determine how the comparison is made. The first manifest, called the control, is used as your baseline. The second manifest, called the test, is then compared against the control (in accordance with a set of rules if supplied). In many cases, it is likely that you will use a rules file to help eliminate any noise from your reports so that you can better focus your efforts.

So now that I have given you some background on the Basic Auditing and Reporting Tool, let's dive into the specifics of this tip. For customers with both large and small Solaris deployments, there is a growing need to manage cost and complexity. The goal of this tip is to highlight how the collection of filesystem information using BART can be securely automated across any number of systems (with any number of zones). Through the use of a centralized collection authority, we will be able to collect BART manifests across a network of Solaris 10 systems using strong authentication, least privilege and encryption over the wire. This allows you to then store and compare these manifests on a well-protected system (or zone) to which access can be significantly limited.

I will now describe the steps that you will need to take to implement this tip. Brief descriptions or guidance will be provided as appropriate. As a matter of convention, I will refer to the two systems in this example as client and manager. The client system is the one being examined by BART. The manager is where all of the BART rules and manifests will be stored and from where all connections to client will be made.

The first thing that we will do is create a new user on client whose only purpose is to collect filesystem information and create BART manifests. While for this example, I am only focused on a single client system, this same type of approach could be applied for a network of systems.

# mkdir -p /export/home
# useradd -d /export/home/bartadm -m -s /bin/pfsh bartadm
64 blocks
# passwd -N bartadm
passwd: password information changed for bartadm

Notice that I created the bartadm account as non-login account. This means that this account does not have a Unix login password, but is otherwise able to access the system (by using other authentication mechanisms or through the use of delayed execution mechanisms such as cron(1M)). This is necessary since the default behavior of useradd(1) is to create an account that is locked. You may also notice that this account was created with a profile shell, /bin/pfsh. This was done to allow commands executed by this user to be evaluated by the Solaris Role-based Access Control ("RBAC"") facility to determine if the command will run with altered privileges.

Now that the account has been created, we will create a Secure Shell public key that will be used to access the account. Note that this does not need to be done on the system where you created the user. In fact, I would recommend that you generate the key on manager. This way, you will not need to transfer the private key over any network.

$ ssh-keygen -t dsa
Generating public/private dsa key pair.
Enter file in which to save the key (/export/home/bartadm/.ssh/id_dsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /export/home/bartadm/.ssh/id_dsa.
Your public key has been saved in /export/home/bartadm/.ssh/id_dsa.pub.
The key fingerprint is:
42:ca:d7:fa:ab:1c:f8:c0:5b:2c:7b:56:28:85:dc:65 bartadm@manager

Once your key-pair has been created, you should copy the public key (id_dsa.pub) from manager to client. As part of this copy, be sure to rename the file id_dsa.pub to authorized_keys Once complete, you should have something like this:

[on manager]

# pwd
/export/home/bartadm/.ssh
# ls -l
total 6
-rw-------   1 bartadm  other        736 Sep 30 23:03 id_dsa
-rw-r--r--   1 bartadm  other        600 Sep 30 23:03 id_dsa.pub

[on client]

# pwd
/export/home/bartadm/.ssh
# ls -l
total 6
-rw-r--r--   1 bartadm  other        640 Oct  1 09:14 authorized_keys

Now, while on client, we will need to make one more change. We must configure Secure Shell to only run a specific command when this public key is used. To do this, we use the command directive. For more information on this capability, see the "authorized_keys File Format" section on sshd(1M). So, at this point, edit the authorized_keys adding the following prefix to the existing public key:

command="/usr/bin/bart create -r -"

This will cause BART to be run in create mode taking a rules file from standard input. This will allow you to specify different BART rules files (as needed) without having to change the configuration of client.

The end result will look something like this (with a different public key):

command="/usr/bin/bart create -r -" ssh-dss AAAAB3NzaC1kc3MAAACBAJ6zG8SJtQVi/Et
OugyktNssLVofLmUepqsh712+D1AObTwRWZwjSH4hE423U3AcfY99u9ZxsdJ0sEpqnnvXmKaym7pMgk
NxMCPoPcnf4mAIcx9IQkpotAiCbCQ+My5lFD4iW4Nxjqh6KwIecEaABcpg2x5nhaX8Bsx0XURO/f+jA
AAAFQCD6dOAM1JunvUeCWNpXoB6tLyLewAAAIAXya1UPijNFIjymsJ0gjQXyCgll8/tORHy2vrloH7v
gh9RJ9YNRWSZZjyRvLlKTd4KFIfcjT43WlVWJKa/A7l14DGntoTS+dRh4MohJXdUjYMvV+OODc1j8V2
p+JWbbHlqDxa+zAuFEskoWNPmBrTnbLNzamIPnQ7ZaqWsbWuePQAAAIEAmqlCaMfuFYWlvDHeak79Fm
xHJjRLqmvRwlPPtkW8XDuF8wn8lj/+glWWY6/VJVtbfgteZLweotdM2wvdfXNqROiU9vvlylOdv29iA
DxsSlPGSrjXkbkNGQXMHTgPQmfbDhmtpnM6occl2R+J8dpDT59zWV7+egNZ0TTV8GNnmng=
gmb@manager

We are in the home stretch now. Next, we will create a RBAC rights profile on client that will allow the bartadm user to run BART with sufficient privileges to collect files across the filesystem. This is done to prevent the bartadm command from running as root. Remember that this account is configured as non-login and its Secure Shell public key is configured to only run the BART command. Even then, you will need possession of the bartadm private key and passphrase (which is stored on the heavily protected manager system). To do this, you will need to add the following lines to the /etc/security/prof_attr and /etc/security/exec_attr files:

# grep "\^File Integrity:" /etc/security/prof_attr
File Integrity:::File Integrity Management:
# grep "\^File Integrity:" /etc/security/exec_attr
File Integrity:solaris:cmd:::/usr/bin/bart:privs=file_dac_read,file_dac_search

Notice that the File Integrity rights profile grants the file_dac_read and file_dac_search privileges. These privileges are needed so that the bartadm user can search directories and read files that normally would not be permitted due to discretionary access controls (Unix permissions, ACLs, etc.) A description of these two privileges can be found using the ppriv(1) command:

# ppriv -l -v file_dac_read
file_dac_read
        Allows a process to read a file or directory whose permission
        bits or ACL do not allow the process read permission.
# ppriv -l -v file_dac_search
file_dac_search
        Allows a process to search a directory whose permission bits or
        ACL do not allow the process search permission.

Lastly, you need to grant the new File Integrity rights profile to the bartadm user. To complete this task, use the follwing command:

# usermod -P "File Integrity" bartadm

This command will add the following line to the /etc/user_attr file:

# grep "\^bartadm:" /etc/user_attr
bartadm::::type=normal;profiles=File Integrity

That was not too bad, right? There are certainly other things that you can do such as limiting access to the bartadm public key by hostname or IP address (for example only allowing access from manager), restricting bartadm access to cron(1M), etc. but at least you now have the basics that you need to get this working. So, let's now verify that everything works as expected from the manager system.

Before we begin, back on manager, I will create a small example BART rules file. This will be used as input to BART on the client passed over a Secure Shell channel that uses public-key authentication to executive a specific command. The output of BART will be displayed to standard output so we can redirect this to a file for later comparison. Here is the sample rules file:

/usr/sbin
CHECK all
This example will only collect information for files under /usr/sbin. When used in comparison mode, all of the collected attributes will be checked. This is just a small and simple example to verify that the functionality works. Once this is achieved, you can then begin to develop more sophisticated policies based on your organization's needs. So, let's try it out (from manager)...

$ cat ./client.rules | ssh -T -l bartadm client
! Version 1.0
! Friday, October 01, 2004 (10:46:56)
# Format:
#fname D size mode acl dirmtime uid gid
#fname P size mode acl mtime uid gid
#fname S size mode acl mtime uid gid
#fname F size mode acl mtime uid gid contents
#fname L size mode acl lnmtime uid gid dest
#fname B size mode acl mtime uid gid devnode
#fname C size mode acl mtime uid gid devnode
/usr/sbin D 4608 40755 user::rwx,group::r-x,mask:r-x,other:r-x 415c6c1d 0 2
/usr/sbin/6to4relay F 9888 100555 user::r-x,group::r-x,mask:r-x,other:r-x 414f3ef2 0 2 5dbc53336307f5caf965e4451abde647
/usr/sbin/acctadm F 28356 100555 user::r-x,group::r-x,mask:r-x,other:r-x 414f3bb4 0 2 ece9d92d00b0c13ed2d56580e3856df7
/usr/sbin/add_drv F 44244 100555 user::r-x,group::r-x,mask:r-x,other:r-x 414f3cda 0 2 10f542c2c228c2a0efdc16bc543d96d6
/usr/sbin/allocate F 18764 104755 user::rwx,group::r-x,mask:r-x,other:r-x 414f3e96 0 2 2e98bb2d02c4e87b875885dfb3838932
/usr/sbin/arp F 9912 100555 user::r-x,group::r-x,mask:r-x,other:r-x 414f3ef2 0 2 203a43e71abc9c3b9ba2a1c38647b285
/usr/sbin/audit F 10140 100555 user::r-x,group::r-x,mask:r-x,other:r-x 414f3e85 0 2 26b6e6241c6a21aab5fc1bebb816f8fc
[... content edited for brevity...]

Looks great, so let's save a two copies to illustrate how to use the compare feature:

$ cat ./client.rules | ssh -T -l bartadm client > ./client.manifest.1
$ cat ./client.rules | ssh -T -l bartadm client > ./client.manifest.2
$ bart compare -r ./client.rules ./client.manifest.1 ./client.manifest.2
$

It should come as no surprise that we get no comparison errors. While this is not overly interesting, it is a very good thing since you know your files have not changed (relative to the baseline - client.manifest.1). As an example, here is a case where the comparison detected two problems:

$ bart compare -r ./client.rules ./client.manifest.1 ./client.manifest.2 /usr/sbin/auditd: acl control:user::r-x,group::r-x,mask:r-x,other:r-x test:user::r-x,group::r-x,mask:r-x,other:rwx contents control:28dd3a3af2fcc103f422993de5b162f3 test:28893a3af2fcc103f422993de5b162f3

In this case, the /usr/sbin/auditd program was modified (contents change) and had its access control list modified - adding write access to "world". Not a very good thing ;-)

Well, that's all for today. I hope you enjoyed this article and find its content useful in helping you and your organizations better leverage Solaris 10. As always, let me know what you think! Take care. Technorati Tag:

About

gbrunett

Search

Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today