Passa al contenuto principale

L'altro giorno mi sono imbattuto in un programma che mi ha permesso di selezionare da una serie di query preconfezionate e di comunicare con un server per recuperare la risposta alla query selezionata. Ho iniziato a chiedermi quando mi sono reso conto che il programma non ha mai chiesto una password per l'autenticazione con il server. Si è scoperto che la password era incorporata nel programma. L'autore ha spiegato che andava bene perché 1) era un file binario in modo che nessuno potesse leggerlo e 2) se fossero riusciti a leggerlo non sarebbero stati in grado di trovare la stringa della password.

Nessuna di queste due ragioni è valida e vorrei usare questo post per dimostrarlo. Il mio programma di esempio scrive solo la "password" sul terminale, ma l'unica differenza tra questo e un programma di produzione vera e propria è il numero di stringhe che un utente malintenzionato dovrebbe cercare.

#include <stdio.h>
#include <string.h>

main ()
{
char password [9] = {"secret"};

printf ("This is the password: %sn", password);

}
Figura 1 - Programma di base con password incorporata

Quando viene eseguito mostra

x1
Questa è la password: segreto
pronto 14:12:16
Figura 2 - Esecuzione del programma di base

Per visualizzare le stringhe nel modulo di programma il nostro utente malintenzionato può usare il comando stringhe dalla directory >sistema>gnu_libreria>bin. Il comando -n5 limita l'output a stringhe di 5 o più caratteri. Ho troncato l'output (. . . . .) per abbreviare la visualizzazione, ma si può vedere che la password è una delle primissime stringhe visualizzate. Avere la password in prossimità di parole chiave come "login" o "password" o di un ID utente identificabile come "admin", "root" o "sql" rende la ricerca più facile.

>sistema>gnu_libreria>biblioteca>bin>corde -n5 x1.pm
bind, Rilascio 17.1.beta.be
phx_vos#
Noah_Davids.CAC
Pre-rilascio
Questa è la password: %s
segreto
s$start_c_programma
_prevenzione_pulizia_pulizia
_uscita
. . . . .
Figura 3 - Uso del comando stringhe GNU per trovare tutte le stringhe più lunghe di 4 caratteri nel modulo di programma

Se il comando stringhe non è disponibile il nostro utente malintenzionato può semplicemente visualizzare il modulo di programma. Sospetto che l'abbiamo fatto tutti per caso e anche se non è carino, visualizzerà la password. Ho di nuovo troncato l'output e di nuovo si può vedere la password.

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`00`00 Questa è la password: %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`[email protected]`00`FF`F8`FF`FE`00`04main`00`00`83`EC`2C'C7D$$`00
. . . .
Figura 4 - Visualizzazione del modulo di programma per trovare la password

Ci sono diverse alternative all'inserimento della password nel programma.

La password può essere inserita in un file e il programma può leggere il file. Solo le persone con "necessità di eseguire" hanno accesso in lettura al file e tutti gli altri hanno accesso nullo. Naturalmente "necessità di eseguire" non può essere equiparato a "necessità di conoscere la password". Inoltre c'è sempre il pericolo che qualcuno cambi per errore l'accesso.

Un'alternativa è quella di mantenere la stringa di password nel programma e di limitare l'accesso al programma. Questa soluzione soffre anche del problema "è facile cambiare una lista di accesso". Se il programma viene mantenuto nella stessa directory di altri programmi che possono essere eseguiti da chiunque, la probabilità di un cambiamento della lista di accesso aumenta.

Infine, è possibile mantenere la password nel modulo di programma, ma in qualche modo offuscare la stringa. Il seguente programma mostra un modo semplice per farlo.

#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 - Programma con stringa di password offuscata

Come si può vedere tutto ciò che fa è prendere i caratteri offuscati e XOR con un altro set di caratteri chiave per creare la password. L'esecuzione del programma produce lo stesso output del primo programma.

x2
Questa è la password: segreto
pronto 14:12:51
Figura 6 - Esecuzione del programma offuscato

Ma una ricerca per stringhe non mostra nulla che assomigli alla password

>sistema>gnu_libreria>biblioteca>bin>corde -n5 x1.pm
bind, Rilascio 17.1.beta.be
phx_vos#
Noah_Davids.CAC
Pre-rilascio
Questa è la password: %s
s$start_c_programma
_prevenzione_pulizia_pulizia
_uscita
. . . .
Figura 7 - il comando stringhe non mostra più la password

E durante la visualizzazione del file verranno visualizzati i caratteri della password offuscati e i caratteri chiave che devono sapere esattamente dove cercare per trovarli e anche come vengono combinati per creare la password.

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`00Questa è la password: %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`[email protected]`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 - Visualizzazione del modulo di programma non mostra più la password riconoscibile

Questa non è ancora una soluzione perfetta poiché il modulo di programma può essere smontato per capire come viene generata la password. Lo smontaggio del programma richiede ancora molta più raffinatezza rispetto alla semplice visualizzazione del modulo di programma.

Ho due idee per mettere la stringa di password offuscata in un file e poi proteggere il file tramite una lista di accesso. Da un lato, se la password dovrà mai essere cambiata, questa è una soluzione molto migliore rispetto all'inserimento della stringa di password offuscata nel programma. D'altra parte sospetto che anche se ci sono altre opzioni di configurazione nel file, l'inserimento della stringa nel file darà al nostro utente malintenzionato meno potenziali stringhe di password su cui indagare. Naturalmente dovrà comunque accedere al file e poi dovrà capire la tecnica di offuscamento e la chiave.

Un ultimo punto: come ho generato i caratteri della password offuscati? La cosa bella dell'operazione XOR è che ((A XOR B) XOR B) è uguale ad A, così ho scritto un breve programma per prendere la password originale XOR i caratteri con la mia chiave e stampare il risultato.

#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 - Programma per generare la password offuscata

© 2020 Stratus Tecnologie.