CTF Starter Pack
Um guia inicial para competições Capture The Flag
- Introdução
- Como identificar uma flag?
- Criptografia
- O que é criptografia?
- Cifra de César
- Cifras de Substituição Simples
- Cifra de Vigenère
- One-Time Pad
- Cifras de Transposição
- Códigos
- Esteganografia
- Cifra de Bacon
- Interpretar imagem como texto
- LSB: Least Significant Bits
- Imagem em áudio
- O que é esteganografia?
- Sites para treinar
Introdução
Este guia destina-se a entusiastas de segurança da informação e que desejam participar de CTFs.
O que são CTFs?
CTF significa Capture the Flag. No contexto de segurança da informação, são competições que envolvem diversas áreas como descoberta de vulnerabilidades, técnicas de espionagem e criação de exploits e ferramentas.
De maneira geral, nessas competições os jogadores são apresentados a problemas, programas com falhas de segurança ou sistemas para serem invadidos. Em cada problema, programa ou sistema, há uma chave secreta ou "flag". Encontrar essa flag é a prova que você resolveu o desafio e enviando no campo especificado faz seu time ganhar pontos.
Tipos de CTFs
Os CTFs são divididos em dois tipos:
Attack-defense
Todos os times recebem uma Máquina Virtual com algumas falhas de segurança. O objetivo é capturar as flags através das vulnerabilidades dos outros times e protegendo seu próprio time de invasões corrigindo suas falhas de segurança.
Jeopardy-sytle
Todos são apresentados a questões de diversas categorias, níveis de dificuldades e pontuações, também chamadas de challenges. As categorias variam de competição para competição, as principais são
-
Crypto: Envolvem problemas relacionados a criptografia.
-
Stegano: Esteganografia é a arte de esconder em plena vista e que envolve basicamente mensagens escondidas em outras mensagens.
-
Forensics: É uma área ampla que pode incluir análise de formato de arquivos, memory dumps e pacotes e até esteganografia.
-
Reversing: São desafios de engenharia reversa. Envolvem encontrar vulnerabilidades de algum programa que você não possui o código.
-
Web Hacking: Envolvem atacar vulnerabilidades comuns no ramo de tecnologia web.
-
Programming: Testam sua habilidade de criar scripts.
-
Miscellaneous: Problemas variados e normalmente com baixa pontuação.
Quando ocorrem os CTFs?
Esses eventos ocorrem em vários perídos e lugares, sendo organizados por pessoas diferentes. Alguns podem acontecer remotamente (on-line) ou presencialmente (on-site).
Uma ótima plataforma para acompanhar as datas das principais competições é o CTFtime.
Como se preparar para CTFs?
O melhor jeito de se preparar para essas competições é praticando.
Abaixo está uma lista de alguns sites com ótimo conteúdo para treinar.
Para auxiliar esse processo, este guia pretende abordar alguns conceitos básicos para resolver esses desafios de forma didática e rápida.
E ainda, uma ótima forma de treinar é observar resoluções (ou write-ups) de desafios que você não conseguiu ou quer ver outra resolução dele.
Onde treinar?
Alguns dos sites abaixo serão usados como exercício para este guia.
WeChall
Plataforma com desafios de diversas áreas e dificuldades.
OverTheWire
Site com diversos wargames onde é necessário conectar no respectivo servidor por meio do terminal. O desafio Bandit é muito recomendado para aprender comandos de Linux.
picoCTF 2018
A edição 2018 de uma competição muito famosa e voltada para estudantes. Apresenta ótimos desafios introdutórios e de diversas áreas.
Hack The Box
Plataforma voltada para invasão de máquinas, simula cenários reais de pentest. Possui também alguns desafios de várias áreas, como os outros, e é preciso "hackear" o site para conseguir o login.
Referências
Como identificar uma flag?
Todo challenge de um CTF costumar ter pelo menos uma chave-secreta como reposta, normalmente chamada de flag.
O formato de como essa flag é apresentada varia de competição para competição. Muitas vezes é uma string bem distintiva, de forma que, quando você ver uma, saberá que é uma flag. Além disso, a competição costuma explicitar o formato de flag que deverá ser enviado.
Por exemplo, flags podem estar explícitas como
flag{M4C4L191Jd912}
Assim, a flag é flag{M4C4L191Jd912}
ou M4C4L191Jd912
, dependendo da competição.
Elas podem ser indicadas por uma frase como
The answer is ABidaBBeBelaB
Assim, a flag é ABidaBBeBelaB
.
Ou apenas um sentença compreensível como
ther5s_n0_Place_l1ke_h0m3
Assim, a flag é a própria sentença ther5s_n0_Place_l1ke_h0m3
.
Mesmo assim, podem existir várias outras formatações diferentes para uma flag, como um link ou uma expressão matemática. Mas essas apresentadas serão as mais comuns.
Exercícios
Criptografia
Aprenda as técnicas de criptografia e como abordá-las em CTFs. Desde a criptografia clássica das cifras até a criptografia moderna das chaves públicas.
O que é criptografia?
Criptografia vem do grego kryptós e graphein, que significam "secreta" e "escrita", respectivamente. Até a era moderna, ela era sinônimo de encriptação, que é a conversão de uma mensagem legível para algo aparentemente sem sentido, e é esse o conceito usado em CTFs.
Para entender melhor essa ideia, digamos que Alice quer mandar uma mensagem para Bob sem que uma terceira pessoa, digamos Eve, descubra seu counteúdo.
Para isso, Alice usa um certo algoritmo para tornar a mensagem ilegível de forma que só Bob saberá reverter a mensagem encriptada.
Assim, quando Eve interceptar a mensagem por meio do canal inseguro, se ela não possui o algoritmo criptográfico usado por Alice e Bob, ela não será capaz de entender a mensagem.
Ao longo da história, várias técnicas de ocultar mensagens foram desenvolvidas. Antes da criptografia pré-computacional, a criptografia clássica era formada por um conjunto de métodos de substituição e transpoisção de caracteres. E com o advento da computação, a criptografia moderna se tornou amplamente embasada em teorias matemáticas e práticas de ciência da computação.
Para esse guia, começaremos com os métodos da criptografia clássica.
Cifra de César
A Cifra de César é um dos métodos mais simples e comuns de encriptação. Mesmo não sendo muito comum em CTFs, ainda é um conhecimento básico de criptografia.
Esse método tem esse nome pois era usado por Júlio César em suas correspondências
Nessa cifra, cada letra da mensagem é substituida por uma letra do alfabeto deslocado por um número fixo.
Por exemplo, se queremos encriptar a mensagem hack the planet
, podemos deslocar cada letra do alfabeto 3 vezes para direita (ou right 3). Assim, a substituição teria esse formato:
original | A | B | C | D | E | F | G | H | I | J | K | L | M |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
right 3 | D | E | F | G | H | I | J | K | L | M | N | O | P |
original | N | O | P | Q | R | S | T | U | V | W | X | Y | Z |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
right 3 | Q | R | S | T | U | V | W | X | Y | Z | A | B | C |
texto original: hack the planet
texto cifrado: kdfn wkh sodqhw
Dessa forma, o texto gerado se torna incompreensível de forma que só quem sabe o algoritmo usado poderá recuperá-lo.
ROT13
Um dos tipos mais comuns de Cifra de César é o ROT13. Nele, o alfabeto é deslocado 13 vezes. Como o alfabeto tradicional possui 26 letras, o ROT13 possui a propriedade de que o mesmo algoritmo usado para encripitar a mensagem é usado para decriptar.
Detectando
Mensagens encriptadas pela cifra de césar normalmente produzirão um amontoado de caracteres sem significado, como kdfn wkh sodqhw
, e suas letras terão uma distribuição de frequência similar à língua usada (provavelmente inglês), mas com as letras trocadas. Esse conceito será abordado com mais profundidade em Cifras de Substituição.
Devido a facilidade de quebrar essa cifra, pode ser conveniente tentar solucioná-la sem nem ao menos uma análise de frequência.
Solucionando
Como num alfabeto usual são usados apenas 26 caracteres, a Cifra de César possui apenas 25 tipos de rotações possíveis (pois a rotação 26 é a própria mensagem). Assim, um testa tudo, onde você faz todos os tipos de rotações possíveis, é a opção mais simples.
Existem ferramentas online muito eficientes para quebrar uma Cifra de César, como o site dcode, porém não é muito difícil codificar um testa tudo para isso.
Codificando um testa tudo
Primeiro, codificaremos uma função rot()
que aplica a rotação em um caractere, de acordo com o deslocamento determinado (o shift
):
def rot(char, shift):
return chr((ord(char) - ord('A') + shift)%26 + ord('A'))
Assim, podemos usar essa função para criar um caesar_brute_force()
que recebe um texto cifrado e imprime todas as rotações possíveis.
def caesar_brute_force(cipher_text):
cipher_text = cipher_text.upper()
for i in range(26):
line = ''
for c in cipher_text:
line += rot(c, i) if c.isalpha() else c
print(f'rot{i}:\t{line}')
Exercícios
Cifras de Substituição Simples
Agora que você está familiarizado com a Cifra de César, vamos apresentar uma generalização desse conceito: as cifras de substituição simples.
Em uma cifra de substituição simples, cada letra é substituida individualmente de acordo com um alfabeto de substituição. Esse alfabeto pode ser uma rotação fixa do alfabeto normal (como a cifra de César) ou algum embaralhamento mais complexo.
Alguns exemplos notáveis de cifra de substituição simples são:
Cifra de Atbash
Seu nome tem origem da primeira, última, segunda e penúltima letra Hebraica (Aleph-Taw-Bet-Shin)
Nessa cifra, cada letra é mapeada para o alfabeto invertido, ou seja, a primeira vira a última, a segunda vira a penúltima e assim por diante.
original: A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
cifra: Z Y X W V U T S R Q P O N M L K J I H G F E D C B A
Assim, se usarmos essa cifra em may the force be with you
, obteremos:
original: M A Y T H E F O R C E B E W I T H Y O U
cifrado: N Z B G S V U L I X V Y V D R G S B L F
A Cifra de Atbash pode ser interpretada como um caso particular da Cifra de Affine, uma cifra que usa aritimética modular para encriptar.
Cifra da Palavra-Chave
A Cifra da Palavra-Chave ou keyword cipher consiste em escolher uma chave e usá-la para decidir como as letras serão susbtituidas.
As palavras repetidas dessa chave serão removidas e a própria chave será o começo do alfabeto a ser mapeado. O resto das letras continuarão em ordem alfabética, tirando as letras já usadas.
Por exemplo, escolhendo a chave Marvin
, o novo alfabeto terá esse formato
original: A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
cifra: M A R V I N B C D E F G H J K L O P Q S T U W X Y Z
Assim, ao encriptar a mensagem Arthur Dent
, obteremos:
original: A R T H U R D E N T
cifrado: M P S C T P V I J S
Detectando
Como mencionado na seção de Cifra de César, uma mensagem encriptada por uma cifra de substituição simples terá uma distribuição de frequência das letras semelhante ao da língua usada, mas com as letras trocadas.
Essa distribuição de frequência de um texto pode ser identificada através de uma análise de frequência.
Nas línguas naturais, algumas letras aparecem mais frequentemente que outras, como uma espécie de digital do idioma. Por exemplo, a letra mais comum na lígua inglesa é o "e", em português é o "a".
Essa análise de frequência pode ser feita simplesmente contando as letras do texto. Existem ferramentas online para isso como o site dcode ou pode ser feito rapidamente com um biblioteca em Python, onde text
é o texto a ser analisado:
from collections import Counter
Counter(text.upper()).most_common()
Solucionando
O ponto fraco de cifras de substituição simples é que elas são muito suscetíveis à análises de frequência.
Assim, se você tiver um texto de tamanho razoável, por volta de 50 caracteres, é possível analisar a frequência com que as letras aparecem e deduzir qual foi o alfabeto de substituição usado.
O site guaballa é um excelente decodificador de cifras de substituição simples.
Referências
Cifra de Atbash: Jeremiah's Game
Cifra da Palavra-Chave: GeeksforGeeks
Exercícios
Cifra de Vigenère
Devido à vulnerabilidade das cifras de substituição simples, foi necessário a criação de uma cifra que conseguisse se proteger disso. A Cifra de Vigenère veio com esse propóstio e é basicamente uma extensão da fórmula da Cifra de César. Ela gera uma distribuição praticamente uniforme em uma análise de frequência e foi considerada inquebrável por 3 séculos.
Ela tem esse nome em homenagem a Blaise de Vigenère
Essa Cifra consiste basicamente em pegar uma palavra-chave e aplicar a cifra de César várias vezes, de acordo com os caracteres da palavra-chave.
Por exemplo, se nós queremos encriptar a mensagem the cake is a lie
usando a palavra-chave portal
, primeiro cada caractere da palavra-chave terá um número de rotações equivalente (de acordo com sua posição no alfabeto):
letra | P | O | R | T | A | L |
---|---|---|---|---|---|---|
rotações | 16 | 15 | 18 | 20 | 1 | 12 |
Assim, para cada letra da mensagem será rotacionada de acordo com a sequência de rotações acima:
mensagem: T H E C A K E I S A L I E
chave: P O R T A L P O R T A L P
mensagem cifrada: I V V V A V T W J T L T T
Essa cifra, diferentemente das cifras de substituição simples, é uma Cifra de Substituição Polialfabética.
Detectando
Um texto encriptado por essa cifra pode ser detectado através de uma análise de frequência.
A Cifra de Vigenère costuma gerar textos com uma distribuição de frequência das letras próximo ao uniforme. Se um texto cifrado que não é esperado esse tipo de distribuição obter esse resultado, provavelmente é Cifra de Vigenère, ou alguma outra Cifra Polialfabética.
Solucinando
Mesmo gerando uma distribuição uniforme em análises de frequência, essa cifra tem uma vulnerabilidade: a palavra-chave é usada várias vezes em um texto grande.
Dessa forma, se a chave tiver tamanho 5, por exemplo, e ajustarmos o texto em linhas de comprimento 5, cada coluna terá a mesma rotação. Assim, podemos chutar tamanhos da palavra-chave e usar a mesma análise de cifra de substituição simples para cada coluna.
Uma ferramenta online muito útill para quebrar a Cifra de Vigenère é o site dcode.
Referências
Exercícios
One-Time Pad
Por muitos anos, o problema de esconder os padrões da língua ainda persistia, porém no final do século XIX surgiu aquele que seria o método mais forte de criptografia: o one-time pad.
Funcionamento
Primeiro, precisamos gerar uma sequência aleatória de bits do mesmo tamanho da mensagem, essa será o one-time pad. Essa chave deverá ser passada por um meio seguro para o destinatário.
Para esse exemplo, usaremos codificação em base64 para os caracteres.
mensagem: H O P E
one-time pad: y T 2 5
Depois, vamos criar o texto cifrado a partir da mensagem e do one-time pad. Para isso, codificaremos a mensagem e o one-time pad em binário e realizamos a operação de ou exclusivo bit a bit, ou XOR.
A operação XOR de dois bits retorna 1, se eles forem diferentes, e 0, se forem iguais.
mensagem: H O P E -> 000111 001110 001111 000100
one-time pad: y T 2 5 -> 110010 010011 110110 111001
|
XOR |
V
texto cifrado: 1 d 5 9 -> 110101 011101 111001 111101
Já para recuperar a mensagem, usamos exatamente a mesma operação, realizando um XOR bit a bit com o texto cifrado e o one-time pad.
Após um uso, o one-time pad deverá ser destruído.
A criptografia perfeita
No final da década de 1940, Claude Shannon provou que se cada chave for usada uma única vez e ela for gerada aleatoriamente, então o método de one-time pad é perfeitamente seguro.
Isso pode ser visualizado pelo seguinte exemplo: digamos que temos uma mensagem de 24 bits, logo temos 2^24 possíveis valores para a chave. A partir disso, temos dois problemas:
Poderíamos tentar verificar todas as chaves. Para uma mensagem de 24 bits, ainda é uma alternativa viável, mas de expandirmos para 54, mesmo se checando 1 milhão de valores por segundo, ainda levaríamos mais de 570 anos para checar todas as possibilidades.
Outro problema é que cada possível chave gera uma possível mensagem com igual probabilidade das demais, assim se checarmos todas as chaves, veríamos todas as combinações possíveis de mensagens de 24 bits.
chave | possível mensagem |
---|---|
A A A A | 1 d 5 9 |
A A A B | 1 d 5 8 |
... | ... |
+ J z 5 | L U K E |
... | ... |
y T 2 5 | H O P E |
... | ... |
Dessa forma, não há como distinguir a mensagem real de todas as outras possibilidades.
Entetanto, mesmo a técnica de One-time pad sendo simples e teoricamente inquebrável, na prática ela possui alguns pontos negativos, que costumam trazer suas vulnerabilidades:
-
A chave precisa ser usada uma única vez. Se repetida, ela pode ser facilmente quebrada. Essa era a principal vulnerabilidade de uma cifra semelhante, a Cifra de Vernam.
-
Ainda é preciso de um canal seguro para distribuir as chaves.
-
Conseguir bits realmente aleatórios é bem difícil. O exército dos Estados Unidos conseguiu decifrar, em 1944, as mensagens alemãs cifradas por one-time pad porque as chaves não eram completamente aleatórias.
-
A chave precisa ser tão longa quanto a mensagem. Isso implica numa grande dificuldade de gerar e armazenar chaves para mensagens longas.
Esses dois últimos pontos, especialmente, acabam tornando o one-time pad teórico impraticável.
Linear Feedback Shift Register
Como alternativa às longas sequências de bits realmente aleatórias, foi criado um algoritmo determinístico capaz de produzir valores pseudo-aleatórios: o linear feedback shift register ou LFSR.
Valores pseudo-aleatórios são sequências de bits que parecem ser aleatórias. Elas não são aleatórias de fato, pois são criadas por algoritmos determinísticos, mas, para efeitos práticos, tem as mesmas propriedades de sequências aleatórias.
Esses valores pseudo-aleatórios são criados da seguinte maneira:
Primeiro, precisamos de uma sequência de bits inicial, chamada de seed. Essa seed dará o tamanho do registrador, que é um elemento que armazena todos os bits necessários para gerar o próximo.
Depois, geraremos uma nova sequência através da operação XOR de dois bits, colocando os bits resultantes à direita.
Por exemplo, a imagem acima representa o registrador com a seed. Nela, os bits 11 e 9 foram escolhidos para gerar o próximo. Essas posições são chamadas de tap, ela é uma numeração que começa do 1, indo da direita para esquerda.
Para descrever essas posições do algoritmo, usamos a notação [N, k] LFSR
, que representa um algoritmo de LFSR com um registrador de N
bits com taps em N
e k
. Na imagem acima, temos um [11,9] LFSR
.
Abaixo, está uma pequena simulação de um [5,4] LFSR
com a seed 00001
.
[5,4] LFSR
novo bit
V
seed -> 00001 0
00010 0
00100 0
01000 1
10001 1
00011 0
00110 0
01100 1
11001 0
10010 1
00101 0
^
registrador
Assim, precisamos apenas criar uma lista de pequenas seeds e distribuí-las por um canal seguro, usando elas para criar chaves do one-time pad, por meio do LFSR.
Exercícios
Referências
Computer Science - Sedgewick & Wayne
Mensagens alemãs não aleatórias
Cifras de Transposição
Na tentativa de encontrar um método alternativo às cifras de substituição simples, que estavam se tornando frágeis, foram criadas as Cifras de Transposição. Nessa cifra, o texto permanece o mesmo mas as ordem dos caracteres são alteradas, embaralhando a mensagem de acordo com um padrão.
Existem vários padrões diferentes para realizar a transposição, os dois mais famosos são a transposição colunar simples e a rail fence.
Transposição colunar
Com essa regra, a mensagem é escrita horizontalmente numa matriz de largura fixa e a saída é o texto lido verticalmente nessa matriz.
Numa transposição colunar simples essa leitura é feita por colunas da esquerda para direita. Por exemplo, com texto a wizard is never late
a encriptação será da forma
Texto: A WIZARD IS NEVER LATE
Matriz:
A W I Z A R
D I S N E V
E R L A T E
Texto cifrado: ADEWIRISLZNAAETRVE
Para decriptar, escrevemos o texto cifrado verticalmente numa matriz de mesma largura e lemos o texto horizontalmente.
A ordem de leitura de colunas pode ser determinada também de acordo com uma palvra-chave. O tamanho da palavra-chave definirá a largura da matriz usada e cada caractere determina a ordem que as colunas serão lidas. Por exemplo, usando a chave FRODO
, numeramos as letras em ordem alfabética: 25314
. Assim, podemos usar essa ordem para ler as colunas e gerar o texto cifrado
Texto: A WIZARD IS NEVER LATE
Ordem: 2 5 3 1 4
Matriz: A W I Z A
R D I S N
E V E R L
A T E
Texto cifrado: ZSRAREAIIEEANLWDVT
Rail Fence
Nesse tipo de transposição, os caracteres são escritos numa matriz usando um padrão fixo em zigue-zague e a saída é o texto lido horizontalmente. o rail fence admite várias variações, como a linha que a primeira letra começa e o número de linhas usadas. Por exemplo, usando um rail fence com duas linhas
Texto: A WIZARD IS NEVER LATE
Matriz:
A - I - A - D - S - E - E - L - T -
- W - Z - R - I - N - V - R - A - E
Texto ciffrado: AIADSEELTWZRINVRAE
Outro exemplo mas com três linhas será da forma
Texto: A WIZARD IS NEVER LATE
Matriz:
A - - - A - - - S - - - E - - - T -
- W - Z - R - I - N - V - R - A - E
- - I - - - D - - - E - - - L - - -
Texto ciffrado: AASETWZRINVRAEIDEL
Para descriptografar, é necessário o conhecimento do padrão usado e preencher as lacunas com o texto cifrado horizontalmente e depois ler em zigue-zague.
Essa técnica foi usada na Guerra Civil norte-americana para cifrar as mensagens dos confederados e dos federalistas.
Identificando
Como apenas a ordem do texto é alterada, a distribuição de frequência das letras será muito parecida com a frequência da língua usada. Assim, uma análise de frequência do texto cifrado é um ótimo método para identificar o uso de uma cifra de transposição.
Além disso, podem ter sido usadas cifras de substituição em conjunto, dificultando a indentificação.
Solucionando
Um primeiro método que podemos pensar para quebrar cifras de transposição é testar todas as possíveis permutações dos caracteres. Porém, um texto de 20
caracteres geraria 20!
possíveis permutações. Se computássemos 100 milhões de valores por segundo, demoraríamos mais de 300 anos para computar todos. Logo, testar todas as possibilidades é inviável.
Como existem vários métodos diferentes de cifras de transposição, cada um necessita de uma abordagem diferente.
Nesses dois posts no StackExchange: [1] e [2], Ilmari Karonen mostra métodos para resolver manualmente cifras de transposição colunar.
Referências
Applied Cryptography, second edition
Exercícios
Códigos
Aprenda várias formas de representar dados no computador e suas aplicações em CTFs.
Dados e códigos
Nos computadores, todos os dados são guardados da mesma forma: em código binário. Esse código é como uma sequência de '0's e '1's, e essas sequências são agrupadas e sofrem modificações para representar tudo o que vemos em um computador.
Mas se tudo são apenas zeros e uns, o que diferencia um texto de uma música? A diferença é o modo como esses dados são representados.
Para cada tipo de dado existe uma codificação diferente aplicada a ela, e por isso um mesmo dado pode ter várias interpretações dependendo da codificação que você trabalha.
Um exemplo de uma representação de um valor binário é como um número.
Um número em binário pode ser convertido para um número em decimal. Por exemplo, 00101010
é o número 42
em decimal.
Uma representação mais comum para um código binário é a base hexadecimal, que tem a vantagem de que cada casa pode representar uma sequência de 4 bits. Por exemplo, o mesmo número 00101010
é 2A
em hexadecimal (0010 = 2 e 1010 = A).
Nas próximas seções, você verá outras formas de representar os dados no computador.
Código ASCII
Nessa seção, vamos apresentar uma das codificações mas famosas para representar texto em um computador: o ASCII.
O nome ASCII vem do inglês American Standard Code for Information Interchange que significa "Código Padrão Americano para o Intercâmbio de Informação"
O ASCII, originalmente baseado no inglês, codifica 128 caracteres específicos com 7 bits. Como um computador normalmente trabalha na escala de bytes (8 bits), o ASCII é mais frequentemente encontrado numa representação de 8 bits.
A tabela abaixo mostra todos os caracteres do código ASCII.
Você pode usar essa tabela para decodificar uma sequência de números em binário, decimal ou hexadecimal para ASCII.
ASCII em Python
Uma maneira mais fácil de manipular a codificação ASCII, em vez de usar manualmente uma tabela, é por meio de códigos. Em Python, usamos as funções ord()
e chr()
para isso.
A função ord()
recebe uma string de tamanho 1 e retorna um inteiro que representa o código da letra, se ela for ASCII, devolverá seu código ASCII. Por exemplo, ord('a')
devolverá 97
.
Já a função chr()
é o inverso da anterior. Ela recebe um inteiro e devolve o caractere com o respectivo código ASCII. Por exemplo, chr(97)
devolverá 'a'
.
Exercícios
Referências
Base64
Agora que você já teve contato com o código ASCII, vamos conhecer o Base64, um método para codificar e decodificar dados binários em caracteres ASCII.
Esse método é utilizado frequentemente para transferir dados em meios que só suportam formatos ASCII, por exemplo, enviar anexos por e-mail (que usa o MIME).
O nome base64 origina-se do fato de que esse sistema é constituido de 64 caracteres, representando exatamente 6 bits de dados. Com isso, três bytes de 8 bits podem ser representados por 4 digitos de 6 bits em Base64.
A tabela abaixo mostra a equivalência entre os valores de um conjunto de 6 bits e os caracteres usados para codificação.
Quando os bits da mensagem original não são multiplos de 6, são adicionados zeros como padding. Assim, na mensagem codificada é colocado um =
para cada dois zeros de padding. Aliás, esse =
é uma forma bem comum de reconhecer um texto codificado em Base64.
Abaixo está um exemplo de um texto codificado em Base64:
texto: M | a | n
8 bits: 0 1 0 0 1 1 0 1 | 0 1 1 0 0 0 0 1 | 0 1 1 0 1 1 1 0
6 bits: 0 1 0 0 1 1 | 0 1 0 1 1 0 | 0 0 0 1 0 1 | 1 0 1 1 1 0
Valor: 19 | 22 | 5 | 46
texto: T | W | F | u
(Base64)
E se tirarmos o n
, a codificação vai necessitar de um padding:
texto: M | a |
8 bits: 0 1 0 0 1 1 0 1 | 0 1 1 0 0 0 0 1 |
6 bits: 0 1 0 0 1 1 | 0 1 0 1 1 0 | 0 0 0 1 0 0 | 0 0 0 0 0 0
Valor: 19 | 22 | 5 | (padding)
texto: T | W | E | =
(Base64)
Ferramentas
Para manipular textos em Base64, pode-se usar o comando Unix base64
.
Por exemplo, se tivermos uma arquivo sagan.txt
com o texto The Cosmos is all that is or ever was or ever will be
. Podemos convertê-lo para um arquivo sagan64.txt
com o comando
base64 sagan.txt > sagan64.txt
O resultado será o arquivo sagan64.txt
com o texto VGhlIENvc21vcyBpcyBhbGwgdGhhdCBpcyBvciBldmVyIHdhcyBvciBldmVyIHdpbGwgYmUK
.
Agora, para decodificar o arquivo sagan64.txt
, usamos o mesmo comando com a flag -d
:
base64 -d sagan64.txt
Exercícios
Esteganografia
Aprenda como esconder uma mensagem em plena vista e suas aplicações em CTFs
Cifra de Bacon
Nessa seção veremos um primeiro exemplo de Esteganografia: a Cifra de Bacon.
Ela tem esse nome pois foi criada por Francis Bacon em 1605.
A ideia por trás dessa cifra, diferente de uma cifra criptográfica comum, é esconder a mensagem secreta por meio de um texto legível, apenas mudando a grafia de suas letras.
Essa é uma cifra de substituição, e cada letra é representada por um conjunto de 5 caracteres binários ('a' e 'b' ou '0' e '1'). O alfabeto de substituição da Cifra de Bacon possui dois modelos:
- A cifra de 24 letras: É a original. Nela, os pares de caracteres (I,J) e (U,V) não possuem distinção.
A = aaaaa I/J = abaaa R = baaaa
B = aaaab K = abaab S = baaab
C = aaaba L = ababa T = baaba
D = aaabb M = ababb U/V = baabb
E = aabaa N = abbaa W = babaa
F = aabab O = abbab X = babab
G = aabba P = abbba Y = babba
H = aabbb Q = abbbb Z = babbb
- A cifra de 26 letras: A segunda versão da cifra. Agora todas as letras possuem um código único.
A = aaaaa I = abaaa Q = baaaa Y = bbaaa
B = aaaab J = abaab R = baaab Z = bbaab
C = aaaba K = ababa S = baaba
D = aaabb L = ababb T = baabb
E = aabaa M = abbaa U = babaa
F = aabab N = abbab V = babab
G = aabba O = abbba W = babba
H = aabbb P = abbbb X = babbb
Dessa forma, substituímos o 'A' da mensagem secreta por 'aaaaa', um 'B' por 'aaaab' e assim por diante. Por exemplo, digamos que queremos esconder a mensagem fly you fools
. Assim, a substituição das letras será da forma abaixo, usando a cifra de 26 letras:
texto original: F L Y Y O U F O O L S
texto cifrado: aabab ababb bbaaa bbaaa abbba babaa aabab abbba abbba ababb baaba
Com isso, podemos usar esse padrão e esconder em uma mensagem comum de tamanho maior ou igual ao texto cifrado, como
according to all known laws of aviation, there is no way a bee should be able to fly
.
Assim, removendo os espaços e pontuações para facilitar a associação, podemos esconder a mensagem no texto de várias formas, como associar letras maiúsculas ao 'a' e minúsculas ao 'b', associar a letras com ou sem itálico ou até com duas fontes diferentes. Para esse exemplo, usaremos maíusculas e minúsculas.
falsa mensagem: accordingtoallknownlawsofaviationthereisnowayabeeshouldbeabletofly
texto cifrado: aababababbbbaaabbaaaabbbababaaaabababbbaabbbaababbbaaba
mensagem final: acCoRdInGTOAllkNOwnlaWSOfAvIatioNtHeREIsnOWAyaBeESHouLdbeabletofly
Voltando à formatação original da mensagem, temos: acCoRdInG TO All kNOwn laWS Of AvIatioN, tHeRE Is nO WAy a BeE SHouLd be able to fly
. Com isso, quem interceptar essa mensagem esteganográfica, não vai imaginar que ela possui algo além de uma escrita engraçada.
Identificando
Em uma primeira observação, uma mensagem oculta pela cifra de Bacon pode ser identificada pela mudança alternada dos padrões das letras: maíuscula e minúscula, itálico, fonte, ou até a alternância explícita de duas letras.
Outra abordagem, seria uma análise de frequência. Como a cifra de Bacon é um tipo de cifra de substituição, ela é sensível a uma análise de frequência.
Solucionando
Para solucionar desafios que contém Cifra de Bacon, o primeiro passo é identificar o modo como a mensagem foi escondida. Depois disso, é preciso percorrer o texto e transformá-lo em sequências de 'a's e 'b's.
Assim, você pode guardar o alfabeto de substituição com um dicionário e usá-lo para substituir os blocos de 5 caracteres pela letra correspondente.
Por exemplo, podemos implementar isso com um código em Python:
bacon_to_letter_26 = {
'aaaaa':'A', 'aaaab':'B', 'aaaba':'C', 'aaabb':'D', 'aabaa':'E',
'aabab':'F', 'aabba':'G', 'aabbb':'H', 'abaaa':'I', 'abaab':'J',
'ababa':'K', 'ababb':'L', 'abbaa':'M', 'abbab':'N', 'abbba':'O',
'abbbb':'P', 'baaaa':'Q', 'baaab':'R', 'baaba':'S', 'baabb':'T',
'babaa':'U', 'babab':'V', 'babba':'W', 'babbb':'X', 'bbaaa':'Y',
'bbaab':'Z'
}
def format(text, a='a', b='b'):
"""Format a steganographic text to a binary sequence"""
formated_text = ''
for c in text:
if not c.isalpha():
continue
if c.istitle():
formated_text += b
else:
formated_text += a
return formated_text
def decode(text, a='a', b='b', bacon_alpha=bacon_to_letter_26):
"""Decode a encrypted Bacon cipher text"""
cipher = format(text, a=a, b=b)
output = ''
while len(cipher) >= 5:
token, cipher = cipher[:5], cipher[5:]
if token in bacon_alpha:
output += bacon_alpha[token]
else:
break
return output
if __name__ == '__main__':
input = input()
output = decode(input)
print(output)
Exercícios
Referências
Interpretar imagem como texto
Como foi explicado na seção de dados e códigos, qualquer arquivo no computador pode ser interpretado como uma sequência binária, e dessa forma, tem sua representação em texto. Assim, esse recurso pode ser usado para esconder informação numa imagem.
Um recurso comum em CTFs é colocar um trecho de texto puro em alguma região arbitrária da imagem. Por exemplo, se queremos esconder a palavra such cake
na imagem doge.jpg
, podemos usar o comando Linux:
echo "such cake" >> doge.jpg
Com isso, "such cake"
ficará no final dos dados da imagem.
Solucionando
Para extrair a informação escondida por esse método, várias ferramentas podem ser usadas. As duas principais são os comandos de Linux strings
e hexdump
.
O comando strings
imprime basicamente todas as sequências de dados imprimíveis de um arquivo. Por exemplo, o comando aplicado a imagem doge.jpg
strings doge.jpg
Com isso, o final da saída do comando será algo da forma:
Já o comando hexdump
permite que a imagem seja analisada de forma mais minuciosa, onde o formato de leitura e impressão pode ser especificado pelo usuário. Por exemplo, um uso do comando com a imagem doge.jpg
, onde a flag -C
representa a forma canônica de impressão hex+ASCII:
hexdump -C doge.jpg
O final da saída desse comando é algo da forma:
Exercícios
Referências
LSB: Least Significant Bits
Um dos métodos mais comuns e populares nos dias de hoje para se esconder uma mensagem numa imagem é a técnica de LSB ou Least Significant Bits. Esse método consiste em esconder a informação nos bits menos significativos de uma imagem.
Representação da imagem
Como mencionado em Dados e Códigos, todos os arquivos no computador são sequências binárias e com as imagens não é diferente.
Uma imagem é composta, na maioria das vezes, por duas partes. O cabeçalho (ou header) é onde ficam armazenadas as informações sobre a imagem, como o seu formato e dimensões. Já o corpo da imagem é onde ficam armazenados a informação dos seus pixels de fato.
Cada formato tem suas particularidades para representar um pixel, por simplicidade vamos considerar um pixel de 24 bits de uma imagem lossless.
Por exemplo, um pixel com a cor em RGB #ebc700
teria sua representação em binário como 11101011 11000111 00000000
onde
Red | Green | Blue |
---|---|---|
8 bits | 8 bits | 8 bits |
11101011 | 11000111 | 00000000 |
Escondendo na imagem por LSB
Para esconder informação em uma imagem usando o método de LSB, alteraremos os bits menos significativos de cada byte no corpo da imagem.
Por exemplo, se temos uma imagem de três pixels
pixel 1: 11101011 11000111 00000000
pixel 2: 01000010 10000110 11110100
pixel 3: 11110100 01010111 01000010
Se queremos esconder o byte 01100001
, uma nova imagem será gerada com a mensagem nos últimos bits (destacado por * * ).
pixel 1: 1110101*0* 1100011*1* 0000000*1*
pixel 2: 0100001*0* 1000011*0* 1111010*0*
pixel 3: 1111010*0* 0101011*1* 01000010
Dessa forma, ao esconder a mensagem nos bits menos significativos, fazemos apenas uma pequena alteração na imagem. Por exexmplo, o pixel 1
foi da cor #ebc700
para #eac701
.
Assim, vemos que a imagem precisa ser maior que a mensagem que vamos esconder nela. Nessa caso, no mínimo 8 vezes maior. Para contornar esse problema, alguns algoritmos usam 2 ou 3 bits menos significativos de cada byte, aumentando a alteração da imagem.
Para recuperar a mensagem, fazemos o processo inverso: identificando os bits menos significativos no corpo e remontando em bytes.
pixel 1: 1110101*0* 1100011*1* 0000000*1*
pixel 2: 0100001*0* 1000011*0* 1111010*0*
pixel 3: 1111010*0* 0101011*1* 01000010
-> mensagem: 01100001
Ferramentas para LSB
Stéganô
O pacote Stéganô possui várias ferramentas para esteganografia. A maioria sua a técnica de LSB.
Ele necessita de Python 3 e pode ser instalado por
sudo pip3 install Stegano
Uma das ferramentas desse pacote é o comando stegano-lsb
.
Ele pode ser usado para esconder uma mensagem em uma imagem com o argumento hide
, como por exemplo
stegano-lsb hide -i dog.png -o dog_steg.png -m "dont-worry-be-happy"
Já com o comando reveal
, podemos recuperar a mensagem a partir da imagem.
stegano-lsb reveal -i dog_steg.png
Além disso, em vez de modificar os pixels sequncialmente a partir do começo, um outro comando, o stegano-lsb-set
, permite inserir a informação de acordo com outros padrões especificados. Ele recebe um argumento para um gerador, como por exemplo eratosthenes
, que produz os pontos onde os pixels serão modificados.
Assim, é preciso usar o mesmo gerador para esconder e recuperar a mensagem:
stegano-lsb-set hide -i dog.png -o dog_steg2.png -g eratosthenes -m "dont-worry-be-happy"
stegano-lsb-set reveal -i dog_steg2.png -g eratosthenes
zsteg
O zsteg é uma ótima e super simples ferramenta para detectar steganografia em imagem. Ela necessita de Ruby e pode ser instalada por
gem install zsteg
Para detectar uma informação escondida por um LSB simples, pode-se digitar apenas
zsteg dog_steg.png
O resultado será algo como
Informações adicionais
Muitas vezes, a técnica de LSB pode ser usada junto a uma criptografia para proteger ainda mais a mensagem e dificultar sua detecção.
Na vida real, a técnica de LSB pode ser usada como marca d'água digital para detectar cópias de mídias não autorizadas. O programa OpenStego é um ótimo exemplo de software com essa finalidade.
Exercícios
(to-do)
Referências
Imagem em áudio
Mais uma forma interessante de esteganografia é esconder uma imagem em um áudio. Nela, a imagem é transformada em ondas sonoras de forma que ela pode ser vista através de seu espectrograma.
O espectrograma
Um espectrograma é uma forma de visualizar a intensidade de um sinal através do tempo e em várias frequências.
Os espectrogramas são gráficos de duas dimensões (frequência x tempo), com a terceira dimensão, a amplitude, sendo representada pela variação das cores. O tempo é normalmente representado no eixo x em sentido crescente. Já a frequência (medida em Hz) é representada no eixo y, com frequências mais baixas em baixo e mais altas em cima. Por fim, a amplitude (medida em dB) é representada com cores mais escuras para amplitudes menores e cores mais claras para maiores.
Para visualizar o espectrograma de um áudio, pode-se usar o programa sonic visualizer (mais simples) ou audacity (mais robusto).
Escondendo uma imagem em um áudio
Primeiro, precisamos realizar a conversão da imagem para o áudio. Isso pode ser feito utilizando a ferramenta img-encoder, no GitHub.
Por exemplo, se queremos converter a imagem aesthetic.png
No demo online dessa ferramenta, adicionamos a imagem em Open-Image...
, e convertemos com Encode
. Renomearemos o resultado para aesthetic.wav
.
Utilizando o sonic-visualizer
para visualizar o áudio gerado, mudamos a visualização para Add spectrogram
, com o comando Shift+G
.
Agora, precisamos juntar esse áudio em outra música para camuflar a informação. Por exemplo, usaremos a música リサフランク420 現代のコンピュー.mp3
. Abrindo a música com audacity
, importamos o nosso áudio com Ctrl+Shift+i
.
Com a ferramenta Time Shift Tool
, podemos mudar a posição do áudio esteganográfico para o começo ou fim (assim a música vai interferir menos o áudio).
Porém, o áudio esteganográfico ainda pode ser percebido devido a seu ruído. Para diminuir esse efeito, primeiro selecionamos a track do áudio (clicando em uma 'área neutra' do Painel de Controle, na parte esquerda da track) e clicando em Effect
e Amplify
. Assim, podemos mudar a amplitude do som para dificultar sua detecção (algo em torno de -20 dB).
Assim, selecinando todas as tracks e exportando a música gerada para WAV, steg-macintosh-plus.wav
, teremos uma música audível mas com uma imagem escondida em seu espectrograma.
Referências
Selecionando Tracks no Audacity
O que é esteganografia?
Em um primeiro contato com a área, esteganografia provavelmente será o nome que lhe causará mais estranheza. O termo vem do grego steganos, que significa "encoberto, escondido" e graphein, que significa "escrita".
Esteganografia é a técnica de ocultar uma mensagem dentro de outra. Diferentemente da criptografia, onde torna-se a mensagem ilegível, a esteganografia procura esconder o fato de que a mensagem existe em primeiro lugar.
Assim, a falsa mensagem funcionará como uma espécie de cobertura da mensagem real, desviando a atenção de quem estiver buscando a mensagem real. Alguns exemplos poderiam ser o ato de escrever com tinta invisível entre as linhas de uma carta comum ou escrever um texto nos bits de uma imagem sem alterá-la visualmente.
Nas próximas seções, serão abordadas técnicas de esteganografia e suas aplicações em CTFs.
Sites para treinar
Bandit
Link para o site
O Bandit é um wargame para totais iniciantes, focado em programas/comandos de terminal do linux. Ele te ensina o básico para você conseguir progredir e te preparar para outros desafios.
Como funciona
Como a maioria dos jogos do tipo, ele é organizado em níveis. Você começa no nível 0 e tenta completá-lo. Ao terminá-lo, você consegue informações para começar o próximo nível (geralmente a senha do usuário do nível X + 1). Todos os níveis do Bandit têm uma página de explicação (vistas na barra lateral), que embora não estritamente necessárias, contém informações importantes sobre como como prosseguir ao próximo nível, além de comandos sugeridos.
Para poder jogar, tudo que você precisa é de um cliente de SSH.
Conecte-se em bandit.labs.overthewire.org
na porta 2220
.
É bem possível (e provável) que você encontre alguma situação em que você fique preso. Não se preocupe e não desista! O objetivo do jogo é te ensinar o básico, e para aprender, muitas vezes é preciso pesquisar. É muito importante saber usar eficientemente uma ferramenta de pesquisa como o Google ou o DuckDuckGo.
Tem muitas coisas que você pode tentar quando não souber exatamente como continuar:
Primeiro, se você sabe de algum comando (e no Bandit você sempre sabe quais comandos são necessários, porque eles estão na página do nível) mas não sabe usá-lo, você pode consultar o manual dele, utilizando o comando man <comando>
. Por exemplo, se quiser saber como funciona o comando find
, basta executar man find
. Aliás, o próprio comando man tem um manual, então se você quiser ler um manual sobre o manual, só executar man man
.
Se o comando não tiver uma página no manual, ele pode ser built-in do shell, então nesse caso você pode executar help <comando>
para ver uma página de ajuda resumida.
Mas se nada der certo, você pode sempre pedir ajuda, seja no nosso Discord, Telegram, ou qualquer outro meio.
Divirta-se!