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.