Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Two-factor no longer works? #445

Open
jaymzh opened this issue Nov 9, 2018 · 65 comments
Open

Two-factor no longer works? #445

jaymzh opened this issue Nov 9, 2018 · 65 comments

Comments

@jaymzh
Copy link
Contributor

jaymzh commented Nov 9, 2018

I reported this in the Workplace bug, but it looks like this is now happening on non-workplace. Two-factor no longer works either in app-password mode, nor in login-approval-code mode.

If you use an app password, you just get permission denied (tried with both "username" and "email" as username).

If you use normal password, Pidgin will tell you about the approval code, you then put it in, and it tries to connect for a minute or so, and then eventually you get invalid username or password (401).

@jaymzh jaymzh changed the title Two-factor no longer works on either FB or Workplace. Two-factor no longer works on either FB or Workplace? Nov 10, 2018
@jaymzh
Copy link
Contributor Author

jaymzh commented Nov 10, 2018

Oh - so it looks like you can make it work, if, before you put in the 2fac code, you go to the site, then click the "did you log in", click yes, then click "save browser", THEN go back to pidgin and put in the code it works, at least for normal fb.

@jaymzh
Copy link
Contributor Author

jaymzh commented Nov 10, 2018

OH! And it works for Workplace too [but the alert comes up on non-workplace]. I'll leave this open for others to find and I'll comment on the workplace thread.

@jaymzh
Copy link
Contributor Author

jaymzh commented Nov 19, 2018

Aaaand, no that stopped working. :(

@jaymzh jaymzh changed the title Two-factor no longer works on either FB or Workplace? Two-factor no longer works? Nov 20, 2018
@jaymzh
Copy link
Contributor Author

jaymzh commented Dec 18, 2018

@dequis - as of now there's no Facebook or Workplace if you use 2fac (which ... I hope most people do). Pretty please for christmas all I want is a chat client? :) :)

@dequis
Copy link
Owner

dequis commented Dec 24, 2018

Can't repro :/

19:44 <@dx|fb-2> ac on
19:44 <@root> Trying to get all accounts connected...
19:44 <@root> facebook - Logging in: Authenticating
19:44 <@root> facebook - Login error: Login approvals are on. Expect an SMS shortly with a code to use for log in (406)
19:44 <@root> facebook - Logging in: Signing off..
19:44 <@root> facebook - Logging in: Reconnecting in 5 seconds..
19:44 <@dx|fb-2> ac off
19:44 <@root> Deactivating all active (re)connections...
19:45 <@dx|fb-2> ac facebook set password '028470'
19:45 <@root> Setting changed successfully
19:45 <@dx|fb-2> ac facebook on
19:45 <@root> facebook - Logging in: Authenticating
19:45 <@root> facebook - Logging in: Fetching contacts
19:45 <@root> facebook - Logging in: Connecting
19:45 <@root> facebook - Logging in: Logged in
19:50 <@dx|fb-work2> ac add facebook [...]
19:50 <@root> Account successfully added with tag facebook
19:50 <@root> You can now use the /OPER command to enter the password
19:50 <@root> Password added to IM account facebook
19:50 <@dx|fb-work2> ac facebook set work on
19:50 <@root> work = `on'
19:50 <@dx|fb-work2> ac facebook on
19:50 <@root> facebook - Logging in: Authenticating
19:50 <@root> facebook - Login error: Login approvals are on. Expect an SMS shortly with a code to use for log in (406)
19:50 <@root> facebook - Logging in: Signing off..
19:50 <@root> facebook - Logging in: Reconnecting in 5 seconds..
19:50 <@dx|fb-work2> ac facebook off
19:50 <@root> Reconnect cancelled
19:50 <@dx|fb-work2> ac facebook set password 736178
19:50 <@root> Setting changed successfully
19:50 <@dx|fb-work2> ac facebook on
19:50 <@root> facebook - Logging in: Authenticating
19:50 <@root> facebook - Logging in: Fetching contacts
19:50 <@root> facebook - Logging in: Connecting
19:50 <@root> facebook - Logging in: Logged in

@jaymzh
Copy link
Contributor Author

jaymzh commented Dec 24, 2018

I should have sent you a debug log, I suck. Doing so now.

@jaymzh
Copy link
Contributor Author

jaymzh commented Dec 24, 2018

So I sent you pidgin debug logs, but just for fun I also tried bitlbee:

11:50 <@phil> account add facebook jaymzh "XXXXXXXXXXXXXXXXXX"
11:50 <@root> Account successfully added with tag facebook
11:50 <@phil> ac on
11:50 <@root> Trying to get all accounts connected...
11:50 <@root> facebook - Logging in: Authenticating
11:51 <@root> facebook - Login error: Login approvals are on. Expect an SMS shortly with a code to use for log in (406)
11:51 <@root> facebook - Logging in: Signing off..
11:51 <@root> facebook - Logging in: Reconnecting in 5 seconds..
11:51 <@root> facebook - Logging in: Authenticating
11:51 <@root> facebook - Login error: Login approvals are on. Expect an SMS shortly with a code to use for log in (406)
11:51 <@root> facebook - Logging in: Signing off..
11:51 <@root> facebook - Logging in: Reconnecting in 15 seconds..
11:51 <@phil> ac off
11:51 <@root> Deactivating all active (re)connections...
11:51 <@phil> ac facebook set password '881202'
11:51 <@root> Setting changed successfully
11:51 <@phil> ac on
11:51 <@root> Trying to get all accounts connected...
11:51 <@root> facebook - Logging in: Authenticating
11:51 <@root> facebook - Login error: Invalid username or password (401)
11:51 <@root> facebook - Logging in: Signing off..

@dequis
Copy link
Owner

dequis commented Dec 26, 2018

I looked around, seems that there's a new auth path like this:

  • credentials_type=two_factor
  • first_factor=string copied from login_first_factor in error_data in the original error message (seems fairly constant for me),
  • twofactor_code=the code you enter manually I guess
  • password=twofactor_code

I drafted an implementation of this with a python script, but the server doesn't like something about it, says "error_msg":"An unknown error occurred (1)". I'm going to need to sniff actual requests to find what i'm doing wrong, and my debugging tooling is in a different continent... Seems unlikely that I'll have time to rebuild that soon.

@dequis
Copy link
Owner

dequis commented Dec 26, 2018

FWIW my dirty request signing script (python2)

import cgi
from urllib import urlencode
import hashlib

FB_API_KEY = '256002347743983'
FB_API_SECRET = '374e60f8b9bb6b8cbb30f78030438895'

def fb_sig(data):
    params = ''.join(['%s=%s' % x for x in sorted(data.items())])
    data['sig'] = hashlib.md5(params + FB_API_SECRET).hexdigest()
    return data

data = {}
data['api_key'] = FB_API_KEY
data['format'] = 'json'
data['method'] = 'auth.login'
data['email'] =... '...'
data['password'] = '...'

#data['credentials_type'] = 'two_factor'
#data['error_detail_type'] = 'button_with_disabled'
#data['first_factor'] = '...'
#data['twofactor_code'] = '...'
#data['password'] = data['twofactor_code']

print("curl 'https://b-api.facebook.com/method/auth.login' -v --data-binary '" + urlencode(fb_sig(data)) + "'")

Replace the ..., run, run its output, uncomment block of #data, fill their .... Not really adding many details here because I'm sure some part is wrong. If I leave out credentials_type it works, but that's just because my "server" still supports the old method of using password for twofactor_code, I bet.

If you somehow manage to get it working, set the hidden setting token to the value of access_token. In purple it's accounts.xml stuff I think.

@jaymzh
Copy link
Contributor Author

jaymzh commented Jan 2, 2019

OK, I'm trying to play with this, but what is data['first_factor'] supposed to be? I treid setting it to data['password'] but that still gives me An unknown error occurred.

@dequis
Copy link
Owner

dequis commented Jan 2, 2019

The error message of the first login attempt has a login_first_factor string in it, I copied that. It could be wrong, though.

@jaymzh
Copy link
Contributor Author

jaymzh commented Jan 2, 2019

Ah I see now, I missed that. So I tried that, and I tried both overriding data['password'] as you did, but also leaving it with the password, and both ways I get:

{"error_code":1,"error_msg":"An unknown error occurred (1)","request_args":[{"key":"method","value":"auth.login"},{"key":"api_key","value":"256002347743983"},{"key":"format","value":"json"},{"key":"first_factor","value":"XXXXXXXXXXXXXXX"},{"key":"credentials_type","value":"two_factor"},{"key":"sig","value":"YYYYYYYYYYYYYy"},{"key":"twofactor_code","value":"AAAAAAAAA"},{"key":"password","value":"--sanitized--"},{"key":"error_detail_type","value":"button_with_disabled"},{"key":"email","value":"phil\u0040ipom.com"}]}

@jaymzh
Copy link
Contributor Author

jaymzh commented Jan 2, 2019

BTW, for anyone else playing along at home, I modified the script slightly to make it a bit easier to use:

#!/usr/bin/python

import sys
import cgi
from urllib import urlencode
import hashlib
import getpass

FB_API_KEY = '256002347743983'
FB_API_SECRET = '374e60f8b9bb6b8cbb30f78030438895'

def fb_sig(data):
    params = ''.join(['%s=%s' % x for x in sorted(data.items())])
    data['sig'] = hashlib.md5(params + FB_API_SECRET).hexdigest()
    return data

data = {}
data['api_key'] = FB_API_KEY
data['format'] = 'json'
data['method'] = 'auth.login'
data['email'] = 'YOUR_EMAIL_HERE'

if len(sys.argv) > 1:
    data['credentials_type'] = 'two_factor'
    data['error_detail_type'] = 'button_with_disabled'
    data['first_factor'] = sys.argv[1]
    data['twofactor_code'] = sys.argv[2]
    data['password'] = data['twofactor_code']
else:
    data['password'] = getpass.getpass()

print("curl 'https://b-api.facebook.com/method/auth.login' -v --data-binary '" + urlencode(fb_sig(data)) + "'")

You can run it once with no argument, and then the second time pass in the first_factor as arg1 and the SMS code as the second arg, like:

$ fb_test.py
Password: <enter your password here>
curl ....
$ fb_test.py XXXXXX 123456
curl ....

@jaymzh
Copy link
Contributor Author

jaymzh commented Jan 2, 2019

Continuing to mess with this I made the script just do the requests for you and prompt you for the bits it needs:

#!/usr/bin/python

import sys
import cgi
from urllib import urlencode
import hashlib
import getpass
import httplib
import urllib
import json
from optparse import OptionParser

DEBUG = False

FB_API_KEY = '256002347743983'
FB_API_SECRET = '374e60f8b9bb6b8cbb30f78030438895'

def fb_sig(data):
    newdata = data.copy()
    params = ''.join(['%s=%s' % x for x in sorted(data.items())])
    newdata['sig'] = hashlib.md5(params + FB_API_SECRET).hexdigest()
    return newdata

def debug(msg):
    global DEBUG
    if DEBUG:
        print "DEBUG: %s", msg

parser = OptionParser()
parser.add_option('-d', '--debug', action='store_true', dest='debug', default=False)
(options, args) = parser.parse_args()

if options.debug:
    DEBUG = True

data = {}
data['api_key'] = FB_API_KEY
data['format'] = 'json'
data['method'] = 'auth.login'
data['email'] = ''
if data['email'] == '':
    print "ERROR: set an email address, please"
    sys.exit()
data['password'] = getpass.getpass()

headers = {"Content-type": "application/x-www-form-urlencoded", "Accept": "*/*"}
conn = httplib.HTTPSConnection('b-api.facebook.com:443')
params = urllib.urlencode(fb_sig(data))
conn.request('POST', '/method/auth.login', params, headers)
response = conn.getresponse()
debug("status, reason: %s, %s" % (response.status, response.reason))
response_data = response.read()
debug("undecoded response: %s" % response_data)
response = json.loads(response_data)
debug(response)
first_fac = json.loads(response['error_data'])['login_first_factor']

data['credentials_type'] = 'two_factor'
data['error_detail_type'] = 'button_with_disabled'
data['first_factor'] = first_fac
data['twofactor_code'] = getpass.getpass('Code: ')
data['password'] = data['twofactor_code']

params = urllib.urlencode(fb_sig(data))
conn.request('POST', '/method/auth.login', params, headers)
response = conn.getresponse()
debug("status, reason: %s, %s" % (response.status, response.reason))
response_data = response.read()
debug("undecoded response: %s" % response_data)
response = json.loads(response_data)
print response

@jaymzh
Copy link
Contributor Author

jaymzh commented Jan 3, 2019

Hey @dequis what's the easiest way to see what the official apps do? I can try debugging, but since it's all SSL, I'm not sure the easiest way to see what's going on..

@dequis
Copy link
Owner

dequis commented Jan 3, 2019

Yeah I just need to rebuild my MITM setup, see:

I'm going to need to sniff actual requests to find what i'm doing wrong, and my debugging tooling is in a different continent... Seems unlikely that I'll have time to rebuild that soon.

For values of "soon" of "one week" which is over now. I'll look into this and other things this weekend, because apparently someone broke other parts of fb, sync sequences are sometimes gone and receiving messages goes on a different queue. Also the TLS 1.3 thing because why not.

FWIW I documented the stuff I did with earlier versions at https://wiki.dequis.org/notes/facebook/ - but it's been long enough that I bet the cert pinning methods changed again.

@jaymzh
Copy link
Contributor Author

jaymzh commented Jan 3, 2019

OK cool, thanks. If I get time to set that stuff up, I'll poke at it, but I'm guessing you'll get to the bottom of this faster than I will.

@jaymzh
Copy link
Contributor Author

jaymzh commented Jan 8, 2019

I didn't have a big enough block of time this weekend to try to setup the whole MITM setup unfortunately. Did you get a chance to look?

@dequis
Copy link
Owner

dequis commented Jan 8, 2019

Nope, I only had enough time to sort the other issues (and one of them was just because someone else came up with the fix which was just bumping a version in the user agent lol).

On the bright side I am no longer technically-homeless!

@jaymzh
Copy link
Contributor Author

jaymzh commented Jan 9, 2019

Having a place to live is definitely more important than fixing my bugs! I'm glad you have a place to live :)

@jaymzh
Copy link
Contributor Author

jaymzh commented Jan 22, 2019

Thought I'd follow up here and see if you had made any progress. As always, happy to donate to you (or your favorite charity) to help the cause.

@dequis
Copy link
Owner

dequis commented Jan 24, 2019

Hi! Sorry, nothing. My next two weekends are already fully booked and evenings ceased to exist. Also thanks for the offer (i genuinely appreciate it) but it wouldn't really buy me more time.

@jaymzh
Copy link
Contributor Author

jaymzh commented Feb 12, 2019

I just tried again (in case they reverted whatever thing they were rolling out), and neither normal Facebook nor workplace work with 2fac, so I (and probably others) still have no ability to use purple-facebook at all.

@rbshadow
Copy link

@jaymzh @dequis
Just active app password in FB.
Settings > Security and Login > App Password > Create an app password.
Then login with that password and your FB username.

It's working for me.

Thanks

@jaymzh
Copy link
Contributor Author

jaymzh commented Feb 26, 2019

This did not work for me when I filed the Issue, but it does work now! It even works on Workplace!

@tofurky
Copy link

tofurky commented Mar 2, 2019

nice. works for me now, too. previously app passwords did not work.

@builuc1998
Copy link

{"error_code":1,"error_msg":"An unknown error occurred (1)","request_args":[{"key":"method","value":"auth.login"},{"key":"api_key","value":"256002347743983"},{"key":"format","value":"json"},{"key":"first_factor","value":"XXXXXXXXXXXXXXX"},{"key":"credentials_type","value":"two_factor"},{"key":"sig","value":"YYYYYYYYYYYYYy"},{"key":"twofactor_code","value":"AAAAAAAAA"},{"key":"password","value":"--sanitized--"},{"key":"error_detail_type","value":"button_with_disabled"},{"key":"email","value":"phil\u0040ipom.com"}]}

Hi. Have you solved this problem yet? please help me

@jaymzh
Copy link
Contributor Author

jaymzh commented Nov 19, 2021

"device_id": 'aba9641c-fed9-4af8-8d32-d12e0dafd506',

I had to replace this with MACHINE_ID and generate my own uuid into MACHINE_ID, but then it worked! Thanks a lot for the script.

Ooops, fixed. Thanks!

@jaymzh
Copy link
Contributor Author

jaymzh commented Nov 19, 2021

I put some work into the script to make it a bit easier for people not familiar with python or dicts or other stuff. It will spit out errors in some common cases instead of crashing. It's also now in py3. Here's a script, that when you run it, looks like this:

$ pidgin-fb-login-test.py
Access Token generator for Facebook 2factor login

This tool will perform 2-factor login to FB and then print out an
access token needed for the FB plugin for bitlbee and pidgin. Take
the resulting code and put it in the "token" tag in accounts.xml

Password: 
Code: 
Access token: <.....>

You need to edit the script to add your email and a UUID (which you can get by running uuidgen), but that's it. The script is here:

https://gist.github.com/jaymzh/3ed8817cf8c20222ca09ce33a544b695

@akhepcat
Copy link

Question about this process that I didn't see an obvious answer to:

if one does:

$ grep -A90 -i prpl-facebook accounts.xml | sed -n '/<\/account>/q;p' | grep setting | egrep 'id|token'

you can see that there already exists some data that looks like it's trying to use in the script:

                        <setting name='cid' type='string'>${CID-base64}</setting>
                        <setting name='uid' type='string'>${UID-base10}</setting>
                        <setting name='did' type='string'>${DID-uuid}</setting>
                        <setting name='mid' type='string'>${MID-base10}</setting>
                        <setting name='token' type='string'>${TOKEN-base64}</setting>

or at the very least, is returned by the python script above:

{u'machine_id': u'${MID-base64}', u'uid': ${UID-base10},u'access_token': u'${TOKEN-base64}'

(the only one not in the response is "cid")

Should we be making sure to update those lines from the response into accounts.xml as well, or just TOKEN?

Also, would it make sense, if it's available, to just use the 'did' from accounts.xml in the python script?

just thinking out loud here...

@jaymzh
Copy link
Contributor Author

jaymzh commented Nov 19, 2021

So, the short answer is: as long as the token is set, it doesn't seem to matter much. And to be clear, this script is just a short-term stop gap until @grimmy get is PR up that implements this natively, otherwise I'd be trying to make it parse-and-edit the accounts.xml, but I didn't care that much for something that I hope dies in a week or two.

All that said, those are all good questions. I actually used mid as my device_id, but I'm not sure. I imagine, looking at the flow you're supposed to pass in a device_id, and then use the machine_id you get back when you auth, but I don't actually know

@grimmy
Copy link
Collaborator

grimmy commented Nov 20, 2021

Yeah, sorry I'm super busy the next few days and not sure when I'll be able to finish this, but I'm hoping I'll have it done next week.

@Azizb750
Copy link

Azizb750 commented Nov 29, 2021

I put some work into the script to make it a bit easier for people not familiar with python or dicts or other stuff. It will spit out errors in some common cases instead of crashing. It's also now in py3. Here's a script, that when you run it, looks like this:

$ pidgin-fb-login-test.py
Access Token generator for Facebook 2factor login

This tool will perform 2-factor login to FB and then print out an
access token needed for the FB plugin for bitlbee and pidgin. Take
the resulting code and put it in the "token" tag in accounts.xml

Password: 
Code: 
Access token: <.....>

You need to edit the script to add your email and a UUID (which you can get by running uuidgen), but that's it. The script is here:

https://gist.github.com/jaymzh/3ed8817cf8c20222ca09ce33a544b695

actually you must use 'did' (device_id) mentioned in the accounts.xml instead of an random uuid, this is how worked on me

@giabao06
Copy link

giabao06 commented Dec 4, 2021

Tip: the stoken setting is actually the OAuth2 secret. Entering that in solved the problem of facebook straight up locking my account after using Pidgin

@Azizb750
Copy link

Azizb750 commented Dec 4, 2021

This is how I logged in successfully (a more detailed version for those who are begginers with pidgin):

  1. Setup the fb account from pidgin and add the account.
  2. Open the accounts.xml and check for 'did''s value and copy it
  3. Setup the python file, put your accounts.xml's 'did'(which indeed is an UUID) to the MACHINE_ID, write your email and save it
  4. Open the terminal and execute the python file
  5. Write down your password and the code you got from the SMS
  6. Copy the token, go to the value <setting name='token' /> and modify it so it must look something like this <settings name='token' type='string'>(the token you got)</setting>
  7. Save the accounts.xml file, then go to the pidgin>buddies>quit
  8. Open the pidgin again, so the program will login using the token instead of resending login request and deleting it.
  9. Now you have logged in successfully.

Yeah me too. But I was able to solve it this way:

1. Put the new password into pidgin

2. Close pidgin, open accounts.xml

3. Clear the stoken and token setting (as in, delete all those settings, not the value)

4. Reauthenticate, get new token, put new token in accounts.xml again

@akhepcat
Copy link

akhepcat commented Jan 8, 2022

Suddenly unable to use 2fa again, using the script above.
(or using my merged script that parses accounts.xml, grabs the correct data, and call the fb login page: https://raw.githubusercontent.com/akhepcat/Miscellaneous/master/pidgin-fb-login-2fa.py )

Don't have enough skills to burp this and figure out what's changed, only that it's not working anymore for me.

@blacklight
Copy link

@akhepcat it broke for me as well in the past 24h, but I have managed to get my bitlbee-facebook account back online by simply generating another token.

@tonitch
Copy link

tonitch commented Jan 25, 2022

On my side, I keep getting 401 invalid username or password even tho I'm pretty sure I did everything right !

@Metalhead33
Copy link

@Azizb750 's instructions with the script worked perfectly for me.

@akorn
Copy link

akorn commented Mar 6, 2022

It's possible to extract the relevant IDs from bitlbee's nickname.xml too; the script (either script) spits out a token, account facebook token <......>, and account facebook on works again.

This is a tremendous quality of life improvement. Thanks a lot!

@akhepcat
Copy link

akhepcat commented Mar 8, 2022

Ahhhh. Yes, the scripts are working just fine.

I was being too quick, and dismissing the "Did you just attempt to sign in" pop-up, which of course stops the SMS code send. Oops.

Ignoring that pop-up and waiting for the SMS made the flow work just fine. Can't believe i didn't try that sooner.

@tbjorheim
Copy link

Hi.

I have tried several times to get this to work again. It was working before, but suddenly stopped working for some time ago.

Tried to follow Azizb750's instructions, but still no luck. But I need to quit Pidgin before editing the accounts.xml file, if not it seems like the token gets overwritten by the blank/default one.

When I start Pidgin after entering the token, I always get "An unknown error occurred (1)".

Any idea?

@Tatsujin
Copy link

I've been banging my head against this one all night. Was about to give up until I got it to work. For reference, Im using Debian Stretch and Bitlbee via Bitlbee's debian repository.

Got to the point where I rewrote the pidgin token generation script script for bitlbee (bitlbee-purple uses a different location for accounts.xml and apparently doesn't properly know how to write to it, it's a known bug).

https://bugs.bitlbee.org/ticket/1327

I prefer the Glowing Bear frontend for weechat relay over Pidgin /w GTK2/3 or Finch /w tmux/screen. I had to do some system kludges because bitlbee encrypts passwords in its configuration and it doesn't let anyone beyond root and the bitlbee service user account touch the config. I'm able to handle the former by just prompting for the password using getpass.getpass instead of reading it from xml, but the latter has to be done from bitlbee and a shell. I also modified the xml to json conversion to account for the differences in the bitlbee configuration versus libpurple.

Here's my procedure before running the script:

In bitlbee

acc facebook del
save
acc add facebook email password
acc facebook on
acc facebook off
accept the 2FA challenge on website to prevent a lockout
save

The final save command will populate /var/lib/bitlbee/USERNAME.xml with the uid/gid/mid/cid. The UID will always be zero, but that's OK since it will update on the first JSON resquest/response and stay the same after that, along with the DID. The MID should change however during the process.

Command Line as non-privileged user

$ sudo chmod o+x /var/lib/bitlbee
$ sudo chmod o+r /var/lib/bitlbee/USERNAME.xml

Run the script

$ cat /etc/issue
Debian GNU/Linux 9 \n \l
$ dpkg -l | grep bitlbee-common
ii  bitlbee-common                       3.6-1+20211113+master+36-gcfe7243b-git amd64        IRC to other chat networks gateway (common files/docs)
$ dpkg -l | grep bitlbee-facebook
ii  bitlbee-facebook                     20210212~8bd37d9~44                    amd64        Facebook protocol plugin for BitlBee
$ python3 --version
Python 3.5.3
$ python3 bitlbee-fb-login-2fa.py

Initial Output

Config xml file is:  /var/lib/bitlbee/USERNAME.xml
Password:
DEBUG: %s Account UID: 0
DEBUG: %s Account DID: --sanitized--
DEBUG: %s Account MID: --sanitized--
Access Token generator for Facebook 2factor login

This tool will perform 2-factor login to FB and then print out an
access token needed for the FB plugin for bitlbee and pidgin. Take
the resulting code and set the token for facebook in bitlbee

DEBUG: %s status, reason: 200, OK
DEBUG: %s undecoded response: b'{"error_code":406,"error_msg":"Login approvals are on. Expect an SMS shortly with a code to use for log in (406)","error_data":"{\\"machine_id\\":\\"--sanitized--\\",\\"uid\\":--sanitized--,\\"login_first_factor\\":\\"FDl9pFNMcxFgpRek8qAKTsuSaRUpOLUZ\\",\\"support_uri\\":\\"https:\\\\\\/\\\\\\/m.facebook.com\\\\\\/two_factor\\\\\\/id_upload\\\\\\/mobile\\\\\\/?idd=AYjJQ0DH9SwUAxVb3I8bazawWtryrf1DsmTFnqjbvdmyUOhSM1XvMinRtmUenegi7NnakqzjSIA5LmQdjypePeNZ&nonce=iAXIqa3Tiebum5up&ext=1648541875&hash=AeT1dCEPQM3er3ZLa2E\\",\\"auth_token\\":\\"1648282675.tr.s:pw.tDBGAiEAxOGw0e2MlQLJzOdlM8G3Bm25GOkApuy2RcSDAcNthsECIQDch2GzWMlL4CJg4JqWoeg2iEyaSsuBYFNScjNgTpmMAw\\",\\"error_title\\":\\"Login Code Required\\",\\"error_message\\":\\"Generate a code from your authentication app or use the code we sent by text message to log in.\\"}","request_args":[{"key":"method","value":"auth.login"},{"key":"uid","value":"0"},{"key":"email","value":"--sanitized--"},{"key":"password","value":"--sanitized--"},{"key":"fb_api_req_friendly_name","value":"authenticate"},{"key":"format","value":"json"},{"key":"sig","value":"977a1ac7d0d1cb3e120f58ae7290f4b7"},{"key":"generate_session_cookies","value":"1"},{"key":"api_key","value":"256002347743983"},{"key":"device_id","value":"--sanitized--"},{"key":"locale","value":"en"},{"key":"generate_machine_id","value":"1"}]}'
Traceback (most recent call last):
  File "bitlbee-fb-login-2fa.py", line 148, in <module>
    response = json.loads(response_data)
  File "/usr/lib/python3.5/json/__init__.py", line 312, in loads
    s.__class__.__name__))
TypeError: the JSON object must be str, not 'bytes'

The script dies before it can load the first request's response data. Some quick googling tells me I need to use decode('utf-8'), so I modified the two instances in the script

from:

response = json.loads(response_data)

to
response = json.loads(response_data.decode('utf-8'))

After those changes, on the next attempt, we finally have something! We get prompted for the 2FA code (note: I wore out my welcome on SMS 2FA debugging, but as other people pointed out codes from your authenticator app work fine). After entering it we get another error, but we also get the Access Token!

DEBUG: %s {'error_data': '{"machine_id":"--sanitized--","uid":--sanitized--,"login_first_factor":"FDl9pFNMcxFgpRek8qAKTsuSaRUpOLUZ","support_uri":"https:\\/\\/m.facebook.com\\/two_factor\\/id_upload\\/mobile\\/?idd=AYjJQ0DH9SwUAxVb3I8bazawWtryrf1DsmTFnqjbvdmyUOhSM1XvMinRtmUenegi7NnakqzjSIA5LmQdjypePeNZ&nonce=iAXIqa3Tiebum5up&ext=1648541875&hash=AeT1dCEPQM3er3ZLa2E","auth_token":"1648282675.tr.s:pw.tDBGAiEAxOGw0e2MlQLJzOdlM8G3Bm25GOkApuy2RcSDAcNthsECIQDch2GzWMlL4CJg4JqWoeg2iEyaSsuBYFNScjNgTpmMAw","error_title":"Login Code Required","error_message":"Generate a code from your authentication app or use the code we sent by text message to log in."}', 'request_args': [{'key': 'method', 'value': 'auth.login'}, {'key': 'uid', 'value': '0'}, {'key': 'email', 'value': '--sanitized--'}, {'key': 'password', 'value': '--sanitized--'}, {'key': 'fb_api_req_friendly_name', 'value': 'authenticate'}, {'key': 'format', 'value': 'json'}, {'key': 'sig', 'value': '977a1ac7d0d1cb3e120f58ae7290f4b7'}, {'key': 'generate_session_cookies', 'value': '1'}, {'key': 'api_key', 'value': '256002347743983'}, {'key': 'device_id', 'value': '--sanitized--'}, {'key': 'locale', 'value': 'en'}, {'key': 'generate_machine_id', 'value': '1'}], 'error_msg': 'Login approvals are on. Expect an SMS shortly with a code to use for log in (406)', 'error_code': 406}
Code: --sanitized--
DEBUG: %s FB Account UID: --sanitized--
FB Account DID not present in error_data: equal to CONFIGFILE.xml did
DEBUG: %s FB Account MID: --sanitized-- (Different value)
DEBUG: %s status, reason: 200, OK
DEBUG: %s undecoded response: b'{"session_key":"5.2B_90p2gYtEZbQ.1648282680.44---sanitized--","uid":--sanitized--,"secret":"5322e5eea92b31d35fe5759b607175b7","access_token":"--sanitized--","machine_id":"OMw-YlVqiess-DymY0U9Bp_f","session_cookies":[{"name":"c_user","value":"--sanitized--","expires":"Sun, 26 Mar 2023 08:18:00 GMT","expires_timestamp":1679818680,"domain":".facebook.com","path":"\\/","secure":true},{"name":"xs","value":"44:2B_90p2gYtEZbQ:2:1648282680:-1:2878","expires":"Sun, 26 Mar 2023 08:18:00 GMT","expires_timestamp":1679818680,"domain":".facebook.com","path":"\\/","secure":true,"httponly":true},{"name":"fr","value":"0by5rp800nXJJa6VE.AWUm-omy2nw5qxZcc5R5aIqioiw.BiPsw4..AAA.0.0.BiPsw4.AWVoWUowGYE","expires":"Fri, 24 Jun 2022 08:17:58 GMT","expires_timestamp":1656058678,"domain":".facebook.com","path":"\\/","secure":true,"httponly":true},{"name":"datr","value":"OMw-YlVqiess-DymY0U9Bp_f","expires":"Mon, 25 Mar 2024 08:18:00 GMT","expires_timestamp":1711354680,"domain":".facebook.com","path":"\\/","secure":true,"httponly":true}],"user_storage_key":"632766dc3ef8444f125aabab0720310762e228d8523c8a8ad67395d8269c025f"}'
Access token: --sanitized--
Traceback (most recent call last):
  File "bitlbee-fb-login-2fa.py", line 193, in <module>
    if ( DID != response['device_id'] ):
KeyError: 'device_id'

I ran the following in bitlbee afterward

acc facebook set token ACCESS_TOKEN
acc facebook on

And it connects! Simply set your options and setup your control channel.

acc facebook set OPTION VALUE
/join &facebook
chan list
chan $N set auto_join true
acc facebook off
acc facebook on
save

To open the control channel on connect, you have to join the control channel, find it in the channel list, and set auto_join on the channel id to true. The final save command will automatically revert your changes to permissions on /var/lib/bitlbee and /var/lib/bitlbee/USERNAME.xml

Looking at the behavior of the script and the JSON requests, I think what is happening is that on the first JSON request, the Facebook API is generating a new DID on its end using uuidgen or something similar and expects the same UUID for the next JSON request/response. I noticed when I finally connected and saved my bitlbee config that the DID stayed the same after the initial response and after bitlbee connected and the config was saved. You still get the KeyError, but you should still get the Access Token since it's in a try/execpt block and the UUID-format DID does not appear to change.

I have uploaded my modified script for bitlbee users to a gist for reference:

https://gist.github.com/Tatsujin/953551fe38d8e38aac43b423998d3deb

I hope you find this useful. If you are using the pidgin script, you might want to try making the decode changes I suggested for the json_loads. Good luck!

@akhepcat
Copy link

Thanks, @Tatsujin - i've upated my script to include the utf-8 parsing as well.

https://raw.githubusercontent.com/akhepcat/Miscellaneous/master/pidgin-fb-login-2fa.py

@tbjorheim
Copy link

Thanks akhepcat for creating this script.

I tried it, but got the following error:

Traceback (most recent call last):
File "./pidgin-fb-login-2fa.py", line 181, in
error_data = json.loads(response['error_data'].decode('utf-8'))
AttributeError: 'str' object has no attribute 'decode'

@akhepcat
Copy link

Thanks akhepcat for creating this script.

I tried it, but got the following error:

Traceback (most recent call last): File "./pidgin-fb-login-2fa.py", line 181, in error_data = json.loads(response['error_data'].decode('utf-8')) AttributeError: 'str' object has no attribute 'decode'

Ah, try removing the ".decode('utf-8')" from that line.

It worked here on my test, but maybe it's failing in some cases, and may not really be needed.

@tbjorheim
Copy link

Hi and thanks for the quick reply.

Tried to remove the decode part, and then I get the token. But also the following error after entering the code:

FB Account DID not present in error_data: equal to accounts.xml did
Access token: ***
Traceback (most recent call last):
File "./pidgin-fb-login-2fa.py", line 212, in
if ( DID != response['device_id'] ):
KeyError: 'device_id'

Tried to add the token to accounts.xml manually, but still get the "An unknown error occurred (1)" when I tries to connect. This is probably not something wrong with the script, but something else. Tried to delete and set up the Facebook account again in Pidgin, but same issue. I get a security notice in Facebook when I try to connect, but I click "Yes, it was me" and "Save browser". But still no luck when try to connect.

@jaymzh
Copy link
Contributor Author

jaymzh commented Jul 21, 2022

Hi and thanks for the quick reply.

Tried to remove the decode part, and then I get the token. But also the following error after entering the code:

FB Account DID not present in error_data: equal to accounts.xml did Access token: *** Traceback (most recent call last): File "./pidgin-fb-login-2fa.py", line 212, in if ( DID != response['device_id'] ): KeyError: 'device_id'

Tried to add the token to accounts.xml manually, but still get the "An unknown error occurred (1)" when I tries to connect. This is probably not something wrong with the script, but something else. Tried to delete and set up the Facebook account again in Pidgin, but same issue. I get a security notice in Facebook when I try to connect, but I click "Yes, it was me" and "Save browser". But still no luck when try to connect.

Try the latest version, that should all be fixed now.

@digfish
Copy link

digfish commented Aug 4, 2022

Hi and thanks for the quick reply.
Tried to remove the decode part, and then I get the token. But also the following error after entering the code:
FB Account DID not present in error_data: equal to accounts.xml did Access token: *** Traceback (most recent call last): File "./pidgin-fb-login-2fa.py", line 212, in if ( DID != response['device_id'] ): KeyError: 'device_id'
Tried to add the token to accounts.xml manually, but still get the "An unknown error occurred (1)" when I tries to connect. This is probably not something wrong with the script, but something else. Tried to delete and set up the Facebook account again in Pidgin, but same issue. I get a security notice in Facebook when I try to connect, but I click "Yes, it was me" and "Save browser". But still no luck when try to connect.

Try the latest version, that should all be fixed now.

Hi
I tried the script by @akhepcat on https://raw.githubusercontent.com/akhepcat/Miscellaneous/master/pidgin-fb-login-2fa.py, pasted the xml code in accounts.xml and I get this error:
OuxmPbFU6n
When I try to connect again, the error stays the same :( .

@jaymzh
Copy link
Contributor Author

jaymzh commented Aug 6, 2022

That happens, I think, when it's trying to sync your history and it's too big.

Go to edit account, advanced, uncheck "show unread messages". The connect, it should work. Once that's done, you can re-check that box and it should work.

@digfish
Copy link

digfish commented Aug 6, 2022

That happens, I think, when it's trying to sync your history and it's too big.

Go to edit account, advanced, uncheck "show unread messages". The connect, it should work. Once that's done, you can re-check that box and it should work.

Hi. Thanks for the reply
Followed your instructions. I unchecked all the boxes in the "Advanced" tab and reconnect. The error stays the same :( .

image

@kflu
Copy link

kflu commented Jan 14, 2023

I ported @jaymzh 's script to python3 and uploaded as a gist here: https://gist.github.com/kflu/1e7c358989b0556e99a919face1ca2f7

Changes:

  • Ported to Python3
  • Auto generate the MACHINE_ID UUID
  • Can set EMAIL from environment variable

USAGE:

FBEMAIL=<YOUR_EMAIL> python3 fb_get_token.py

If you have 2FA, it will ask for the 2FA code after you type in password.

OK, just shoving in a UUID seems to work. Combining @jackblk 's stuff with my previous script, this seems to work. Jam your email and a random UUID at the top

#!/usr/bin/python2.7

import sys
import cgi
from urllib import urlencode
import hashlib
import getpass
import httplib
import urllib
import json
from optparse import OptionParser

DEBUG = False
# put a UUID in here
MACHINE_ID = ''
# put your email in here
EMAIL = ''
FB_API_KEY = '256002347743983'
FB_API_SECRET = '374e60f8b9bb6b8cbb30f78030438895'


def fb_sig(data):
    newdata = data.copy()
    params = ''.join(['%s=%s' % x for x in sorted(data.items())])
    newdata['sig'] = hashlib.md5(params + FB_API_SECRET).hexdigest()
    return newdata

def debug(msg):
    global DEBUG
    if DEBUG:
        print "DEBUG: %s", msg

if EMAIL == '':
    print "ERROR: set an email address, please"
    sys.exit()

if MACHINE_ID == '':
    print "ERROR: set a machine id (to any UUID), please"
    sys.exit()

parser = OptionParser()
parser.add_option('-d', '--debug', action='store_true', dest='debug', default=False)
(options, args) = parser.parse_args()

if options.debug:
    DEBUG = True

data = {
    "fb_api_req_friendly_name": "authenticate",
    "locale": "en",
    "format": "json",
    "api_key": FB_API_KEY,
    "method": "auth.login",
    "generate_session_cookies": "1",
    "generate_machine_id": "1",
    "email": EMAIL,
    "device_id": MACHINE_ID,
}
data['password'] = getpass.getpass()

headers = {"Content-type": "application/x-www-form-urlencoded", "Accept": "*/*"}
conn = httplib.HTTPSConnection('b-api.facebook.com:443')
params = urllib.urlencode(fb_sig(data))
conn.request('POST', '/method/auth.login', params, headers)
response = conn.getresponse()
debug("status, reason: %s, %s" % (response.status, response.reason))
response_data = response.read()
debug("undecoded response: %s" % response_data)
response = json.loads(response_data)
debug(response)
error_data = json.loads(response['error_data'])
first_fac = error_data['login_first_factor']

data['credentials_type'] = 'two_factor'
data['error_detail_type'] = 'button_with_disabled'
data['first_factor'] = first_fac
data['twofactor_code'] = getpass.getpass('Code: ')
data['password'] = data['twofactor_code']
data['userid'] = error_data['uid']
data['machine_id'] = error_data['machine_id']

params = urllib.urlencode(fb_sig(data))
conn.request('POST', '/method/auth.login', params, headers)
response = conn.getresponse()
debug("status, reason: %s, %s" % (response.status, response.reason))
response_data = response.read()
debug("undecoded response: %s" % response_data)
response = json.loads(response_data)
print response

But doing as @dequis recommended and putting the resulting access_token into token into accounts.xml does not work for me, I still get a "Login approvals are on..." error. Also 'stoken' keeps showing up. I put the token into both token and stoken, but I haven't made it work yet. Anyone else?

@jaymzh
Copy link
Contributor Author

jaymzh commented Jan 18, 2023

BTW, I stopped using my script and used @akhepcat 's fork of my script, it's nicer in that it pulls the password automatically from the file and such.

@kofany
Copy link

kofany commented Nov 10, 2024

Up to date script to get token:

https://github.com/kofany/get-fb-token/blob/main/fb-token.py

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests