Geo-chat, bots dañinos y esteganografía: enriquecer el conocimiento sobre Telegram


¿Qué sabes sobre los telegramas en Telegram? ¿Y puede distinguir la esteganografía en VideoNote (popularmente, round-robin)? ¡Analizamos la misma tarea NeoQUEST-2020 , que causó la mayor cantidad de preguntas y exclamaciones a nuestro apoyo! Spoiler: sí, y también habrá un poco de cifrado aquí :)

En la leyenda de NeoQUEST-2020 , encontramos un enlace al perfil de un robot viajero en Instagram. Nada fuera de lo común, ¿verdad? Así que también lo decidimos, pero aún tenemos que resolver la tarea, por lo que consideramos cuidadosamente todas las imágenes en el perfil y buscamos al menos algunas pistas. Una pequeña meditación sobre una hermosa imagen del lago Baikal, y nos damos cuenta de que la pista está en la última publicación:


Gracias a la imagen, entendemos que de alguna manera necesita conectar Baikal (Shaman Rock) y Telegram ("U puede unirse a mi ..." - ¿no se parece a nada?). Al principio, decidimos no darles a los participantes una pista directa de geo-chat (¡eso es exactamente!), Y muchos de ellos lograron superar la tarea con éxito utilizando un emulador o un dispositivo móvil con la capacidad de cambiar la ubicación geográfica. Shamanim Establecemos las coordenadas (53.20074, 107.349426) (se puede ver a simple vista) en el área de la roca Shamanka y nos preparamos para lo más difícil: la espera. Telegram trabaja extrañamente con geo-posicionamiento y obtiene contactos y chats relevantes durante una hora. Por nuestra diligencia y paciencia, se nos paga por completo: el chat deseado aparece en la sección Contactos -> Buscar personas cercanas -> Grupos cercanos.


Voila, estamos en el negocio!


El bot nos encuentra con una tarea en forma de un archivo de algunos bytes con contenido no identificado, en el que podemos leer las líneas "Descifrarme" y "Apocalipsis no ahorra a nadie".

Entendemos la primera línea sin ningún problema, pero ¿qué significa la segunda? ... Aquí, los participantes se dividieron en dos campos: algunos nos escribieron por correo, porque llegaron a un callejón sin salida, mientras que otros observaron cuidadosamente la frase "Apocalipsis no perdona a nadie" y discernieron que ? ¡Derecha! Buen formato ASN.1 antiguo ( aquí ya escribimos sobre cómo analizarlo).


Vamos a hacerlo bien. En el interior hay 2 estructuras. En uno, encontramos un conjunto de bytes marcado "Descifrarme", del cual asumimos que este es texto cifrado. En la segunda estructura, vemos dos números. Es poco probable que esta sea una clave generosamente presentada por el participante junto con el texto cifrado, lo que significa muy probablemente. Estamos tratando con una clave pública. Toda la información reunida nos lleva a la conclusión obvia: ¿por qué no probar RSA ?

Entonces, tenemos un módulo y un indicador abierto, que, por cierto, es bastante grande. Después de un estudio convulsivo de la RSA para reflexionar, concluimos que el indicador cerrado es pequeño, ¿qué significa? ¡Bingo! Definitivamente podemos jugar a malos y usar el ataque de Wiener .

Lo pensamos bien incluso para aquellos a quienes no les gusta la criptografía: podría usar una versión preparada del ataque, por ejemplo, esto .

Entonces conseguimos el valor de una figura cerrada d=40553818206320299896275948250950248823966726834704013657854904761789429403771y descifrar el texto cifrado: key=nq2020faAeFeGUCBjYf7UDrH9FapFCdFPa4u;pass=passCxws3jzYhp0HD5Fy84.

Obtenemos la clave "nq2020faAeFeGUCBjYf7UDrH9FapFCdFPa4u" para la primera parte del trabajo y la contraseña "passCxws3jzYhp0HD5Fy84", que necesita para alimentar al representante del bot. Se puede encontrar entre los participantes del chat con el nombre @neoquestbot.

Al estar en la onda positiva al recibir la primera clave, no nos damos cuenta de inmediato de que el bot es exigente en la comunicación y todo el tiempo dice que no ve al interlocutor:


Pero el bot recibe felizmente los mensajes redondos de VideoNote e incluso los responde ... en la misma forma redonda:


Parece que el video y el sonido son los mismos, pero esto es solo a primera vista. ¿Qué pasa si nuestro bot nos da algunas señales secretas? Para averiguarlo, guardaremos y compararemos el video original con la respuesta del bot. Para esto y para los próximos pasos, el paquete FFmpeg es excelente para nosotros . Entonces, veamos qué hay allí:



Formato aac -> flac, frecuencia 44100 Hz -> 98000 Hz. Descubrieron que seguimos trabajando más con el audio.

Con un movimiento hábil de las manos, lo sacamos del video:


Lo mismo se puede hacer con nuestro mensaje original, para que podamos compararlos más tarde. Para mayor claridad, abra ambas pistas en Audacity .


El salto en amplitud en la respuesta de audio del bot llama inmediatamente su atención (especialmente extraño si estuviéramos en silencio). En una inspección más cercana, notamos los límites claros de los intervalos durante la alternancia del "silencio de onda":


Sugerimos dejar de lado todas las cosas y contar un poco. Analizamos por fragmentos:

0 - 0.005 - silencio
0.005 - 0.01 - onda
0, 01 - 0.0225 - silencio
0.025 - 0.04 - onda
0.04 - 0.045 - silencio

El intervalo más pequeño es 0.005, y todos los demás los intervalos son múltiplos de 0.005.
Tomamos la presencia de una onda de 0.005 por 1, y silencio por 0. ¡No obtenemos nada más que un código binario!
Recordamos que la frecuencia ha cambiado e intentamos mirar el gráfico de espectro (Análisis -> Gráfico de espectro):


Vemos que la señal más potente es a una frecuencia de ~ 44100 Hz, que es la ecografía.
Entonces, deberías trabajar solo con altas frecuencias.

De hecho, el bot superpone su señal en el audio original en el espectro audible. Y aquellos participantes que habían sonado en el video original notaron esto en Audacity.

Cortamos las frecuencias altas con un filtro de paso alto, ya sea en Audacity o en el mismo ffmpeg:


Entonces, tenemos un archivo mono wav de 16 bits. Consiste en un encabezado, una secuencia de audio sin comprimir y metadatos. El flujo de audio en sí está dividido en cuadros (y los cuadros pueden almacenar varias muestras en sí mismos, pero esta es una historia completamente diferente), en nuestro caso de 16 bits cada uno (esto se indica con las letras pcm_s16 en las capturas de pantalla). Los marcos son secuencias de bits que describen la amplitud de la onda a la vez para uno o más canales (en nuestro caso, para uno). La frecuencia de muestreo de la secuencia de audio es 98000 cuadros (es decir, 98000 cuadros por segundo), 490 cuadros por intervalo de 0,005 segundos.

Por lo tanto, seguimos trabajando de acuerdo con un algoritmo simple: leemos 490 cuadros, determinamos si es una onda o silencio y, dependiendo de esto, establecemos el bit en 0 o 1. Usaremos

Python y un paqueteola para analizar archivos wav.
Si se produce el error "wave.Error: formato desconocido: 65534" al abrir el archivo, reemplace "wFormatTag" en el encabezado de 'FE FF' a '01 00 ':

fh = open(input_file, "r+b")
fh.seek(20)
fh.write(b'\x01\x00')
fh.close()

Entonces, abra el archivo, procese 490 cuadros y calcule el valor promedio:

file = wave.open(input_file,"r")
    for i in range (1, int(file.getnframes()/490)+1):
        frames = file.readframes(490)
        bit = 0
        sum = 0
        for k in range(0, 246):
            frame_bytes = frames[k*2:k*2+2]
            sum += int.from_bytes(frame_bytes, "big")
        if sum/490 > 16000:
            bit = 1
        bits.append(bit)

Es posible que donde haya silencio (compárese con la imagen en Audacity), el ruido pueda permanecer. Por lo tanto, establecemos el umbral (sea 16000), al exceder lo que consideramos que la señal es 1.

Luego agrupamos los bits en bytes:

bytes = []    
for i in range (1, int(len(bits)/8)+1):
        b1 = bits[i*8-8]
        b2 = bits[i*8-7]
        b3 = bits[i*8-6]
        b4 = bits[i*8-5]
        b5 = bits[i*8-4]
        b6 = bits[i*8-3]
        b7 = bits[i*8-2]
        b8 = bits[i*8-1]
        byte = (b1 << 7) | (b2 << 6) | (b3 << 5) | (b4 << 4) | (b5 << 3) | (b6 << 2) | (b7 << 1) | b8
        bytes.append(byte.to_bytes(1, byteorder='big')) 

Si todo se hace correctamente, el resultado es la cadena "Givemethepassword". Dado que el bot se comunica en círculos usando esteganografía, será lógico ingresarle una contraseña (y la recibimos junto con la clave como resultado del descifrado) en el mismo formato.

Para comenzar, componga una pista de audio con una contraseña. Para hacer esto, utilizamos los datos obtenidos durante el análisis del mensaje del bot: frecuencia de muestreo 98000 Hz; la duración de la señal que describe cada bit es de 5 ms; la frecuencia de la señal correspondiente al valor de bit "1" - como vimos en los gráficos, 44100 Hz.

Ahora necesitamos "generar" silencio. Hacemos esto neutralizando:

sample_rate = 98000.0
def generate_silence(duration_milliseconds=5):
    fragment = []
    num_samples = duration_milliseconds * (sample_rate / 1000.0)
    for x in range(int(num_samples)): 
        fragment.append(0.0)
    return fragment

Para generar sonido, utilizaremos una onda sinusoidal (la información se puede leer aquí ):

def generate_sinewave(
        freq=41000.0, 
        duration_milliseconds=5, 
        volume=0.5):
    fragment = []
    amplitude = volume * 32767.0
    num_samples = duration_milliseconds * (sample_rate / 1000.0)
    for x in range(int(num_samples)):
        fragment.append(amplitude * math.sin(2 * math.pi * freq * ( x / sample_rate )))
    return fragment

Ahora la cosa es pequeña: queda por convertir la contraseña en bits y luego en sonido.

Nota: El bot usa la pista de video de entrada original para superponer su mensaje, como se mencionó anteriormente. Por lo tanto, debe agregar algunos bytes cero después de la contraseña para borrar toda la clave del bot, y no solo su comienzo (la longitud de la clave fue de 36 bytes).

Generación de sonido
    audio = []
    f = open(input_file, 'rb')
    for character in f.read():
        a = character
        b8 = a & 0b00000001 
        b7 = (a & 0b00000010) >> 1 
        b6 = (a & 0b00000100) >> 2
        b5 = (a & 0b00001000) >> 3
        b4 = (a & 0b00010000) >> 4
        b3 = (a & 0b00100000) >> 5
        b2 = (a & 0b01000000) >> 6
        b1 = (a & 0b10000000) >> 7
        if b1 == 1:
            audio += generate_sinewave()
        else:
            audio += generate_silence()
        if b2 == 1:
            audio += generate_sinewave()
        else:
            audio += generate_silence()
        if b3 == 1:
            audio += generate_sinewave()
        else:
            audio += generate_silence()
        if b4 == 1:
            audio += generate_sinewave()
        else:
            audio += generate_silence()
        if b5 == 1:
            audio += generate_sinewave()
        else:
            audio += generate_silence()
        if b6 == 1:
            audio += generate_sinewave()
        else:
            audio += generate_silence()
        if b7 == 1:
            audio += generate_sinewave()
        else:
            audio += generate_silence()
        if b8 == 1:
            audio += generate_sinewave()
        else:
            audio += generate_silence()


Ahora crearemos el archivo wave terminado:

wav_file=wave.open(file_name,"w")
    nchannels = 1
    sampwidth = 2
    nframes = len(audio)
    comptype = "NONE"
    compname = "not compressed"
    wav_file.setparams((nchannels, sampwidth, sample_rate, nframes, comptype, compname))
    for sample in audio:
        wav_file.writeframes(struct.pack('h', int(sample)))
    wav_file.close()

Guardamos nuestra pista, por ejemplo, en pass.wav. En el camino, verificamos con nuestro decodificador stego si se reconoce la contraseña. Si todo está bien, obtenemos un nuevo video con una contraseña del video original my_video.mp4, reemplazando la pista de audio:


Ahora tenemos que hacer VideoNote de esto. Puede intentar buscar los que funcionen (algunos de los participantes, por ejemplo, encontraron @TelescopyBot), o puede escribir su bot usando TelegramAPI.


De todos modos, adelante a nuestro bot:


Recibimos una nueva ronda y felicitaciones (¡habríamos hecho un trabajo así!), Decodificamos el audio de acuerdo con el escenario ya resuelto, y obtuvimos la clave: "nq2020SyOMK7SnnJP1sNlvbTs8zt35vUrrsD"

De hecho, la esteganografía se considera una de las áreas más difíciles de ciberseguridad sin ninguna razón. ¡Intenta adivinar todas estas cosas aquí! Pero los participantes de NeoQUEST mostraron una excelente destreza y sentido del humor durante esta tarea, por lo que nos dirigimos a nuestra sincera admiración (desde las felicitaciones del robot).

All Articles