[HowTo] 방법론 · 작성: 2026-07-29 09:10:18 · 수정: 2026-07-29 18:12:46 · 조회 194
소스 코드 없이 웹서버를 진단할 때 실제로 하는 일은 특정 입력을 넣고 서버가 평소와 다르게 반응하는지 관찰하는 것이다. 이 반응 하나하나가 내부 로직을 추론할 수 있는 유일한 단서라서, "이런 반응이 나오면 이런 약점을 의심한다"는 대응 관계를 많이 알고 있을수록 진단 속도와 정확도가 올라간다. 아래는 실무에서 자주 쓰는 반응-취약점 대응표다.
| 관찰되는 반응 | 의심되는 취약점 | 왜 그런 반응이 나오는가 |
|---|---|---|
| 에러 페이지에 DB 드라이버 이름, 쿼리 구문, 테이블/컬럼명이 그대로 노출 | SQL 인젝션 (에러 기반) | 입력값이 이스케이프 없이 쿼리 문자열에 그대로 붙어서, DB가 뱉은 파싱 에러가 필터링 없이 화면까지 전달됨 |
에러는 안 뜨지만 id=1 AND 1=1과 id=1 AND 1=2의 응답 본문/길이가 다름 |
SQL 인젝션 (불리언 블라인드) | 조건절이 그대로 WHERE에 반영되고, 그 참/거짓 결과가 화면 분기(정상 표시 vs "결과 없음")로 새어나옴 |
응답 자체는 동일한데 특정 입력에서만 응답 시간이 일관되게 늘어남(예: SLEEP(5) 삽입 시 5초 지연) |
SQL 인젝션 (시간 기반 블라인드) | 다른 채널로는 결과가 안 보여도, 조건에 따라 DB가 실제로 대기하는 시간 차이는 외부에서 측정 가능 |
| 입력값이 HTML 이스케이프 없이 응답 본문에 그대로 반사됨 | 반사형 XSS | 서버가 사용자 입력을 출력 인코딩 없이 템플릿에 끼워 넣음 — CSP 헤더 부재도 같은 방향의 신호 |
| 게시글/댓글 등록 후, 다른 세션에서 조회했을 때도 스크립트 태그가 그대로 남아있음 | 저장형 XSS | 서버가 저장 시점과 조회 시점 어느 쪽에서도 새니타이즈를 하지 않음 |
| URL의 숫자 ID(주문번호, 사용자ID)를 다른 값으로 바꿨을 때도 200과 함께 데이터가 내려옴 | IDOR / 접근 제어 우회 | 서버가 "요청자가 이 리소스의 소유자인가"를 확인하지 않고 존재 여부만으로 응답함 |
| 관리자 전용 URL을 로그인 없이/낮은 권한 세션으로 직접 호출했을 때도 200이 뜸 | 접근 제어 미비(수직 권한 상승) | 프론트엔드에서만 메뉴를 숨기고 서버 쪽 권한 검사가 빠져 있음 |
| 로그인 실패 메시지가 "존재하지 않는 아이디"와 "비밀번호 불일치"를 다르게 표시 | 계정 열거(User Enumeration) | 서버가 인증 실패 사유를 그대로 노출해서, 유효한 아이디 목록을 반응 차이만으로 추릴 수 있음 |
| 로그아웃하거나 비밀번호를 바꾼 뒤에도 이전 세션 토큰으로 요청이 그대로 통과 | 세션 관리 결함 | 서버 쪽에서 토큰을 무효화하지 않고 만료 시간에만 의존함 |
웹훅/이미지 프록시/PDF 렌더러 등에 내부망 주소(예: 169.254.169.254, localhost)를 넣었을 때 응답 시간이나 에러 메시지가 외부 주소를 넣었을 때와 다름 |
SSRF | 서버가 대신 그 주소로 요청을 보내고 있다는 뜻 — 확실히 하려면 자신이 통제하는 서버로 아웃오브밴드 콜백을 걸어 확인 |
확장자를 .jpg.php, MIME 타입만 image/png로 바꾼 실행 파일 업로드가 그대로 통과 |
파일 업로드 취약점 | 확장자·MIME 타입·매직바이트 검증 중 일부만 검사하고 있음 |
| 상태 변경 요청(비밀번호 변경, 계좌이체 등)에 CSRF 토큰 없이 보내도 그대로 처리됨 | CSRF | 서버가 요청 출처(Origin/Referer)나 별도 토큰을 검증하지 않음 |
XML을 받는 엔드포인트에 외부 엔티티(<!ENTITY xxe SYSTEM "file:///etc/passwd">)를 넣었을 때 그 파일 내용이 응답에 포함되거나 서버가 외부로 DNS 조회를 시도함 |
XXE | XML 파서가 외부 엔티티 처리를 비활성화하지 않은 기본 설정 그대로 동작 |
파일명 파라미터에 ../../etc/passwd를 넣었을 때 실제 시스템 파일 내용이 응답에 섞여 나옴 |
경로 탐색(Path Traversal) / LFI | 사용자 입력을 그대로 파일 경로에 이어붙이고, 결과 경로가 원래 디렉터리 안인지 재검증하지 않음 |
콘솔 폰트나 세미콜론(; whoami), 백틱을 넣었을 때 응답 시간 지연이나 명령 실행 결과가 응답에 섞여 나옴 |
OS 커맨드 인젝션 | 사용자 입력이 셸 명령 문자열에 그대로 연결되어 실행됨 |
리다이렉트 파라미터(?next=, ?return_url=)에 외부 도메인을 넣었을 때 그 도메인으로 그대로 이동 |
오픈 리다이렉트 | 허용 도메인 화이트리스트 없이 파라미터 값으로 바로 리다이렉트함 — 피싱에 악용되기 쉬움 |
| 로그인/비밀번호 재설정 폼에 짧은 시간 안에 수백 번 요청해도 차단이나 지연 없이 전부 처리됨 | Rate Limiting 부재 → 브루트포스 가능 | 실패 횟수를 서버가 추적하지 않음 |
/, .git/, .env, 백업 파일(.bak, ~), 디버그 모드 스택 트레이스가 그대로 열람됨 |
정보 노출 | 배포 시 불필요한 파일/디버그 설정을 제거하지 않음 — 취약점이라기보다 다른 취약점의 실마리가 되는 경우가 많음 |
OPTIONS, PUT, DELETE 같은 HTTP 메서드를 임의로 보내도 405가 아니라 실제로 처리됨 |
HTTP 메서드 오용 | 라우팅에서 허용 메서드를 제한하지 않고 핸들러가 모든 메서드를 받아들임 |
| 가격/수량 파라미터를 음수나 소수로 바꿔도 서버가 그대로 계산해서 처리 | 비즈니스 로직 결함 | 서버가 클라이언트가 보낸 값을 그대로 신뢰하고 서버 측에서 재검증하지 않음 |
몇 가지는 표 하나로 끝나지 않는다. 예를 들어 시간 기반 블라인드 SQLi는 우연히 서버가 느려진 것과 구분해야 하므로, 지연 시간을 5초·10초로 바꿔가며 응답 시간이 정확히 비례하는지 최소 두세 번 반복 확인한 뒤에야 가설을 확정한다. IDOR도 마찬가지로, ID를 하나 바꿔서 데이터가 내려왔다고 바로 취약점이라 단정하지 않고 실제로 "내 계정이 아닌 다른 사용자의 데이터"라는 걸 확인해야 리포트에 쓸 수 있는 근거가 된다. 반응은 가설을 세우는 단서일 뿐이고, 그 가설을 재현 가능한 형태로 확인하는 단계를 건너뛰면 오탐이 섞인다.