Skip to content

Latest commit

 

History

History
167 lines (126 loc) · 7.06 KB

CTF10.md

File metadata and controls

167 lines (126 loc) · 7.06 KB

Classical Cipher

O objetivo desta atividade foi decifrar uma mensagem que foi encriptada utilizando uma cifra clássica.

Material Fornecido

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.

Recolha de Dados Para a Resolução

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:

Frequência de letras 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.

Processo de Resolução

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',
}

Conclusão

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.