Bug 39731 - "unsafe" UMCP commands are accessible via "safe" HTTP GET method
"unsafe" UMCP commands are accessible via "safe" HTTP GET method
Status: CLOSED FIXED
Product: UCS
Classification: Unclassified
Component: UMC (Generic)
UCS 4.0
Other Linux
: P5 critical (vote)
: UCS 4.2
Assigned To: Florian Best
Alexander Kläser
: interim-1
Depends on: 34498 43389
Blocks: 42408 43710
  Show dependency treegraph
 
Reported: 2015-11-03 15:29 CET by Florian Best
Modified: 2021-06-23 07:29 CEST (History)
3 users (show)

See Also:
What kind of report is it?: Security Issue
What type of bug is this?: ---
Who will be affected by this bug?: ---
How will those affected feel about the bug?: ---
User Pain:
Enterprise Customer affected?:
School Customer affected?:
ISV affected?:
Waiting Support:
Flags outvoted (downgraded) after PO Review:
Ticket number:
Bug group (optional): API change, Security
Max CVSS v3 score:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Florian Best univentionstaff 2015-11-03 15:29:58 CET
There are a lot commands which can be accessed via the HTTP GET method by just opening the URL in the browser. HTTP defines the method GET as "safe" i.e. meaning executing that method doesn't have effects on the state of the resource.

That can be a problem because if you are authenticated at UMC calling the following links will cause unsafe actions:

Stop the service "ntp":
/univention-management-console/command/services/stop?ntp=1

Kill the proccess(es) with pid=23238:
/univention-management-console/command/top/kill?signal=SIGKILL&pid=23238&pid=23238

Reboot the system:
/univention-management-console/command/updater/installer/reboot

Shutdown the system:
/univention-management-console/command/lib/server/shutdown

(There are some more like reporting a traceback, uploading a traceback, importing a license, remove user quota, upgrade the system to version x.y-z.)
Using UDM (e.g. to change a password) seems not possible.

As there are url-shorteners or iframes/html framesets this can also be easily used by an attacker.

This functionality is used in UCS@school e.g. to display screenshots of computers and in adconnector to download certificates (maybe some more).

It's a design problem of UMCP - which drops all important HTTP information (method, headers).
Comment 1 Alexander Kläser univentionstaff 2016-03-08 11:44:48 CET
See also: https://en.wikipedia.org/wiki/Cross-site_request_forgery
Comment 4 Alexander Kläser univentionstaff 2016-05-12 11:09:46 CEST
I went through the documentation and, AFAIS, it would be sufficient to apply the following strategies:
* Limit cookies to reside below /univention-management-console (this is already 
  implemented)
* Along with each request, send a custom HTTP header entry that contains the same
  value as the session cookie does. We would then need to allow specific commands
  to be accessible without the custom header entry (e.g., UCS school computer room
  screenshots).
* Ensure that the HTTP Referer entry contains the path
  /univention-management-console, this would harden the security for cases in 
  which the custom HTTP header entry (see above) is not needed.
Comment 5 Florian Best univentionstaff 2016-05-12 11:42:11 CEST
(In reply to Alexander Kläser from comment #4)
> I went through the documentation and, AFAIS, it would be sufficient to apply
> the following strategies:
> * Limit cookies to reside below /univention-management-console (this is
> already 
>   implemented)
Yes, but keep in mind that scripts in /foo can also make XHR requests to /univention-management-console/ and the browser will send the cookie then.

> * Along with each request, send a custom HTTP header entry that contains the
> same value as the session cookie does. We would then need to allow specific
> commands to be accessible without the custom header entry (e.g., UCS school
> computer room screenshots).
Yes, the value wouldn't necessarily need to be the session id but probably better a secret not predictable value.

> * Ensure that the HTTP Referer entry contains the path
>   /univention-management-console, this would harden the security for cases
> in which the custom HTTP header entry (see above) is not needed.
I discourage this. This is only superficial benefit of security. Also the referrer is not always set (e.g. I explicit remove it everywhere via some browser settings).
Comment 6 Florian Best univentionstaff 2016-05-12 11:43:42 CEST
> I discourage this.
I discourage to require a referrer to be set in every request.
The check can be done if the header is present.
Comment 7 Alexander Kläser univentionstaff 2016-05-25 15:11:11 CEST
(In reply to Florian Best from comment #5)
> (In reply to Alexander Kläser from comment #4)
> > I went through the documentation and, AFAIS, it would be sufficient to apply
> > the following strategies:
> > * Limit cookies to reside below /univention-management-console (this is
> > already 
> >   implemented)
> Yes, but keep in mind that scripts in /foo can also make XHR requests to
> /univention-management-console/ and the browser will send the cookie then.

Of course, however, if you require JavaScript to read the cookie value and sent it as custom header, I would consider it to be secure. In fact, both aspects only work together. AFAIK, OX had also implemented this strategy.

> > * Along with each request, send a custom HTTP header entry that contains the
> > same value as the session cookie does. We would then need to allow specific
> > commands to be accessible without the custom header entry (e.g., UCS school
> > computer room screenshots).
> Yes, the value wouldn't necessarily need to be the session id but probably
> better a secret not predictable value.

See above.

> > * Ensure that the HTTP Referer entry contains the path
> >   /univention-management-console, this would harden the security for cases
> > in which the custom HTTP header entry (see above) is not needed.
> I discourage this. This is only superficial benefit of security. Also the
> referrer is not always set (e.g. I explicit remove it everywhere via some
> browser settings).

... a more superficial, yet, additional check. Can it be easily modified with JavaScript? What is your reason for discouraging it?
Comment 8 Florian Best univentionstaff 2017-01-17 16:40:21 CET
(In reply to Alexander Kläser from comment #7)
> ... a more superficial, yet, additional check. Can it be easily modified
> with JavaScript? What is your reason for discouraging it?
I already said in comment #6 that we shouldn't enforce a Referer header to be set because a browser might be set up to don't send them and all the curl,etc. calls also don't set them.
Comment 9 Florian Best univentionstaff 2017-01-17 18:30:14 CET
* Limit all requests (except e.g. screenshots) to POST
→ This prevents that they are loaded in a iframe/image/other source on any origin.
 <img src="http://demo.univention.de/univention-management-console/command/services/stop?ntp=1"/>
 <iframe src="http://demo.univention.de/univention-management-console/command/services/stop?ntp=1"></iframe>

* Check the Referer request header for the origin to be /univention/, but don't enforce it to be set
→ This prevents that scripts underneath of /~user/ or /dudle/ can send requests to /univention/ but only if the referer is enabled in the browser.
→ The referer might be disabled for privacy reasons or not set in scripts using curl.

* Require the Content-Type header to be application/json and the content well rendered JSON.
→ HTML forms are restricted to application/x-www-form-urlencoded, text/plain and multipart/form-data
→ The Content-Type header needs to be checked as with text/plain a valid JSON document can be rendered. This is already the case.
 <!DOCTYPE html>
 <html>
 <body onload="document.forms[0].submit()">
 <form action="http://demo.univention.de/univention-management-console/command/ucr/add" method="POST" enctype="text/plain" >··
 <input name='{"options":[{"object":{"key":"auth/sshd/group/Domain Users","value":"yes","description[en]":"' value='"},"options":null}]}'type='hidden'>
 </form>
 </body>
 </html>

→ This would prevent regular automatic form submission attack
 <!DOCTYPE html>
 <html>
 <body onload="document.forms[0].submit()">
 <form action="http://demo.univention.de/univention-management-console/command/services/stop?ntp=1" method="POST">
 </form>
 </body>
 </html>

* Make sure no Cross-Origin-Requests are allowed i.e. Access-Control-Allow-Origin must not be set to "*" or any untrusted domain
→ This header is set for our ucs-sso.$domainname hostname - probably a not so good idea but required for our current login dialog.
→ If the UCR variable 'ucs/server/sso/virtualhost'is set to false this is also for UMC the case

This already solves most of the problems, but it doesn't solve the problems of a XHR-Request from the same origin (e.g. if apache mod_userdir is enabled and exposes /~user/.
This could be exploited with e.g. the following script:
  var xhttp = new XMLHttpRequest();
  xhttp.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
      alert(this.responseText);
    }
  };
  xhttp.withCredentials = true;
  xhttp.open("POST", "/univention-management-console/get/modules/list", true);
  xhttp.setRequestHeader('Referer', null);
  xhttp.send();

A possible solution would be to require UMC to be in a special subdomain as http://umc.master1.example.com/. But this doesn't work with IP based systems.

The other solution would be to force every(?) request to contain a special server side generated truly-random token.

This breaks the current "API" of UMC and requires all HTTP clients communicating with UMC to apply some logic which we define and need to keep stable!
It enforces every script which communicates with UMC to be adjusted (e.g. the one for the AppCenter Self-Service).
It removes the possibility for a UCS 4.1 System to communicate with a UCS 4.2 system.
It forces the communication to be stateful. This blocks changing UMC into a RESTful web service.
It adds an extra effort to daily tasks like testing via curl.

The token needs to be a Cookie limited to the path=/univention/ with httpOnly=False. Then scripts underneath of /univention/ can read the cookie while scripts underneath of /~user/ can not.
This cookie needs to be send in the request as HTTP header (e.g. X-XSRF-Protection). It must not be allowed to set this parameter as Query-String parameter (e.g. ?xsrf-protection=foo) or POST request payload because this can be e.g. hijacked by 1. lookup the browser history 2. lookup the request body 3. find some request where the URL is returned (e.g. by a HTTP redirection or some error condition).

→ I would like to prevent using this solution, but the only fix I can imagine is providing UMC via a subdomain, which we probably cannot do.
Comment 10 Florian Best univentionstaff 2017-01-31 17:11:56 CET
* The UMC-Server and UMC-Webserver have been adapted to transmit HTTP headers and Cookies
* The HTTP Server now evaluated HTTP request method, HTTP Referer and the custom X-XSRF-Protection header.
* All library functions communicating with UMC have been adapted to include this proprietary request header
Comment 11 Florian Best univentionstaff 2017-02-01 09:50:33 CET
REOPEN: File uploads are detected as XSRF-Attack.
Comment 12 Florian Best univentionstaff 2017-02-01 17:37:21 CET
Fix UDM license upload and AD connector certificate upload.
Comment 13 Alexander Kläser univentionstaff 2017-02-17 10:42:49 CET
We need to allow a GET request for the AD connector certificate download, AFAIR.
→ REOPEN
Comment 14 Florian Best univentionstaff 2017-02-17 15:41:46 CET
(In reply to Alexander Kläser from comment #13)
> We need to allow a GET request for the AD connector certificate download,
> AFAIR.
> → REOPEN
I can't find anything such like this.

Additionally the content-type header is now also checked in the UMC-Server backend.
Also the HTML encoding of the tools.parseError().message attribute has been fixed.
Comment 15 Alexander Kläser univentionstaff 2017-02-17 16:10:22 CET
(In reply to Florian Best from comment #14)
> (In reply to Alexander Kläser from comment #13)
> > We need to allow a GET request for the AD connector certificate download,
> > AFAIR.
> > → REOPEN
> I can't find anything such like this.

It seems that I cannot find it, either.

> Additionally the content-type header is now also checked in the UMC-Server
> backend.
> Also the HTML encoding of the tools.parseError().message attribute has been
> fixed.

OK

* HTTP header X-XSRF-Protection must be set with session ID from cookie → OK
* Limit all requests (except e.g. screenshots) to POST → OK, returns 401 error
* Referer request header must be /univention/ → OK
* Require the Content-Type header to be application/json and the content well 
  rendered JSON. → OK, request with wrong type is blocked in web server
* Make sure no Cross-Origin-Requests are allowed i.e. Access-Control-Allow-
  Origin must not be set to "*" or any untrusted domain → OK, has been removed
* License upload → OK
* Authentication → OK
* UMC CLI → OK
* univention-lib → OK
* Code Review → OK, with little typo fix:
  r76801 | Bug #39731: fix constructor for UMC_Error
* Changelog → OK

→ VERIFIED
Comment 16 Stefan Gohmann univentionstaff 2017-04-04 18:29:03 CEST
UCS 4.2 has been released:
 https://docs.software-univention.de/release-notes-4.2-0-en.html
 https://docs.software-univention.de/release-notes-4.2-0-de.html

If this error occurs again, please use "Clone This Bug".