GNU/Linux >> Znalost Linux >  >> Linux

Jak bezpečný je idiom `ssh … “$(typeset -f Foo); Foo""?

Předpokládejme, že nějaká funkce shellu foo je definován v aktuální relaci shellu. Poté příkaz

typeset -f foo

vytiskne zdrojový kód této funkce. To znamená, že alespoň v principu lze tuto funkci spustit na vzdáleném hostiteli pomocí ssh jak je uvedeno níže:

ssh <REMOTE-HOST> "$(typeset -f foo); foo"

(Pro účely této otázky předpokládejme, že všechny příkazy a cesty k souborovému systému uvedené foo jsou k dispozici v <REMOTE-HOST> . Předpokládejme také, že bash je plášť na obou koncích.)

Můj instinkt je, že slepé získávání nějakého automaticky generovaného zdrojového kódu, jako je tento, by bylo extrémně křehké, ale nebyl jsem schopen přijít s příkladem funkce foo kde tento idiom selhává.

Moje otázka zní:Jak bezpečný je tento idiom? Pokud to není bezpečné, může mi někdo dát konkrétní příklad, který ilustruje, jak to selhává? (Otázka bezpečnosti zahrnuje následující:does bash zaručit, že takové použití typeset -f jsou bezpečné?)

Poznámka: V tomto příspěvku nehledám alternativy; Chci jen porozumět vlastnostem tohoto konkrétního idiomu.

EDIT:objasněno, že bash je plášť na obou koncích.

Přijatá odpověď:

Není bezpečné, pokud kód není interpretován ve stejném národním prostředí jako to, kde byl vygenerován (nebo pokud název národního prostředí je stejný, ale definice tohoto národního prostředí se mezi hostitelem klienta ssh a hostitelem serveru liší).

Zvláště důležité je kódování znaků a členství znaků v blank , alpha a alnum kategorie.

Například α znak (malé řecké písmeno alfa) ve znakové sadě BIG5 je zakódován jako 0xa3 0x5c, 0x5c je v ASCII (a všech znakových sadách včetně BIG5).

Pokud tedy máte foo funkce definovaná v této znakové sadě jako:

foo() {
  echo α
}

typeset -f vypíše jej jako takový, ale pokud bude interpretován v jiném národním prostředí, jako je C, nebude 0xa3 0x5c považováno za α ale jako neznámý znak 0xa3 následovaný zpětným lomítkem. To lze zneužít jako s:

$ env LC_ALL=zh_TW.big5 $'BASH_FUNC_foo%%=() { echo xa3\\;}; echo gotcha; }' bash -c 'typeset -f foo' | bash
gotcha
bash: line 5: syntax error near unexpected token `}'
bash: line 5: `}'

The foo() { echo α;}; echo gotcha; } se stalo foo() { echo <0xa3>\; }; echo gotcha; } při interpretaci v jiném národním prostředí.

Další problémy:

à znak v UTF-8 je zakódován jako 0xc3 0xa0. V iso8859-1 a několika dalších iso8859 znakové sady, 0xa0 je znak pevné mezery. Na některých systémech je tento znak zahrnut do prázdného místa znaková třída, kterou bash ctí jako oddělovač tokenů ve své syntaxi.

Související:Linux – Spustit pouze oprávnění k souboru?

Solaris je jedním z takových systémů, kde je U+00A0 považováno za prázdné:

$ env $'BASH_FUNC_foo%%=() { nawk -v x=àBEGIN'{system("echo gotcha")}' 1;}' bash -c 'typeset -f foo; echo foo'  | ssh solaris LC_ALL=en_GB.ISO8859-1 bash
gotcha

Podívejte se, jak:

nawk -v x=àBEGIN... 1

byl interpretován jako:

nawk -v x=<0xc3> 'BEGIN{system("...")}' 1

Všimněte si, že pokud byla funkce definována v národním prostředí, kde 0xa0 nebylo prázdné nebo kde 0xa3 0x5c bylo alfa, typeset -f bude mít stále stejný výstup, i když je volán v národním prostředí, kde je prázdný (při interpretaci vytvoří jiný výstup)

$ LC_ALL=zh_TW.big5 bash -c $'f() { echo xa3x5c$(uname); }; export LC_ALL=C; typeset -f f | bash'
bash: line 3: syntax error near unexpected token `('
bash: line 3: `    echo �$(uname)'

Obecněji řečeno, výstup typeset , alias , export -p , set , locale jsou všechny myšleny být vhodný pro opětovné zadání do shellu, ale kromě těchto problémů s místním prostředím je známo, že různé implementace mají několik problémů, a nepřekvapilo by mě, kdyby jich bylo ještě mnohem více.

Takže ano, souhlasím s tím, že to považujete za nebezpečné správně, a je dobré je používat pouze v kontextu, kde víte, odkud pocházejí data, která jsou výstupem. Například v případě typeset -f foo , použijte jej pouze na foo funkci, kterou vás mít definované (a nepoužívejte v něm znaky jiné než ASCII).


Linux
  1. Je Rsync ~/foo Target/foo stejný jako Rsync ~/foo/ Target/foo/?

  2. Jak poznám název souboru skriptu ve skriptu Bash?

  3. Jak si mohu vybavit argument předchozího příkazu bash?

  1. Jak číst předposlední řádek v souboru pomocí Bash?

  2. Jak přidat ikonu do výzvy bash

  3. Jak získám absolutní adresář souboru v bash?

  1. Jak nastavit barvu příkazového řádku v Bash?

  2. Jak najít index slova v řetězci v bash?

  3. Jak změnit rozlišení Bash pro Debian VM?