mirror of https://github.com/xBytez/duo-cli
commit
5741daf915
|
@ -1 +1,3 @@
|
||||||
*.pyc
|
*.pyc
|
||||||
|
duotoken.hotp
|
||||||
|
response.json
|
||||||
|
|
14
README.md
14
README.md
|
@ -1,8 +1,8 @@
|
||||||
## Duo One Time Password Generator
|
## Duo One Time Password Generator
|
||||||
|
|
||||||
This is a little script I put together after I reverse engineered the Duo 2FA
|
This is a little script I put together after I reverse engineered the Duo 2FA
|
||||||
Mobile App and figured out how their auth flow works. This can be ported into
|
Mobile App and figured out how their auth flow works. This can be ported into
|
||||||
probably a useful desktop app or chrome extention and can probably be used to
|
probably a useful desktop app or chrome extention and can probably be used to
|
||||||
write bots for MIT Services that require auth.
|
write bots for MIT Services that require auth.
|
||||||
|
|
||||||
### Usage
|
### Usage
|
||||||
|
@ -27,6 +27,12 @@ If everything worked you can then generate a code by running:
|
||||||
./duo_gen.py
|
./duo_gen.py
|
||||||
```
|
```
|
||||||
|
|
||||||
Warning: These are HOTP tokens and generate codes increments a counter. If you
|
Warning: These are HOTP tokens and generate codes increments a counter. If you
|
||||||
get too far out of sync with the server it will stop accepting your codes.
|
get too far out of sync with the server it will stop accepting your codes.
|
||||||
|
|
||||||
|
```
|
||||||
|
./duo_export.py
|
||||||
|
```
|
||||||
|
|
||||||
|
Export the duo hotp secret as a QR code for inclusion in third-party hotp apps
|
||||||
|
like freeotp.
|
||||||
|
|
|
@ -1,47 +1,59 @@
|
||||||
#!/usr/bin/env python2.7
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
import pyotp
|
import pyotp
|
||||||
import requests
|
import requests
|
||||||
import base64
|
import base64
|
||||||
import json
|
import json
|
||||||
import sys
|
import sys
|
||||||
from urllib2 import unquote
|
|
||||||
|
|
||||||
if len(sys.argv) < 2:
|
if len(sys.argv) < 2:
|
||||||
print "Usage: python duo_bypass.py <url to duo qr>"; exit()
|
print("Usage: python duo_bypass.py <url to duo qr>")
|
||||||
|
sys.exit()
|
||||||
|
|
||||||
qr_url = sys.argv[1]
|
qr_url = sys.argv[1]
|
||||||
data = qr_url #unquote(qr_url.split('=')[1])
|
|
||||||
|
|
||||||
hostb64 = data.split('-')[1]
|
host = 'api-%s' % (qr_url.split('/')[2].split('-')[1],)
|
||||||
|
code = qr_url.rsplit('/',1)[1]
|
||||||
|
|
||||||
print "hostb64", hostb64
|
url = 'https://{host}/push/v2/activation/{code}?customer_protocol=1'.format(host=host, code=code)
|
||||||
|
headers = {'User-Agent': 'okhttp/2.7.5'}
|
||||||
|
data = {'jailbroken': 'false',
|
||||||
|
'architecture': 'armv7',
|
||||||
|
'region': 'US',
|
||||||
|
'app_id': 'com.duosecurity.duomobile',
|
||||||
|
'full_disk_encryption': 'true',
|
||||||
|
'passcode_status': 'true',
|
||||||
|
'platform': 'Android',
|
||||||
|
'app_version': '3.23.0',
|
||||||
|
'app_build_number': '323001',
|
||||||
|
'version': '8.1',
|
||||||
|
'manufacturer': 'unknown',
|
||||||
|
'language': 'en',
|
||||||
|
'model': 'Pixel C',
|
||||||
|
'security_patch_level': '2018-12-01'}
|
||||||
|
|
||||||
host = base64.b64decode(hostb64 + '='*(-len(hostb64) % 4))
|
r = requests.post(url, headers=headers, data=data)
|
||||||
code = data.split('-')[0]
|
|
||||||
|
|
||||||
print "host", host
|
|
||||||
print "code", code
|
|
||||||
|
|
||||||
url = 'https://{host}/push/v2/activation/{code}'.format(host=host, code=code)
|
|
||||||
r = requests.post(url)
|
|
||||||
response = json.loads(r.text)
|
response = json.loads(r.text)
|
||||||
|
|
||||||
print "url", url
|
try:
|
||||||
print "r", r
|
secret = base64.b32encode(response['response']['hotp_secret'])
|
||||||
print "response", response
|
except KeyError:
|
||||||
secret = base64.b32encode(response['response']['hotp_secret'])
|
print(response)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
print "secret", secret
|
print("secret", secret)
|
||||||
|
|
||||||
print "10 Next OneTime Passwords!"
|
print("10 Next OneTime Passwords!")
|
||||||
# Generate 10 Otps!
|
# Generate 10 Otps!
|
||||||
hotp = pyotp.HOTP(secret)
|
hotp = pyotp.HOTP(secret)
|
||||||
for _ in xrange(10):
|
for _ in xrange(10):
|
||||||
print hotp.at(_)
|
print(hotp.at(_))
|
||||||
|
|
||||||
f = open('duotoken.hotp', 'w')
|
f = open('duotoken.hotp', 'w')
|
||||||
f.write(secret + "\n")
|
f.write(secret + "\n")
|
||||||
f.write("0")
|
f.write("0")
|
||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
|
with open('response.json', 'w') as resp:
|
||||||
|
resp.write(r.text)
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import pyotp
|
||||||
|
import pyqrcode
|
||||||
|
import json
|
||||||
|
import base64
|
||||||
|
import sys
|
||||||
|
|
||||||
|
file_json = "response.json"
|
||||||
|
|
||||||
|
with open('response.json', "r") as f:
|
||||||
|
response = json.loads(f.read())['response']
|
||||||
|
|
||||||
|
with open('duotoken.hotp', "r") as f:
|
||||||
|
counter = int(f.readlines()[1])
|
||||||
|
|
||||||
|
label = response['customer_name']
|
||||||
|
issuer = 'Duo'
|
||||||
|
# base32 encoded hotp secret, with the padding ("=") stripped.
|
||||||
|
secret = base64.b32encode(bytes(response['hotp_secret'], 'utf-8')).decode('utf-8').replace('=', '')
|
||||||
|
qrdata = 'otpauth://hotp/{label}?secret={secret}&issuer={issuer}&counter={counter}'.format(label=label, secret=secret, issuer=issuer, counter=counter)
|
||||||
|
qrcode = pyqrcode.create(qrdata)
|
||||||
|
print(qrcode.terminal(quiet_zone=1))
|
||||||
|
print(qrdata)
|
20
duo_gen.py
20
duo_gen.py
|
@ -1,24 +1,24 @@
|
||||||
#!/usr/bin/env python2.7
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
import pyotp
|
import pyotp
|
||||||
import requests
|
|
||||||
import base64
|
|
||||||
import json
|
|
||||||
import sys
|
import sys
|
||||||
from urllib2 import unquote
|
|
||||||
|
|
||||||
f = open("duotoken.hotp","r+");
|
if len(sys.argv) == 2:
|
||||||
|
file = sys.argv[1]
|
||||||
|
else:
|
||||||
|
file = "duotoken.hotp"
|
||||||
|
|
||||||
|
f = open(file, "r+");
|
||||||
secret = f.readline()[0:-1]
|
secret = f.readline()[0:-1]
|
||||||
offset = f.tell()
|
offset = f.tell()
|
||||||
count = int(f.readline())
|
count = int(f.readline())
|
||||||
|
|
||||||
print "secret", secret
|
print("secret", secret)
|
||||||
print "count", count
|
print("count", count)
|
||||||
|
|
||||||
hotp = pyotp.HOTP(secret)
|
hotp = pyotp.HOTP(secret)
|
||||||
print "Code:", hotp.at(count)
|
print("Code:", hotp.at(count))
|
||||||
|
|
||||||
f.seek(offset)
|
f.seek(offset)
|
||||||
f.write(str(count + 1))
|
f.write(str(count + 1))
|
||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue