How to implement Web's Hospital

InfoSec in a wishful nutshell

PoC || GTFO: #Docker + #Traefik + #Jenkins + #OWASP — BB 0.8


N.B: [This paper is not].append[‘Cloud/InfoSec Tutorial/Workshop’].

It should only be considered as a “Spontaneous Prose” of an ongoing journey, about building a bridge between InfoSec and DevOps industries through #SE, #Cloud, #OpenSource and #BugBounty. After all, it’s only full of open-source ideas shared in CC BY-NC 3.0.

Excuse my French, Kudos for challenging.

TL;DR: RedPill below, BluePill by the end


الواجب على الناظر في كتب العلوم، إذا كان غرضه معرفة الحقائق، أن يجعل نفسه خصماً لكل ما ينظر فيه

أبو علي الحسن بن الحسن بن الهيثم


Oh hai o/

Let’s cut it straight to technical shenanigans.

This PoC is an attempt to implement this wishful aim of InfoSec prevention, as close as legally possible to the Code Factory.

make target:

make dry-run:

  • 100% Open Source tech legos. Because the 2 muchData 1 API is not my cup of tea.

  • It needs to run on cheap servers. Coz I’m a 99% dealing with a lawsuit.

  • KISS and lazy coding. Don’t judge the dev that I’m not.

  • Monitoring, Registry management and image scanning are out of scope, because I need to submit this paper tonight.

make build:

  • A vulnerable app,

  • A kinda State-Diagram, waterfall-proof \o/

Dia is so powerful …

  • A kinda KISS Architecture. Yes, containers are floppy disks in my mind.

… And ugly at the same time #kudos

  • And a bunch of files:
    user@yogosha:~/code/PoC$ tree
    .
    ├── etc
    │   └── traefik.toml        <- Load Balancer config
    ├── Jenkinsfile             <- Pipeline as Code
    ├── LICENSE                 <- MIT
    ├── Makefile                <- RTFM
    ├── README.md               <- You are reading it
    └── src
        ├── php                 <- PHP sqli vulnerable
        │   ├── debian.png
        │   ├── Dockerfile      <- Build recipe
        │   ├── docker.png
        │   ├── index.php       <- App Code
        │   ├── jenkins.png
        │   ├── lamp.jpg
        │   ├── owasp.png
        │   ├── scaleway.svg
        │   ├── star.png
        │   └── traefik.png
        └── sql
            ├── production.sql  <- Prod Data
            └── staging.sql     <- Staging Data

    4 directories, 17 files

Make run:

Get yourself comfortable behind your favorite terminal, and install docker.

Start by cloning the repo, make build Dev environment & make it run.

You should get this webapp running and vulnerable to a SQL Injection.

SQLi & FrontEnd Skillz

Happy with it? Let’s call our friends, Traefik & Jenkins Pipeline, by running the commands:

Cheshire Cat eating Reblochon in HTTPS

    docker run -d -p 8666:8080 -p 80:80 -p 443:443
               -v /var/run/docker.sock:/var/run/docker.sock 
               -v traefik:/data -v $PWD/etc/traefik.toml:/traefik.toml 
               -v $PWD/conf/acme.json:/acme.json traefik

The White Rabbit

docker run -p 8080 -d -v  /data/jenkins/var/jenkins_home:/var/jenkins_home 
           -v  /var/run/docker.sock:/var/run/docker.sock 
           -v $(which docker):/usr/bin/docker 
           -v $(which make):/usr/bin/make 
           --label  traefik.backend='jenkins' 
           --label traefik.port='8080' 
           --label  traefik.protocol='http' 
           --label traefik.weight='10' 
           --label traefik.frontend.rule='Host:chocobo.yogosha.com'
           --label traefik.frontend.passHostHeader='true' 
           --label traefik.priority='10' 
jenkinsci/docker-workflow-demo

Create a new Pipeline project in Jenkins as following:

As simple as a git clone

Congrats. You’ve run your first DevOpsSec process \o/

The trick:

No tricks. Only code. One file that mimics the initial State Diagram.

node{
  def appname = "redpill"
stage 'Checkout'
  git url: 'https://www.github.com/h-a-t/RedPill'

stage 'Pull img'
  sh 'make pull'

stage 'Test build'
  sh 'make build'

stage('SonarQube analysis') {
    // requires SonarQube Scanner 2.8+
    def scannerHome = tool 'SonarQubeScanner';
    sh "ls -la"
    withSonarQubeEnv('SonarQube') {
      sh "${scannerHome}/bin/sonar-scanner -D sonar.projectKey=${appname} -D sonar.sources=src/php/"
    }
  }

stage 'Building env'
  def state = "staging"

  // Puts app stuff
  def busy = docker.image('busybox');
  busy.inside("-v ${appname}-app:/data"){
    sh "cp -r ./src/php/* /data/"
    sh "chown -R www-data:www-data /data"
  }
  // Puts db stuff
  busy.inside("-v ${appname}-${state}-db:/data"){
    sh "rm -rf /data/*"
    sh "cp -r ./src/sql/staging.sql /data/"
  }
  // Prepares containers
  def php = docker.build("${appname}-app", './src/php/')
  def zap = docker.image('owasp/zap2docker-weekly')
  def db = docker.image('mysql/mysql-server:5.6')

  // Defines staging param
  def db_param = "-e 'MYSQL_RANDOM_ROOT_PASSWORD=yes' -e 'MYSQL_USER=user' -e 'MYSQL_PASSWORD=password' -e 'MYSQL_DATABASE=sqli' --label 'traefik.enable=false'"
  def app_param = "--label traefik.backend='app-${state}' --label traefik.port='80' --label traefik.protocol='http' --label traefik.weight='10' --label traefik.frontend.rule='Host:${state}.chocobo.yogosha.com' --label traefik.frontend.passHostHeader='true' --label traefik.priority='10' -e BUILD_STAGE=${state}"


  // Starts Staging instances
  def staging_db = db.run("${db_param} -v ${appname}-${state}-db:/docker-entrypoint-initdb.d/")
  def staging_app = php.run ("-P ${app_param} -v ${appname}-app:/var/www/html  --link ${staging_db.id}:db")

  // Runs quick security check
stage 'Test with OWASP ZapProxy'
  zap.inside("--link ${staging_app.id}:app -v ${appname}-zap:/zap/wrk") {
          println('Waiting for server to be ready')
          sh "until \$(curl --output /dev/null --silent --head --fail http://app/index.php); do printf '.'; sleep 5; done"
          println('It Works!')
          sh "ls -la"
          // Active scan, a bit more permissive and customizable
          sh "zap-cli quick-scan --self-contained --start-options '-config api.disablekey=true' http://app/index.php"
          // Passive scan, build will fail if any WARN is returned -> #blame.
          // sh "zap-baseline.py -t http://app/index.php -r report.html"
}

  // "Oh hai o/ Can I haz a quality check?"
  stage 'QA'
  input "Is https://${state}.chocobo.yogosha.com going according to plan?"

  staging_app.stop()

  // "N33d Help for securitay?"
  stage 'Bug Bounty'
  // Defines bb param
  state = "bb"
  app_param = "--label traefik.backend='app-${state}' --label traefik.port='80' --label traefik.protocol='http' --label traefik.weight='10' --label traefik.frontend.rule='Host:${state}.chocobo.yogosha.com' --label traefik.frontend.passHostHeader='true' --label traefik.priority='10' -e BUILD_STAGE=${state}"
  def bb_app = php.run ("-P ${app_param} -v ${appname}-app:/var/www/html  --link ${staging_db.id}:db")

  stage 'Production'
  // Loading a snapshot of Production data
  state = "prod"
  busy.inside("-v ${appname}-${state}-db:/data"){
    sh "rm -rf /data/*"
    sh "cp -r ./src/sql/production.sql /data/"
  }

  // Push to the interwebz!
  app_param = "--label traefik.backend='app-${state}' --label traefik.port='80' --label traefik.protocol='http' --label traefik.weight='10' --label traefik.frontend.rule='Host:${state}.chocobo.yogosha.com' --label traefik.frontend.passHostHeader='true' --label traefik.priority='10' -e BUILD_STAGE=${state}"
  db_param = "-e MYSQL_RANDOM_ROOT_PASSWORD=yes -e MYSQL_USER=user -e MYSQL_PASSWORD=p4s5w0rd -e 'MYSQL_DATABASE=sqli' --label traefik.enable=false"

  def prod_db = db.run("${db_param} -v ${appname}-${state}-db:/docker-entrypoint-initdb.d/")
  def prod_app = php.run ("-d -P ${app_param} -v ${appname}-app:/var/www/html  --link ${prod_db.id}:db")
}

In a nutshell, it’s only doing what you just did, runs a security test using ZAP on it, then push it to registry.

To sum up:

This is your last chance. After this, there is no turning back. You take the blue pill — the story ends, you wake up in your bed and believe whatever you want to believe. You take the red pill — you stay in Wonderland, and I show you how deep the rabbit hole goes. Remember: all I’m offering is the truth. Nothing more.

H.A.T
H.A.T
Gentleman {Entrepreneur, Researcher}

H.A.T is an independent researcher that describes himself as an InfoSec Kepo, curious about playing with computers since his Moroccan early ages.