February 2006 Archives

Sun Feb 19 15:06:53 2006

Security by PAL

While auditing commercial software for security issues, you often come across the pattern of proprietary authentication, authorization and object access control. The software designers, or, in case it wasn't really designed, the developers, implement their own user credential and access permission mechanisms. Doing so always significantly degrades the security of the entire solution and the custom mechanisms almost always go down in flames the first time someone looks at them too hard.

I vividly remember the fascination of coming up with your own authentication mechanisms. 14 years ago, I was doing the same. This was at the times of MS-DOS, where there wasn't any such facility provided by the operating system. While it still didn't make too much sense to implement something that was called in autoexec.bat to check for credentials (remember the F5 key?), it wasn't mission critical or even commercial software either, so I hope it's forgivable. Interestingly enough, one year later, I was presented with an access control software that was used by the German postal service to secure access to their MS-DOS machines. The person showing it to me said: "You can't break into this, it is commercial grade software." while I rebooted the machine and pressed F5. Well, yes, I could.

When designing identity checks and object access control, the guiding principle should be: PAL. It is a German slang acronym and stands for "Problem anderer Leute", which can roughly be translated to "someone else's problem". In most cases, your underlying operating system or database does require authentication anyway and does offer a fine granularity of access control mechanisms based on the credentials used in the authentication process. Use them!

When moving into a new house or flat, nobody in his right mind would go into a hardware store (as in "Home Depot", not as in "Radio Shack") and buy metal, rasp and small drill bits to make himself a lock for the front door. The person would instinctively know that the expense in time and money exceeds buying a commercial door lock. Additionally, the person would normally realise that a homemade lock will not provide the same level of security.

In many applications, the homemade approach is favoured. By implementing it's own authentication and authorization schemes and using a single almighty user account on the operating system and/or database, the vendor makes his own door lock out of cardboard or wood and embeds the original key to the commercial door lock in the mechanism, so the original door lock still functions. Sounds silly? It is.

Imagine a kiosk type application, such as a cash register or device control system, running on a modern version of Microsoft Windows and compare the following two design approaches. First, we look at what's usually done, namely the kiosk application implements it's own authentication and authorization scheme:

  • For the application to run, the Windows system must be configured with auto-logon, which means leaving the password of the operating system account in clear text in the registry.
  • Since the application runs always with the same system account, you cannot use any of the access control mechanisms on file systems or the registry.
  • The application must try to prevent access to any other functionality a logged on Windows user normally has (i.e. explorer, regedit). This usually fails and even if not, requires a lot of code writing and additional hooking to take place.
  • Any additional credentials the kiosk application needs, for example a database account, must be stored somewhere. But since the application always runs in the same account context, the only place to prevent access to the information is by the application itself. It might even use a fancy crypto algorithm such as AES to protect the information, using a hidden static key.
  • For any special functionality, such as archiving stored transactions, creating new users or modifying existing ones, the application needs new code and must check access permissions of the currently logged in application account to perform this operation.

It should be fairly obvious by now that, by implementing it's own authentication, the application actually disabled all build-in security provided. And, regardless of your opinion on Microsoft, it's fair to say that they probably spent significantly more time on making sure their authentication and authorization is correct than the developer(s) of the kiosk application.

If, on the other hand, the application would be designed to use the Windows user accounts as means of authentication, the picture is a lot different:

  • If the user does not possess a valid Windows account, she cannot even logon and therefore not run the application nor access any data.
  • Access to files in the file system and information in the registry can be restricted to read-only or read/write according to the privileges the account has. The access checks are done by the operating system, which requires no additional code and probably performs better. Also, there is no chance for the application developer to forget about a permission check.
  • The application can be integrated as the shell for the respective user account. The user might still be able to access other native Windows functionality, but the harm caused is very limited, since access to the critical files is not allowed, regardless of the tools the attacker uses. The attacker would need a privilege escalation vulnerability to get there.
  • The additional credentials the application requires can be stored on a per-user bases using integrated protected storage. The CryptProtectData API function can be used to store a user account for the database. Again, the one-to-one mapping allows for the database to use it's own integrated permission checking and not allow an unprivileged user to change any tables she's not supposed to.
  • To manage user accounts, the existing tools of the Windows operating system can be used. The same holds true for the database. No additional code is required.
  • Introducing containers, such as groups, into such a design is easy, because it's already there. Additionally, if the application suddenly needs to do central authentication, no code must be changed since the functionality essentially would not change by dropping an Active Directory into the picture.

The same approach works on almost every modern operating system, although the almighty root account on UNIX type systems makes it a little more complicated to securely store user related credentials. The approach also works with most web servers and databases. Side effects include less code to develop, higher security due to the use of well-audited code and kissing goodbye authentication bypass vulnerabilities.

Interestingly enough, some commercial web application developers have already learned this lesson and are using frameworks that handle authentication and session tracking for them. Next time you evaluate the design of a to-be-build solution or a to-be-purchased product, ask how authentication and authorization are implemented. If you hear stories about strong encryption and their own user management, at least ask why.

Posted by FX | Permanent link | File under: paradigms

Tue Feb 14 11:19:43 2006

Security by weglassen

Recently I met a friend of mine, who is responsible for a fairly large production network with well-founded high security requirements. One of the interesting aspects of his work was the plan to actually remove some of the security devices and appliances deployed. Removing, you ask? Yes!

The driving force for looking at the effectiveness of their network security was of course money, namely the money needed to operate and maintain it. When this network was built, a great deal was spent on the security of it, much like many people in the industry and all security appliance vendors recommend. But when looking at the cost years later, they decided to grab available data and see what type and how many actual attacks happened since the deployment of all the firewalls, IDS sensors and whatnot. The result: very little. So they get rid of some.

On the other hand, think about the security devices as targets and not protections for a minute.

Take a fairly simple protocol, such as HTTP. A web server only needs to implement the functionality of this one clear text protocol correctly and will be fine. Now, how many major web servers do you know that didn't have a HTTP parsing vulnerability in the past? But the parsing of a HTTP request is implemented in a fairly small share of the web server's code base, because it also has to deal with things like MIME types, virtualization of path information, finding and opening files and other stuff.

Compare this to an network intrusion detection system (NIDS) sensor. It needs to do the same thing, namely implement protocol parsing correctly, but for 100 some times complex protocols (the number is from ISS's Proventia). Also, the protocol inspection is it's job, so the lion share of binary code executed is actually attackable surface. In the past, people used TAPs (RX-only network connection) and stated that this prevents attackers from breaking into the NIDS sensors, because they would be unable to communicate with it. Did anybody ever evaluate a fully deployed NIDS under the assumption of one sensor running non-interactive attacker code? I think a not too complex multi-stage shellcode (the term is a bit misleading here) should be able to exploit the central NIDS management server from the implicitly trusted NIDS sensor and phone home from there. Stuff like this has been done before.

Today, everyone deploys inline network IPS. eEye showed nicely [1, 2] what it means to deploy something with such a large attack surface in the middle of your communication stream: namely, your IPS gets owned first and used as a very convenient jump point into the management network. I also vividly remember when K2 presented at DefCon 9 on polymorphic shellcode [3] and the ISS sensor, which was supposed to just not notice the exploit, crashed in front of the audience while parsing the modified exploit. And please don't think this is about ISS's products, this is a general issue.

On the organizational side of larger IT operations, the same or related teams usually manage the firewall and NIDS rules. In practice, this means the firewall will have a rule saying "block port 99" and the NIDS will have a rule saying, "alert on internal port 99 traffic". So you have two types of NIDS sensors deployed, the ones on the outside producing several thousand alarms per minute and the ones on the inside reporting traffic violations and P2P leech. Is this worth thousands of bucks per month operational cost?

But the only actual reason many organizations have these devices is for forensics, since nobody is watching them in real time anyway. If I were to be called into a case where systems are owned using 0day, I would much prefer a full packet dump covering the last 30 days instead of a selection of may-be-accurate information the IDS has for the same time period. Running a full packet log with a rotation of 30 days is going to cost you very little. A common 100 GB hard drive will be easily able to handle a day worth of traffic and one can reproduce the entire day completely without a semi-intelligent piece of hot needle software pre-filtering the data.

Again, the very old recommendation to keep things simple and stupid holds ground. If your deployed software does not act on input such as network traffic, the same can be as malformed as it wishes to be. I wonder how many IDS sensors choke on HTTP chunked encoding reassembly when the "protected" web server behind it does not even support this transfer method.

Consider throwing away at least parts of your IDS and reinvesting the saved money and staff time into their education. Even a little talented network security person will be able to use additional knowledge more intelligently than any of your alert filtering software solutions. And, you don't have to script them: they are voice controllable.

Posted by FX | Permanent link | File under: paradigms

Mon Feb 13 19:21:58 2006

Let's start with a 0day

The intention of this Lablog is to reflect on a more abstract level upon what works and what doesn't in computer security. Like something wanted to make a point, the setup of this very piece of software to run the Lablog and RSS feeds proved to be a showcase of the later.

Although I very much want to, I currently cannot change the average fault ratio in software that is stable since the 70s: 0,5 - 2 faults per 1000 lines of source code. While I can't change that number, I can reduce my risk by reducing the number of code lines executed for what I want. You can't screw up that much in a "Hello World" program.

Therefore, I refrained from using some of the major blog solutions because they contain a lot of code and I don't run PHP. Instead, I selected a lightweight Python solution: PyBlosxom. Setting it up caused the usual system administration issues, but that was expected and fairly quickly dealt with.

The big surprise came, when I configured the categories plugin. Selecting the / category twice as a test produced a URL that ended on three slashes: /cgi-bin/pyblosxom.cgi///. To my astonishment, the blog presented several files from the system's /var/spool/ and /etc/ directories in my web browser. After double and triple checking my various configurations, verifying that I was running the latest version and diffing the distribution package I used against a fresh copy of the source, I had to conclude I was indeed looking at a 0day bug.

This left me with two options: reverting the entire installation, selecting another piece of software and beginning from the scratch or finding and eliminating the bug. The later seemed the more feasible, since the installation already did what I wanted. The debug log mode of the software did only produce two entries per request in the log file, so it was little help. Therefore, I had to read the code. My Python skills aren't very good yet, which made it an extra challenge.

After introducing a number of new debug logging messages and some more reading and testing, the fault became clear: When parsing the requested resource, the code would check if it begins with a / and remove it:

if path_info.startswith("/"):
    path_info = path_info[1:]

After that, it would use it's configured directory root and combine the two using os.path.join:

absolute_path = os.path.join(config["datadir"], path_info)

Checking the Python documentation, it would read: "Joins one or more path components intelligently. If any component is an absolute path, all previous components are thrown away, and joining continues" Therefore, requesting any absolute system path from the blog software will cause the path to be read and interpreted as entries directory and displayed. Ergo: arbitrary file read.

I fixed the software. Submitting a bug into their bug tracking system required a login and the site also mentioned you should rather post to the mailing list. My post to the same still awaits moderator approval, since I didn't subscribe.

The story highlights several general issues we are facing: First, writing in a programming language that is considered modern, robust and object oriented does not prevent bugs and these bugs may very well be security issues. Second, nobody has several days spare time to source code audit the software just because she wants to setup a simple blog. We need solutions to those problems, and this Lablog will talk about some of the ways we try to get there.

Update For anyone running PyBlosxom, version 1.3.2 was released, fixing the bug.

Posted by FX | Permanent link