Eu não sinto vontade de procurar pelas fontes de shells de 25 anos, mas
Pode ser uma vulnerabilidade format-string .
Se o shell contiver código como
printf(str);
em que str é uma string retirada da entrada do usuário, o conteúdo da string será a string de formatação que printf usa. O %s diz ao printf para imprimir uma string apontada por um argumento. Se os argumentos não forem fornecidos (como acima, há apenas a string de formatação), a função lerá alguns outros dados da pilha e os seguirá como ponteiros. Provavelmente acessando memória não mapeada e travando o processo.
De certa forma, acho que o texto da mensagem sugere uma solução como essa também. Se você digitar !xxx , o que a shell faz visivelmente é imprimir uma mensagem de erro como !xxx: event not found . A partir daí, não é um grande salto tentar também imprimir !xxx%s%s%s%s%s%s%s%s: event not found , com a implicação de uma vulnerabilidade de string de formato.
Eu não deveria, mas dei uma olhada na fonte aqui ( 4.3BSD-Tahoe/usr/src/bin/csh , as datas são de 1988).
findev(cp, anyarg) em sh.lex.c parece que pode ser a função para encontrar um evento de histórico correspondente:
percorre uma lista vinculada de struct Hist chamada Histlist . Se não encontrar nada, chama seterr2(cp, ": Event not found"); a noev() . cp aqui parece ser a string pesquisada no histórico.
seterr2() define a variável err como concatenação dos argumentos e err é usado como if (err) error(err); em alguns locais em process() , em sh.c . Finalmente, error() (em sh.err.c ) contém uma vulnerabilidade de string de formato clássico: if (s) printf(s, arg), printf(".\n");
Em alguns outros lugares, error() é chamado com um argumento, como error("Unknown user: %s", gpath + 1); , então a ideia é que o primeiro argumento para error() pode ser uma string de formato.
Eu não seria honesto se dissesse que entendi as funções de substituição de histórico na íntegra. É bastante uncommented manipulação de seqüência de caracteres manual em C. % tem um significado especial na substituição de histórico, mas só posso vê-lo sendo tratado especialmente como o primeiro caractere (como em !% ) ou após findev() é chamado.