shellshock
디렉토리
shellshock.c
포인트
1. 환경 변수 설정하는 과정에서 취약점이 발생
"() {"로 시작하는 문자열을 시스템 환경변수에 저장하면 동일한 이름을 가진 함수로 선언됨
이 과정에서 함수 선언문 끝에 임의의 명령어를 추가로 삽입할 경우,
bash가 이 후 코드를 무시하거나 오류를 발생하지 않고 추가로 삽입한 명령어를 계속 실행
2. "/home/shellshock/bash"는 서브쉘
bash를 실행시킴으로 서브쉘이 실행되는게 다른 명령어 실행되는 거랑 뭔 상관?
bash의 동작 원리
1. bash 실행
2. bash 환경변수 초기화 -> 여기서 취약점 발생
3. bash shell prompt 출력
4. 명령어 기다림
5. (명령어 수행할 경우) 명령어를 문자열로 저장해 해당 문자열 parsing(해석) 수행
-> bash 명령어 해석기는 함수를 환경변수에 저장하는 방식 사용
6. parsing된 구조체를 이용해 명령어 수행
foo 라는 변수 선언함 -> bash -c 통해 서브쉘 실행시킴
이 때 조작된 변수를 환경변수로 초기화해주게 되고 그 과정에서 명령어 실행됨
이 취약점은 Shell을 획득하지 않은 상태에서도 공격가능
왜? bash 서브쉘이 실행될 때 {} 이후에 있는 코드가 실행되는 것이기 때문
-> 굳이 shell통해서가 아니라도 특정 프로그램이 subshell 실행하면 가능
조금 더 심화적으로 들어가보면
bash가 소스코드 분석시,
evalstring.c 파일 내 정의되어 있는 parse_and_execute()함수에서 bash에 전달된 명령어를 처리하여 실행
이 때 명령어 문자열을 처리하는 과정에서 while을 사용하는데,
함수 선언문 뒤에 명령어가 삽입된 것을 확인하고 반복문을 종료시키는 코드가 없다.
따라서 함수 선언문의 끝까지 처리한 뒤에도 반복문이 계속 실행되어 삽입된 명령어가 실행됨
ex1. foo의 함수 인식과 이후 명령어 수행
export foo='() { echo hello; }; 은 변수 환경 변수를 설정하는 형식임에도 '() {'로 시작하면
이후 subshell이 실행될 때 {...} 부분을 함수로 인식하고 뒤에 삽입된 명령어를 수행
ex2. echo test 수행후 echo hi 수행 - test출력되면 취약
ex3.
정답
1) 서브쉘에서 /bin/cat flag 결과로 출력한 문자열 확인
2) 서브쉘에서 /bin/cat flag 결과로 출력한 문자열을 환경변수로 설정하고 확인
참고
1. 환경변수
1) 설정
- 변수 환경 변수 : export foo=3
- 함수 환경 변수 : foo() { echo hello; } -> export -f foo
* '{'와 'echo' 사이는 항상 한 칸 이상의 공백 필요 -> 없으면 syntax error
export 안해주면 현재 실행되는 bash에서만 해당 환경 변수 유효, 해주면 subshell까지 유효
같은 이름으로 함수와 변수 모두 선언 가능
2) 접근 : 변수- $foo, 함수-foo
3) 삭제 : 변수- unset foo, 함수- export -nf foo
2. env과 export의 차이
env : 환경변수를 출력
export : 환경변수 설정(값을 지정한 후 export)
쉘 변수를 환경변수로 만들어줌 -> 로그아웃하면 초기화
영구적으로 설정 : /etc/profile(전체 시스템) or ~/.bash_profile(개인 사용자) 파일 안에 선언
3. echo에서 작은 따옴표(''), 큰 따옴표(""), 역따옴표(``) 차이
작은 따옴표 : 문자열 그대로 ex. echo '$HOME' -> $HOME
큰 따옴표 : 변수가 가진 값 ex. echo "$HOME" -> /home
역 따옴표 : 명령문을 실행한 결과 ex. echo `pwd` -> /home
4. bash 함수 반환 값 받기
- 일반적인 방법 : echo
function foo() { echo 'hello'; }
ret=`foo`
echo $ret -> hello
- 전역변수로 전달
function foo() { ret=hello2; }
foo -> echo $ret -> hello2 출력
- return으로 전달 (정수 1~255까지만)
function foo() { return 123; }
foo
echo $? -> 123
5. /bin/bash -c 옵션 : 뒤에 오는 문자열 실행
ex. /bin/bash -c 'echo "test"' : 쉘 실행 후 echo "test" 실행
= /bin/bash -c 'echo test'
6. 리눅스 쉘
1) Shell의 위치 : H.W - Kernel - Shell - 사용자 or 응용프로그램
- 구동과정 : 사용자가 Shell에게 자연어로 명령 -> Shell은 명령을 기계어로 번역해 Kernel로 전달
-> Kernel이 명령 수행 후 결과를 Shell에 전달 -> Shell이 자연어로 번역해 사용자에게 전달
즉, Shell은 의사소통 담당
2) 현재 사용가능한 Shell 출력 : cat /etc/shells
3) 현재 사용중인 Shell 출력 : echo $SHELL
4) 로그인쉘/서브쉘의 차이
로그인쉘 : 쉘에서 실행된 내용이나 실행환경은 로그아웃 할 때까지 없어지지 않음
서브쉘 : 쉘에서 실행된 내용이나 실행환경이 서브쉘이 종료되는 순간 없어짐
사용자가 필요에 따라 그때그때 임시적으로 변경해 사용하는 쉘
사용자가 되면 "/etc/passwd"파일에 그 정보가 생성되어 있다.
ex. 서브쉘에서 cp등으로 디렉토리 위치 바껴도 서브쉘이 종료되면 작업중이었던 디렉토리 위치는 변경되지 않음
7. { 명령;명령 }과 $(명령) 차이
- { 명령;명령 } : 현재 쉘에서 실행
- `명령`, $명령 : 서브쉘에서 실행하는 거라 아웃풋을 현재 쉘에서 받을 수 없음
8. 쉘에서 다수의 작업처리
bash ; ps의 ps는 서브쉘의 ps이기 때문에 본쉘에서 출력 되지 않는다.