Como extrair chaves TOTP 2FA a partir de QRCODE (Google Authenticator)
Aprenda a extrair chaves TOTP de QRCODEs usados em autenticação de dois fatores (2FA) com ferramentas Linux e um script Python.
[ Hits: 65 ]
Por: Fábio Berbert de Paula em 19/10/2025 | Blog: https://fabio.automatizando.dev
QR-Code:otpauth-migration://offline?data=CkwKFBVIs9WO4MSysvXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXNTNhOGYxNzAzODQ1MDc0MTM5EAIYASAA scanned 1 barcode symbols from 1 images in 0 seconds
#!/usr/bin/env python3 # -------------------------------------------------------------------- # Extract Google Authenticator secrets from a QR Code image # # DEPENDÊNCIAS (Ubuntu/Debian): # sudo apt install zbar-tools # # USO: # python3 extrair-google-auto-qrcode imagem.png # # O QUE O SCRIPT FAZ: # 1. lê a imagem usando `zbarimg --raw` # 2. extrai o "data=..." do esquema otpauth-migration # 3. decodifica o protobuf manualmente (sem dependências externas) # 4. imprime os segredos 2FA em Base32 e otpauth://totp # # ATENÇÃO: # O segredo extraído permite gerar códigos 2FA. Guarde com segurança. # -------------------------------------------------------------------- import sys import subprocess from urllib.parse import unquote import base64 # ---------------------- CHECAGEM DO ARGUMENTO ---------------------- if len(sys.argv) < 2: print("ERRO: informe a imagem como parâmetro.") print("Exemplo: python3 extract_gauth_from_qr.py qrcode.png") sys.exit(1) img = sys.argv[1] # ---------------------- LÊ O QR COM zbarimg ------------------------ try: output = subprocess.check_output(["zbarimg", "--raw", img], stderr=subprocess.DEVNULL) qr_text = output.decode().strip() except FileNotFoundError: print("ERRO: zbarimg não encontrado. Instale com: sudo apt install zbar-tools") sys.exit(1) except subprocess.CalledProcessError: print("ERRO: não foi possível ler o QRCode da imagem.") sys.exit(1) # ---------------------- VALIDA O FORMATO --------------------------- if not qr_text.startswith("otpauth-migration://"): print("ERRO: QRCode não é do tipo otpauth-migration.") sys.exit(1) # extrai valor do data= if "data=" not in qr_text: print("ERRO: não foi encontrado parâmetro data= no QRCode.") sys.exit(1) DATA_PARAM = qr_text.split("data=")[1] # ---------------------- FUNÇÕES DE DECODE -------------------------- def read_varint(b, i): shift = 0 result = 0 while True: byte = b[i]; i += 1 result |= (byte & 0x7F) << shift if not (byte & 0x80): break shift += 7 return result, i def read_length_delimited(b, i): length, i = read_varint(b, i) data = b[i:i+length] return data, i+length # ---------------------- DECODE PAYLOAD ----------------------------- raw = base64.b64decode(unquote(DATA_PARAM)) i = 0 otp_messages = [] while i < len(raw): tag, i = read_varint(raw, i) field_num = tag >> 3 wire_type = tag & 0x7 if field_num == 1 and wire_type == 2: # repeated OTPParameters msg_bytes, i = read_length_delimited(raw, i) otp_messages.append(msg_bytes) else: if wire_type == 0: _, i = read_varint(raw, i) elif wire_type == 2: _, i = read_length_delimited(raw, i) elif wire_type == 1: i += 8 elif wire_type == 5: i += 4 def parse_otp_params(b): out = {}; i = 0 while i < len(b): tag, i = read_varint(b, i) field_num = tag >> 3 wire_type = tag & 0x7 if wire_type == 2: data, i = read_length_delimited(b, i) out[field_num] = data.decode('utf-8') if field_num in (2,3) else data elif wire_type == 0: val, i = read_varint(b, i) out[field_num] = val elif wire_type == 1: out[field_num] = b[i:i+8]; i+=8 elif wire_type == 5: out[field_num] = b[i:i+4]; i+=4 return out def to_base32(raw): return base64.b32encode(raw).decode('utf-8').rstrip('=') # ---------------------- RESULTADO FINAL ---------------------------- print(" === RESULTADOS EXTRAÍDOS ===") for idx, msg in enumerate(otp_messages, 1): f = parse_otp_params(msg) secret = f.get(1, b'') name = f.get(2, '') issuer = f.get(3, '') digits = f.get(5, 6) b32 = to_base32(secret) label = f"{issuer}:{name}" if issuer else name otpauth = f"otpauth://totp/{label}?secret={b32}&digits={digits}&algorithm=SHA1" if issuer: otpauth += f"&issuer={issuer}" print(f" --- ENTRY {idx} ---") print("Name :", name) print("Issuer :", issuer) print("Secret :", b32) print("URL :", otpauth) print(" Concluído. ")
=== RESULTADOS EXTRAÍDOS === --- ENTRY 1 --- Name : FBP12#775678 Issuer : Registro.br Secret : CVELHVMO4DCLFMX44UGBXWBRVDENTFP3 URL : otpauth://totp/Registro.br:FBP12#775678?secret=CVELHVMO4DCLFMX44UGBXWBRVDENTFP3&digits=1&algorithm=SHA1&issuer=Registro.br --- ENTRY 2 --- Name : Fberbert Instagram Issuer : Secret : 3D5ZICX6IC6SENWKSEVNAQPBAV4ZJZMZ URL : otpauth://totp/Fberbert Instagram ?secret=3D5ZICX6IC6SENWKSEVNAQPBAV4ZJZMZ&digits=1&algorithm=SHA1 Concluído.
Como baixar vídeos do Facebook via terminal
Wayland em alta, IA em debate e novos ventos para distros e devices
Como criar um clicador de sites com NodeJS
Convertendo Texto em Fala com Python e pyttsx3
Como criar um keylogger em Python
Esteganografia e Esteganálise: transmissão e detecção de informações ocultas em imagens digitais
RapidScan - Multi-Tool WEB Vulnerability Scanner
Qu1cksc0pe - All-in-One Static Malware Analysis Tool
Introdução a Threads e como implementá-las em Python
Nenhum comentário foi encontrado.
Como extrair chaves TOTP 2FA a partir de QRCODE (Google Authenticator)
Linux em 2025: Segurança prática para o usuário
Desktop Linux em alta: novos apps, distros e privacidade marcam o sábado
IA chega ao desktop e impulsiona produtividade no mundo Linux
Novos apps de produtividade, avanços em IA e distros em ebulição agitam o universo Linux
Digitando underscore com "shift" + "barra de espaços"
Como ativar a lixeira e recuperar aquivos deletados em um servidor Linux
Como mudar o nome de dispositivos Bluetooth via linha de comando
Problema em SSD ao dar boot LinuxMint LMDE FAYE 64 (0)
Baixar jogos Independentes para Ubuntu [RESOLVIDO] (4)
PIP3 - erro ao instalar módulo do mariadb para o Python (1)
Linux x Plataformas de Trading - um problema (in-)solúvel? (4)