Damn Vulnerable Web Service
Last updated
Last updated
This is the list from the documentation To keep track, I will check everytime I find one
git clone https://github.com/snoopysecurity/dvws-node.git
cd dvws-node
docker compose up
It should start building
Once done edit your /etc/hosts
file and add this line 127.0.0.1 dvws.local
All the other infos we need are here
Launch burp or zap and setup your scope settings
Now we can visit http://dvws.local/
we get this page
Let's create an account
Once logged in we get this home page:
However we do not need to be logged in to access the home page. We can access it right away if we go here http://dvws.local/home.html
Here http://dvws.local/upload.html
we have the possibility to upload files. So this is definitely something to keep aside for later.
Another page to keep for later explorations http://dvws.local/passphrasegen.html
Another one http://dvws.local/search.html
We can access the admin area as well without any cookie http://dvws.local/admin.html
This looks fun too http://dvws.local/notes.html
If we try to create a note without a token it won't work. So we can access the page but we can not write notes.
Directory enum small list
Directory enum big list
=> Nothing more than in the small one.
When I explored I saw that the schema for the api was /api/v2
. This is good to know (I found it in my burp history). This way we have the api endpoints schema.
Let's try another wordlist, I really want to find the documentation. This time I will use the intruder and the wordlist swagger.txt
Here is my position tab in the intruder
Notice that I did not put a / after the GET http verb
My payloads tab look like this
Make sure to unchek the URL-encode these characters at the bottom
Then we can launch the attack. We order the results by Status we get to endpoints worth checking
Both these endpoints have the documenation
http://dvws.local/api-docs/
http://dvws.local/api-docs/swagger.json
Create an admin user we add the parameter admin and set it to true admin=true
It works. Our new user is admin
So in our burp history we have a users
endpoint which gives a list of users and their password hashes.
So now we can log in as admin
When we access our passphrases, it calls the following endpoint /api/v2/passphrase/csbygb
so it takes the username as id.
So we could try to access the admin one /api/v2/passphrase/admin
It works! Funny thing here is we do not even need a cookie to access it.
Note: I added a passphrase myself for the sake of the demo here.
When we try to access the admin area with a normal user through the browser we get redirected.
However when we use an admin user we access the endpoint /api/v2/sysinfo/uname
And the web browser shows this page.
So we can try to access the same endpoint but with a user Token.
Access with admin Token
So this is the legitimate request. We get info aobut the server.
Access with user Token
So this should not be possible, we access admin info with a user token.
If we try the functionality to search for a user we see this in the browser.
So it calls this endpoint and the request and response look like this in burp
So we can send the request to the repeater and change the token for a user one to see if we could access to the "admin" user info for example. And it works!
If we enter a user name with an xss payload in the user field the input is not sanitized and our paylaod is interpreted.
Now if we click on login we get our pop up
We can do it with this command python3 jwt_tool.py <JWT-TOKEN-HERE> -o -C -d /usr/share/wordlists/rockyou.txt
It works and we get the password access
Then we would just have to use this new generated token to access admin resources.
When playing with the user search we had an XML Content. So this is definitely the place to check for XXE. Let's try to insert these lines at the top
Then we can use this &xxe;
in the usernames tags to print the file we need (here the passwd).
And it works we get the passwd file of the server.
When playing with the notes we have a number attributed to the secret notes we create like this:
Here we have a note no 4 and no 9
We could try to check if the endpoint can also request only one specific note, using this number as an id.
This endpoint /api/v2/notes
will return all the notes let's try something like /api/v2/notes/note-number
And it works we can access any note from any user.
For example here is a note from csbygb
with the token of csbygb-otheruser
After this we could enumerate all the notes with an automatic tool like burp intruder for example and by incrementing the note no.
So if we analyze the swagger we found during the enumeration phase.
We have an endpoint that is different than the others /api/v1/info
so this is an old functionnality.
Well, let's try it.
This discloses a lot of information on the server.
The error page has un interesting response.
If we try the request from the article we get a less verbose response but it is still really interesting.
We can see the dvws.checkuptime from the error and it does also have pingback. So let's try the service mentionned in the error.
So this way we can access application that runs in the internal network fo the server. We could also scan the ports.
When we explored the application we found a few request that did not need any token or credentials.
For example /api/v2/passphrase/admin
to request the passphrase that is called admin.
See here, we do not need any credentials and we have Access-Control-Allow-Credentials: true
in the response header.
When we explored we found an endpoint (/api/v2/sysinfo/uname
) that was doing a uname in a server. This screams for command injection.
If we append send this instead we can indeed execute another command /api/v2/sysinfo/uname;id
We can see that our user is root From this the next step would be to try to get a reverse shell.
And it works we get the full config file. It seems that it was taking the version from a config file (which also contains passwords).
There is an endpoint that allows to check if a user exists and it uses XMK rpc dvwsuserservice
.
When we log out a user it sends a get request to this endpoint /api/v2/users/logout/dvws.local
This basically makes a redirection as we can see here.
Download forms can be vulnerable to path traversal. Let's try to tamper with this request
We even get an error to check where we directory tree.
Let's try a few more dots and slashes
We are getting there.
And it works!
With this information we can for example attempt to crack the admin hash. First let's find out which hash this is. We go to hascat examples hashes page and we search $2b$10
on the page.
This way we see it is bcrypt. Now we can crack the hash with john (or hashcat) and we get the password of the admin user letmein
.
Let's play a little with the jwt token. For this we can use jwt_tool. See for how to install it.
Once we get a key we can use it to update our rights and become admin by adding a permission.
Here we can add the permission "user:admin"
Here is how we could this with
So if we play with the quotes and try some NoSQL payload (you can find some ), we can trigger a NoSQL injection on the endpoint /api/v2/notesearch
.
It works and we get all the notes, including the secret ones
We can see also in the user agent the use of xmlrpc. So we could try to interact with it because it is known to have a few vulnerabilities that affected a lot of wordpress websites. This article mentions it.
So let's try a cors PoC to see if it is vulnerable we can find plenty of poc online (I found mind ). If you are not familiar with , this page on portswigger is very helpful to learn more about this.
And here we get the passphrase
You can check the explainations about this vulnerability in the official writeup
You can find the official writeup for the SQL Injection
To give the version on the home page it uses this endpoint /api/v2/release/0.0.1
If we inject a quote in the end we get an xpath error
We can try a few payloads from
What if we change dvws.local with another url? Well it redirects us to this url
You can find a good definition of this vulnerability
When we download a file it makes a post request to this endpoint /api/download
shows an example of insecure deserialization in nodejs. The request to /api/v2/export sends a serialize object to the server, this is how it fetches the requested document What is we could try to request for something else that we should be able to access.