Brute-Forcing a Website Passkey by Spoofing Web Authentication Using cURL
by ZU1PH3R
When my friend asked me to penetrate his Jellyfin media server, I had anticipated a brute-force attack should be the first method I would use in an attempt to break down the walls hiding all of the freshly uploaded anime and video game soundtracks.
What I hadn't expected was encountering a secondary authentication method outside of the regular passkey I would be trying to find. This is where I was introduced to Web Authentication.
Web Authentication is a process that verifies a user's identity before allowing any further authentication to continue. In Jellyfin's case, it needed to authenticate my web client as well as my device ID in order to continue with the authentication process. This would not be an issue if I simply went to my friend's website and manually typed in each password guess I had on the main portal, but this brute-force method is time consuming and non-reliable.
This is where cURL comes in. cURL, or Client URL, is a command line based tool that allows for users to transfer and request web data, such as authentication and file transferring.
A simple cURL password attempt could look something like this in a terminal:
$ curl -x -H "Content-Type: applications/json" -d '{"user":"foo","pass":"bar"}' http://example.com:1234/loginThis posts an HTTP request to the server which carries the JSON packet holding your authentication information to the login page.
This will either validate (200 status code) or invalidate (401).
In the case of Jellyfin, this will not authenticate even if the credentials are correct. This is due to the lack of any Web Authentication and/or a malformed HTTP request. The server needs to authenticate your identity which it is unable to do if you are not giving it any client information, such as what browser you are using.
That is where the wonderful world of HTTP headers comes in. Headers carry extra information that an HTTP request might require.
In the example above, Content-Type is a header, preceded by the self-proclaiming -H (header) flag. This header's purpose is to tell the server that the data I am trying to post to it is in JSON format.
Fortunately, we are able to abuse headers and spoof the Web Authentication headers that the server needs in order to authenticate the client. In a simple example that is done as follows:
$ curl -x -H "Authorization: MediaBrowser Client='Jellyfin Web', Device=Firefox" -H "Content-Type: applications/json" -d '{"user":"foo","pass":"bar"}' http://example.com:1234/loginThis will now tell the server that the request is coming from a Firefox browser and not from a command line client, or null client.
It's important to note that this is not a full header example for Jellyfin's Web Authentication, but it exceeds at giving an example on how spoofing the authentication headers can let a user Web Authenticate using cURL.
In order to avoid malformed requests and obtain the necessary headers, one would need to perform an authentication request; an attacker can utilize Inspect Element on the website. To do this, an attacker simply needs to view the HTTP requests between them (or someone else they want to spoof from) and the server after attempting a password on the actual website portal.
Most web browsers should let anyone copy this request as cURL, doing all of the command line work for an attacker. Now an attacker has the necessary authentication headers in order to brute-force the password. Once I figured all this out, I now needed a way to actually automate the attack!
First, I converted the cURL command to a Python function using a cURL converter, which are easily available on the web. I then wrote the brute-force script by supplying the now Python HTTP request function, then spamming those requests by using a variable for the password header, which would loop through rockyou.txt until the password was found.
While this method can circumvent Web Authentication, it also has a few drawbacks. A decent firewall would be able to see the request spam coming through and block all requests coming from that IP, or even lock the main account altogether. It also does not support anonymity since you do have to fork over some type of valid Web Authentication, but this can be easily fixed by spoofing someone else's Web Authentication headers. This brute-force method also takes a long time, since it has to go through the Internet. I was able to brute-force 1234 for the password in roughly seven minutes, which is considerably long once you realize how high up on the rockyou.txt 1234 is.
In conclusion, spoofing Web Authentication headers allows for an attacker to continue to brute-force password and Web Authenticated websites by abusing HTTP headers, allowing for an automated script to be run.
This can also work on other forms of authentication that are handled in the HTTP request such as any tokens one might need.
While my friend did have to reduce the server's firewall for this attack to work, the adrenaline from gaining access and having all the new media on my hands was well worth it.