Come posso proteggermi da questo tipo di abuso negli appunti?

170

Abuso di appunti dai siti web

Molti siti Web utilizzano JavaScript o CSS per inserire o sostituire furtivamente il testo negli appunti dell'utente ogni volta che copiano informazioni dalla pagina. Per quanto ne so, questo è usato principalmente per scopi pubblicitari, ma è stato dimostrato che il PoC per gli exploit è stato dimostrato.

Tuttavia ho scoperto che non è nemmeno necessario che JS o CSS realizzino un exploit con effetti dannosi se incollato in un terminale. Incollare caratteri backspace nascosti può cambiare l'intero significato di un comando shell. Anche incollare in un editor basato sui termini non è sicuro. Incollare Esc e :! può causare un'istanza di Vim in esecuzione per eseguire un comando di shell. Incollando ^X^C si esce da Emacs e / o anche cat . Incollare ^Z bloccherà principalmente qualsiasi editor basato sui termini e tornerà alla shell.

Ciò che rende peggiore è che molti siti Web attendibili non disinfettano questi caratteri non stampabili. Twitter filtra Esc ma non backspace. Pastebin.com non sembra filtrare nulla. Neanche Stack Exchange , quindi il seguente exploit ( ATTENZIONE: codice dannoso, NON copiare e incollare in un terminale Unix !! ) che potrebbe benissimo essere trasformato in qualcosa di peggio e più probabile che venga incollato da una vittima:

echo '.!: keS i3l ldKo -1+9 +2-1' > /tmp/lol
echo ':!. keS i3l ldKo -2+9 +7-1' >> /tmp/lol
echo '.:! keS i3l ldKo -3+9 +4-1' >> /tmp/lol
sleep 1
md5sum /tmp/lol

Modifica : i backspaces grezzi ora vengono filtrati da Stack Exchange, quindi questo PoC richiede & # escape. / Modifica

Ecco come lo esegue il rendering di Chrome:

Firefoxnonvieneingannatofacilmente,marimanecomunqueignarodell'approccioJSoCSS:

E quando incollato in un terminale, uccide solo tutti i processi dell'utente.

Che cosa fare?

Ciò che sostanzialmente mi dice è che non dovrei mai e poi mai copiare nulla da una pagina web e incollarlo in un'applicazione terminale . Bene, bene. Il mio ambiente di lavoro è fondamentalmente un browser Web e 40 finestre / schede terminali. Copia e incolla frammenti di codice sempre.

Ora, c'è qualcuno che può proteggermi dalle mie cattive abitudini (che, onestamente, non penso siano così male)? Venditori di browser? Venditori di terminali? Fornitori di sistemi di appunti? Forse un'applicazione di terze parti?

    
posta sam hocevar 18.07.2013 - 02:08
fonte

7 risposte

26

Si noti che dalla versione 292 , xterm rimuove i caratteri di controllo ASCII ad eccezione di \b , \r , \t , DEL (0x7f) e \n (converte \n in \r s come altri terminali) e puoi riportarli con la risorsa allowPasteControls . VTE (la libreria dell'emulatore di terminale utilizzata da gnome-terminal , terminator , xfce-terminal ...) anche lo fa da ottobre 2015

Quindi in quei terminali, ^C , ^[ , ^D , ^Z , ^\ , ^U , ^W non sono più un problema ma DEL, \b , \t (molto pericoloso con alcune configurazioni (inclusa quella di default) di zsh dove il completamento può espandere le sostituzioni di comando), \r e \n lo sono ancora.

xterm ha anche un paio di modalità di incollamento che possono aiutarti qui.

  • la modalità di scrittura tra parentesi attivata con la sequenza \e[?2004h utilizzata in alcuni zsh o vim sicuri - incolla plug-in .

    zsh ( zle ) dal 5.1 e bash ( readline ) da 4.4 ora hanno il supporto per quello integrato. Mentre è abilitato per impostazione predefinita in zsh , devi abilitarlo manualmente con bind 'set enable-bracketed-paste on' in bash (o nella configurazione readline in ~/.inputrc o /etc/inputrc ).

    Questo avvolge la selezione tra \e[200~ e \e[201~ .

    La maggior parte degli altri terminali moderni come quelli basati su VTE ( gnome-terminal , xfce-terminal , terminator ...), rxvt , konsole , OS / X Terminal ora supportano anche quello.

    In alcuni di quegli altri terminali (o versioni di questi) però (o con allowPasteControls in xterm ), ciò è difettoso in quanto \e[201~ potrebbe apparire nella selezione, e sarebbe preso come parentesi di chiusura.

    Potrebbe essere risolto da bracketing come \e\e[201~\e[200~201~ , ma non è ancora stato eseguito da alcun emulatore di terminale AFAIK (e significherebbe che l'applicazione vedrebbe più paste).

    Anche

    ^C / ^Z / ^\ causerebbe ancora l'invio di segnali al gruppo di processi in foreground del terminale se ISIG non è stato disabilitato nella disciplina della linea tty.

  • La modalità Incolla quotata abilitata con la sequenza \e[?2005h (disabilitata con \e[?2005l ).

    Questo antepone ogni carattere (in realtà un byte) con un carattere ^V .

    ^V è il carattere predefinito lnext ( letterale successivo ) della disciplina della linea tty in modalità canonica ed è anche riconosciuto come tale da vi e altri editor e alcuni editor di righe come readline o zsh s zle.

    Questo non ha lo stesso problema della modalità con parentesi sopra, e ha il vantaggio di funzionare per la modalità canonica del terminale (come quando fai cat > file ) e alcune altre applicazioni ma ha alcuni inconvenienti:

    • newline e CR finiscono per essere resi come ^M . Ciò può essere evitato con un'altra sequenza di escape: \e[?2006h , ma ciò fa sì che le newline vengano inserite come caratteri NUL in vim e mostrino come ^J (a meno che non si faccia stty -echoctl ) nella modalità canonica terminale (sebbene è solo un problema estetico).
    • Non funziona molto bene per i caratteri multi-byte che non sono inseriti correttamente in zle o vim per esempio.
    • alcune applicazioni visive non gestiscono ^V come literal next , quindi potresti dover ancora disattivarlo in modo selettivo.
    • non puoi usarlo in vim come ^V 1 per esempio non inserisce 1 ma ^A lì.
    • Non sono a conoscenza di nessun altro terminale accanto a xterm che lo supporta, ma poi non ho fatto un sondaggio completo.
  • ti consente anche di definire la tua modalità di incollaggio tra parentesi tramite la configurazione. Ad esempio, con:

     XTerm*allowPasteControls: true
     XTerm.VT100.translations: #override \
       Ctrl Shift<KeyPress> Insert: \
         insert-formatted("3[202~%S~%s", CLIPBOARD,PRIMARY,CUT_BUFFER0)'
    

    inserirà CLIPBOARD / PRIMARY / CUT_BUFFER0 come ^[[202~<size-in-bytes>~<content> su Maiusc + Ctrl + Inserisci . L'applicazione potrebbe quindi interpretarla in modo affidabile (sarebbe comunque necessario disabilitare ISIG nella disciplina della linea tty).

Un altro approccio sarebbe utilizzare un wrapper pseudo-tty che inserisca quei ^V solo davanti ai caratteri di controllo. Tale wrapper dovrebbe essere in grado di rilevare i caratteri di controllo in paste con un po 'di affidabilità perché i tasti di tastiera reali manderebbero solo un carattere alla volta o una sequenza di caratteri che iniziano con ESC, mentre le paste invierebbero diverse alla volta .

Avresti ancora il problema delle newline mostrate come ^J nella modalità canonica terminale o ^@ in vim , ma con la cooperazione potrebbe essere aggirato con la shell

Una dimostrazione del concetto:

Da utilizzare ad esempio come:

./safe-paste bash

Per avviare una shell bash sotto quel wrapper.

#!/usr/bin/perl

use IO::Pty;
use IO::Stty;

my $pty = new IO::Pty;
my $pid = fork();
die "Cannot fork" if not defined $pid;
unless ($pid) {
  $pty->make_slave_controlling_terminal();
  my $slave = $pty->slave();
  close $pty;
  $slave->clone_winsize_from(\*STDIN);

  open(STDIN,"<&". $slave->fileno())
    or die "Couldn't reopen STDIN for reading, $!\n";
  open(STDOUT,">&". $slave->fileno())
    or die "Couldn't reopen STDOUT for writing, $!\n";
  open(STDERR,">&". $slave->fileno())
    or die "Couldn't reopen STDERR for writing, $!\n";

  close $slave;

  exec(@ARGV);
  die "Cannot exec(@ARGV): $!";
}
$pty->close_slave();

$SIG{WINCH} = sub {
  $pty->slave->clone_winsize_from(\*STDIN);
};

my $old = IO::Stty::stty(\*STDIN, '-g');
IO::Stty::stty(\*STDIN, 'raw', '-echo');
$tty = fileno($pty);
my ($rin,$ein) = ('','','');
vec($rin, 0, 1) = 1;
vec($rin, $tty, 1) = 1;
vec($ein, $tty, 1) = 1;
my ($to_stdout, $to_tty) = ('', '');
my $eof;
$SIG{CHLD} = sub {$eof = 1};
until ($eof && $to_stdout eq '' && $to_tty eq '') {
  my ($rout,$wout,$eout,$timeleft);
  my $win = '';
  vec($win, 0, 1) = 1 if ($to_stdout ne "");
  vec($win, $tty, 1) = 1 if ($to_tty ne "");
  ($nfound,$timeleft) = select($rout=$rin,$wout=$win,$eout=$ein,undef);
  if ($nfound > 0) {
    if (vec($eout, $tty, 1)) {
      print STDERR "Exception on $tty\n";
    }
    if (vec($rout, 0, 1)) {
      my $buf;
      if (sysread(STDIN, $buf, 4096)) {
        if ($buf =~ /.[
 XTerm*allowPasteControls: true
 XTerm.VT100.translations: #override \
   Ctrl Shift<KeyPress> Insert: \
     insert-formatted("3[202~%S~%s", CLIPBOARD,PRIMARY,CUT_BUFFER0)'
-77]/ || $buf =~ /^(?:[
./safe-paste bash
-24-7]|3.*?[~a-zA-NP-Z])./) { $buf =~ s/[
#!/usr/bin/perl

use IO::Pty;
use IO::Stty;

my $pty = new IO::Pty;
my $pid = fork();
die "Cannot fork" if not defined $pid;
unless ($pid) {
  $pty->make_slave_controlling_terminal();
  my $slave = $pty->slave();
  close $pty;
  $slave->clone_winsize_from(\*STDIN);

  open(STDIN,"<&". $slave->fileno())
    or die "Couldn't reopen STDIN for reading, $!\n";
  open(STDOUT,">&". $slave->fileno())
    or die "Couldn't reopen STDOUT for writing, $!\n";
  open(STDERR,">&". $slave->fileno())
    or die "Couldn't reopen STDERR for writing, $!\n";

  close $slave;

  exec(@ARGV);
  die "Cannot exec(@ARGV): $!";
}
$pty->close_slave();

$SIG{WINCH} = sub {
  $pty->slave->clone_winsize_from(\*STDIN);
};

my $old = IO::Stty::stty(\*STDIN, '-g');
IO::Stty::stty(\*STDIN, 'raw', '-echo');
$tty = fileno($pty);
my ($rin,$ein) = ('','','');
vec($rin, 0, 1) = 1;
vec($rin, $tty, 1) = 1;
vec($ein, $tty, 1) = 1;
my ($to_stdout, $to_tty) = ('', '');
my $eof;
$SIG{CHLD} = sub {$eof = 1};
until ($eof && $to_stdout eq '' && $to_tty eq '') {
  my ($rout,$wout,$eout,$timeleft);
  my $win = '';
  vec($win, 0, 1) = 1 if ($to_stdout ne "");
  vec($win, $tty, 1) = 1 if ($to_tty ne "");
  ($nfound,$timeleft) = select($rout=$rin,$wout=$win,$eout=$ein,undef);
  if ($nfound > 0) {
    if (vec($eout, $tty, 1)) {
      print STDERR "Exception on $tty\n";
    }
    if (vec($rout, 0, 1)) {
      my $buf;
      if (sysread(STDIN, $buf, 4096)) {
        if ($buf =~ /.[%pre%-77]/ || $buf =~ /^(?:[%pre%-24-7]|3.*?[~a-zA-NP-Z])./) {
          $buf =~ s/[%pre%-77]/6$&/g;
          # TODO: add UTF-8 sanitizing
          $buf =~ y/\r/\n/;
        }
        $to_tty .= $buf;
      } else {
        $eof = 1;
        vec($rin, 0, 1) = 0;
      }
    }
    if (vec($rout, $tty, 1)) {
      my $buf;
      if (sysread($pty, $buf, 4096)) {
        $to_stdout .= $buf;
      } else {
        $eof = 1;
        vec($rin, $tty, 1) = 0;
        $to_tty = '';
      }
    }
    if ($to_tty ne '' && vec($wout, $tty, 1)) {
      my $written = syswrite($pty, $to_tty);
      $to_tty = substr($to_tty, $written) if $written;
    }
    if ($to_stdout ne '' && vec(wout, 1, 1)) {
      my $written = syswrite(STDOUT, $to_stdout);
      $to_stdout = substr($to_stdout, $written) if $written;
    }
  }
}
END{IO::Stty::stty(\*STDIN, $old)}
-77]/6$&/g; # TODO: add UTF-8 sanitizing $buf =~ y/\r/\n/; } $to_tty .= $buf; } else { $eof = 1; vec($rin, 0, 1) = 0; } } if (vec($rout, $tty, 1)) { my $buf; if (sysread($pty, $buf, 4096)) { $to_stdout .= $buf; } else { $eof = 1; vec($rin, $tty, 1) = 0; $to_tty = ''; } } if ($to_tty ne '' && vec($wout, $tty, 1)) { my $written = syswrite($pty, $to_tty); $to_tty = substr($to_tty, $written) if $written; } if ($to_stdout ne '' && vec(wout, 1, 1)) { my $written = syswrite(STDOUT, $to_stdout); $to_stdout = substr($to_stdout, $written) if $written; } } } END{IO::Stty::stty(\*STDIN, $old)}

Un approccio migliore sarebbe probabilmente quello di utilizzare un gestore di appunti in cui è possibile specificare la modalità di incollamento e che contrassegnerebbe le selezioni potenzialmente pericolose.

    
risposta data 04.03.2014 - 09:05
fonte
45

Potresti averlo indovinato, ma non usare mai i terminali che incollano le funzionalità per incollare le cose in vim / emacs . È come inviare un batch di comandi all'editor, che può fare qualsiasi cosa.

Per questi motivi, gli editor hanno la propria funzionalità di copia-incolla, che non può essere iniettata. Ad esempio, in vim, dovresti usare il registro + per scambiare dati con gli appunti del sistema ( "+p per incollare).

Per quanto riguarda la shell o altre applicazioni terminali: è stato stabilito , che non devi incollare dati non sicuri nel tuo terminale.

Esiste un plug-in Safe-paste per zsh, che impedisce l'esecuzione effettiva del codice quando incollato, ma qualcuno ha già lo ha comunque sfruttato .

Inoltre, una domanda a> (su incollatura accidentale) è stato chiesto su apple.se. La maggior parte delle soluzioni potrebbe funzionare anche per te.

Aggiornamento: In vim, se viene utilizzato set mouse=a , incollare con il pulsante centrale del mouse è sicuro. Puoi comunque incollare con Maiusc + Inserisci.

    
risposta data 18.07.2013 - 14:02
fonte
19

Bene, il mio attuale approccio agli appunti è buono per mitigarlo.

Quando copia i frammenti incollati tra le schede, copio semplicemente la pasta normalmente.

Tuttavia, quando copiate incollando in una sessione terminale / PuTTY, io (essendo un po 'contrario alla modifica del testo nel terminale), di solito lo assembliamo in Notepad ++ o Emacs (a seconda del sistema operativo) e poi copia-incolla il testo finale nel terminale. Entrambi gli editori mostrano i caratteri di controllo (e altri caratteri non stampabili), quindi è facile notare qualcuna di questi ostacoli.

Purtroppo non posso affermare di utilizzare l'approccio dell'editor di testo intermedio per ragioni di sicurezza, perché non sono ancora esperto di vim o di qualsiasi altro editor basato su terminale.

    
risposta data 18.07.2013 - 10:08
fonte
17

Potrei affermare che qualsiasi copia e incolla di snippet di codice è una cattiva abitudine, ma questo è un passo in avanti nella risoluzione. Personalmente scrivo tali elementi di codice invece di copiarli, ma è perché di solito voglio cambiare alcune cose in essi, o imparare come fare il compito a portata di mano; o forse sono solo un maniaco delirante.

Quello che potresti fare è per disinfettare automaticamente i contenuti degli appunti . Un'applicazione in background può monitorare costantemente il contenuto del buffer di taglio e rimuovere i caratteri di controllo; Non sono sicuro che X11 possa essere convinto a inviare un evento per una modifica del buffer di taglio, ma il polling 10 volte al secondo farebbe il trucco. La dualità X11 (taglia i buffer e le selezioni) renderà le cose un po 'più complesse ma credo che ciò possa essere fatto (e, inoltre, credo che tu puoi farlo)

L'igienizzazione dei contenuti può essere complicata. Ad esempio, supponiamo di rimuovere tutti i byte nell'intervallo 0..31 (i caratteri di controllo ASCII) tranne newline (10), carriage return (13) e tabulazioni (9). Quindi, se scrivo questo (sistema Linux):

printf "\xC0\x9B:!kill -9 -1\n" | xclip

e poi lo incollo in un'istanza vim in esecuzione in xterm (in modalità UTF-8), quindi uccido tutti i miei processi ... sebbene il buffer di taglio non contenga mai alcun carattere di controllo "indesiderato" in qualsiasi punto. La sequenza C0 9B non è UTF-8 valida, ma abbastanza vicina in modo che xterm proverà a decodificarlo comunque, e decodifica a 0x1B , alias Escape ... altre sequenze difficili includono E0 80 9B . Nota che mentre UTF-8 valido mai include un byte di valore C0 , può contenere byte di valore E0 , 80 e 9B (ma non in quella sequenza). Il processo di sanificazione dovrebbe quindi essere accurato e rigoroso.

Una funzionalità aggiuntiva di tale strumento sarebbe quella di convertire automaticamente sequenze CR + LF e CR solitario in LF. È possibile convertire i sanguinosi personaggi CP-1252 dalla gamma 128..159 nelle rispettive controparti standard. Questo non è solo un problema di sicurezza; potrebbe essere uno strumento utile in situazioni non dannose.

    
risposta data 18.07.2013 - 15:10
fonte
3

Recentemente ho risolto questo problema eseguendo il mio browser Web in una macchina virtuale. La selezione x non è sincronizzata tra la VM e l'host, quindi non è più possibile per me fare clic con il tasto sinistro del mouse per incollare elementi dal web in un terminale.

    
risposta data 13.08.2013 - 18:12
fonte
2

È molto più profondo delle modifiche alle line incorporate in cui si dovrebbe almeno vedere cosa è successo; o almeno vedere che qualcosa si stava nascondendo. Potrei pubblicare un frammento di codice dall'aspetto benigno come questo:

let t_BE="\<esc>[?2004h"

Quindi cerca di indurre le persone a copiarlo e incollarlo in uno specifico editor di testo in uno specifico emulatore di terminale, suggerendo ad esempio che è necessario attenuare un problema (forse anche un problema di sicurezza) che i due hanno quando operano insieme .

Ciò che potresti copiare nel frammento di codice precedente contiene caratteri di controllo e codice che possono essere eseguiti invisibilmente , quindi non sei consapevole che qualcosa di sinistro potrebbe essere successo (a condizione che tu lo incolli nell'adeguato editor tramite un terminale adatto, che elaboriamo con un po 'di ingegneria sociale).

Questo risultato si ottiene usando l'enigma convenzionale del testo nascosto combinato con una sequenza di escape per convincere il terminale che l'operazione di incollatura è completa (descritta in altre risposte qui) e una serie di comandi da tastiera che l'editor può eseguire così rapidamente che lo schermo non mostra loro che stanno accadendo. Infine, i comandi dannosi vengono cancellati dalla cronologia interna in modo che non vengano scoperti in seguito.

Per arrotondare questo in una risposta; questa dimostrazione è per lo più storica. La modalità di inserimento in bracketing è ampiamente supportata e nella maggior parte dei terminali non è possibile romperla con escape incorporati (controllare questo e aggiornare / report secondo necessità). Devi configurare la tua shell, i tuoi editor e qualsiasi altra cosa che potresti incollare per abilitare la modalità di inserimento bracketing.

    
risposta data 10.04.2018 - 09:43
fonte
1

Quello che faccio per proteggerlo è usare la modalità di inserimento tra parentesi. Come ha detto Stéphane, zsh e urxvt lo supportano di default. Se ti limiti a incollare solo quando in un prompt di zsh in urxvt, l'unico vero problema che ti rimane (non vedo alcun problema con ^C o ^Z che causa segnali nel prompt) è che l'incolla potrebbe contenere la sequenza di escape per terminare la pasta e interpretare il resto come se fosse stato digitato.

La risoluzione di questo problema in sospeso è l'argomento di questa risposta. Scriverò quello che ho fatto per il mio caso, ma dovrebbe essere fattibile anche in altri terminali, se non per estensione poi per patch.

urxvt supporta le estensioni perl. Ho scritto questo in ~/.urxvt/ext/filter-paste :

sub on_tt_paste {
    my ($term, $octets) = @_;
    $octets =~ s/\x1b\[201~//g;
    $term->tt_paste($octets);
    return true;
}

incluso nella lista delle estensioni perl da caricare in ~/.Xresources :

URxvt.perl-ext-common: filter-paste

e ricaricato la configurazione per le nuove finestre di terminale con xrdb ~/.Xresources .

Con questo, urxvt rimuove tutte le istanze della sequenza di escape della modalità di incollamento di chiusura da ciò che viene incollato nel terminale.

La pagina web, link , ha 2 esempi di exploit per questo al momento della stesura di questo documento. Prima di scrivere l'estensione, zsh con urxvt sarebbe invulnerabile per il primo esempio, ma non per il secondo che include la sequenza di escape per terminare la modalità Incolla. Dopo averlo scritto, non ha funzionato, e il contenuto completo di ciò che è stato incollato verrà visualizzato nel prompt, in attesa di un Invio prima dell'esecuzione (zsh non eseguirà un comando incollato con la modalità di scrittura tra parentesi anche se contiene una nuova riga fino a quando non premi Invio ).

EDIT: richiesto dal commento di sh1, ho testato altri emulatori di terminale per vedere quali erano ancora vulnerabili.

|----------------+---------+--------|
| terminal       | version | fixed  |
|----------------+---------+--------|
| yakuake        |   3.0.5 | ok     |
| gnome-terminal |  3.28.1 | ok     |
| konsole        | 18.04.0 | ok     |
| xterm          |     332 | ok     |
| sakura         |   3.5.0 | ok     |
| vte3           |  0.52.1 | ok     |
| st             |   0.8.1 | failed |
| qterminal      |   0.8.0 | failed |
| putty          |    0.70 | failed |
|----------------+---------+--------|

Tutte le versioni sono quelle attualmente presenti al momento della stesura nei repository di Archlinux (Archlinux è a rotazione). sh1 collegato a un commit in PuTTY che corregge questo, ma sembra che non sia ancora stato rilasciato in una nuova versione.

    
risposta data 19.04.2018 - 23:47
fonte

Leggi altre domande sui tag