James Stanley


I found a security vulnerability in SMS Privacy this morning

Mon 7 August 2017
Tagged: smsprivacy

I woke up this morning to find an email from my SMS Privacy server informing me about an error:

[Mon Aug  7 06:05:09 2017] [error] Died at [smsprivacy] line 1341.

(I have a script that emails me whenever the SMS Privacy web service reports any errors).

Worried that I might have to give somebody a refund (e.g. if it died halfway through handling a purchase), I investigated further. Line 1341 of the file in question just checks that the URL you're accessing is in a list of valid possibilities, and dies otherwise. But it turned out to be in a code path that is only accessible if you're authenticated as an admin. That's funny... I'm the only admin and I wasn't awake at 6am.

I looked in the nginx log and found that the request was to /admin/login.php (presumably from an automated vulnerability scanner). That explains why it died: login.php isn't in the list of valid possibilities.

But why did that code even execute in the first place? Don't they have to authenticate as an admin first?

my $admin = under('/admin' => sub {
    my ($c) = @_;
    if ($c->is_user_authenticated && $c->current_user->is_admin) {
        return 1;
    }
    $c->redirect_to('/login');
});
 
$admin->get('/' => sub { ... });
$admin->get('/foo' => sub { ... });
... etc. ...

This is the code that checks whether a user is an admin. under() is a Mojolicious function that allows you to restrict access to certain URLs "under" a parent URL. In this case, we're restricting access to URLs beginning /admin.

You'll note that the function returns 1 if the user is authenticated as an admin, and redirects to /login otherwise. Unfortunately, $c->redirect_to returns a true value, and in Perl a function implicitly returns the value of its last statement. I knew all of these things, I had just failed to put them together.

If you're not an admin, it would write a redirect response to the socket, followed by the actual content that an admin would see. The upshot of this is that it always allows any user to view the content in the admin area! Shit.

Upon figuring out what the vulnerability was, I immediately fixed it (add a "return 0" after the redirect), and then tried to work out whether it had been exploited.

The index page of the admin area gives revenue statistics. It also has hyperlinks to pages listing information about user accounts, Bitcoin payments, and user survey responses. None of the pages can show phone numbers or message contents. Passwords are hashed and salted using Crypt::PBKDF2, but the hashes are not shown anywhere in the admin area. None of the pages can modify any information.

I only had logs for the past 10 days, but I saw logs of people accessing the admin index page, although I don't know whether they actually knew how to read the responses, or whether they were just running automated scanners that threw the results away. In any case, the best they got was revenue statistics. I didn't see any logs of people accessing the pages that contain more sensitive information.

So at this point I knew it was possible that people had seen some sensitive user information, although there is no proof that they did. I quickly wrote up a disclosure for users and published it on the SMS Privacy website (read it if you're interested). I also resolved to get the site professionally security tested and to publish the results. I have now found somebody to do the testing.

I wasn't sure whether writing the disclosure was a good move or not. It's certainly the right thing to do, but is it a profitable thing to do? As far as I know, nobody else in the world knew about this vulnerability. I could have just silently fixed it and probably nobody would be any the wiser. Even if somebody was exploiting it, they'd be unlikely to admit to it, so I'd probably get away with it. However, the SMS Privacy customer base skews very strongly towards the tech-savvy side of the spectrum, so I think they'll understand that admitting that the vulnerability existed is a good thing rather than a bad thing. I've not received any hate mail so far, at any rate.



If you like my blog, please consider subscribing to the RSS feed or the mailing list: