O objetivo desta atividade foi decifrar uma mensagem que foi encriptada utilizando uma cifra clássica.
O nosso grupo recebeu o ficheiro L07G05.cph
que contém a mensagem encriptada:
]$.-$.&[]?]-]$/+]/*?]!$/].%/&!]-$></!&[$-*&!]-&<*&?+&-]?>&/%,&!]#$|&?!#&/*$/&$#]--%:$|>?&+&-&]$.#$/^&.$/*]!&-!%:$?-&-$/*%!&!$-$/:]|:%!&-/&+]/*%/<%!&!$!$-*$*%#]!$?$</%&]&.&|%&>/?]|>&#?&**-#$!?](<?.$-*$?*?]:&/*$^$?.&/_]-$.&?%]|&>%/^&.&?%&_]&]$|$-$.<%*]-]<*?]-$-*&]^]_$_</*]-/<.&>&|&#$|&|<*&+]/*?&&-%!&/]+]|%-$<!]-?$+?$%]-&-^]?>&/%,&!]#$|&|%>&#]?*<><$-&+]/*?&&-%!&]$-#$+*&+<|]#?$*$/!$+]/*?%(<%?#&?&.](%|%,&?*]!&&>$/*$!$-*?<%?*&(<-$[&|-]-.]?&|%-.]-#&?&/<.!%&|]>][?&/+]$/<.&&*%*<!$&($?*&$](_$+*%:&|<*&?.]-{|>+%/+_-&!$?^|]%}
Sabemos que esta mensagem está originalmente em português, retirada de um jornal, e podemos também afirmar que não tem espaços.
Para resolver este desafio, seguimos o exemplo dos SEED Labs e utilizamos a análise de frequência para decifrar a mensagem. Para tal, procuramos a frequência de cada letra na língua portuguesa:
imagem retirada da Wikipedia
Seguidamente, utilizamos o nosso próprio script em Python para contar a frequência de sequências de letras de qualquer comprimento na mensagem encriptada.
from collections import Counter
cipher_text = "]$.-$.&[]?]-]$/+]/*?]!$/].%/&!]-$></!&[$-*&!]-&<*&?+&-]?>&/%,&!]#$|&?!#&/*$/&$#]--%:$|>?&+&-&]$.#$/^&.$/*]!&-!%:$?-&-$/*%!&!$-$/:]|:%!&-/&+]/*%/<%!&!$!$-*$*%#]!$?$</%&]&.&|%&>/?]|>&#?&**-#$!?](<?.$-*$?*?]:&/*$^$?.&/_]-$.&?%]|&>%/^&.&?%&_]&]$|$-$.<%*]-]<*?]-$-*&]^]_$_</*]-/<.&>&|&#$|&|<*&+]/*?&&-%!&/]+]|%-$<!]-?$+?$%]-&-^]?>&/%,&!]#$|&|%>&#]?*<><$-&+]/*?&&-%!&]$-#$+*&+<|]#?$*$/!$+]/*?%(<%?#&?&.](%|%,&?*]!&&>$/*$!$-*?<%?*&(<-$[&|-]-.]?&|%-.]-#&?&/<.!%&|]>][?&/+]$/<.&&*%*<!$&($?*&$](_$+*%:&|<*&?.]-{|>+%/+_-&!$?^|]%}"
# os valores numéricos podem ser incrementados para obter sequências de diferentes comprimentos:
sequences = [cipher_text[i:i+1] for i in range(len(cipher_text) - 0)]
frequency = Counter(sequences)
# o valor numérico na if statement pode ser alterado para filtrar sequências com frequência superior a um certo valor:
for char, freq in frequency.items():
if freq > 0:
print(f"'{char}': {freq}")
Com isto obtemos os seguintes resultados:
&: 74 ocorrências
]: 54 ocorrências
$: 54 ocorrências
-: 39 ocorrências
?: 37 ocorrências
*: 34 ocorrências
/: 33 ocorrências
%: 32 ocorrências
!: 26 ocorrências
<: 21 ocorrências
|: 21 ocorrências
.: 18 ocorrências
+: 15 ocorrências
#: 14 ocorrências
>: 13 ocorrências
:: 6 ocorrências
^: 6 ocorrências
(: 6 ocorrências
_: 6 ocorrências
[: 4 ocorrências
,: 3 ocorrências
{: 1 ocorrência
}: 1 ocorrência
Foi nos dada a dica de que os caracteres {
e }
não foram alterados e apenas indicam que o conteúdo da flag está entre eles. Assim, podemos ignorar as suas ocorrências para a análise.
Como os espaços foram removidos da mensagem, analisar a frequência de bigramas e trigamas como no exemplo dos SEED Labs não é útil, visto que muitos dos bigramas e trigamas não são válidos. Por isso, decidimos ficar apenas com a frequência de letras individuais.
Para decifrar a mensagem, criamos um script em Python que substitui cada caractere da mensagem encriptada por um caractere que nós achemos correto, com base na frequência de letras na língua portuguesa.
cipher_sequence = "]$.-$.&[]?]-]$/+]/*?]!$/].%/&!]-$></!&[$-*&!]-&<*&?+&-]?>&/%,&!]#$|&?!#&/*$/&$#]--%:$|>?&+&-&]$.#$/^&.$/*]!&-!%:$?-&-$/*%!&!$-$/:]|:%!&-/&+]/*%/<%!&!$!$-*$*%#]!$?$</%&]&.&|%&>/?]|>&#?&**-#$!?](<?.$-*$?*?]:&/*$^$?.&/_]-$.&?%]|&>%/^&.&?%&_]&]$|$-$.<%*]-]<*?]-$-*&]^]_$_</*]-/<.&>&|&#$|&|<*&+]/*?&&-%!&/]+]|%-$<!]-?$+?$%]-&-^]?>&/%,&!]#$|&|%>&#]?*<><$-&+]/*?&&-%!&]$-#$+*&+<|]#?$*$/!$+]/*?%(<%?#&?&.](%|%,&?*]!&&>$/*$!$-*?<%?*&(<-$[&|-]-.]?&|%-.]-#&?&/<.!%&|]>][?&/+]$/<.&&*%*<!$&($?*&$](_$+*%:&|<*&?.]-{|>+%/+_-&!$?^|]%}"
substitutions = {
'&': ' ',
']': ' ',
'$': ' ',
'-': ' ',
'?': ' ',
'*': ' ',
'/': ' ',
'%': ' ',
'!': ' ',
'<': ' ',
'|': ' ',
'.': ' ',
'+': ' ',
'#': ' ',
'>': ' ',
':': ' ',
'^': ' ',
'(': ' ',
'_': ' ',
'[': ' ',
',': ' ',
}
decoded_sequence = ''.join(substitutions.get(char, char) for char in cipher_sequence)
print(decoded_sequence)
Como a mensagem encriptada não é muito longa, as frequências de letras individuais podem não ser muito precisas. Isto confirmou-se quando tentamos decifrar a mensagem puramente com base nas frequências de letras na língua portuguesa, o que devolveu uma mensagem sem sentido.
Explorando mais a mensagem, encontramos uma sequência de caracteres com um comprimento de 14 caracteres que estranhamente se repetia duas vezes: ]?>&/%,&!]#$|&
.
Decidimos que esta sequência podia ser uma palavra importante, ou até uma sequência de palavras, e tentamos decifrar apenas esta sequência mais pequena em vez da mensagem inteira.
Após algumas tentativas, descobrimos que a sequência ]?>&/%,&!]#$|&
decifrava para organizadopela
, o que nos forneceu vários caracteres corretos para a mensagem inteira.
Após esta descoberta, continuamos a decifrar a mensagem letra a letra, utilizando os caracteres descobertos e a frequência de letras na língua portuguesa como guia. O resultado final foi a seguinte mensagem:
oemsemaforosoencontrodenominadosegundafestadosautarcasorganizadopelardpantenaepossivelgracasaoempenhamentodasdiversasentidadesenvolvidasnacontinuidadedestetipodereuniaoamaliagnrolgaprattspedroburmestertrovantehermanjosemariolaginhamariajoaoelesemuitosoutrosestaohojejuntosnumagalapelalutacontraasidanocoliseudosrecreiosashorganizadopelaligaportuguesacontraasidaoespectaculopretendecontribuirparamobilizartodaagentedestruirtabusefalsosmoralismosparanumdialogofrancoenumaatitudeabertaeobjectivalutarmos{lgcincjsaderhloi}
Com a mensagem decifrada, conseguimos encontrar a flag que se situava no fim da mensagem, entre as chavetas {}
:
{lgcincjsaderhloi}
Sendo a chave de decifração final a seguinte:
substitutions = {
'&': 'a',
']': 'o',
'$': 'e',
'-': 's',
'?': 'r',
'*': 't',
'/': 'n',
'%': 'i',
'!': 'd',
'<': 'u',
'|': 'l',
'.': 'm',
'+': 'c',
'#': 'p',
'>': 'g',
':': 'v',
'^': 'h',
'(': 'b',
'_': 'j',
'[': 'f',
',': 'z',
}
Este desafio foi semelhante ao exercício dos SEED Labs, mas com certas diferenças que dificultaram imenso a resolução:
- A mensagem não tinha espaços, o que impossibilitou a análise de bigramas e trigamas.
- A mensagem estava em português, que era diferente do exemplo dos SEED Labs.
- A mensagem era curta, o que tornou as frequências de letras menos precisas.
Contudo, com a ajuda de uma sequência comprida repetida na mensagem, conseguimos decifrar a mensagem com sucesso e obter a flag.