
AdultFriendFinder was hacked - xurukefi
https://www.leakedsource.com/blog/friendfinder
======
Animats
Friendfinder and their brands are run by Andrew Conru. They're quite
successful; they own Penthouse. At one point he tried to buy Playboy, but
Hefner wouldn't sell. They don't really have 300,000,000 accounts; there's
been litigation over their fake accounts. It's probably going to turn out to
be like Ashley Madison, where over 95% of the female accounts were fake.

They had a breach last year, but it wasn't as big.[1]

[1] [http://www.ibtimes.com/adult-friend-finder-dating-site-
known...](http://www.ibtimes.com/adult-friend-finder-dating-site-known-casual-
sex-hacked-blackmail-purposes-1934545)

~~~
MilnerRoute
They _don 't_ own Penthouse. That's one of the things that's so weird about
all this. They sold Penthouse.com in February -- but then still managed to
lose all of its login credentials in a database breach 8 months later...

[https://it.slashdot.org/story/16/11/13/2144229/hack-
exposes-...](https://it.slashdot.org/story/16/11/13/2144229/hack-
exposes-412-million-accounts-on-adultfriendfinder-sites)

~~~
mcguire
They kept a backup?

~~~
stingraycharles
Which is usually not allowed after acquisition, exactly for reasons like this.

------
coldcode
"the hashed passwords seem to have been changed to all lowercase before
storage". I have no words to describe how idiotic this is. How do people come
up with this and still get paid?

~~~
kpdyer
I agree that password-typo tolerance may seem like a horrible idea on the
surface. The "str to lower" approach is an especially aggressive way to
increase usability.

However, there's recent work [0] from Cornell that explores the security-
usability tradeoff when correcting password typos. It turns out that accepting
specific classes of typos (e.g., caps lock on: if password is "Password" then
allow "pASSWORD") can increase usability with minimal security impact.

[0]
[https://www.cs.cornell.edu/~rahul/projects/pwtypos.html](https://www.cs.cornell.edu/~rahul/projects/pwtypos.html)

~~~
nsgi
Or you could just show a message if the caps lock is on.

~~~
alasdair_
How do you detect if caps lock is on with JavaScript in the browser?

------
catoc
How does this work? \- The site lists 3.87 million Dutch speaking accounts. \-
Dutch is almost exclusively spoken in the Netherlands. \- The total adult
population (15-55) is 4.45 million
([http://www.indexmundi.com/netherlands/demographics_profile.h...](http://www.indexmundi.com/netherlands/demographics_profile.html))

This would mean that 80% of the Dutch adult population has an Adult Friend
Feinnder account!? (Of course people may have multiple accounts, but still,
80% is when taking into account the full (men+women) population.)

~~~
jj89
You need to double that, unless you exclude females. Why do you stop at 55?

"15-24 years: 12.11% (male 1,050,889/female 1,010,596) 25-54 years: 39.83%
(male 3,400,998/female 3,377,311)"

~~~
catoc
Thanks for correcting that. Doubling checking halves the estimate to just over
40%. Still high, but more likely (given the already mentioned
bots/spammers/double accounts etc). Indeed why stop at 55. Why shouldn't a
pensionado be on a swinger site. Who am I to judge ;-)

------
aikah
> How did it happen? They were hacked via a Local File Inclusion exploit and
> you can read more about the situation when it was initially reported from
> this link.

> LFI vulnerabilities allow an attacker to include files located elsewhere on
> the server into the output of a given application.

How did they do that ? append /../../../etc to an url that is supposed to
serve a file and hope the server doesn't check for directory traversal ?

~~~
wyager
IMO, if you're checking the URL for directory traversal it's already too late.
Whenever I build a server that serves files, I maintain a whitelist set of
served files, and the first thing I do in the file request handler is check if
the URL is in the set. If not, immediately drop to 404. There's too much that
can go wrong with trying to sanitize inputs; it's better to rule out the
possibility of unsanitized data by design. There's more than one approach to
this, and none of them admit directory traversal.

~~~
andybak
How would you allow user uploads with that a whitelist? Accepted uploads get
automatically added to your whitelist? That sounds problematic.

~~~
wereHamster
Problematic how? It doesn't mean the whitelist has to be in the code, it could
be 'generated' from a database (let whitelist be the result of select
file_name from uploaded_files_table)

~~~
paulddraper
Then file_name needs to be reasonable and not arbitrary, right?

I don't care where you push your checks around to, just as long as they exist.

~~~
wyager
A hex-encoded file hash as a file name is a safe bet. You can resolve file
names (unsanitized, stored safely in a database) to hashes and load the files
from disk.

This general approach (whitelisting file URLs) lets us localize any path
sanitation to the file upload code, rather than every single request.

------
peter303
EVERYTHING done online could be public someday. Act like it.

~~~
wepple
I feel this is a defeatist stance to take; LFI's are a solved problem and we
should be looking to how and why this happened and prevent it in the future.

Another angle: we're supposed to not do anything that requires any form of
confidentiality online? can't book a doctors appointment, transfer money, send
emails to family?

~~~
twelve40
It's not defeatist, it's personal hygiene. Sure there are some convenience
trade offs and edge cases, but things like Facebook, Dropbox, etc can almost
assuredly be treated as "eventually public" no matter how many buttons and
knobs they add. The sooner people realize it, the better.

~~~
anigbrowl
What about people who want to communicate and socialize but want some privacy?

~~~
intrasight
Go for a hike in the woods with them

------
perlgeek
> Friend Finder Network Inc is a company that operates a wide range of 18+
> services and was hacked in October of 2016 for over 400 million accounts
> representing 20 years of customer data which makes it by far the largest
> breach we have ever seen

They didn't see the Yahoo break with 500m accounts?

Also, why is "pakistan" such a popular password? Deployed soldiers?

~~~
aliakhtar
As a pakistani, that cracked me up. We are at the top of the list of porn
searching countries, I think ( [http://tribune.com.pk/story/823696/pakistan-
tops-list-of-mos...](http://tribune.com.pk/story/823696/pakistan-tops-list-of-
most-porn-searching-countries-google/) ) and porn sites often have
AdultFriendFinder ads, so it is possible that a pretty large number of
pakistani people signed up. (Assuming there's a free sign up)

------
asafira
So I have always wondered this, but what is the most common way to realize
that your data was hacked? Is it from very careful monitoring of connection
logs? Do hackers typically leave notes and/or obvious traces? Do you start to
notice your stored information online (possibly for sale) in sketchy places?
Do specifically your customers start getting spam?

~~~
rarrrrrr
If you're being proactive about it, one approach is to create "canary"
accounts: single purpose email addresses that signup for your service and
nothing else. When those email addresses start getting spam, it's a strong
indicator your database has been accessed.

Many users signup for each online service with a single-purpose email address.
e.g. <servicename>@uniquedomain.com, so many customers will often know of a
leak as soon as the service provider does.

~~~
guitarbill
You can also do this with Gmail aliases[0]: "For example, messages sent to
jane.doe+notes@gmail.com are delivered to jane.doe@gmail.com." Although the
number of sites with incorrect email validation (that reject perfectly valid
email addresses) is shocking. I do this, and you can then just block the alias
if it starts recieving spam.

[0]
[https://support.google.com/mail/answer/12096?hl=en](https://support.google.com/mail/answer/12096?hl=en)

~~~
shimo5037
While it may have worked in the past (for a while anyway), what exactly
prevents spammers from stripping the suffix, given that the functionality has
been public knowledge for many years? Best case they'll be lazy and try both
with and without, and you'll end up knowing. Blocking the alias cannot
possibly have any effect.

~~~
guitarbill
> Blocking the alias cannot possibly have any effect.

Ah, but it does work (for me, twice). Of course spammers could strip the
suffix. But since spam is a numbers game, I'm not sure it's worth the effort
for them.

------
Kenji
_AdultFriendFinder.com

103,070,536 passwords already plainly visible

232,137,460 passwords hashed with SHA1

99.3% of all passwords from this website are now plaintext (cracked)._

As someone who cares about security, this is very, very painful to read. But
it also makes me curious about that password data set. It might be used for
security research, like estimating the entropy of passwords more accurately.

~~~
coldcode
It definitely shows how terrible people are at password generation and reuse
but even more so how little it matters on individual sites if those folks have
no understanding or don't care about protecting passwords. Yet people keep
using 123456 as a password.

~~~
user5994461
Lots of bots and throwaway on AdultFriendFinder. It's normal to have many
users using "123456" and the likes, they are not real users.

------
supersan
I often store my password using PHP's password_hash('password',
PASSWORD_DEFAULT) function. This function has been baked into the language
since version 5.0 I think. I'm sure most other languages must have a similar
function too, yet so many sites save the password in plain text. Doesn't make
any sense.

~~~
inglor
Major props to Anthony
[https://github.com/ircmaxell](https://github.com/ircmaxell) for adding this
as a language supported feature to PHP as well for his work on techniques for
preventing injection.

I work with C#, Java, Python Go and JS on backends a lot and no other language
I worked with had such a simple but secure API.

~~~
avinassh
Not a std lib in Python, but Django has nice API as well for saving the
password [0].

    
    
        from django.contrib.auth.models import User
        u = User.objects.get(username='john')
        u.set_password('new password')
        u.save()
    
    

And here is the code which does all the magic - [1]. You can also generate
nice passwords [2], use many available different hashers [3] Or write your own
[4]

[0] -
[https://docs.djangoproject.com/en/dev/topics/auth/default/#c...](https://docs.djangoproject.com/en/dev/topics/auth/default/#changing-
passwords)

[1] -
[https://github.com/django/django/blob/stable/1.10.x/django/c...](https://github.com/django/django/blob/stable/1.10.x/django/contrib/auth/base_user.py#L104)
and
[https://github.com/django/django/blob/stable/1.10.x/django/c...](https://github.com/django/django/blob/stable/1.10.x/django/contrib/auth/hashers.py#L66)

[2] -
[https://docs.djangoproject.com/en/dev/topics/auth/customizin...](https://docs.djangoproject.com/en/dev/topics/auth/customizing/#django.contrib.auth.models.BaseUserManager.make_random_password)

[3] -
[https://docs.djangoproject.com/en/dev/topics/auth/passwords/...](https://docs.djangoproject.com/en/dev/topics/auth/passwords/#included-
hashers)

[4] -
[https://docs.djangoproject.com/en/dev/topics/auth/passwords/...](https://docs.djangoproject.com/en/dev/topics/auth/passwords/#writing-
your-own-hasher)

~~~
EE84M3i
One really nice feature that Django has that is rare and well done is the
password upgrading workflow. Not only do they let your app support multiple
algorithms at the same time (with one preferred), they also let you chain
algorithms during upgrade [0], so if you have a legacy database with all SHA1
passwords, you can upgrade all of them to PBKDF2. At first these will all be
PBKDF2(SHA1(pw)), and they will get migrated to just PBKDF2(pw) as users log
in, if you set PBKDF2 to your preferred algo.

Note that of course the password algorithms are typed, so this doesn't cause a
problem in the corner case that a user's password is a sha1 hash of something
else.

[0] -
[https://docs.djangoproject.com/en/dev/topics/auth/passwords/...](https://docs.djangoproject.com/en/dev/topics/auth/passwords/#password-
upgrading-without-requiring-a-login)

------
have_faith
I would be interested to see if it is possible to work out what percentage of
the profiles are fake/bots from the data leaked. Is that possible or would
they simply blend in too easily?

~~~
CoryG89
It would probably be difficult to prove with certainty, but depending on what
the passwords are, you could potentially be able to do something like that.
For example, if there are enough accounts that have the same password (which
is also relatively unique), then at some point it will be a statistical
impossibility that they were all created by different people.

------
dredmorbius
My first thought was "again"? This just happened.

Yes. _Again_ :

 _This event also marks the second time Friend Finder has been breached in two
years, the first being around May of 2015._

Data are liability.

------
inostia
17 fuckyou 34,498. What a strange password choice.

The interesting thing to me is that password choices clearly reflect the
demographic of the users.

~~~
junto
I think that is a response based upon the dark UI pattern of the site.

If you want to view a profile, they force you to register.

Hence the user clicks on a profile, gets a registration form, and fills it out
in a bad mood, since they are being forced register to continue when they
don't want to. Hence "fuckyou" or "fuckoff" becoming their password choice.

It would be interesting to see what email addresses these specific users gave.
Possibly throwaways that use equally fruity names?

------
anc84
tl;dr: Last months AdultFriendFinder.com, Cams.com, Penthouse.com,
Stripshow.com, iCams.com databases in a "statistics" advertisement for
leakedsource.com's services.

------
encoderer
If they don't want it to be mineable, why not a search feature that emails
results to the email in question?

~~~
auganov
I'm guessing they got an exclusive on that one. Want to ramp up the PR machine
before delivering the goods. They'll drop it when everyone's excited enough. I
doubt they care about privacy, the whole point of their service is/was not
caring about it (as opposed to haveibeenpwned).

------
Buge
They say the hashes were peppered. What does that mean? If it's similar to a
unique salt per user, I find it hard to believe they could crack that many
very strong looking passwords.

~~~
bcoates
All peppering does is make it trivially more difficult to check for duplicate
passwords. A system with a decent amount of GPU power can try passwords
against SHA-1 at billions of attempts per second.

~~~
Buge
What does peppering mean though? I don't even know the definition.

Per-user unique salts are definitely helpful in leaks like this. With
400,000,000 users, it would take 400,000,000x more compute power to crack the
same number of passwords.

~~~
slau
Going to take it from the top. Skip down for the actual pepper information if
you're already familiar with hashing and salting (I assume most people will
be).

Let's assume you want to store a password. The first, obvious step, is to
store it in plain text. This is obviously brain dead, but well, we live in the
world we live in.

    
    
        $user_pw = $password;
    

The second step is to hash it. This means that the password can't just be read
out of the database.

    
    
        $user_pw = hash($password);
    

The problem with this approach is that with the amount of computing available,
it's fairly trivial to just bruteforce everything, and with the advent of
rainbow tables (pre-cracked hashes), it gets even easier.

The next obvious step is to salt the password. Salting means that you add a
random piece of information to what you hash, in order to disable the use of
rainbow tables. Every password has to be cracked individually. The salt needs
to be included in the stored form of the hash, because otherwise you can't
calculate incoming authentication requests against it.

    
    
        $user_pw = concat($salt, ':', hash(concat($salt, password)));
    

This makes a targeted attack possible, but mass attack over a long list of
passwords gets quite a bit more difficult.

The problem is that now, you have the salt always stored with the password.
This means that if your database gets stolen/dumped, an attacker has all the
information required to crack specific hashes.

In order to alleviate this, you can use a pepper, which is similar to a salt,
except that it is global and unique to your application, and doesn't change
all the time. It is a static piece of data that gets hashed as well, but isn't
stored alongside the hashes in the database.

    
    
        $user_pw = concat($salt, ':', hash(concat($salt, $PEPPER, password)));
    

This obviously only changes anything if your pepper doesn't get stolen
alongside the database, so this is usually an application-specific constant
that doesn't get stored in the database.

~~~
EE84M3i
I've never heard of this before (at least not called "pepper") - I think I've
heard similar things called stuff like 'sidewide salt' and 'per-password
salt'.

"peppering" as described is conceptually similar to storing passwords as
HMAC's under some key not stored in the database.

------
lemming
I'm amused to see "ifyourreadingthisitstoolate" among the long passwords.
Quite!

~~~
mitchh
Could just be a reference to the Drake album

------
chomp
Is there a torrent or something of the database that is not hidden behind a
paywall?

------
WhitneyLand
Why are they not making the data searchable?

I don't see how that helps anyone when a technical person can trivially setup
a search, and a non-tech person could pay someone a small sum to do the same.

------
codedokode
If we could use a different identifier (like email address) for every website
such hack would not be a problem. Or if we used a hardware key without email
address.

------
ommunist
I wonder how much Adobe and Dropbox data from their breaches overlap with AFF
data? What a Klondike for a sociologist.

------
SorryImAnon
> If Twitter decides to ban them [their new @BigSecurityNews account] as well,
> we are going to start giving exclusive content to the terrorist group ISIS
> so they too get banned from Twitter because it seems like that's what it'll
> take to get Twitter to take action against accounts of those who enjoy
> cutting the heads off their enemies.

Savage. It's interesting why twitter seems to be blind against obvious
terrorists accounts.

------
blah39832908
Is it possible for such a leak on Google searches? I.e. massive leak of
accounts to search data, or 3rd party leaks?

~~~
Kenji
Of course it's possible, the question is how likely it is.

------
wepple
can we _please_ not refer to a kid who exploits a 10-year-old known
vulnerability as a "researcher".

~~~
ftxdri
Your ego is showing.

Just because the vulnerability is old doesn't mean you can disrespect his
profession. Sometimes people just write bad code. I'm sure you've done the
same.

~~~
wepple
I've definitely written bad code, for sure. I don't mean to sound
disrespectful, I chose my words pretty poorly there.

I'm arguing that this isn't research. There was no novel technique used or
investigation into original paths of exploitation or increasing our
understanding of previously unknown areas of anything.

There's a material reason I said the above; calling the individual a
researcher suggests that the exploitation of AFF was something quite
complicated requiring a previously unknown attack, taking away from the fact
that having an LFI in your app in 2016 is potentially bad luck but more likely
just negligent; it should be highlighted as such.

------
teppopo
How they crack the hashed passwords?

~~~
user5994461
top 1000 passwords list + brute force + rainbow table + dictionary attack +
fingerprinting attack.

All of that running on GPU. It's terribly effective. Even more so when 90% of
accounts are throwaway/bots/fake accounts.

I'd make a blog post about cracking 99.7% of AdultFriendFinder passwords in 1
hour. But then I realized that it's evil and I shall not.

~~~
truth_sentinell
And what do they hit to make sure the password was cracked? Do they make bots
to login? I don't understand.

~~~
joaodlf
SHA1 is a hashing algorithm (as opposed to an encryption algorithm), this
means the string you're trying to hash will always have the same result. As an
example, the string "password" will always have the same SHA1 hash
(5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8). If you have the list of hashes,
you can always find a lot of the passwords by using the techniques explained
above.

~~~
truth_sentinell
Oh ok, I guess this doesn't happen with bcrypt, right? Because it spits out a
different hash every time you hash it.

~~~
gruturo
Uh? Of course not. It will spit out exactly the same hash every time, given
the same input.

How else would you verify that the password _matches_ ?

~~~
truth_sentinell
I don't know. Laravel uses a hash algorithm that uses bcrypt and never outputs
the same hash.

~~~
nommm-nommm
Bcrypt uses 22 character salt.

The output of your library's BcryptEncoder.encode(password) includes not only
the password hash but information about the algorithm and the salt. That's
what you store in your database. That extra information tells the decode
function how to decode later on.

See here:

[http://stackoverflow.com/questions/6832445/how-can-bcrypt-
ha...](http://stackoverflow.com/questions/6832445/how-can-bcrypt-have-built-
in-salts)

