J'ai entendu parler du problème Bash Shellshock depuis hier et je suis curieux de voir où dans le code source ce problème se produit. J'ai téléchargé la source de Bash 4.2 depuis ici .
Où dois-je rechercher Shellshock dans le code source de Bash 4.2?
J'ai pu trouver ce correctif informations pour 4.2 (à partir de ce page ), mais si quelqu'un pouvait expliquer clairement où Shellshock se produit, ce serait utile.
CVE-2014-6271 a été la première vulnérabilité découverte. Un patch peut être trouvé ici .
De Wikipedia :
Les définitions de fonction sont exportées en les codant dans la liste des variables d'environnement en tant que variables dont les valeurs commencent par des parenthèses ("()") suivies d'une définition de fonction. La nouvelle instance de Bash, au démarrage, analyse sa liste de variables d'environnement pour les valeurs dans ce format et les reconvertit en fonctions internes.
Bash effectue cette conversion en créant un fragment de code qui définit la fonction et en l'exécutant, mais il ne vérifie pas que le fragment est simplement une définition de fonction . Par conséquent, toute personne pouvant provoquer l'exécution de Bash avec une paire nom/valeur particulière dans son environnement peut également exécuter des commandes arbitraires en ajoutant ces commandes à une définition de fonction exportée.
Dans le code source, nous pouvons voir l'importation des variables de fonction dans variables.c
:
/* Initialize the Shell variables from the current environment.
If PRIVMODE is nonzero, don't import functions from ENV or
parse $SHELLOPTS. */
void
initialize_Shell_variables (env, privmode)
char **env;
int privmode;
{
[...]
for (string_index = 0; string = env[string_index++]; )
{
[...]
/* If exported function, define it now. Don't import functions from
the environment in privileged mode. */
if (privmode == 0 && read_but_dont_execute == 0 && STREQN ("() {", string, 4))
{
[...]
parse_and_execute (temp_string, name, SEVAL_NONINT|SEVAL_NOHIST);
[...]
}
}
Nous pouvons voir une boucle for sur toutes les variables d'environnement données à la fonction, puis un if pour savoir si nous sommes en mode privilégié, mais cela est désactivé la plupart du temps. La partie "ne pas vérifier que le fragment n'est qu'une définition de fonction" se trouve dans la ligne parse_and_execute
. La description de la fonction de builtins/evalstring.c
:
/* Parse and execute the commands in STRING. Returns whatever
execute_command () returns. This frees STRING. FLAGS is a
flags Word; look in common.h for the possible values. Actions
are:
(flags & SEVAL_NONINT) -> interactive = 0;
(flags & SEVAL_INTERACT) -> interactive = 1;
(flags & SEVAL_NOHIST) -> call bash_history_disable ()
(flags & SEVAL_NOFREE) -> don't free STRING when finished
(flags & SEVAL_RESETLINE) -> reset line_number to 1
*/
int
parse_and_execute (string, from_file, flags)
char *string;
const char *from_file;
int flags;
{
Ainsi, tout ce qui est passé à la fonction est exécuté comme s'il s'agissait d'une commande bash ordinaire. Les drapeaux SEVAL_NONINT
Et SEVAL_NOHIST
Sont explicites ( explication de l'interactivité , NOHIST
n'ajoute pas la définition à votre historique bash) don ' t éviter de transmettre autre chose que des définitions de fonction. Le patch introduit des drapeaux SEVAL_FUNCDEF
Et SEVAL_ONECMD
Qui peuvent être passés dans le champ des drapeaux à parse_and_execute
:
+ #define SEVAL_FUNCDEF 0x080 /* only allow function definitions */
+ #define SEVAL_ONECMD 0x100 /* only allow a single command */
Le correctif ajoute également des fonctionnalités à parse_and_execute
Pour se conformer à ces nouveaux indicateurs et modifie l'appel à parse_and_execute
Pour passer ces indicateurs:
- parse_and_execute (temp_string, name, SEVAL_NONINT|SEVAL_NOHIST);
+ /* Don't import function names that are invalid identifiers from the
+ environment. */
+ if (legal_identifier (name))
+ parse_and_execute (temp_string, name, SEVAL_NONINT|SEVAL_NOHIST|SEVAL_FUNCDEF|SEVAL_ONECMD);
CVE-2014-7169 se base sur un problème d'analyse de fonction qui a été souligné par Tavis Ormandy. Le correctif de parse.y
Semble très simple, mais c'est plus délicat que CVE-2014-6271:
/* Called from Shell.c when Control-C is typed at top level. Or
by the error rule at top level. */
void
reset_parser ()
[...]
FREE (Word_desc_to_read);
Word_desc_to_read = (Word_DESC *)NULL;
+ eol_ungetc_lookahead = 0;
+
current_token = '\n'; /* XXX */
last_read_token = '\n';
token_to_read = '\n';
La variable eol_ungetc_lookahead
Est expliquée lors de sa définition:
/* This implements one-character lookahead/lookbehind across physical input
lines, to avoid something being lost because it's pushed back with
Shell_ungetc when we're at the start of a line. */
static int eol_ungetc_lookahead = 0;
Il est lu à l'intérieur de la fonction Shell_getc
, Et s'il est défini, son contenu (à un caractère) est lu à la place.
La commande rm echo; env -i X='() { function a .>\' bash -c 'echo date'; cat echo
crée d'abord une erreur de syntaxe avec le caractère .
(Vous pouvez également utiliser d'autres caractères ici, comme a
ou =
), Puis utilise le nettoyage insuffisant de la variable eol_ungetc_lookahead
dans la fonction reset_parser
pour injecter le caractère >
dans la chaîne 'date d'écho' qui est également donnée à bash. Son équivalent à rm echo; bash -c '> echo date'; cat echo
.
Autres ressources sur la liste de diffusion oss-sec .