Outro dia, encontrei um programa que me permitia selecionar entre um conjunto pré-definido de consultas e, em seguida, comunicava-se com um servidor para recuperar a resposta à consulta selecionada. Comecei a me perguntar quando percebi que o programa nunca solicitava uma senha para autenticação com o servidor. Acontece que a senha estava incorporada ao programa. O autor explicou que isso era aceitável porque 1) era um arquivo binário, então ninguém poderia lê-lo e 2) se pudessem lê-lo, não seriam capazes de encontrar a sequência de caracteres da senha.
Nenhuma dessas razões é válida e gostaria de usar esta publicação para demonstrar isso. Meu programa de exemplo apenas escreve a “senha” no terminal, mas a única diferença entre ele e um programa de produção real é o número de strings que um usuário mal-intencionado teria que pesquisar.
#include <stdio.h>
#include <string.h>
main ()
{
char password [9] = {"secret"};
printf ("This is the password: %sn", password);
}
|
| Figura 1 – Programa básico com senha incorporada |
Quando executado, exibe
x1 Esta é a senha: secret pronto 14:12:16 |
| Figura 2 – Execução do programa básico |
Para exibir as strings no módulo do programa, nosso usuário mal-intencionado pode usar o comando strings do diretório >system>gnu_library>bin. O -n5 limita a saída a strings de 5 caracteres ou mais. Eu trunquei a saída (. . . .) para encurtar a exibição, mas você pode ver que a senha é uma das primeiras strings exibidas. Ter a senha próxima a palavras-chave como “login” ou “password” ou a um ID de usuário identificável como “admin”, “root” ou “sql” facilita a pesquisa.
>system>gnu_library>bin>strings -n5 x1.pm
bind, Release 17.1.beta.be
phx_vos#
Noah_Davids.CAC
Pré-lançamento
Esta é a senha: %s
secret
s$start_c_program
_preemption_cleanup
_exit.
. . . .
|
| Figura 3 – Usando o comando strings do GNU para encontrar todas as strings com mais de 4 caracteres no módulo do programa |
Se o comando strings não estiver disponível, nosso usuário mal-intencionado pode simplesmente exibir o módulo do programa. Suspeito que todos nós já fizemos isso acidentalmente e, embora não seja muito elegante, ele exibirá a senha. Mais uma vez, trunquei a saída e, novamente, você pode ver a senha.
d x1.pm
%phx_vos#m16_mas>SysAdmin>Noah_Davids>x1.pm 11-01-13 14:13:59 mst
`00`01`00`1Abind, Release 17.1.beta.be`00`00`00`00`00`00`00`04ctp
`00`00`00`00`0
+`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`0
0phx_vos
+#`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`
00`00Noa.
. . .
+`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`C
D'`8B`C0
+`00`00`00`00Esta é a senha: %s
`00`00`00`00`00`00`00secret`00`00`00`00`00`00`00`04`B0`00`00`00`00`01`00
`00`00,`
+`00`00`04`00`00`00`03@`00`FF`F8`FF`FE`00`04main`00`00`83`EC`2C`C7D$$`00.
. . .
|
| Figura 4 – Exibindo o módulo do programa para encontrar a senha |
Existem várias alternativas para incorporar a senha no programa.
A senha pode ser colocada em um arquivo e o programa pode ler o arquivo. Somente as pessoas com “necessidade de execução” recebem acesso de leitura ao arquivo e todos os outros recebem acesso nulo. É claro que “necessidade de execução” pode não ser equivalente a “necessidade de saber a senha”. Além disso, sempre existe o risco de alguém alterar o acesso por engano.
Uma alternativa é manter a sequência de caracteres da senha no programa e apenas limitar o acesso ao programa. Essa solução também sofre com o problema de “ser fácil alterar uma lista de acesso”. Se o programa for mantido no mesmo diretório que outros programas que podem ser executados por qualquer pessoa, a probabilidade de uma alteração na lista de acesso aumenta.
Por fim, você pode manter a senha no módulo do programa, mas ofuscar a string de alguma forma. O programa a seguir mostra uma maneira simples de fazer isso.
#include <stdio.h>
#include <string.h>
main ()
{
char obfuscate [9] = {0x0c, 0x81, 0xe2, 0x94, 0xe6, 0x9c};
char key [9] = {127, 228, 129, 230, 131, 232, 133, 234, 135};
char password [9];
int i;
for (i = 0; i < strlen (obfuscate); i++)
password [i] = obfuscate [i] ^ key [i];
password [i] = 0x0;
printf ("This is the password: %sn", password);
}
|
| Figura 5 – Programa com sequência de senha ofuscada |
Como você pode ver, tudo o que ele faz é pegar os caracteres ofuscados e aplicá-los a XOR com outro conjunto de caracteres-chave para criar a senha. A execução do programa produz o mesmo resultado que o primeiro programa.
x2 Esta é a senha: secret pronto 14:12:51 |
| Figura 6 – Execução do programa ofuscado |
Mas uma pesquisa por sequências de caracteres não mostra nada que se pareça com a senha.
>sistema>gnu_library>bin>strings -n5 x1.pm bind, Versão 17.1.beta.be phx_vos# Noah_Davids.CAC Pré-lançamento Esta é a senha: %s s$start_c_program _preemption_cleanup _exit. . . . |
| Figura 7 – O comando strings não mostra mais a senha |
E, embora a exibição do arquivo mostre os caracteres ofuscados da senha e os caracteres-chave, você precisa saber exatamente onde procurar para encontrá-los e também como eles são combinados para criar a senha.
d x2.pm
%phx_vos#m16_mas>SysAdmin>Noah_Davids>x2.pm 11-01-13 14:15:27 mst
. . . .
+`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`00`CD'`8B`
C0`00`0
+0`00`00Esta é a senha: %s
`00`00`00`00`00`00`00`0C`81`E2`94`E6`9C`00`00`00`00`00`00`00`00`00`00`7F
`E4`81`
+E6`83`E8`85`EA`87`00`00`00`00`04`B0`00`00`00`00`01`00`00`00`00`00`00`0
4`01`B0
+`00`03@`00`FF`F0`00`08`FF`FE`00`04main`00`00`83`EC`89$X`89t$T`89|$P`C
7D$L`00
|
| Figura 8 – A exibição do módulo do programa não mostra mais a senha reconhecível |
Esta ainda não é uma solução perfeita, pois o módulo do programa pode ser desmontado para descobrir como a senha é gerada. No entanto, desmontar o programa requer muito mais sofisticação do que apenas exibir o módulo do programa.
Tenho dúvidas sobre colocar a sequência de caracteres ofuscada da senha em um arquivo e, em seguida, proteger o arquivo por meio de uma lista de acesso. Por um lado, se a senha precisar ser alterada, essa é uma solução muito melhor do que incorporar a sequência de caracteres ofuscada da senha no programa. Por outro lado, suspeito que, mesmo que haja outras opções de configuração no arquivo, colocar a sequência de caracteres no arquivo dará ao nosso usuário mal-intencionado menos sequências de caracteres potenciais da senha para investigar. É claro que ele ainda precisará obter acesso ao arquivo e, em seguida, descobrir a técnica de ofuscação e a chave.
Um último ponto: como gerei os caracteres ofuscados da senha? O bom da operação XOR é que ((A XOR B) XOR B) é igual a A, então apenas escrevi um pequeno programa para pegar a senha original, fazer o XOR dos caracteres com minha chave e imprimir o resultado.
#include <stdio.h>
#include <string.h>
main ()
{
char password [9];
char key [9] = {127, 228, 129, 230, 131, 232, 133, 234, 135};
char newPW [9];
int i;
strcpy (password, "secret");
for (i = 0; i < strlen (password); i++)
{
newPW [i] = password [i] ^ key [i];
printf ("%xn", newPW [i]);
}
}
|
| Figura 9 – Programa para gerar senha ofuscada |
