1. ๋ฌธ์
https://dreamhack.io/wargame/challenges/330
[wargame.kr] crack crack crack it
Description .htaccess crack! can you local bruteforce attack?
dreamhack.io
2. ํด๊ฒฐ ๊ณผ์
(1) ๋ฌธ์ ํ์ด์ง ํ์ธ
htpasswd ํ์ผ์ ๋ถ์ํด์ Brute Force๋ฅผ ํตํด ํจ์ค์๋๋ฅผ ์์๋ด์ผ ํ๋ ๋ฌธ์ ์ด๋ค.

htpasswd ํ์ผ์ ์ผ๋ฐ์ ์ผ๋ก HTTP ์ธ์ฆ์ ์ํด ์ฌ์ฉ๋๋ ํ์ผ์ด๋ค. $์๊ณ ๋ฆฌ์ฆ$์ํธ$ํด์๋๋น๋ฐ๋ฒํธ์ผ๋ก ๊ตฌ์ฑ๋๋ค.
์ด๋ ํจ์ค์๋๋ ํด์ํ๋์ด ์ ์ฅ๋๊ธฐ ๋๋ฌธ์ G4HeulB๋ก ์์ํ๋ค๋ ํํธ๋ฅผ ํตํด ์ต๋ํ ํจ์จ์ ์ผ๋ก ๋ธ๋ฃจํธ ํฌ์ค ๊ณต๊ฒฉ์ ์ฌ์ฉํด์
๋น๋ฐ๋ฒํธ๋ฅผ ์์๋ด์ผ ํ๋ค.
- username:$1$saltvalue$hashed_password :
- MD5: $1$๋ก ์์
- username:$sha1$saltvalue$hashed_password
- SHA-1: $sha1$๋ก ์์์ ์ฒด ํด์ ๋ฌธ์์ด์ ๋ณดํต ๋ค์๊ณผ ๊ฐ์ ๊ตฌ์กฐ๋ฅผ ๊ฐ์ง๋๋ค: $์๊ณ ๋ฆฌ์ฆ$์ํธ$ํด์๋๋น๋ฐ๋ฒํธ
- username:$2y$10$saltvalue$hashed_password
- bcrypt: $2y$ ๋๋ $2a$๋ก ์์ (๋ฒ์ ์ ๋ฐ๋ผ ๋ค๋ฆ)
์ผ๋ฐ์ ์ผ๋ก MD5, SHA-1, bcrypt ๋๋ APR1(MD5 ๋ณํ) ๋ฑ์ ํด์ฑ ์๊ณ ๋ฆฌ์ฆ์ด ์ฌ์ฉ๋๊ธฐ ๋๋ฌธ์ ์ด๋ค ํด์ฑ ์๊ณ ๋ฆฌ์ฆ์ ์ฌ์ฉํ๋์ง
์์๋ด์ผ ํ๋ค. htpasswd ํ์ผ์์ ํ์ธ๋ ํจ์ค์๋ ํด์ ๊ฐ์ $1$RF1ij51F$f7Ak1R4/gX3WOI9gliA981์ด๋ฉฐ, ์ด๋ MD5-Crypt (APR1-MD5) ํด์ ๋ฐฉ์์ด๋ค.
blueh4g:$1$RF1ij51F$f7Ak1R4/gX3WOI9gliA981
- $1$ : MD5 ์๊ณ ๋ฆฌ์ฆ ์๋ณ์
- RF1ij51F : salt ๊ฐ
- f7Ak1R4/gX3WOI9gliA981 : ์ค์ ํด์๋ ๋น๋ฐ๋ฒํธ
(3) ์ต์คํ๋ก์
๊ฐ๋จํ๊ฒ ์ต์คํ๋ก์ ์ฝ๋๋ฅผ ์๋์ ๊ฐ์ด ์์ฑํด์ฃผ์๋ค.
๋น๋ฐ๋ฒํธ์ ๊ธธ์ด๋ฅผ ๋ชจ๋ฅด๊ธฐ ๋๋ฌธ์ ์ผ๋จ +10๊น์ง(์ด 17์)๋ก ๊ฐ์ ํ๊ณ ์งํํ์๋ค.
import crypt
import string
import itertools
import time
# htpasswd ํ์ผ ๋ด์ฉ
htpasswd_line = "blueh4g:$1$RF1ij51F$f7Ak1R4/gX3WOI9gliA981"
# ์ฌ์ฉ์๋ช
, ํด์ ์ถ์ถ
username, password_hash = htpasswd_line.strip().split(':')
print(f"์ฌ์ฉ์๋ช
: {username}")
print(f"๋น๋ฐ๋ฒํธ ํด์: {password_hash}")
# ๋น๋ฐ๋ฒํธ๊ฐ 'G4HeulB'๋ก ์์
password_prefix = "G4HeulB"
print(f"๋น๋ฐ๋ฒํธ ์ ๋์ฌ: {password_prefix}")
# ๋ธ๋ฃจํธํฌ์ค์ ์ฌ์ฉํ ๋ฌธ์ ์งํฉ (์ซ์ ๋ฐ ์๋ฌธ์)
charset = string.digits + string.ascii_lowercase
print(f"์ฌ์ฉํ ๋ฌธ์ ์งํฉ: {charset}")
def test_password(password, password_hash):
"""์
๋ ฅ๋ ๋น๋ฐ๋ฒํธ๊ฐ ํด์์ ์ผ์นํ๋์ง ํ์ธ"""
# ํด์์์ ์ํธ ๊ฐ ์ถ์ถ
salt = password_hash.split('$')[2]
full_salt = f"$1${salt}$"
# ์
๋ ฅ๋ ๋น๋ฐ๋ฒํธ์ ํด์ ์์ฑ
test_hash = crypt.crypt(password, full_salt)
return test_hash == password_hash
def brute_force():
"""๋ธ๋ฃจํธํฌ์ค ๊ณต๊ฒฉ ์ํ (๋น๋ฐ๋ฒํธ ์ฐพ๊ธฐ)"""
start_time = time.time()
attempts = 0
print("๋ธ๋ฃจํธํฌ์ค ๊ณต๊ฒฉ ์์")
# ๋น๋ฐ๋ฒํธ ๋ท๋ถ๋ถ 1-10๊น์ง ์ฆ๊ฐ
for length in range(10):
print(f"{length}์๋ฆฌ ์ถ๊ฐ ๋ฌธ์๋ฅผ ํฌํจํ ๋น๋ฐ๋ฒํธ ์๋ ์ค...")
for suffix in itertools.product(charset, repeat=length):
suffix_str = ''.join(suffix)
password = password_prefix + suffix_str
attempts += 1
if attempts % 100000 == 0:
elapsed = time.time() - start_time
print(f"{attempts}๊ฐ์ ๋น๋ฐ๋ฒํธ๋ฅผ ์๋ํจ ({elapsed:.2f}์ด ๊ฒฝ๊ณผ). ํ์ฌ ์๋ ์ค์ธ ๋น๋ฐ๋ฒํธ: {password}")
if test_password(password, password_hash):
elapsed = time.time() - start_time
print(f"\n๋น๋ฐ๋ฒํธ๋ฅผ ์ฐพ์์ต๋๋ค! {attempts}๋ฒ ์๋ ํ {elapsed:.2f}์ด ๊ฒฝ๊ณผ")
print(f"์ฐพ์ ๋น๋ฐ๋ฒํธ: {password}")
return password
elapsed = time.time() - start_time
print(f"\n๋น๋ฐ๋ฒํธ๋ฅผ ์ฐพ์ง ๋ชปํ์ต๋๋ค. ์ด {attempts}๋ฒ ์๋, {elapsed:.2f}์ด ๊ฒฝ๊ณผ.")
return None
if __name__ == "__main__":
found_password = brute_force()
if found_password:
print(f"\n์ฑ๊ณต! {username}์ ๋น๋ฐ๋ฒํธ๋: {found_password}")
else:
print("\n๋น๋ฐ๋ฒํธ ์ฐพ๊ธฐ ์คํจ")
[๊ฒฐ๊ณผ]

ํ๋๊ทธ ํ๋ ์ฑ๊ณต ><

1. ๋ฌธ์
https://dreamhack.io/wargame/challenges/330
[wargame.kr] crack crack crack it
Description .htaccess crack! can you local bruteforce attack?
dreamhack.io
2. ํด๊ฒฐ ๊ณผ์
(1) ๋ฌธ์ ํ์ด์ง ํ์ธ
htpasswd ํ์ผ์ ๋ถ์ํด์ Brute Force๋ฅผ ํตํด ํจ์ค์๋๋ฅผ ์์๋ด์ผ ํ๋ ๋ฌธ์ ์ด๋ค.

htpasswd ํ์ผ์ ์ผ๋ฐ์ ์ผ๋ก HTTP ์ธ์ฆ์ ์ํด ์ฌ์ฉ๋๋ ํ์ผ์ด๋ค. $์๊ณ ๋ฆฌ์ฆ$์ํธ$ํด์๋๋น๋ฐ๋ฒํธ์ผ๋ก ๊ตฌ์ฑ๋๋ค.
์ด๋ ํจ์ค์๋๋ ํด์ํ๋์ด ์ ์ฅ๋๊ธฐ ๋๋ฌธ์ G4HeulB๋ก ์์ํ๋ค๋ ํํธ๋ฅผ ํตํด ์ต๋ํ ํจ์จ์ ์ผ๋ก ๋ธ๋ฃจํธ ํฌ์ค ๊ณต๊ฒฉ์ ์ฌ์ฉํด์
๋น๋ฐ๋ฒํธ๋ฅผ ์์๋ด์ผ ํ๋ค.
- username:$1$saltvalue$hashed_password :
- MD5: $1$๋ก ์์
- username:$sha1$saltvalue$hashed_password
- SHA-1: $sha1$๋ก ์์์ ์ฒด ํด์ ๋ฌธ์์ด์ ๋ณดํต ๋ค์๊ณผ ๊ฐ์ ๊ตฌ์กฐ๋ฅผ ๊ฐ์ง๋๋ค: $์๊ณ ๋ฆฌ์ฆ$์ํธ$ํด์๋๋น๋ฐ๋ฒํธ
- username:$2y$10$saltvalue$hashed_password
- bcrypt: $2y$ ๋๋ $2a$๋ก ์์ (๋ฒ์ ์ ๋ฐ๋ผ ๋ค๋ฆ)
์ผ๋ฐ์ ์ผ๋ก MD5, SHA-1, bcrypt ๋๋ APR1(MD5 ๋ณํ) ๋ฑ์ ํด์ฑ ์๊ณ ๋ฆฌ์ฆ์ด ์ฌ์ฉ๋๊ธฐ ๋๋ฌธ์ ์ด๋ค ํด์ฑ ์๊ณ ๋ฆฌ์ฆ์ ์ฌ์ฉํ๋์ง
์์๋ด์ผ ํ๋ค. htpasswd ํ์ผ์์ ํ์ธ๋ ํจ์ค์๋ ํด์ ๊ฐ์ $1$RF1ij51F$f7Ak1R4/gX3WOI9gliA981์ด๋ฉฐ, ์ด๋ MD5-Crypt (APR1-MD5) ํด์ ๋ฐฉ์์ด๋ค.
blueh4g:$1$RF1ij51F$f7Ak1R4/gX3WOI9gliA981
- $1$ : MD5 ์๊ณ ๋ฆฌ์ฆ ์๋ณ์
- RF1ij51F : salt ๊ฐ
- f7Ak1R4/gX3WOI9gliA981 : ์ค์ ํด์๋ ๋น๋ฐ๋ฒํธ
(3) ์ต์คํ๋ก์
๊ฐ๋จํ๊ฒ ์ต์คํ๋ก์ ์ฝ๋๋ฅผ ์๋์ ๊ฐ์ด ์์ฑํด์ฃผ์๋ค.
๋น๋ฐ๋ฒํธ์ ๊ธธ์ด๋ฅผ ๋ชจ๋ฅด๊ธฐ ๋๋ฌธ์ ์ผ๋จ +10๊น์ง(์ด 17์)๋ก ๊ฐ์ ํ๊ณ ์งํํ์๋ค.
import crypt import string import itertools import time # htpasswd ํ์ผ ๋ด์ฉ htpasswd_line = "blueh4g:$1$RF1ij51F$f7Ak1R4/gX3WOI9gliA981" # ์ฌ์ฉ์๋ช
, ํด์ ์ถ์ถ username, password_hash = htpasswd_line.strip().split(':') print(f"์ฌ์ฉ์๋ช
: {username}") print(f"๋น๋ฐ๋ฒํธ ํด์: {password_hash}") # ๋น๋ฐ๋ฒํธ๊ฐ 'G4HeulB'๋ก ์์ password_prefix = "G4HeulB" print(f"๋น๋ฐ๋ฒํธ ์ ๋์ฌ: {password_prefix}") # ๋ธ๋ฃจํธํฌ์ค์ ์ฌ์ฉํ ๋ฌธ์ ์งํฉ (์ซ์ ๋ฐ ์๋ฌธ์) charset = string.digits + string.ascii_lowercase print(f"์ฌ์ฉํ ๋ฌธ์ ์งํฉ: {charset}") def test_password(password, password_hash): """์
๋ ฅ๋ ๋น๋ฐ๋ฒํธ๊ฐ ํด์์ ์ผ์นํ๋์ง ํ์ธ""" # ํด์์์ ์ํธ ๊ฐ ์ถ์ถ salt = password_hash.split('$')[2] full_salt = f"$1${salt}$" # ์
๋ ฅ๋ ๋น๋ฐ๋ฒํธ์ ํด์ ์์ฑ test_hash = crypt.crypt(password, full_salt) return test_hash == password_hash def brute_force(): """๋ธ๋ฃจํธํฌ์ค ๊ณต๊ฒฉ ์ํ (๋น๋ฐ๋ฒํธ ์ฐพ๊ธฐ)""" start_time = time.time() attempts = 0 print("๋ธ๋ฃจํธํฌ์ค ๊ณต๊ฒฉ ์์") # ๋น๋ฐ๋ฒํธ ๋ท๋ถ๋ถ 1-10๊น์ง ์ฆ๊ฐ for length in range(10): print(f"{length}์๋ฆฌ ์ถ๊ฐ ๋ฌธ์๋ฅผ ํฌํจํ ๋น๋ฐ๋ฒํธ ์๋ ์ค...") for suffix in itertools.product(charset, repeat=length): suffix_str = ''.join(suffix) password = password_prefix + suffix_str attempts += 1 if attempts % 100000 == 0: elapsed = time.time() - start_time print(f"{attempts}๊ฐ์ ๋น๋ฐ๋ฒํธ๋ฅผ ์๋ํจ ({elapsed:.2f}์ด ๊ฒฝ๊ณผ). ํ์ฌ ์๋ ์ค์ธ ๋น๋ฐ๋ฒํธ: {password}") if test_password(password, password_hash): elapsed = time.time() - start_time print(f"\n๋น๋ฐ๋ฒํธ๋ฅผ ์ฐพ์์ต๋๋ค! {attempts}๋ฒ ์๋ ํ {elapsed:.2f}์ด ๊ฒฝ๊ณผ") print(f"์ฐพ์ ๋น๋ฐ๋ฒํธ: {password}") return password elapsed = time.time() - start_time print(f"\n๋น๋ฐ๋ฒํธ๋ฅผ ์ฐพ์ง ๋ชปํ์ต๋๋ค. ์ด {attempts}๋ฒ ์๋, {elapsed:.2f}์ด ๊ฒฝ๊ณผ.") return None if __name__ == "__main__": found_password = brute_force() if found_password: print(f"\n์ฑ๊ณต! {username}์ ๋น๋ฐ๋ฒํธ๋: {found_password}") else: print("\n๋น๋ฐ๋ฒํธ ์ฐพ๊ธฐ ์คํจ")
[๊ฒฐ๊ณผ]

ํ๋๊ทธ ํ๋ ์ฑ๊ณต ><
