U.S. Dept Of Defense · Report #223936
Multiple cryptographic vulnerabilities in login page on ███████
How it was found
Summary: I realize that this report's title may not make sense yet. In one sentence: users logging in to the ███████ Server REST API Login page can have their passwords stolen by an attacker on the same LAN or WiFi as the victim trying to log in.
Description: To save the reader any confusion, I'll point out that this is an unusual case where, instead of using HTTPS for password confidentiality in transit, the server sends RSA encryption scripts to the browser. The browser then encrypts the password before sending the login request to the server. Using ARP poisoning I was able to Man-in-the-Middle (MitM) traffic between a victim and the login server. This enabled me to inject my public key into the login page, capture the encrypted password and decrypt it (using my private key), revealing the victim's plaintext password.
Impact
User accounts on the ████████ Server REST API server could be compromised.
Step-by-step Reproduction Instructions
Because this report is so long, I'm only putting in this summarized list of steps. But if you want a full step-by-step with screenshots, the Ettercap filter, my Python decryption script and everything, I've already written it up. Just ask.
- The attacker must be on the same Layer 2 network segment (LAN, or WiFi) as the victim's computer.
- The attacker runs Ettercap, specifying the IP addresses of:
- The gateway router
- The victim's computer
- Using Ettercap, the attacker conducts an ARP Poisoning attack against the victim's computer and that of the gateway router, thereby acting as a proxy for traffic between those two devices.
- When the victim's browser sends a
GETforhttp://███/server/rest/login, the attacker:- intercepts the server's response,
- modifies the HTML form, replacing the server's public key modulus string with the attacker's public key modulus string.
- The victim enters
usernameandpasswordvalues in the modified HTML form and clicks theLoginbutton. TheRSA.js(and other scripts) run in the victim's browser as usual, but the resulting ciphertext is the user's password encrypted for the public key of the attacker. The victim's browser sends these values in aPOSTto/server/rest/login, but because of the ARP Poisoning attack, thePOSTis sent to the attacker's computer. - The attacker, using OpenSSL and their own RSA private key, decrypts the encrypted password, thus recovering the plaintext password.
- Optional: The attacker re-encrypts the victim's plaintext password using the login page's original public key.
- Optional: The attacker places the now encrypted password value into a new
POSTto/server/rest/loginand sends the request to the gateway router, thereby allowing the victim to authenticate to the server. - At this point the attack is successful. Note: the attacker still needs to tell Ettercap to stop the ARP Poisoning attack, causing it to send the ARP Correction packet, thereby restoring normal connectivity between the victim and the gateway router.
Product, Version, and Configuration (If applicable)
Suggested Mitigation/Remediation Actions
- Require HTTPS for sending username/password to the server.
- This would solve the whole problem
- At the risk of sounding pedantic, client-side encryption via Javascript is not an effective security control. But I do realize that there may be use-case requirements for your application that I don't know about.
- If you do have some reason why you must continue using client-side encryption, please know that the
RSA.jsscript is using a vulnerable padding standard (PKCS#1v1.5). Unfortunately, the developer's new RSA.js script is still using PKCS#1v1.5 padding which is vulnerable to a chosen ciphertext attack. The Cryptosense blog explains in detail. FYI I did not attempt to exploit this padding vulnerability.