본문 바로가기
드림핵

[wargame.kr] dun worry about the vase 풀이

by jwcs 2024. 2. 24.
728x90

https://dreamhack.io/wargame/challenges/325

 

[wargame.kr] dun worry about the vase

Description Do you know about "padding oracle vulnerability" ?

dreamhack.io

 

https://bperhaps.tistory.com/entry/%EC%98%A4%EB%9D%BC%ED%81%B4-%ED%8C%A8%EB%94%A9-%EA%B3%B5%EA%B2%A9-%EA%B8%B0%EC%B4%88-%EC%84%A4%EB%AA%85-Oracle-Padding-Attack

 

오라클 패딩 공격 기초 설명 Oracle Padding Attack

Padding Oracle Attack for beginner K.knock 손민성 본 문서는 패딩오라클 어택에 전반적인 이해와 공부를 위해 작성되었으며, 본 문서를 이용하여 벌어지는 일에 대한 책임은 자신에게 있습니다. 오라클

bperhaps.tistory.com

위 사이트에서 큰 도움을 받았다.

 

패딩 오라클 문제이다.

/

기본 페이지는 로그인 페이지다. guest로 로그인할 수 있도록 값이 입력돼있다.

 

/main.php

guest로 로그인했다. admin 세션을 구하라고한다.

세션 확인

L0g1n이라는 쿠키가 다음과 같이 있다.(원래는 url 인코딩된 값을 가지고 있었는데 가독성을 위해 디코딩한 값을 넣었다.)

 

패딩 오라클로부터 힌트를 받아 앞쪽 인코딩 부분이 초기벡터, 뒤쪽 부분이 암호화된 data인 것으로 추측된다.

그럼 data 부분을 복호화 한 후 iv로 xor한 값이 guest이기 때문에 `hi guest ~~~`가 나온 것으로 보인다. 따라서 `admin\03\03\03`을 IV값으로 XOR하면 flag를 구할 수 있을 것이지만, 그럼 공부하는 맛이 안사니 검증 과정을 거치면서 패딩 오라클에 대해 알아보자.

base64 decode

바로 디코딩하니까 이런 값이 나왔다. 이대로 사용하기는 어려울 것 같아서 직접 디코딩한 후 16진수로 변환해줬다. base64는 비트스트림을 6비트씩 쪼갠 후 각 영역을 테이블에 맞춰 매핑시킨다. 이 값이 우리가 본 base64 인코딩된 값인 것이다.

base64 인코딩 표

이걸 역으로 해서 구해봤다.

52225537DC145492

초기 벡터 부분만 했을 때 위와 같은 값이 나왔다.

 

패딩 오라클을 활용해서 문제는 푸는 방법에 대해 알아보자.

패딩 오라클은 패딩이 올바르게 삽입됐는지 검사하고 대답하는 시스템이다. 이 문제에서는 4가지 응답 패턴을 보였다.

 

1. 정상

정상

검사 결과 오류가 없는 정상적인 상태다

 

2. Invalid iv

Invalid iv

잘못된 초기 벡터 값을 넣었을 때

 

3. Invalid user

Invalid user

패딩이 정상적으로 이루어졌으나 복호화된 값이 유효한 user의 값과 일치하지 않을 경우

 

4. padding error

padding error

패딩이 정상적으로 이루어지지 않은 상태

 

2번째 invalid iv의 경우 본인이 잘못된 풀이로 가고 있는 경우가 아니라면 뜨지 않을 것이다.

정상적으로 풀이가 진행된다면 1,3,4의 경우가 뜰 것이다. 그럼 이러한 것을 이용해서 어떻게 풀 수 있다는 것인지 알아보자.

복호화 과정

대충 복호화 과정에 대해서 그려봤다. 암호화된 값을 복호화하면 `IV xor 평문`의 값이 나올 것이다. 이 값과 IV가 xor한다면 평문만 남게 될 것인데, 우리는 IV를 조작할 수 있다. 평문만 남았을 때 unpadding 과정에서 오류검출이 이루어질 것이다. 

우리는 IV를 조작해서 `IV xor plain`을 구할 수 있다.

악필 ㅈㅅ

 우리가 가지고 있는 IV을 iv로 표현했다. 일반적으로 iv를 조작하면 패딩이 제대로 이루어지지 않아서 padding error가 뜰 것이다. 하지만 조작이 잘 되어 결과값 끝 한 바이트가 0x01이 된다면 unpadding이 이루어질 것이다. unpadding이 이루어진다면 유효한 유저를 찾지 못해 `unvalid user`가 나오게 될 것이다. 이 결과를 바탕으로 unpadding이 이루어지나 안이루어 지나를 판단할 수 있다.

 unpadding이 이루어진다면 위의 사진과 같은 과정을 통해 `IV xor plain`을 구할 수 있다. 이러한 과정을 똑같이 거쳐서 2바이트, 3바이트.... 8바이트까지 구할 수 있다. 그럼 모든 바이트의 `IV xor plain`을 구할 수 있는 것이다.

 그럼 어떻게 iv를 조작해야 0x01이 되는 경우를 찾을 수 있을까? 브루트 포싱이다.

import requests
import base64
original_base64="UiJVN9wUVJI=E6YQ34GHm5s="
iv="52225537DC145492"
IV_plain= "35573044A8175791"

def find_non_empty_response():
    url = "http://host3.dreamhack.games:20774/main.php"
    val_prefix = ''  # val의 고정된 부분
    val_suffix = '5F384CA01F5F99'

    for i in range(0,256):  # 00부터 FF까지 반복
        hex_val = f"{val_prefix}{i:02X}{val_suffix}"  # 16진수 값을 생성
        
        hex_bytes = bytes.fromhex(hex_val)  # 16진수를 바이트로 변환
        base64_encoded = base64.b64encode(hex_bytes).decode()  # Base64로 인코딩
        
        cookies = {'L0g1n': base64_encoded+'E6YQ34GHm5s='}  # 쿠키에 인코딩된 값을 설정
        
        response = requests.get(url, cookies=cookies)  # 요청을 보내고 응답을 받음
        
        print(hex_val)
        text = '<script>alert("padding error");window.location.href=\'./index.php\';</script>'
        if response.text.strip() != text:  # 응답이 공백이 아닌 경우
            return hex_val, response.text.strip()  # 16진수 값과 응답 텍스트를 반환

    return None, "No non-empty response found."

print(find_non_empty_response())

위 코드에서 `IV_plain`와 `val_prefix`, `val_suffix`는 수동으로 수정해가며 풀었다. 

코드에 대해 설명해보자면 내가 가진 iv 값 중 수정되기 전의 값을 val_prefix

브루트 포싱을 통해 알아낸 `IV xor plain`의 값을 `IV_plain`에 수동으로 적었다

뒷 부분은 브루트 포싱에 해당하지 않으면서 언패딩에 관여하는 부분을 val_suffix에 넣었다

그 아래는 브루트 포싱에 대한 내용이다.

 

브루트 포싱 중, 응답 값이 padding error가 아니라면 unpadding에 성공했다 간주하고 그 값을 출력하도록 했다.

 

예시로 한 사이클에 대해서 설명해보겠다.

첫 바이트 째를 구할 때, `52225537DC145400`~`52225537DC1454FF`까지 브루트 포싱을 하는 경우다.

val_prefix에는 `52225537DC1454`가 들어가며 val_suffix에는 ``가 들어간다. 

unpadding 성공

언패딩 성공인 경우 끝 한바이트 `90`을 `0x01`과 xor 해준다. 이 값이 IV_plain의 끄트머리 한 바이트다.

앞으로는 언패딩의 값이 `0x02`, `0x03`....`0x08`이 될테니 상황에 맞춰서 xor 값을 바꿔주면 된다.

 

IV_plain= "35573044A8175791"

위와 같은 방법으로 알아낸 값이다. 이 값을 초기 벡터와 XOR 해주면 plain의 값을 알 수 있을 것이다.

 

plain

`35573044A8175791` XOR `52225537DC145492`을 한 결과다. 예상대로 guest라는 문자열과 `030303`만큼 패딩되어 있다. 그러면 admin030303을 입력하면 flag를 구할 수 있을 것이다.

 

`admin + padding 03`을 16진수로 표현한 결과 ` 54335D2DC6145492`이다. base64로 인코딩하면 `VDNdLcYUVJI=`이다. 이 값을 넣어보자.

flag

짜잔

 

대응 방안

패딩 오라클에 대한 대응이 이루어지기 힘들어 사용이 중지됐다고 들었다.

728x90
반응형

'드림핵' 카테고리의 다른 글

[드림핵][wargame.kr] dmbs335 풀이  (0) 2024.02.25
[드림핵] BypassIF 풀이  (0) 2024.02.25
[드림핵][wargame.kr] md5 password 풀이  (0) 2024.02.23
[드림핵] web-deserialize-python 풀이  (1) 2024.02.12
[드림핵] funjs 풀이  (1) 2024.02.11