rocky_dvwa_install.shellscript
8.7 KB · text/x-shellscript · 업로드 2026-07-06 14:42
#!/usr/bin/env bash
# Rocky Linux 9.x + Apache + MariaDB + PHP + DVWA 설치 스크립트
# - MariaDB modular metadata 오류 대응
# - mysql_secure_installation expect 자동화 제거
# - DVWA 설정 파일을 안전하게 패치
#
# 사용법:
# chmod +x asd_fixed.sh
# ./asd_fixed.sh
#
# 선택 옵션:
# DB_PW='원하는비밀번호' ./asd_fixed.sh
# MARIADB_STREAM=11.8 ./asd_fixed.sh # auto, 11.8, 10.11, none 중 선택 가능
set -Eeuo pipefail
DB_PW="${DB_PW:-asd123!@}"
MARIADB_STREAM="${MARIADB_STREAM:-auto}"
DVWA_DIR="/var/www/html/dvwa"
DVWA_REPO="https://github.com/digininja/DVWA.git"
if [[ ${EUID} -eq 0 ]]; then
SUDO=()
else
SUDO=(sudo)
fi
log() { echo -e "\n[+] $*"; }
warn() { echo "[!] $*" >&2; }
die() { echo "[ERROR] $*" >&2; exit 1; }
run() { "${SUDO[@]}" "$@"; }
trap 'die "스크립트 실패: line ${LINENO}. 위쪽 오류 메시지를 확인하세요."' ERR
sql_escape() {
local s=${1//\\/\\\\}
s=${s//\'/\'\'}
printf '%s' "$s"
}
choose_mariadb_stream() {
local module_list
if [[ "$MARIADB_STREAM" != "auto" ]]; then
[[ "$MARIADB_STREAM" == "none" ]] && return 0
printf '%s' "$MARIADB_STREAM"
return 0
fi
module_list="$(run dnf -q --refresh module list mariadb 2>/dev/null || true)"
if grep -Eq '^[[:space:]]*mariadb[[:space:]]+11\.8([[:space:]]|$)' <<<"$module_list"; then
printf '11.8'
elif grep -Eq '^[[:space:]]*mariadb[[:space:]]+10\.11([[:space:]]|$)' <<<"$module_list"; then
printf '10.11'
else
return 0
fi
}
find_nonmodular_mariadb_server() {
# 모듈 메타데이터가 깨진 저장소에서는 11.8/10.11 module 패키지 대신
# non-module mariadb-server 10.5 계열을 정확한 NEVRA로 지정해 설치한다.
run dnf -q repoquery --available --qf '%{nevra}' mariadb-server 2>/dev/null \
| grep -v 'module+' \
| sort -V \
| tail -n 1 || true
}
install_packages() {
local stream="$1"
local nonmodular_server=""
local base_pkgs=(
httpd
php
php-cli
php-fpm
php-mysqlnd
php-gd
php-mbstring
php-xml
python3
git
nano
firewalld
policycoreutils
libsemanage-utils
)
if [[ -n "$stream" ]]; then
log "MariaDB 모듈 스트림 mariadb:${stream} 활성화"
run dnf -y module reset mariadb || true
run dnf -y module enable "mariadb:${stream}" || true
run dnf -y module switch-to "mariadb:${stream}" || true
else
warn "mariadb 모듈 메타데이터를 찾지 못했습니다. non-module mariadb-server 패키지로 우회 시도합니다."
fi
log "Apache / MariaDB / PHP / DVWA 필요 패키지 설치"
if run dnf -y --refresh install "${base_pkgs[@]}" mariadb-server; then
return 0
fi
warn "일반 mariadb-server 설치가 실패했습니다. DNF 캐시 정리 후 non-module MariaDB로 재시도합니다."
run dnf clean all || true
run dnf -y module reset mariadb || true
run dnf -y module disable mariadb || true
nonmodular_server="$(find_nonmodular_mariadb_server)"
if [[ -z "$nonmodular_server" ]]; then
die "mariadb-server의 정상 모듈 메타데이터도, non-module 패키지도 찾지 못했습니다. /etc/yum.repos.d/의 AppStream 저장소 또는 로컬 미러 repodata를 확인하세요."
fi
log "non-module MariaDB 패키지로 설치: ${nonmodular_server}"
run dnf -y --refresh install "${base_pkgs[@]}" "$nonmodular_server"
}
mysql_root() {
local mysql_bin="$1"
shift
if run "$mysql_bin" -uroot --protocol=socket -e 'SELECT 1' >/dev/null 2>&1; then
run "$mysql_bin" -uroot --protocol=socket "$@"
elif run "$mysql_bin" -uroot -p"$DB_PW" -e 'SELECT 1' >/dev/null 2>&1; then
run "$mysql_bin" -uroot -p"$DB_PW" "$@"
else
die "MariaDB root 접속 실패. fresh install이면 'sudo mariadb'가 되어야 합니다. 기존 DB가 있으면 root 인증 방식을 확인하세요."
fi
}
log "DNF 캐시/메타데이터 정리"
run dnf clean packages || true
run dnf clean metadata || true
run dnf makecache --refresh
run dnf -y --refresh install dnf-plugins-core || true
STREAM="$(choose_mariadb_stream)"
install_packages "$STREAM"
log "서비스 활성화 및 시작"
run systemctl enable --now firewalld || true
run systemctl enable --now mariadb
run systemctl enable --now php-fpm || true
run systemctl enable --now httpd
MYSQL_BIN="$(command -v mariadb || command -v mysql || true)"
if [[ -z "$MYSQL_BIN" && -x /usr/bin/mariadb ]]; then
MYSQL_BIN="/usr/bin/mariadb"
elif [[ -z "$MYSQL_BIN" && -x /usr/bin/mysql ]]; then
MYSQL_BIN="/usr/bin/mysql"
fi
[[ -n "$MYSQL_BIN" ]] || die "mariadb/mysql 클라이언트를 찾지 못했습니다."
DB_PW_SQL="$(sql_escape "$DB_PW")"
log "DVWA 데이터베이스 및 계정 생성"
mysql_root "$MYSQL_BIN" <<SQL
DROP DATABASE IF EXISTS test;
CREATE DATABASE IF NOT EXISTS dvwa CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
DROP USER IF EXISTS 'dvwa_user'@'localhost';
CREATE USER 'dvwa_user'@'localhost' IDENTIFIED BY '${DB_PW_SQL}';
GRANT ALL PRIVILEGES ON dvwa.* TO 'dvwa_user'@'localhost';
FLUSH PRIVILEGES;
SQL
log "DVWA 소스 설치"
run mkdir -p /var/www/html
if [[ -d "$DVWA_DIR" && ! -d "$DVWA_DIR/.git" ]]; then
backup_dir="${DVWA_DIR}.bak.$(date +%Y%m%d%H%M%S)"
warn "기존 ${DVWA_DIR} 디렉터리가 git 저장소가 아니므로 ${backup_dir} 로 백업합니다."
run mv "$DVWA_DIR" "$backup_dir"
fi
if [[ -d "$DVWA_DIR/.git" ]]; then
log "기존 DVWA 저장소 업데이트"
run git config --global --add safe.directory "$DVWA_DIR" || true
run git -C "$DVWA_DIR" fetch --all --tags
run git -C "$DVWA_DIR" reset --hard origin/master || run git -C "$DVWA_DIR" reset --hard origin/main
else
run git clone "$DVWA_REPO" "$DVWA_DIR"
fi
log "DVWA config.inc.php 생성 및 DB 접속 정보 반영"
run cp "$DVWA_DIR/config/config.inc.php.dist" "$DVWA_DIR/config/config.inc.php"
run env DB_PW="$DB_PW" DVWA_DIR="$DVWA_DIR" python3 - <<'PY'
from pathlib import Path
import os
import re
cfg = Path(os.environ["DVWA_DIR"]) / "config" / "config.inc.php"
s = cfg.read_text(encoding="utf-8")
def php_single(value: str) -> str:
return value.replace("\\", "\\\\").replace("'", "\\'")
values = {
"db_server": "127.0.0.1",
"db_database": "dvwa",
"db_user": "dvwa_user",
"db_password": os.environ["DB_PW"],
"db_port": "3306",
}
for key, value in values.items():
pattern = r"\$_DVWA\[\s*'" + re.escape(key) + r"'\s*\]\s*=\s*'[^']*';"
line = "$_DVWA[ '{}' ] = '{}';".format(key, php_single(value))
s, count = re.subn(pattern, lambda _m, line=line: line, s)
if count == 0:
if "?>" in s:
s = s.replace("?>", line + "\n?>", 1)
else:
s += "\n" + line + "\n"
cfg.write_text(s, encoding="utf-8")
PY
log "DVWA용 PHP 설정 적용"
run tee /etc/php.d/99-dvwa-lab.ini >/dev/null <<'EOF_PHP'
; DVWA lab only. Do not use on a public production server.
allow_url_fopen = On
allow_url_include = On
display_errors = On
EOF_PHP
log "DVWA 권한 및 SELinux 컨텍스트 설정"
run mkdir -p "$DVWA_DIR/external/phpids/0.6/lib/IDS/tmp" "$DVWA_DIR/hackable/uploads"
run touch "$DVWA_DIR/external/phpids/0.6/lib/IDS/tmp/phpids_log.txt"
run chown -R apache:apache "$DVWA_DIR"
run find "$DVWA_DIR" -type d -exec chmod 755 {} \;
run find "$DVWA_DIR" -type f -exec chmod 644 {} \;
run chmod 775 "$DVWA_DIR/config" "$DVWA_DIR/hackable/uploads" "$DVWA_DIR/external/phpids/0.6/lib/IDS/tmp" || true
run chmod 664 "$DVWA_DIR/external/phpids/0.6/lib/IDS/tmp/phpids_log.txt" || true
if command -v getenforce >/dev/null 2>&1 && [[ "$(getenforce)" != "Disabled" ]]; then
run setsebool -P httpd_can_network_connect 1 || true
run setsebool -P httpd_unified 1 || true
run restorecon -R "$DVWA_DIR" || true
fi
log "방화벽 HTTP 오픈 및 웹 서비스 재시작"
if command -v firewall-cmd >/dev/null 2>&1 && run firewall-cmd --state >/dev/null 2>&1; then
run firewall-cmd --permanent --add-service=http
run firewall-cmd --reload
else
warn "firewalld가 실행 중이 아니어서 방화벽 설정은 건너뜁니다."
fi
run systemctl restart mariadb
run systemctl restart php-fpm || true
run systemctl restart httpd
cat <<EOF_DONE
==================================================================
[완료] DVWA 설치 스크립트가 끝났습니다.
==================================================================
▶ DVWA DB 이름: dvwa
▶ DVWA DB 사용자: dvwa_user
▶ DVWA DB 비밀번호: ${DB_PW}
▶ MariaDB root 접속: sudo mariadb
==================================================================
브라우저에서 다음 주소로 접속하세요.
http://[로키_아이피]/dvwa/setup.php
접속 후 맨 아래 [Create / Reset Database] 버튼을 누르면 마무리됩니다.
주의: DVWA는 취약점 실습용입니다. 공인 IP에 그대로 노출하지 마세요.
==================================================================
EOF_DONE