나는 이것을 Chris Down의 위의 훌륭한 답변에 대한 튜토리얼 스타일의 재구성으로 작성했습니다.
bash에서는 다음과 같은 쉘 변수를 가질 수 있습니다
$ t="hi there"
$ echo $t
hi there
$
기본적으로 이러한 변수는 하위 프로세스에서 상속되지 않습니다.
$ bash
$ echo $t
$ exit
그러나 내보내기로 표시하면 bash는 하위 프로세스 환경으로 이동한다는 것을 의미하는 플래그를 설정합니다 ( envp
매개 변수는별로 보이지 않지만 main
C 프로그램에는 세 개의 매개 변수가 있습니다. main(int argc, char *argv[], char *envp[])
마지막 포인터 배열은 배열입니다) 정의가있는 쉘 변수).
t
다음과 같이 내보내십시오 .
$ echo $t
hi there
$ export t
$ bash
$ echo $t
hi there
$ exit
위의 내용 t
은 서브 쉘에서 정의되지 않았지만 이제는 내보내기 후에 나타납니다 ( export -n t
내보내기를 중지하려는 경우에 사용 ).
그러나 bash의 기능은 다른 동물입니다. 다음과 같이 선언하십시오.
$ fn() { echo "test"; }
이제 다른 쉘 명령 인 것처럼 호출하여 함수를 호출 할 수 있습니다.
$ fn
test
$
다시 한번, 서브 쉘을 생성하면 함수가 내보내지지 않습니다 :
$ bash
$ fn
fn: command not found
$ exit
다음과 export -f
같이 함수를 내보낼 수 있습니다 .
$ export -f fn
$ bash
$ fn
test
$ exit
까다로운 부분은 다음과 같습니다 . fn
셸 변수 내보내기 t
가 위와 같이 내 보내진 함수 가 환경 변수로 변환됩니다 . 이것은 fn
로컬 변수 일 때 발생하지 않지만 내보내기 후에는 셸 변수로 볼 수 있습니다. 그러나 동일한 이름의 일반 (예 : 함수가 아닌) 쉘 변수를 가질 수도 있습니다. bash는 변수의 내용에 따라 구별됩니다.
$ echo $fn
$ # See, nothing was there
$ export fn=regular
$ echo $fn
regular
$
이제 env
내보내기로 표시된 모든 셸 변수를 표시하고 일반 fn
및 함수가 모두 fn
표시됩니다.
$ env
.
.
.
fn=regular
fn=() { echo "test"
}
$
하위 셸은 두 가지 정의를 수집합니다. 하나는 일반 변수이고 다른 하나는 함수입니다.
$ bash
$ echo $fn
regular
$ fn
test
$ exit
fn
위에서와 같이 또는 직접 일반 변수 할당으로 정의 할 수 있습니다 .
$ fn='() { echo "direct" ; }'
이것은 매우 특이한 일입니다. 일반적으로 fn
위와 같이 fn() {...}
구문 으로 함수 를 정의 합니다. 그러나 bash는 환경을 통해 파일을 내보내므로 위의 일반 정의로 직접 "바로 가기"할 수 있습니다. (직관을 고려하여) 이것은 현재 쉘에서 사용 가능한 새로운 기능을 제공 하지 않습니다fn
. 그러나 만약 당신이 ** 서브 ** 쉘을 스폰한다면, 그렇게 될 것입니다.
함수 내보내기를 취소 fn
하고 fn
위와 같이 새로운 규칙을 그대로 유지 합시다 .
$ export -nf fn
이제 함수 fn
는 더 이상 내 보내지 않지만 일반 변수 fn
는 내보내고 그 안에 들어 () { echo "direct" ; }
있습니다.
이제 서브 쉘이 시작하는 일반 변수를 ()
보면 나머지 변수를 함수 정의로 해석합니다. 그러나 이것은 새로운 쉘이 시작될 때만 입니다. 위에서 보았 듯이, 일반 쉘 변수로 시작 ()
한다고해서 함수처럼 작동하지는 않습니다. 서브 쉘을 시작해야합니다.
이제 "shellshock"버그 :
방금 보았 듯이 새 쉘이 일반 변수의 정의를 수집 할 때 ()
함수로 해석합니다. 그러나 함수를 정의하는 닫는 중괄호 뒤에 더 많은 것이 있으면 거기에있는 모든 것을 실행 합니다.
이것들은 다시 한 번 요구 사항입니다.
- 새로운 배쉬가 생성됩니다
- 환경 변수가 수집됩니다
- 이 환경 변수는 "()"로 시작하고 중괄호 안에 함수 본문을 포함하고 이후에 명령을가집니다.
이 경우 취약한 bash는 후자의 명령을 실행합니다.
예:
$ export ex='() { echo "function ex" ; }; echo "this is bad"; '
$ bash
this is bad
$ ex
function ex
$
정기적으로 내 보낸 변수 ex
는 함수로 해석 된 서브 쉘로 전달 ex
되었지만 this is bad
서브 쉘이 생성 될 때 후행 명령이 실행되었습니다 ( ).
매끄러운 한 줄 테스트 설명
Shellshock 취약점을 테스트하는 데 널리 사용되는 단일 라이너는 @jippie의 질문에서 인용 된 것입니다.
env x='() { :;}; echo vulnerable' bash -c "echo this is a test"
여기에 고장이 있습니다. 먼저 :
bash는의 약어입니다 true
. true
그리고 :
둘 다 bash에서 true로 평가합니다 (추측).
$ if true; then echo yes; fi
yes
$ if :; then echo yes; fi
yes
$
둘째, env
(또한 bash는 내장) 명령을 사용하여 환경 변수를 출력 (우리가 위에서 본 바와 같이)뿐만 아니라 그 명령에 주어진 보낸 변수 (또는 변수)와 하나의 명령을 실행하는 데 사용할 수 있습니다, 그리고 bash -c
에서 하나의 명령을 실행의 명령 줄 :
$ bash -c 'echo hi'
hi
$ bash -c 'echo $t'
$ env t=exported bash -c 'echo $t'
exported
$
이 모든 것들을 함께 꿰매어 bash를 명령으로 실행하고 (예와 같이 bash -c echo this is a test
) 더미 작업을 수행 ()
하고 서브 쉘이 함수로 해석하도록 시작하는 변수를 내보낼 수 있습니다. 쉘 쇼크가 존재하면 서브 쉘에서 후행 명령도 즉시 실행합니다. 우리가 전달하는 함수는 우리와 관련이 없기 때문에 (구문 분석해야합니다!) 상상할 수있는 가장 짧은 유효한 함수를 사용합니다.
$ f() { :;}
$ f
$
여기서 함수 f
는 :
명령을 실행하여 true를 반환하고 종료합니다. 이제 "악한"명령을 추가하고 정규 변수를 서브 쉘로 내 보내면 승리합니다. 다시 한 줄짜리가 있습니다.
$ env x='() { :;}; echo vulnerable' bash -c "echo this is a test"
따라서 끝 x
이 echo vulnerable
붙은 간단한 유효한 함수를 사용하여 일반 변수로 내보내집니다 . 이것은 bash에 전달되며 bash x
는 함수 (우리가 신경 쓰지 않는)로 해석 한 다음 아마도 echo vulnerable
shellshock이 있는 경우 if를 실행합니다 .
this is a test
메시지 를 제거하여 원 라이너를 약간 줄일 수 있습니다 .
$ env x='() { :;}; echo vulnerable' bash -c :
이것은 귀찮게하지 않고 this is a test
자동 :
명령을 다시 실행 합니다. (이를 그대로두면 -c :
서브 쉘에 앉아 수동으로 종료해야합니다.) 아마도 가장 사용자 친화적 인 버전은 다음과 같습니다.
$ env x='() { :;}; echo vulnerable' bash -c "echo If you see the word vulnerable above, you are vulnerable to shellshock"