sudo --stdin 및 임의의 문자가 포함된 비밀번호를 사용한 zsh 이상한 동작

sudo --stdin 및 임의의 문자가 포함된 비밀번호를 사용한 zsh 이상한 동작

이것은 여러분이 매일 기대하거나 보는 것처럼 시작되지 않는 게시물입니다. 여기 내 루트 비밀번호가 있습니다. :4\g&8n:6_F[`9Touc8Ls+L'8)>6!3,nNmUzR&Ub~w7NTd'^Lb0]`0`."u>tP\>XAspMLTt!@}=F6CP)NsSMYY7*xm'A!7`!n'tmAaGWoBhS|u4{k$*v/o|'%)mbXMw
기억하기 어렵죠? 글쎄, 그건 문제가 아니야. 그리고 당신이 나에게 소리를 지르기 전에, 네, 제가 바꿨어요. 이제 dummy_root테스트를 위해 해당 비밀번호를 가진 사용자가 있습니다 .

TL;DR

stdin의 sudo에 이 비밀번호를 전달하는 zsh를 깨뜨렸습니다.

(매우) 긴 버전

따라서 잘못된 점은 다음과 같습니다. 플래그 sudo와 함께 사용합니다 targetpw. 이는 sudo가 요청한 비밀번호가 내 비밀번호가 아닌 대상 사용자의 비밀번호임을 의미합니다. 저는 pass비밀번호 관리자(대지) 내 모든 컴퓨터/서버의 루트 비밀번호를 포함한 모든 것에 대해. 확실한 보안상의 이유로 이 비밀번호는 128자로 무작위로 생성됩니다(그렇지 않기 때문입니다). 나는 게으른 사람으로서(당신도 그럴 것이라고 확신합니다) 다음과 같은 별칭을 사용하고 싶습니다.

alias sudo='pass mydomain.tld/hostname/users/root/password | sudo --stdin'

pass에 익숙하지 않은 분들을 위해 기본적으로 GnuPG를 사용하여 디렉토리 트리의 비밀번호를 암호화하고, 호출하면 pass directory/subdirectory/password비밀번호를 복호화하여 stdout에 인쇄합니다(물론 디렉토리는 선택 사항이므로 루트에 모든 것을 무질서하게 저장할 수 있습니다. 그러나 권장되지는 않습니다). 별칭의 목적은 이 작업을 하루에 수십 번씩 방지하는 것입니다.

$ pass --clip root_password #Copy root password to clipboard 
$ sudo command
[sudo] password for root: paste
#command output (if the password is right of course)

그러나 alias 명령을 테스트하면 다음과 같은 일이 발생합니다.

$ pass root_password | sudo --stdin --shell
[sudo] password for root: %
$

여기서 %기호는 색상이 반전되어 있습니다. 내 터미널은 검정색 배경에 흰색 텍스트이고 %흰색 배경에 검정색이며 일종의 흰색으로 강조 표시되어 있으며 암호를 해독한 후 인쇄됩니다. 이 인쇄 [sudo] password for root:와 인쇄 사이에 %GPG는 내 개인 키 암호를 요청합니다. 나는 이미 어떤 경우에 반전된 퍼센트 기호를 보았고, 그것을 어디서, 언제 봤는지 나는 그것이 인쇄하는 것이라고 믿습니다. EOF(여기서 조심하십시오. 나는 이것에 대해 전혀 확신하지 못합니다. 이것을 인쇄하세요 %). 이 이상한 표시 뒤에는 루트가 아니지만 echo $?반환된다는 점에 유의하세요 0.

pass root_password그래서 해당 캐릭터에 대한 추가 정보를 얻을 수 있는지 확인하기 위해 의 출력을 16진수 덤프했습니다 . 결과는 다음과 같습니다.

$ pass root_password
:4\?g&8n:6_F[`9Touc8Ls+L'8)>6!3,nNmUzR&Ub~w7NTd'^Lb0]`0`."u>tP\>XAspMLTt!@}=F6CP)NsSMYY7*xm'A!7`!n'tmAaGWoBhS|u4{k$*v/o|'%)mbXMw
$ pass root_password | hexdump -C
00000000  3a 34 5c 3f 67 26 38 6e  3a 36 5f 46 5b 60 39 54  |:4\?g&8n:6_F[`9T|
00000010  6f 75 63 38 4c 73 2b 4c  27 38 29 3e 36 21 33 2c  |ouc8Ls+L'8)>6!3,|
00000020  6e 4e 6d 55 7a 52 26 55  62 7e 77 37 4e 54 64 27  |nNmUzR&Ub~w7NTd'|
00000030  5e 4c 62 30 5d 60 30 60  2e 22 75 3e 74 50 5c 3e  |^Lb0]`0`."u>tP\>|
00000040  58 41 73 70 4d 4c 54 74  21 40 7d 3d 46 36 43 50  |XAspMLTt!@}=F6CP|
00000050  29 4e 73 53 4d 59 59 37  2a 78 6d 27 41 21 37 60  |)NsSMYY7*xm'A!7`|
00000060  21 6e 27 74 6d 41 61 47  57 6f 42 68 53 7c 75 34  |!n'tmAaGWoBhS|u4|
00000070  7b 6b 24 2a 76 2f 6f 7c  27 25 29 6d 62 58 4d 77  |{k$*v/o|'%)mbXMw|
00000080  0a                                                |.|
00000081

0aNL에 따르면 입니다 man ascii. 여기 %에서 기호가 없고 sudo에 필요한 개행 문자( 참조)가 여기에 있음을 알 수 있습니다 man sudo.

하지만 잠깐만요, 이제 재미가 시작됩니다. 새로 시작된 터미네이터 창이나 tty에서 명령을 두 번 실행하면 다음과 같은 일이 발생합니다.

$ pass root_password | sudo --stdin --shell
[sudo] password for root: %
$ pass root_password | sudo --stdin --shell
zsh: parse error near `)'
$

그리고 그때부터 zsh가 깨진 것처럼 보입니다. 첫 번째 명령의 출력을 실행하려는 것 같지만 sudo두 번째 명령만 실행됩니다. 다음은 "깨진" 셸의 몇 가지 예입니다.

$ echo testpw | sudo --stdin --shell
zsh: command not found: testpw
$ echo testpw | cat
testpw
$ echo testpw | wc --bytes
11
$ echo anothertestpw | sudo --stdin --shell
zsh: command not found: anothertestpw
$ pass root_password | sudo --stdin --shell
zsh: parse error near `)'
$ exec zsh
$ echo testpw | sudo --stdin --shell
zsh: command not found:testpw

여기서 무슨 일이 일어나고 있는 걸까요? 표시된 것처럼 evec가 zsh 인스턴스를 다른 인스턴스( exec zsh)로 교체해도 이 문제가 해결되지 않습니다. 여기서 실제로 깨진 것은 무엇입니까? 통과, zsh 또는 sudo?

계속해서 더 테스트하고 새 터미널 창에서 또 다른 hexdump를 수행해 봅시다(분명히 zsh를 "정상" 상태로 되돌리는 방법을 모르기 때문입니다).

$ pass root_password | sudo --stdin --shell 2>&1 | hexdump -C
00000000  5b 73 75 64 6f 5d 20 70  61 73 73 77 6f 72 64 20  |[sudo] password |
00000010  66 6f 72 20 72 6f 6f 74  3a 20                    |for root: |
0000001a
$

이 퍼센트 기호는 어디로 갔나요? 몰라. 여기에 없고 아직 루트가 아니지만 쉘은 이제 손상된 상태입니다(이 "깨진 상태"의 이름을 올바르게 지정하는 방법을 확실히 모르겠습니다). 이 명령 이후에 명령 을 실행하면 pass root_password | sudo --stdin --shell이전과 동일한 오류 메시지가 표시됩니다. tty와 터미네이터, 심지어 이 사악한 캐릭터에서도 모든 것이 동일하다는 점에 유의해야 합니다 %.

도움이 필요할 수 있다고 생각되는 모든 정보는 다음과 같습니다. 저는 Arch Linux를 사용하고 있으며 언급된 모든 패키지는 오늘(2017-04-16 또는 15, 지구상 위치에 따라 현재 프랑스 오전 4시) 현재 최신 상태입니다. 즉( pacman -Q출력):

  • 커널: 4.10.9-1
  • zsh: 5.3.1-2
  • sudo: 1.8.19.p2-1
  • 패스: 1.7.1-1
  • 그누프: 2.1.20-1
  • 터미네이터: 1.91-5

여기에는링크내 .zshrc에 추가하면 도움이 될 수도 있습니다.

%그리고 약속 한 대로 pass. 여러 줄의 비밀번호를 생성하고 Ctrl+를 누르면 D뒤에 새 줄을 추가하지 않고 비밀번호를 완료하면 이 문자가 인쇄됩니다. 여기서는 텍스트가 있는 줄의 끝에서 Ctrl+를 누르는 것만으로는 충분하지 않다는 것을 알았습니다 D. 두 번 눌러야 합니다. 하지만 이 여러 줄 비밀번호에 후행 라인을 추가하는 경우 한 번 누르면 이를 표시하지 않고 비밀번호 입력이 종료됩니다.

$ pass insert --multiline test_evil_percent
Enter contents of test_evil_percent and press Ctrl+D when finished:
fooReturn
barCtrl+DCtrl+D%
거기는 !

그러나 후행 줄이 있으면 나타나지 않으며 Ctrl+를 D한 번만 누르면 프롬프트가 다시 나타납니다.

$ pass insert --multiline test_evil_percent
Enter contents of test_evil_percent and press Ctrl+D when finished:
fooReturn
barReturn
Ctrl+D
$

따라서 근본적인 질문은 내 별칭을 작동시키는 방법입니다. 궁금하신 분들을 위해 저는 사용자 정의 스크립트 디렉토리에 한 줄의 스크립트를 작성하여 파일 에 있는 이 스크립트의 전달에 pass root_password환경 변수를 호출하고 설정했습니다. 또 다른 질문은 다음과 같습니다. 여기서 zsh 및 sudo에 도대체 무슨 일이 벌어지고 있는 걸까요?SUDO_ASKPASS.zshrc


2017-04-16 편집: 솔루션

덕분에마이클 호머내 문제에 대해 다음 솔루션을 선택했습니다.

  • askpass-sudo호출하는 이름의 한 줄 스크립트를 작성하십시오.pass root_password
  • SUDO_ASKPASS내 환경 변수를 .zprofile이 스크립트의 경로로 설정합니다.
  • alias sudo='sudo -A'내 줄을 추가했습니다 ..zshrc

그리고 짜잔! 이제 호출하면 sudo command원하는 대로 GnuPG 키 암호를 사용하여 루트 암호를 해독하도록 요청하고 이를 통해 sudo --shell루트 쉘이 제대로 생성됩니다.

답변1

pass root_password | sudo --stdin --shell성공했습니다. pass비밀번호를 인쇄하고 sudo읽고 쉘을 시작했습니다. 출력이 종료되었습니다. 이는 쉘의 pass출력 및 입력에 사용된 스트림이 닫혔음을 의미합니다 . pass쉘이 EOF에서 성공적으로 종료되었습니다.

내의 후속 실행sudo시간 초과 창인증이 필요하지 않았기 때문에 쉘이 비밀번호 자체를 수신하고 이를 명령으로 실행하려고 시도하여 해당 오류가 발생했습니다.


쉘을 원하거나 stdin에서 읽는 일부 명령을 실행하려는 경우 별칭이 작동하지 않을 수 있습니다(그러나 그렇지 않은 명령의 경우에는 작동합니다). 원하는 경우 실행되는 별칭을 설정한 pass root_password | sudo --stdin true다음 제한 시간을 활용하여 비밀번호 없이 명령을 실행할 수 있습니다.

원하는 동작을 제공하는 일종의 AskPass 도우미를 구축할 수도 있습니다. pass언제를 통해 비밀번호를 제공합니까 ?물었다그것을 위해 sudo.

관련 정보