Descripción

The terrorists have improved their communications. Help me please!

Write-Up

Se nos proporcionan un archivo que contiene la canción Careless Whisper de George Michael con las siguientes características:

darahh@hackiit:biological_hazard_II$ file terrorist_music.wav
terrorist_music.wav: RIFF (little-endian) data, WAVE audio, Microsoft PCM, 16 bit, mono 48000 Hz

Como podemos ver es un archivo .wav y que tiene una frecuencia de muestreo de 48 kHz, una frecuencia un tanto más alta de lo normal.

Si lo escuchamos no podemos distinguir nada extraordinario y a simple vista, al abrirlo con Audacity tampoco vemos nada extraño.

Para analizar más a fondo, podemos visualizar, por ejemplo, el espectro de frecuencias.

Podemos ver dos extraños picos en las frecuencias 20 kHz y 22 kHz. Recordemos que estas frecuencias no son audibles por el oído humano así que debe haber algo oculto que estamos pasando por alto.

Si cambiamos la vista a modo Espectrograma y cambiamos la frecuencia máxima a 24 kHz podemos ver algo sospechoso.

Si hacemos zoom, despejamos cualquier duda sobre lo que esconde el archivo, una cadena de valores binarios.

Hay que extraer la cadena para comprobar si tiene algún significado. Podemos optar por hacer la extracción a mano, algo que nos llevaría demasiado tiempo, o escribir un script que realice la tarea.

Pero antes de escribir y ejecutar cualquier programa, debemos limpiar el audio y filtrar la parte que nos interesa. Para ello, podemos aplicar un filtro paso alta usando Audacity. Vemos como nos queda solo la parte interesante.

La extracción de la cadena la realizo en este caso con el siguiente script escrito en MATLAB:

%% Decodificación de StegoCancion
fichero='terrorist_music_filtered.wav';
[x,Fs]=audioread(fichero);
%% Cálculo de la PSD
Fres=50;               % Resolución espectral de la PSD (Hz)
Nfft=Fs/Fres;          % Dimensión de la FFT
Lwin=Nfft;             % Ventana de análisis
Noverlap=Lwin/2;       % Solapamiento
Ventana=hanning(Lwin); % Ventana de análisis
[Pxx,Fxx]=pwelch(x,Ventana,Noverlap,Nfft,Fs);
Fxx=Fxx/1e3;       % Frecuencia en KHz
Psd=10*log10(Pxx); % PSD en dB/Hz
figure(1)
plot(Fxx,Psd);
axis([Fxx(1) Fxx(end) -100 -20]);
grid on
xlabel('Frecuencia (KHz)');
ylabel('PSD(dB/Hz)');
% Buscamos los máximos de la PSD
n=2:length(Psd)-1;
idx=(Psd(n)>=Psd(n-1)).*(Psd(n)>=Psd(n+1)).*(Psd(n)>(max(Psd)-20));
nmax=find(idx==1)+1; % Por haber eliminado el primer valor
F1=Fxx(nmax(1)); % Frecuencias de los máximos en KHz
F2=Fxx(nmax(2));
fprintf('Máximos en %.1f KHz y %.1f KHz\n',F1,F2);
%% Espectrograma (para ver la evolucion temporal)
figure(2);
spectrogram(x,Ventana,Noverlap,Nfft,Fs,'reassigned','yaxis');
axis([-Inf Inf 17 23]);
axis([-Inf Inf 17 23]); % No se porque hay que repetirlo 2 veces
%% Se ve que es una modulación FSK con dos tonos de 18KHz y 22 KHz
% Con un periodo de símbolo de alrededor de T=0.1 s | R=10 bps
% Construimos un receptor de filtro dual
% Traslación a banda-base y filtrado paso-baja
% Filtro paso-baja de 1KHz
Fc=1000; % Frecuencia de corte de 1KHz
h = fir1(200,Fc/(Fs/2));
fvtool(h);
t=[0:length(x)-1]/Fs;
x1=abs(filter(h,1,x.*exp(-1j*2*pi*F1*1e3*t)));
x2=abs(filter(h,1,x.*exp(-1j*2*pi*F2*1e3*t)));
xd=x2-x1;
figure(4);
plot(t,xd);
grid on
title(sprintf('Señal en banda base (Fs=%.0fKHz)',Fs/1e3));
xlabel('Time(secs)');
%% Decimación
% Tras filtrar la señal a 1KHz, la podemos decimar porque la Fs original 
% Representa un sobremuestreo elevado
% Decimamos en un factor 400 pasando de 48KHz a 120 Hz
% Lo que representa 12 muestras/símbolo
Ndec = 400;
xd=xd(Ndec:Ndec:end);
Fs2=Fs/Ndec;
%% Filtro adaptado
T=0.1;
R=1/T;
Nss=Fs2/R;
g=ones(Nss,1);
q=conv(xd,g);
% Instante óptimo de muestreo
Nss2=floor(Nss/2);
kmax=1;
Es=0;
qs=[];
for k=Nss2:Nss+Nss2
    qq=q(k:Nss:end);
    es=sum(qq.^2);
    if(es>Es)
        kmax=k;
        Es=es;
        qs=qq;
    end
end
% Trazado de la salida del filtro adaptado y los instantes de muestreo
figure(5);
plot(q);
hold on
kmues=[kmax:Nss:length(q)];
plot(kmues,q(kmues),'or');
hold off
grid on
title(sprintf('Salida del filtro adaptado (decimada a Fs=%.0f Hz)',Fs2));
xlabel('Muestras');
% bit-stream e impresión del mensaje binario
b=(qs>0);
b=b(18:end); % recortamos las muestras basura
fprintf('Mensaje: ');
for k=1:length(b)
    fprintf('%1d',b(k));
end
fprintf('\n');

Tiene como salida:

0100001101000001010101000100001101000011010001110100000101000011010000110100011101010100010000010100001101010100010000110101010001000011010000010100000101000011010000110101010001000001010001110100001101000111010000110100001101000011010000110101010001010100010000110100011101000011010001110100001101000001010101000101010001000011010101000100000101000111010000110100001101010100010101000100001101000111010001110100000101000011010000110100001101000011010000110100011101010100010000110100001101000111010000010100001101000011010001110101010001000111010000110101010001000111010001111011111101

Si pasamos la cadena de ceros y unos a caracteres ASCII, obtenemos lo siguiente:

CATCCGACCGTACTCTCAACCTAGCGCCCCTTCGCGCATTCTAGCCTTCGGACCCCCGTCCGACCGTGCTGG

Se trata de una cadena compuesta por cuatro caracteres distintos y está relacionada con el ADN (Ácidos nucleicos).

Tras investigar un poco podemos ver que en algunos casos se ha codificado cada ácido como parejas de bits, ’00’ (A), ’01’ (C), ’10’ (G), ’11’ (T).

Por tanto, podemos decodificar la cadena y comprobar si hemos obtenido la flag. Para ello, podemos escribir un simple script en python.

dictionary = {"A":'00',"C":'01',"G":'10',"T":'11'}

msg = 'CATCCGACCGTACTCTCAACCTAGCGCCCCTTCGCGCATTCTAGCCTTCGGACCCCCGTCCGACCGTGCTGG'
binary = ''

for c in msg:
	binary += dictionary[c]

print "DNA string:     " + msg
print "Binary string:  " + binary
print "Decoded string: " + ''.join(chr(int(binary[i*8:i*8+8],2)) for i in range(len(binary)//8))

Obtenemos como salida:

darahh@hackiit:biological_hazard_II$ python dnadecoder.py 
DNA string:     CATCCGACCGTACTCTCAACCTAGCGCCCCTTCGCGCATTCTAGCCTTCGGACCCCCGTCCGACCGTGCTGG
Binary string:  010011010110000101101100011101110100000101110010011001010101111101100110010011110111001001011111011010000101010101101101011000010110111001111010
Decoded string: MalwAre_fOr_hUmanz

Por tanto, la flag es:

hackiit_flag{MalwAre_fOr_hUmanz}

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *