TOTP: It's not Google Authenticator

I’ve been meaning to write about this since Twitter announced that only the eight-dollar-checkmark class would have access to SMS-based 2-factor authentication (2FA)1. Infosec circles got back into heated debates about the security implications of SMS-based authentication compared to the risk of losing access to the more-secure option of TOTP. This post isn’t really about that debate, but the major takeaways from either side are that:

User friction is a very real issue, and TOTP will always be more frictional than SMS; I can’t solve that in this post. Personally, I prefer to use TOTP when available due to the risk of a SIM-swapping attack2. This post, however, is more concerned with the matter of keeping your secret portable and within your control if you decide to use TOTP for 2FA.

If you’ve made it this far without knowing what TOTP is, well, that’s almost certainly by design. I would hazard that most people who are aware of it know it exclusively as Google Authenticator. Getting an increasingly-vital, open standard to be almost exclusively associated with one shitty app from one shitty company is certainly very good for that company, but very bad for everyone else. So the first order of business here is to clarify that whenever you see a site advertising 2FA via ‘Google Authenticator,’ what they actually mean is TOTP, or more accurately RFC 6238, an open standard3. Additionally, if you’re reading this and you currently implement TOTP on a site you manage or are planning to, I implore you to describe it accurately (including Google Authenticator as one of several options, if necessary) rather than feeding into the belief that the magical six-digit codes are a product of Alphabet.

So what, then, is TOTP? Even if you know it isn’t A Google Thing, the mechanism by which a QR code turns into a steady stream of six-digit codes is not entirely obvious. This is, typically, how we set up TOTP – we’re given a QR code which we photograph with our authenticator app, and suddenly we have TOTP codes. The QR code itself contains just a few pieces of URI-encoded data. This may include some specifics about the length of the code to be generated, the timing to be used, the hash method being used, and where the code is intended to be used. Crucially, it also contains an important secret – the cryptographic key that, along with a known time reference, is the foundation from which the codes are cryptographically generated. Essentially, a very strong password is kept secure, and from this an easily-digestible temporary code is generated based on time. Because it comes from a cryptographic hash function, exposing one (or more) of these codes does not have the same security implications as exposing the key itself.

Keeping the key itself secret is, in fact, extremely important. Vendor lock-in aside, I assume this partially contributes to the opacity of what happens in between scanning the QR code and having a functional 2FA setup. A large part of the debate over whether ‘Google Authenticator’ is a good 2FA solution is the fact that once your secret is in the Google Authenticator app, it is not coming out. If your app data gets corrupted, or if something misbehaves during a phone transition, you’re out of luck. Hopefully you’ve kept the recovery codes for your accounts safe somewhere. If to you, as to most people, TOTP means Google Authenticator, then this is a very real concern. One goof could simultaneously lock you out of all of your accounts that are important enough to you that you enabled their 2FA.

When I was de-Googling myself years ago, I went through the somewhat-laborious process of generating all new codes to put into Authy. In addition to (or in lieu of, I’m not entirely sure) local storage, Authy keeps your TOTP info in the cloud, allowing you to keep several devices in sync, including a desktop app. While this is a better solution than Google Authenticator, I’m not linking to it as I still think it’s a pretty bad one. The desktop app is an awful web-browser-masquerading-as-desktop-software creation. The system of PINs and passwords to access your account is convoluted. And, while in theory you can put the desktop app into a debug mode and extract your data, there’s no officially-supported path toward data portability. The unofficial method could go away at any time; in fact, while I will credit Indrek Ardel with the original method4, it seemingly no longer works and one must find more recent forks that do. On top of this, the aforementioned bad desktop app and confusing set of passwords meant that it was still just easier to start fresh with new codes when I recently switched away from Authy. Finally, Authy is another corporate product. It’s owned by Twilio, and they seem to want a piece of that lock-in pie as well, offering their own 2FA service that is a quasi-proprietary implementation of TOTP5, as outlined by Ardel.

For years, I’ve been using various KeePass implementations in conjunction with one another as a portable password management solution. I can keep a copy of the database in my OneDrive (or whatever cloud storage I happen to have access to; right now it’s OneDrive but frankly that’s because it’s cheap — not because it’s good) and have access to it from my phone and various computers. I can sync copies to flash drives if necessary, or drop a copy on an M-Disc with other important files to stash in a safe. I was, for a long time, using an unmaintained fork, KeePassX, because it simply vibes better with how I want computers to look and feel than its replacement, KeePassXC does. On mobile, I’ve been using Strongbox6. At some point, I noticed they added support for TOTP codes! The app will happily scan a QR code and add the relevant data to an entry.

This was interesting and novel, and I was already thinking about moving all of my codes into it, simply because storing them that way meant the data was easily recoverable. If I wanted to switch again in the future, I now had access to the secret and any other relevant parameters, and could generate a new QR code from them if need be. But then I happened to notice that KeePassXC, the desktop software I had been avoiding, also supports TOTP codes. And Strongbox’s implementation is fully compatible with KeePassXC’s! This changed things – suddenly this was a portable solution for accessing my TOTP codes and not merely the data behind them. I generated new codes for everything I use (and upgraded my security on a few things that had implemented TOTP without my noticing) and ditched Authy.

While you can add TOTP codes directly in the KeePassXC desktop app, you can’t do it directly from a QR code. Windows is fond of capturing screenshots to the clipboard7; I would love to see an option in KeePassXC that scans an image in the clipboard for a QR code (and then clears the clipboard). Getting codes out is extremely straightforward. Since the data is just in normal entries in my database, a code I scan in via Strongbox will show up in KeePassXC once OneDrive catches up. It is worth noting that this rather shatters the ‘something you know / something you have’ model of 2FA, but the flexibility is there to manage codes and passwords however the user is comfortable. The most important aspect for me was liberating my TOTP data from a series of lockboxes for which I lacked the key.

Ultimately, I don’t think average users care much about data portability until they’re forced to. By the time their hands are forced, the path of least resistance tends to just be to stick with the vendor that’s locked them in8. With TOTP, the ramifications of this can be extremely annoying. More importantly, however, I think Google has done a very good job at preventing users from even knowing that TOTP portability is possible. Whether I convince anyone to store their codes in KeePass databases or not is immaterial; I really just want people to know they have options, and why they might want to use them. I want people to give just a small amount of thought to the implications of having a login credential that you not only have zero knowledge of, but also have zero access to. Frankly, I want people to stop doing free advertising for Google. And finally, I genuinely want a return to an internet where, occasionally, we make our users learn one little technical term instead of letting multi-billion dollar corporations coöpt everything good.


Learning opsec with Nermal

A few years back, (ISC)2’s charitable trust, the Center for Cyber Safety & Education partnered up with Paws, Inc. to create four comic books putting Garfield and friends in various educational cyber situations. The topics are privacy, safe posting, downloading, and cyberbullying. The fact that the Center for Cyber Safety & Education has, seemingly, three websites all dedicated to pushing this (one, two, three), the fact that they all demand you accept their usage of cookies, the fact that the Center seems proud to partner with Nielsen and Amazon… none of these things scream ‘privacy awareness’ to me.

"I don't know what to say" (external)

I’m behind on posting about this, but given my potential audience, I wouldn’t be doing so as a warning anyway but rather a curiosity. A couple of weeks ago, malicious code was discovered in an npm package called flatmap-stream placed as a dependency inside event-stream. Publish rights to event-stream were apparently handed off to the bad actor, a user with no history whatsoever, because according to the original author:

he emailed me and said he wanted to maintain the module, so I gave it to him. I don’t get any thing from maintaining this module, and I don’t even use it anymore, and havn’t for years.

The attack was quite targeted – a payload was encrypted using the description of another package, the code would only be executed if this package was present. It appears that the end goal was getting bitcoin wallet access, as this targeted package was directly related to the Copay wallet. I don’t have much experience with npm, but I’ve gathered that its approach to dependencies is decentralized ownership/maintenance with centralized package lists/names/etc. It also seemingly pushes minor updates (as declared by the author) automatically, but not major ones. The vector of attack here was quite fascinating then: find a package that doesn’t appear to have been maintained for a while and that is often used alongside a well-maintained package that you want to infiltrate; ask to maintain the first package; push malicious code as a minor update and remove it immediately in a major update; sit back as it makes its way through projects everywhere.

Title link goes to the event-stream issue thread, which is well worth reading for information on the discovery, the forensics process, and a bit of back-and-forth about maintainer responsibility in the open source world. Additionally, in a gist, the original author responded to these issues of responsibility. Finally, if you don’t want to piece it together via the thread, Zach Schneider has an excellent explanation of the attack.


Lava lamps as HRNGs (external)

I never thought I’d link to one of those terrible sites that forces you to scroll through an entire page worth of image before you can even begin reading, but here we are. If you haven’t visited Wired recently, be warned: it is very user-antagonistic. But this article, despite its brevity and reading like an ad for Cloudflare, is pretty interesting. The gist is that one of Cloudflare’s hardware random number generation techniques involves photographing an array of lava lamps.


HTTPS and categories

Meta-post time, as I’ve made a few site updates. Most notably, HTTPS works now. I wouldn’t say that Chrome 68 pushed me to finally do this, but hearing everyone talk about Chrome 68 was a good reminder that I was really running out of excuses. So, only this site as of right now, I’ll get around to fenipulator, the archive, and a couple of other projects that aren’t actually tied to my name shortly. My hosting provider, NearlyFreeSpeech.NET, has a little shell script in place that makes setting up with Let’s Encrypt an entirely effortless ordeal, with full ACME tools available if necessary. I still need to edit my .htaccess to force the matter.

A while back I also did some category overhauls. There are still quite a few categories that only contain a single post, but that seems likely to change in the future. I got rid of any categories where I didn’t really see myself adding more. I do have a tag taxonomy in place, which I need to start making better use of, for more detailed keywords. I planned to use this (plus categories, plus titles) for a sort of half-baked keyword search implementation, which I may still do at some point. I also ‘fixed’ the problem of categories showing up out of order by just making them all lowercase for the time being. It’s ludicrous to me that Hugo has no case-insensitive sorting.


An interesting memcached/UDP amplification attack (external)

A handful of reports out there about a recent DDOS attack that relied on memcached and DDOS’s best friend, UDP. Link is to Cloudflare’s blog post about the attack, which is a thorough yet accessible explanation. It seems like this is the most amplified amplification attack yet, and without even using a significant number of memcached vectors. A lot of potential vectors were from cloud hosts like AWS and Linode – many of these have apparently closed up the hole. Hopefully this minimizes the potential for a larger attack, but it’s worth quoting Cloudflare:

The [UDP] specification shows that it’s one of the best protocols to use for amplification ever! There are absolutely zero checks, and the data WILL be delivered to the client, with blazing speed! […] Developers: Please please please: Stop using UDP.

Cloudflare also touches on the fact that the larger problem is IP spoofing, and they wrote a followup post about that specifically. I just found the memcached amplification attack fascinating.


Weird Amazon/CreateSpace fraud (external)

Brian Krebs reports on one of the stranger scams I’ve read about in recent years. Essentially an author’s name (and tax info) was used to publish a book of pure nonsense using CreateSpace, and sell it for an exorbitant price, presumably as part of a money-laundering scheme:

Reames said he suspects someone has been buying the book using stolen credit and/or debit cards, and pocketing the 60 percent that Amazon gives to authors. At $555 a pop, it would only take approximately 70 sales over three months to rack up the earnings that Amazon said he made.

Patrick Reames, the (real) author in question, discovered the whole thing upon being sent a 1099 for massive earnings he hadn’t actually made. A rather convoluted scheme, but it’s easy to see how it wouldn’t be detected for quite some time. Fascinating read.


"You're scaring us" (external)

Somehow I missed this until now, but of course after Mozilla went and released their first good web browser in forever, they then went and mucked everything up. Apparently the ‘Shield Studies’ feature, which is supposed to act as a distributed test system for new features, was instead used to unwittingly install a disturbing-looking extension that was effectively an ad for a TV show. The problem ultimately seems to stem from a disconnect between Mozilla (the corporation) and Mozilla (the NPO and community) – and in fact, their developers were not thrilled about it. This is a huge breach of trust, and if Mozilla (the corporation) can’t wrap their head around their own manifesto, I can’t imagine a very good future. Mozilla did acknowledge that they fucked up, but the apology seems rather half-hearted at best. I know I have disabled Shield Studies, and until I see some evidence that a genuine attempt is being made to restore user trust, I will remain skeptical of Mozilla’s motives.


A billion points: an SVG bomb

SVGs, via the <use> tag, are capable of symbolic references. If I know I’m going to have ten identical trees in my image, I can simply create one tree with an id="tree" inside of an undrawn <defs> block, and then reference it ten times inside the image along the lines of <use xlink:href="#tree" x="50" y="50"/>.

A billion laughs is a bomb-style attack in which an XML document makes a symbolic reference to an element ten times, then references that symbol ten times in a new symbol, and again, and again, until a billion (109) of these elements are being created. It creates a tremendous amount of resource consumption from a few kilobytes of code. Will symbolic references in an SVG behave similarly?

I briefly searched for SVG bombs, and as expected mostly came up with clipart. I did find one Python script for generating SVG bombs, but it relied on the same XML strategy as the classic billion laughs attack1. The answer is that yes, in about 2.3kB we can make a billion points and one very grumpy web browser:

<svg version="1.2" baseProfile="tiny" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" xml:space="preserve">
<path id="a" d="M0,0"/>
<g id="b"><use xlink:href="#a"/><use xlink:href="#a"/><use xlink:href="#a"/><use xlink:href="#a"/><use xlink:href="#a"/><use xlink:href="#a"/><use xlink:href="#a"/><use xlink:href="#a"/><use xlink:href="#a"/><use xlink:href="#a"/></g>
<g id="c"><use xlink:href="#b"/><use xlink:href="#b"/><use xlink:href="#b"/><use xlink:href="#b"/><use xlink:href="#b"/><use xlink:href="#b"/><use xlink:href="#b"/><use xlink:href="#b"/><use xlink:href="#b"/><use xlink:href="#b"/></g>
<g id="d"><use xlink:href="#c"/><use xlink:href="#c"/><use xlink:href="#c"/><use xlink:href="#c"/><use xlink:href="#c"/><use xlink:href="#c"/><use xlink:href="#c"/><use xlink:href="#c"/><use xlink:href="#c"/><use xlink:href="#c"/></g>
<g id="e"><use xlink:href="#d"/><use xlink:href="#d"/><use xlink:href="#d"/><use xlink:href="#d"/><use xlink:href="#d"/><use xlink:href="#d"/><use xlink:href="#d"/><use xlink:href="#d"/><use xlink:href="#d"/><use xlink:href="#d"/></g>
<g id="f"><use xlink:href="#e"/><use xlink:href="#e"/><use xlink:href="#e"/><use xlink:href="#e"/><use xlink:href="#e"/><use xlink:href="#e"/><use xlink:href="#e"/><use xlink:href="#e"/><use xlink:href="#e"/><use xlink:href="#e"/></g>
<g id="g"><use xlink:href="#f"/><use xlink:href="#f"/><use xlink:href="#f"/><use xlink:href="#f"/><use xlink:href="#f"/><use xlink:href="#f"/><use xlink:href="#f"/><use xlink:href="#f"/><use xlink:href="#f"/><use xlink:href="#f"/></g>
<g id="h"><use xlink:href="#g"/><use xlink:href="#g"/><use xlink:href="#g"/><use xlink:href="#g"/><use xlink:href="#g"/><use xlink:href="#g"/><use xlink:href="#g"/><use xlink:href="#g"/><use xlink:href="#g"/><use xlink:href="#g"/></g>
<g id="i"><use xlink:href="#h"/><use xlink:href="#h"/><use xlink:href="#h"/><use xlink:href="#h"/><use xlink:href="#h"/><use xlink:href="#h"/><use xlink:href="#h"/><use xlink:href="#h"/><use xlink:href="#h"/><use xlink:href="#h"/></g>
<g id="j"><use xlink:href="#i"/><use xlink:href="#i"/><use xlink:href="#i"/><use xlink:href="#i"/><use xlink:href="#i"/><use xlink:href="#i"/><use xlink:href="#i"/><use xlink:href="#i"/><use xlink:href="#i"/><use xlink:href="#i"/></g>
</svg>

It works precisely the same way as a billion laughs: it creates one point, a, at 0,0; then it creates a group, b with ten instances of a; then group c with ten instances of b; and so on until we have 109 (+1, I suppose) instances of our point, a. I’m not entirely sure how a renderer handles ‘drawing’ a single point with no stroke, etc. (essentially a nonexistent object), but it is interesting to note that if we wrap the whole thing in a <defs> block (which would define the objects but not draw them), the bomb still works. Browsers respond a few different ways…


The internet sucks (external)

Well, this sucks. My host, NFSN, is doing a major overhaul to their pricing scheme simply because the internet has become such a horrible hotbed of malice. To be clear, when I say ‘this sucks’, I don’t mean any negativity toward NFSN. The article link up there goes to their blog post explaining the matter, and it frankly seemed inevitable that fighting DDOS attacks would catch up to their pricing scheme. Previously, if you had a static site with low bandwidth and storage, you could probably get a year out of a quarter (domain registration not included, of course). The new plan allows for basically a $3.65 annual minimum which is still impressive (especially given what NFSN offers). But it’s a bummer that it’s come to this.

I would like to reiterate that this is not a complaint against NFSN. I will continue to use them for hosting, I will continue to recommend them, I will continue to praise them. I believe this is a necessary move. I’m just really, really pissed off that this is where we are with the internet. I don’t know what’s going on behind the scenes as far as law enforcement, but the internet is a global network (really?) and that’s not an easy problem to solve. I just hope something is happening to clean this wasteland up, because the advancements we’ve made in the information age are too important to bury under a sheet of malice.


Compromised

Recently, a financial account of mine was compromised. As a person who, while entirely fallible, is pretty well-versed in infosec, I have a lot of thoughts on the matter. Honestly the whole thing has been more fascinating to me than anything. Maybe it’s because my bank has been very accommodating so far, maybe it’s because (relatively speaking) trivial amounts of money have been sucked from my accounts, or maybe it’s because I’m petty and vengeful and when you make a direct bank transfer your name, the recipient’s name, it is revealed to the sender1.

I’m curious about the vector of attack. My assumption is that primarily my card was physically compromised, but I’m not sure. The timeline began with the reception of notifications that my online banking password had been reset. I assumed, or, hoped for a glitch and reset it. Then it reset again. And again. Then a transfer account was added. Then, while I was dialing in to the bank, $100 had been transferred out. This is when it gets a little panicky, but having that information, having a number of controls in front of me to mitigate the situation, and having quick response from the bank’s customer service all led to a fairly painless resolution.

The means of ingress was not the internet, it was not ‘hacking’. When you start telling people about an attack like this, the overwhelmingly rudimentary understanding of security lends itself to responses like ‘ah, well you have this account and now that account was hacked! The hackers hacked it!’ The term ‘hacking’ evokes some real man-vs.-machine WarGames type shit, but the sort of attacks that tend to affect most of us are far less sexy. Things like malware and card skimmers meticulously mining data to then be sold off in batches to lesser criminals.

So that was the first breach, and then several days later it was followed by fraudulent card purchases. I was able to temporarily mitigate this by disabling the card, before ultimately contacting the issuer and having the card entirely deactivated and a new one issued. In between these two things happening, I received a call from ‘my bank’ enquiring about card fraud (which had not yet occurred). The incoming number (which is trivially spoofed) did appear to resolve to the bank’s fraud department, but the callback number was unknown to the internet. I assume this was an attempt by attackers to phish more information while I was at my most vulnerable.

When I mention that the vector of attack likely began with the card, this is because there are some safeguards in place for doing the password reset over the phone. Some, like driver’s license numbers in many states, are completely trivial to reproduce, and financial institutions really need to stop relying on faux secret information. The card number is another potential identifier, and I think these two things with a dash of good old-fashioned social engineering thrown in probably led to multiple over-the-phone password resets being granted in a fifteen-minute window. Just the handful of dealings I had with the bank gave a lot of insight into how one could pull off such an attack, which itself is a little concerning.