Bash에는 분명히 취약점(CVE-2014-6271)이 있습니다.Bash 특수 제작된 환경 변수 코드 주입 공격
나는 무슨 일이 일어나고 있는지 알아내려고 노력하고 있지만, 내가 그것을 이해하고 있는지 완전히 확신할 수 없습니다. echo
작은따옴표로 어떻게 처리하나요?
$ env x='() { :;}; echo vulnerable' bash -c "echo this is a test"
vulnerable
this is a test
편집 1:패치된 시스템은 다음과 같습니다.
$ env x='() { :;}; echo vulnerable' bash -c "echo this is a test"
bash: warning: x: ignoring function definition attempt
bash: error importing function definition for `x'
this is a test
편집 2: 관련 취약점/패치가 있습니다.CVE-2014-7169약간 다른 테스트를 사용합니다.
$ env 'x=() { :;}; echo vulnerable' 'BASH_FUNC_x()=() { :;}; echo vulnerable' bash -c "echo test"
패치되지 않은 출력:
vulnerable
bash: BASH_FUNC_x(): line 0: syntax error near unexpected token `)'
bash: BASH_FUNC_x(): line 0: `BASH_FUNC_x() () { :;}; echo vulnerable'
bash: error importing function definition for `BASH_FUNC_x'
test
부분(이전 버전) 패치 출력:
bash: warning: x: ignoring function definition attempt
bash: error importing function definition for `x'
bash: error importing function definition for `BASH_FUNC_x()'
test
패치 출력CVE-2014-7169까지:
bash: warning: x: ignoring function definition attempt
bash: error importing function definition for `BASH_FUNC_x'
test
편집 3: 이야기는 계속됩니다:
답변1
bash는 내보낸 함수 정의를 환경 변수로 저장합니다. 내보낸 함수는 다음과 같습니다.
$ foo() { bar; }
$ export -f foo
$ env | grep -A1 foo
foo=() { bar
}
즉, 환경 변수에는 foo
리터럴 콘텐츠가 있습니다.
() { bar
}
Bash의 새로운 인스턴스가 시작되면 특별히 제작된 환경 변수를 찾아 함수 정의로 해석합니다. 직접 작성하여 여전히 작동하는지 확인할 수도 있습니다.
$ export foo='() { echo "Inside function"; }'
$ bash -c 'foo'
Inside function
안타깝게도 문자열(환경 변수)에서 함수 정의를 구문 분석하면 예상보다 더 광범위한 영향을 미칠 수 있습니다. 패치되지 않은 버전에서는 함수 정의가 종료된 후 발생하는 임의의 명령도 해석합니다. 이는 환경에서 허용 가능한 함수형 문자열을 결정하는 데 제약이 부족하기 때문입니다. 예를 들어:
$ export foo='() { echo "Inside function" ; }; echo "Executed echo"'
$ bash -c 'foo'
Executed echo
Inside function
bash 시작 중에 함수 정의 외부의 에코가 예기치 않게 실행된다는 점에 유의하세요. 함수 정의는 평가 및 활용의 한 단계일 뿐입니다. 함수 정의 자체와 사용되는 환경 변수는 임의적입니다. 쉘은 foo
자신이 알고 있는 함수 정의의 제약 조건을 충족하는 것으로 보이는 환경 변수 sees 를 살펴보고 행을 평가하며 실수로 echo(악성 여부와 상관없이 모든 명령일 수 있음)를 실행합니다.
변수 자체는 일반적으로 허용되지 않거나 그 안에 포함된 임의의 코드를 직접 호출할 것으로 예상되지 않기 때문에 이는 안전하지 않은 것으로 간주됩니다. 어쩌면 프로그램이 신뢰할 수 없는 사용자 입력을 기반으로 환경 변수를 설정할 수도 있습니다. 놀랍게도 이러한 환경 변수는 코드에 명시된 이유로 환경 변수를 사용하여 명시적인 의도 없이 사용자가 임의의 명령을 실행할 수 있는 방식으로 조작될 수 있습니다.
이는 가능한 공격의 예입니다. 귀하가 실행하는 웹 서버는 수명 주기의 일부로 어딘가에서 취약한 셸을 실행합니다. 웹 서버는 환경 변수를 bash 스크립트에 전달합니다. 예를 들어 CGI를 사용하는 경우 HTTP 요청에 대한 정보는 일반적으로 웹 서버의 환경 변수로 포함됩니다. 예를 들어 HTTP_USER_AGENT
사용자 에이전트에 설정될 수 있는 항목입니다. 이는 사용자 에이전트를 '() { :: }; echo foo '와 같이 스푸핑하면 쉘 스크립트가 echo foo
실행될 것임을 의미합니다. 다시 말하지만, echo foo
악의적이든 아니든 무엇이든 될 수 있습니다.
답변2
이는 무슨 일이 일어나고 있는지 추가로 증명하는 데 도움이 될 수 있습니다.
$ export dummy='() { echo "hi"; }; echo "pwned"'
$ bash
pwned
$
취약한 셸을 실행 중인 경우 새 하위 셸을 시작하면(여기서는 bash 문만 사용됨) echo "pwned"
시작 과정의 일부로 임의의 코드( )가 즉시 실행되는 것을 볼 수 있습니다. 분명히 쉘은 환경 변수(가상)에 함수 정의가 포함되어 있음을 확인하고 해당 정의를 평가하여 함수가 해당 환경에 정의되도록 합니다(함수를 실행하지 않는다는 점에 유의하십시오. 이는 "hi"를 인쇄합니다.)
불행하게도 함수 정의뿐만 아니라 함수 정의 다음에 나오는 잠재적으로 악의적인 문을 포함하여 환경 변수 값의 전체 텍스트도 평가합니다. 초기 함수 정의가 없으면 환경 변수는 평가되지 않으며 단순히 텍스트 문자열로 환경에 추가됩니다. Chris Down이 지적했듯이 이는 내보낸 쉘 기능 가져오기를 구현하기 위한 특정 메커니즘입니다.
새 셸에 정의된 함수를 볼 수 있고(내보낸 것으로 표시됨) 이를 실행할 수 있습니다. 또한 더미는 텍스트 변수로 가져오지 않았습니다.
$ declare -f
dummy ()
{
echo "hi"
}
declare -fx dummy
$ dummy
hi
$echo $dummy
$
이 함수의 생성과 실행 시 수행되는 모든 작업은 공격의 일부가 아닙니다. 이는 공격을 수행하기 위한 도구일 뿐입니다. 요점은 공격자가 내보낸 환경 변수에 배치된 텍스트 문자열에 악성 코드를 제공할 수 있고 그 앞에 최소한의 중요하지 않은 함수 정의를 제공할 수 있다면 서브셸이 시작될 때 해당 코드가 실행된다는 것입니다. 이는 일반적인 이벤트입니다. 스크립트. 또한 스크립트의 권한으로 실행됩니다.
답변3
나는 위의 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
현재 셸에서 새 기능을 사용할 수 있습니다 . 그러나 **sub** 쉘을 생성하면 그렇게 됩니다.
함수 내보내기를 취소 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
유창한 한 줄 테스트 설명
@jippie의 질문에는 Shellshock 취약점을 테스트하는 데 널리 사용되는 한 줄이 인용되었습니다.
env x='() { :;}; echo vulnerable' bash -c "echo this is a test"
분석 내용은 다음과 같습니다. 첫째, :
bash에서는 true
. bash 에서는 true
둘 다 :
true로 평가됩니다.
$ if true; then echo yes; fi
yes
$ if :; then echo yes; fi
yes
$
둘째, 이 명령(bash에도 내장되어 있음)은 위에서 본 것처럼 환경 변수를 인쇄하지만 단일 명령을 실행하고 해당 명령에 하나 이상의 내보내기 변수를 제공하고 명령줄에서 단일 명령을 실행하는 데 env
에도 사용할 수 있습니다 .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
)을 제공하고 로 시작하는 변수를 내보내 ()
서브셸이 이를 함수로 해석하도록 할 수 있습니다. shellshock이 있는 경우 하위 셸의 모든 후행 명령도 즉시 실행됩니다. 우리가 전달하는 함수는 우리와 아무 관련이 없으므로(하지만 구문 분석해야 합니다!) 상상할 수 있는 가장 짧고 효율적인 함수를 사용합니다.
$ f() { :;}
$ f
$
여기의 함수는 명령을 f
실행하고 true를 반환한 후 종료됩니다. :
이제 몇 가지 "악한" 명령을 추가하고 일반 변수를 서브쉘로 내보내면 승자가 됩니다. 또 다른 한 줄의 내용은 다음과 같습니다.
$ env x='() { :;}; echo vulnerable' bash -c "echo this is a test"
따라서 x
일반 변수로 내보내고 echo vulnerable
끝에 간단한 유효한 함수를 추가하십시오. 이는 bash로 전달되어 이를 x
함수(우리는 신경 쓰지 않음)로 해석한 다음 echo vulnerable
shellshock이 있는 경우 실행할 수 있습니다.
메시지를 제거하여 조금 단축할 수 있습니다 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"
답변4
이 내용은 링크된 기사에 설명되어 있습니다.
Bash 쉘을 호출하기 전에 특별히 제작된 값으로 환경 변수를 생성할 수 있습니다. 이러한 변수에는 셸이 호출되면 실행될 코드가 포함될 수 있습니다.
이는 호출하는 bash가 -c "echo this is a test"
호출될 때 작은따옴표로 묶인 코드를 실행한다는 것을 의미합니다.
Bash에는 기능이 있지만 구현이 다소 제한되어 있으며 이러한 bash 기능을 환경 변수에 넣을 수 있습니다. 이 결함은 이러한 함수 정의의 끝에(환경 변수 내에서) 추가 코드가 추가될 때 발생합니다.
게시한 코드 예제는 호출 bash가 할당을 수행한 후에도 문자열 평가를 중단하지 않는다는 사실을 활용한다는 의미입니다. 이 예에서는 기능 할당입니다.
제가 이해한 바로는 귀하가 게시한 코드 조각의 특별한 점은 실행하려는 코드 앞에 함수 정의를 배치하면 일부 보안 메커니즘을 우회할 수 있다는 것입니다.