'Hacking/Crypto'에 해당되는 글 1건

반응형

0. 개요

웹 어플리케이션에서 입력값 검증을 할 경우 Hash value의 유일성을 이용하는 경우가 종종 있다.

이 때 공격자는 hash value를 만드는 SecretKey 값을 알지 못하더라도 원본 메시지와 그에 따른 해쉬값을 알고 있을 경우 이를 토대로 원하는 데이터를 추가한 해쉬값을 구할 수 있는데, 이를 Length extension attack이라고 한다.



1. Message Authentication Code(MAC)이란?

Length extension attack은 MAC(Message Authentication Code)에서 exploit 된다. 여기서 MAC란 간단히 말해 메시지가 변하지 않았다는 것을 증명하기 위한 코드라고 보면 된다.


이 MAC을 계산하기 위해 MD5, SHA-1, SHA-2와 같은 잘 알려진 해시 알고리즘과 sender와 receiver 사이에 공유되는 secret key이 함께 사용된다. secret key(K)를 메시지(M)에 추가하여 해시(H)를 계산한 것이 MAC이다. sender는 해당 HASH와 함께 원본 메시지를 receiver에게 전송한다. receiver는 미리 공유된 비밀키 K와 수신 메시지 M으로부터 해시 H'를 계산하고 전달받은 해시 H와 비교하여 메시지가 변하였는지 진위 여부를 확인한다.


위의 문장을 하나의 그림으로 표현하면 다음과 같다.



2. 공격이 이루어지는 방식

Length extension attack은 공격자가 원본 메시지를 비밀키로 해시한 값(H1)와 원본 메시지(M1)를 알 경우 메시지 M2가 추가된 (M1+M2)에 대한 해시값을 구할 수 있다.


위 문장을 하나의 그림으로 표현하면 다음과 같다.



3. 공격 분석

[ 2. 공격이 이루어지는 방식 ]에서 말한 새로운 메시지가 추가된 해시 H2를 구하는 방식에 대하여 예시와 함께 더 자세히 분석해보자.


다음과 같은 가정으로 예시를 진행하겠다.


 ◎ secret = "rootable"

 ◎ data = "user"

 ◎ H = md5()

 ◎ signature = hash(secret||data) = e4ff40aabfd7bbcd96aa5a5a8d2e2701

 ◎ append = "hacker"


사용자는 "user" 라는 메시지와 이에 따른 해시 값을 알고 있다는 가정하에 공격이 진행된다. 물론 사용자는 해시 값의 길이(128-bit)를 통해 해시 알고리즘은 MD5임을 알 수 있을 것이다.


3.1 Padding

새로운 해시 H2를 만들기 위해서는 해시 계산할 시의 패딩에 대해 알아야 한다.


해시(secret + data)를 계산할 때 문자열은 하나의 '1' 비트와 여러 '0' 비트로 패딩되며, 뒤이어 문자열의 길이가 따라온다. 이것을 hex 형태로 보면 패딩은 0x80 뒤에 여러 0x00 바이트 및 길이가 붙는 형식으로 이루어진다.  여기서 0x00 바이트와 길이에 예약된 바이트 수 및 길이가 인코딩되는 방식은 알고리즘과 블록 사이즈에 따라 달라진다.


MD4, MD5, SHA-1, SHA-256을 포함한 많은 알고리즘들은 64로 나누었을 때 나머지가 56바이트일 때까지 패딩된다. 이를 다시 말하자면 길이가 전체 블록(64바이트)보다 8바이트 낮을 때까지 패딩된다. 왜냐하면 8바이트는 인코딩된 길이 필드의 사이즈이기 때문이다.


길이 필드의 바이트 순서 또한 알고리즘에 따라 달라지는데 MD4, MD5는 little-endian인 반면, SHA 알고리즘을은 big-endian이다.


여기까지의 내용을 우리의 예시에 적용시켜보도록 하겠다.


secret와 data를 연결한 length("rootableuser")는 12(0x0c) 바이트 또는 96(0x60) 비트이다. 따라서 우리는 12 바이트의 데이터, ("rootableuser"), 44 바이트의 패딩 (80 00 00 ....), 그리고 8 바이트의 리틀엔디안 길이 필드 (60 00 00 00 00 00 00 00), 총 64 바이트 ( 또는 한 block)을 가지고 있다. 


이것을 함께 나타내면 다음과 같다.

◎ "rootable" = secret

◎ "user" = data

◎ 80 00 00 ... = 0x80으로 시작하는 44 byte의 패딩

◎ 60 00 00 00 00 00 00 00 = 리틀 엔디안으로 나타낸 bit 길이 


이것이 H1으로 해시된 정확한 데이터이다.


3.2 공격

위에서 H1 해시의 데이터를 확인하였으므로 실제적인 공격이 어떻게 수행되는지 보자.


먼저 문자열에 추가할 메시지인 "hacker"를 추가해보자. 이것은 다음과 같다.


위의 블록에 대한 해시를 계산하는 것은 두가지 방식이 있다.

① 새로운 메시지를 추가하여 해시화한다.

② 첫번째 블록의 끝에서 시작하여 이미 알고있는 시그니처를 이용해 메시지가 추가된 상태의 해시를 구한다.


첫번째 방식은 서버에서 할 것이고 두번째 방식은 공격자가 할 것이다. 우선 서버에서의 방식을 보도록 하자.


3.3 서버에서의 계산

서버는 비밀키를 문자열 앞에 붙일 것이므로 우리는 비밀키를 제외한 문자열을 전송해야 한다.


그럼 서버는 여기에 비밀키를 추가하여 다음과 같은 문자열이 만들어진다.


그리고 이 문자열의 해시는 다음과 같다.

2ae22da066e3311036d6edc5924db87a


해당 해시값을 구하는 python 코드는 다음과 같다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import hashlib
 
secret="rootable"
data="user"
string=""
append="hacker"
 
string+=secret
string+=data
string+="\x80\x00\x00\x00\x00\x00\x00\x00"\
        "\x00\x00\x00\x00\x00\x00\x00\x00"\
        "\x00\x00\x00\x00\x00\x00\x00\x00"\
        "\x00\x00\x00\x00\x00\x00\x00\x00"\
        "\x00\x00\x00\x00\x00\x00\x00\x00"\
        "\x00\x00\x00\x00"\
        "\x60\x00\x00\x00\x00\x00\x00\x00"
string+=append
 
print hashlib.md5(string).hexdigest()
cs


3.4 클라이언트에서의 계산

이제 비밀키 없이 추가할 메시지가 포함된 해시값을 구해보도록 하자.

먼저 우리는 다음과 같은 값들을 가지고 있는지 확인한다 : 원본 메시지, 추가할 메시지, 해시 알고리즘, 원본 해시값


우리는 기존 해시 알고리즘을 이용한 새로운 해시 함수 H'를 정의해야하며 이는 원본 해시값으로부터 시작한다.


영문사이트에 C언어로 되어있는 것을 Python 코드로 변경해보려 했는데 생각보다 쉽지않다.

MD5에 대해 더 깊이 알아보고 업데이트하겠다.


궁금하신 분들은 https://github.com/cbornstein/python-length-extension의 코드를 분석해보세요.


4. 공격 툴

해당 기법을 python에서 편하게 할 수 있도록 도와주는 것이 hashpumpy이다.

hashpumpy 사용법은 다음과 같다.


import hashpumpy

hash,message = hashpumpy.hashpump('Know Hash(H1)','Known Message(M1)','Message to appen(M2)',KeyLength)



참고

https://blog.skullsecurity.org/2012/everything-you-need-to-know-about-hash-length-extension-attacks

https://www.roguesecurity.in/2017/05/14/length-extension-attack-and-how-it-can-be-exploited/

반응형
블로그 이미지

rootable

,