PHP Code Audit 8—SSRF Vulnerability

1. Basics of SSRF Vulnerabilities

1. Vulnerability principles and defense methods

1) Vulnerability principle

Most of the formation of SSRF is due to the fact that the server provides the function of obtaining data from other server applications, and there is no filtering and restriction on the target address. For example, the hacker operates the server to obtain the text content of the web page from the specified URL address, loads the picture at the specified address, etc., and uses the request forgery of the server.

2) Defense method

  • It is easier to filter the returned information and verify the remote server's response to the request. If the web application is to obtain a certain type of file. Then verify whether the returned information meets the standards before displaying the returned results to the user.

  • Unify the error information to prevent users from judging the port status of the remote server based on the error information.

  • Limit the port of the request to the port commonly used by http, for example, 80, 443, 8080, 8090.

  • Blacklist intranet ip. Prevent applications from being used to obtain intranet data and attack the intranet.

  • Disable unnecessary protocols. Only http and https requests are allowed. It can prevent problems caused by file:///, gopher://, ftp://, etc.

2. Trigger functions and vulnerability scenarios

1) Common functions that trigger SSRF

  • curl(): It is used to execute the specified CURL session. It supports many protocols. The protocols commonly used in SSRF are tested and supported, such as dict, ghoper, and file.
  • file_get_content(): Write the file into a string. When the url is an intranet file, it will first read out the content of the file and then write it in, resulting in the file being read
  • fopen(): open a file
  • readline(): Open a file and read the content line by line

2) Common vulnerability scenarios

  • Social sharing function: Get the title and other content of the hyperlink for display
  • Transcoding service: optimize the web content of the original address through the URL address to make it suitable for mobile phone screen browsing
  • Online translation: translate the content of the corresponding web page for the URL
  • Image loading/downloading: For example, clicking in a rich text editor to download an image locally; loading or downloading an image through a URL address
  • Picture/article collection function: mainly it will take the title and text content in the URL address as display for a good user experience
  • Website collection, where the website is crawled: some websites will perform some information collection work on the url you input
  • Request resources from a remote server (upload from url such as discuz!; import & expost rss feed such as web blog; places using xml engine objects such as wordpress xmlrpc.php)

3. Common usage scenarios

0) Pre-knowledge: common protocols

Pseudo agreement allow_url_fopen allow_url_incude other instructions
php://input on/off on It is invalid to access the POST datapart in the POST request .enctype="multipart/form-data"php://input
php://filter on/off on/off Commonly used and read source code, the read content is output after Base64 encoding
file:// on/off on/off read local file
data:// on on From now on, data stream wrappers PHP>=5.2.0can be used to pass data in the corresponding format. data://Usually can be used to execute PHP code.
http:// & https:// on on/off Initiate http or https request
gopher:// on/off on/off Use TCP port 70, the mainstream protocol before www, and support sending GET and POST requests. The usage requirements are PHP > v5.3, Java JDK < v1.7
dict:// on/off on/off

1) Read local files

读取本地文件,常用的方法就是使用file://,php://等伪协议进行读取。下面是两个读取本地文件的示例:
?file=file:///etc/passwd
?file=php://filter/read=convert.base64-encode/resource=C://windows/win.ini

2) Intranet IP and port detection

In the SSRF vulnerability, the dict protocol and the http protocol can be used to detect the survival and port opening of intranet hosts.

eg: ?url=dict://127.0.0.1:8000

In this case, we can use the intruder brute force module of bursuite to test, and judge by the length of the response result or the response time.

3) Attack the intranet web program

攻击内网web程序,通常用gopher协议进行,当然也可以使用http或者https协议,但是http协议通常只能对内网应用发起GET型的请求,应用面比较局限。

4) Attack applications that can be exploited without authorization on the intranet

常见的利用方法就是攻击内网的redis、postgrasql、MongoDB、Fast-CGI等。

4. Common defense bypass methods

1) DNS rebinding

原理:攻击者控制了或者拥有一台DNS服务器,将一个子域绑定到了两个不同的IP,IP地址再不断轮换,目标服务器在检测URL和访问URL时指向的IP地址不同,导致白名单检测被绕过。

2) IP address translation

常用的方法就是将IP地址转换为不同的进制,例如192.168.0.1:
8进制格式:0300.0250.0.1
16进制格式:0xC0.0xA8.0.1
10进制整数格式:3232235521
16进制整数格式:0xC0A80001

3) Use xip.io

xip.io这是个特别的 域名,是别人搭好的网站,具体信息可以访问来查看,他会把如下的域名解析到特定的地址,其实和dns解析绕过一个道理:
http://10.0.0.1.xip.io = 10.0.0.1
www.10.0.0.1.xip.io= 10.0.0.1
http://mysite.10.0.0.1.xip.io = 10.0.0.1
foo.http://bar.10.0.0.1.xip.io = 10.0.0.1
10.0.0.1.xip.name resolves to 10.0.0.1
www.10.0.0.2.xip.name resolves to 10.0.0.2
foo.10.0.0.3.xip.name resolves to 10.0.0.3
bar.baz.10.0.0.4.xip.name resolves to 10.0.0.4

4) Other bypass methods

利用"句号”绕过:比如127。0。0。1会被解析成127.0.0.1
利用nclosed alphanumerics绕过:比如 ⓔⓧⓐⓜⓟⓛⓔ.ⓒⓞⓜ >>> http://example.com
利用短网址绕过:例如https://dwz.lc/2fGYWaE  >>>> https://www.baidu.com
利用302跳转。
....

2. Analysis and utilization of SSRF-labs

1、file_get_content()

Look at the code first:

if(isset($_POST['read'])){
    
    
	$file=trim($_POST['file']);
	echo htmlentities(file_get_contents($file));
} 

Very simple logic, here is to get the file name through the file parameter, and then hand it over to your file_get_content() function to read without any processing, which leads to the generation of SSRF vulnerability.

Here, if we set the value passed in by the $file parameter to the value of other resources in the remote or intranet, it can also be accessed, and if the PHP pseudo-protocol is used, local files can be read, or other operations can be performed.

Simple use: read local files

1) Read the hosts file using the file protocol:

insert image description here

2) Use the php:/filter protocol to read the win.ini file

insert image description here

2、DNS_spoofing.php

Or analyze the source code first:

if(isset($_POST['read'])){
    
    
  $file=strtolower($_POST['file']);   //获取file参数并转换为小写
  if(strstr($file, 'localhost') == false && preg_match('/(^https*:\/\/[^:\/]+)/', $file)==true){
    
      //如果localhost不存在于$file,并且是以http开头
    $host=parse_url($file,PHP_URL_HOST); //后去URL解析后的host,比如 http://127.0.0.1/index ——》127.0.0.1
    if(filter_var($host, FILTER_VALIDATE_IP)) {
    
     //检测IP是否为私有IP,如果是继续检测。
        if(filter_var($host, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_NO_PRIV_RANGE |  FILTER_FLAG_NO_RES_RANGE)== false) {
    
    
            echo '<table width="50%" cellspacing="0" cellpadding="0" class="tb1" style="opacity: 0.6;">
                 <tr><td align=center style="padding: 10px;" >
                The provided IP is from Private range and hence not allowed
                 </td></tr></table>
                 <table width="50%" cellspacing="0" cellpadding="0" class="tb1" style="margin:10px 2px 10px;opacity: 0.6;" >';
          }else {
    
    
            echo '<textarea rows=20 cols=60>'.file_get_contents($file)."</textarea>";
          }
    }else{
    
    
        echo '<textarea rows=20 cols=60>'.file_get_contents($file)."</textarea>";
    }
  }elseif(strstr(strtolower($file), 'localhost') == true && preg_match('/(^https*:\/\/[^:\/]+)/', $file)==true){
    
       //如果URL包含localhost,弹出错误
      echo '
      <table width="30%" cellspacing="0" cellpadding="0" class="tb1" style="opacity: 0.6;"><tr><td align=center style="padding: 10px;" >
                Tyring to access Localhost o_0 ? 
                 </td></tr></table>
                 <table width="50%" cellspacing="0" cellpadding="0" class="tb1" style="margin:10px 2px 10px;opacity: 0.6;" >';
    } else {
    
    
      echo '<textarea rows=20 cols=60>'.file_get_contents($file)."</textarea>";
    }	
} 

From the above code, we can guide that the topic filters and detects private IP addresses such as 127, 192, 10, 172, and detects localhost. So we need to find a way to bypass detection.

Here, since the detection of IP addresses is relatively strict, and file_get_content() can only be a conventional URL address, methods such as hexadecimal encoding, short address bypass, etc. are not feasible. But it can be found that if we do not apply the http protocol, the program can directly access our UR link through file_get_content(), so here we can continue to use the pseudo-protocol for utilization.

insert image description here

3. Analysis of CTF sample questions

1. Example 1

First look at the source code:

 <?php
  error_reporting(0);
  highlight_file(__FILE__);
  $url=$_POST['url'];
  $x=parse_url($url);
  if($x['scheme']==='http'||$x['scheme']==='https'){
    
     //以http或者https协议开头的允许访问
    if(!preg_match('/localhost|127.0.0/')){
    
     //设置黑名单,不允许URl带localhost和127.0.0
      $ch=curl_init($url);
      curl_setopt($ch, CURLOPT_HEADER, 0);
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
      $result=curl_exec($ch);  //curl函数获取内容
      curl_close($ch);
      echo ($result);
    }else{
    
    
        die('hacker');
    }
  }else{
    
    
     die('hacker');
  }
?> 

It can be seen that the method of IP address blacklist is adopted here, and we are only allowed to use the http or https protocol.

For the IP address blacklist, there are still various bypass methods. You can consider using IP address base conversion or breaking address bypass.

Bypass exploit:

进制转换绕过:
十六进制:?url=http://0x7F.0.0.1/xxx.php
八进制:  ?url=http://0177.0.0.1/xxx.php
.....
特殊省略绕过:
?url=http://0/flag.php

2. Example 2

source code:

<?php
if (isset($_POST['url'])) {
    
    
    $url = $_POST['url'];
  	//连接必须以http或者https开头
    if (preg_match('/^http[s]?:\/\/([(\w|\d)+\.]+[\/]?)*/', $url, $matches)) {
    
    
      	//获取文件内容,对URL未经过滤,说明存在SSRF漏洞
        $content = file_get_contents($_POST['url']);
        $filename = str_replace('/', '', $matches[1]);
      	//将文件名设置为$md5($filename).IP,这里并不会加上文件名
        $filename = './chuoybinu/' . md5($filename) . $matches[1];
 				//将文件写入"//chuoybinu/md5($filename)”文件中
        file_put_contents($filename, $content);
      	//获取图片信息,并检测文件格式是否是图片
        $image = getimagesize($filename);
        $image_type = $image[2];
      	//如果是图片,将URL使用img标签跳转,否则使用a标签设置链接
        if(in_array($image_type, array(IMAGETYPE_GIF, IMAGETYPE_JPEG, IMAGETYPE_PNG, IMAGETYPE_BMP))) {
    
     
            echo '<img src="' . $url . '">';
        } else {
    
    
            echo '<a href="' . $url . '">' . $url . '</a>';
        }
      //或者是以file://开头,并且获取URL中的文件内容
    } else if (preg_match('/^file:\/\/([\/\w\d\.]+)/', $url)) {
    
    
        $content = file_get_contents($url);
        readfile($file);
        $filename = './chuoybinu/' . md5(time());
        file_put_contents($filename, $content);
        if (strpos($url, '_')) {
    
    
            echo '<p>Flag is not such easy to get!(:◎)≡</p>';
        } else {
    
    
            echo '<a href="' . $filename . '">' . $filename . '</a>';
        }
    } else {
    
    
        echo '<p>Protocol Not Supported!(:◎)≡</p>';
    }
} else {
    
    
?>

It can be seen that the http[s] or file protocol is allowed to read the file here, and the URL of the file is subject to any filtering, which leads to the SSRF vulnerability.

At the same time, because the content of the obtained file will be saved in the local ./chuoybinu directory, but after careful analysis, we found that in the case of using the http protocol, after the file is saved, it will only be saved as ` md 5 ( md5 (The form of m d 5 ( filename).IP does not save the file suffix, so it is not possible to remotely read the file getshell, but you can still use the http protocol to detect basic vulnerabilities such as intranet port detection.

So to read system files, etc., you still need to use the file protocol to read.

Exploitation :

Read a local file:

insert image description here

It can be seen that after the file is read, it is saved to the ./chuoybinu/2afeb826cb4bf4c88119ab3d37c0f278 file. After we visit it, we can see the contents of the normal hosts file:

insert image description here

4. References

Guess you like

Origin blog.csdn.net/qq_45590334/article/details/126124919
Recommended