Permalink
Browse files

Add docker for LFI (#158)

* Create docker helper

* Adjust cmd emulator

* fix errors

* remove extra stuff

* fix tests

* fix null errors

* fix session association

* fix null handling

* fix exception types

* fix tests
  • Loading branch information...
rnehra01 authored and afeena committed Jun 24, 2017
1 parent df372e5 commit 64fcf8d549e30b5aa902a281187500d5dd37af47
View
@@ -1,6 +1,8 @@
sudo: required
services:
- docker
before_install:
- docker pull busybox:latest
language: python
python:
- "3.5"
View
@@ -10,6 +10,5 @@
url='https://github.com/mushorg/tanner',
packages=find_packages(exclude=['*.pyc']),
scripts=['bin/tanner'],
data_files=[('/opt/tanner/db/',['tanner/data/db_config.json']),
('/opt/tanner/data/',['tanner/data/dorks.pickle','tanner/data/vdocs.json'])]
data_files=[('/opt/tanner/data/',['tanner/data/dorks.pickle'])]
)
View
@@ -11,7 +11,7 @@
'REDIS': {'host': 'localhost', 'port': 6379, 'poolsize': 80, 'timeout': 1},
'EMULATORS': {'root_dir': '/opt/tanner'},
'SQLI': {'type':'SQLITE', 'db_name': 'tanner_db', 'host':'localhost', 'user':'root', 'password':'user_pass'},
'CMD_EXEC': {'host_image': 'busybox:latest'},
'DOCKER': {'host_image': 'busybox:latest'},
'LOGGER': {'log_debug': '/opt/tanner/tanner.log', 'log_err': '/opt/tanner/tanner.err'},
'MONGO': {'enabled': 'False', 'URI': 'mongodb://localhost'},
'LOCALLOG': {'enabled': 'False', 'PATH': '/tmp/tanner_report.json'},
View

This file was deleted.

Oops, something went wrong.
View
@@ -11,7 +11,7 @@ class BaseHandler:
def __init__(self, base_dir, db_name, loop=None):
self.emulators = {
'rfi': rfi.RfiEmulator(base_dir, loop),
'lfi': lfi.LfiEmulator(base_dir),
'lfi': lfi.LfiEmulator(),
'xss': xss.XssEmulator(),
'sqli': sqli.SqliEmulator(db_name, base_dir),
'cmd_exec': cmd_exec.CmdExecEmulator()
@@ -1,80 +1,25 @@
import asyncio
import docker
import yarl
import concurrent
# TODO : Replace docker with aiodocker
import logging
from tanner.config import TannerConfig
from tanner.utils import docker_helper
from tanner.utils import patterns
class CmdExecEmulator:
def __init__(self):
try:
self.docker_client = docker.from_env(version='auto')
except docker.errors as docker_error:
self.logger.error('Error while connecting to docker service %s', docker_error)
self.host_image = TannerConfig.get('CMD_EXEC', 'host_image')
self.logger = logging.getLogger('tanner.cmd_exec_emulator.CmdExecEmulator')
async def setup_host_image(self):
try:
if not self.docker_client.images.list(self.host_image):
self.docker_client.images.pull(self.host_image)
except docker.errors as docker_error:
self.logger.error('Error while pulling %s image %s', self.host_image, docker_error)
async def get_container(self, container_name):
container = None
try:
container_if_exists = self.docker_client.containers.list(all= True,
filters= dict(name= container_name)
)
if container_if_exists:
container = container_if_exists[0]
except docker.errors.APIError as server_error:
self.logger.error('Error while fetching container list %s', server_error)
return container
self.helper = docker_helper.DockerHelper()
async def create_attacker_env(self, session):
await self.setup_host_image()
container_name = 'attacker_' + session.sess_uuid.hex
container = await self.get_container(container_name)
if not container:
try:
container = self.docker_client.containers.create(image= self.host_image,
stdin_open= True,
name= container_name
)
session.associate_env(container_name)
except docker.errors as docker_error:
self.logger.error('Error while creating a container %s', docker_error)
container = await self.helper.create_container(container_name)
if container:
session.associate_env(container_name)
return container
async def get_cmd_exec_results(self, container, cmd):
execute_result = ''
try:
container.start()
executor = concurrent.futures.ThreadPoolExecutor(max_workers=1)
cmd_future = executor.submit(container.exec_run, ['sh', '-c', cmd])
try:
execute_result = cmd_future.result(timeout= 1).decode('utf-8')
except concurrent.futures.TimeoutError as timeout_error:
self.logger.error('Error while executing %s in container %s', cmd, timeout_error)
container.kill()
except docker.errors.APIError as server_error:
self.logger.error('Error while executing command %s in container %s', cmd, server_error)
result = dict(value= execute_result)
execute_result = await self.helper.execute_cmd(container, cmd)
result = dict(value= execute_result, page= '/index.html')
return result
async def delete_env(self, container_name):
container = await self.get_container(container_name)
try:
if container:
container.remove(force = True)
except docker.errors.APIError as server_error:
self.logger.error('Error while removing container %s', server_error)
def scan(self, value):
detection = None
if patterns.CMD_ATTACK.match(value):
View
@@ -1,54 +1,29 @@
import asyncio
import json
import os
import re
import shlex
from tanner import config
from tanner.utils import docker_helper
from tanner.utils import patterns
class LfiEmulator:
def __init__(self, root_path):
self.vdoc_path = os.path.join(root_path, 'virtualdocs/linux')
self.whitelist = []
self.setup_or_update_vdocs()
def __init__(self):
self.helper = docker_helper.DockerHelper()
def available_files(self):
for root, dirs, files in os.walk(self.vdoc_path):
for filename in files:
self.whitelist.append(os.path.join(root, filename))
async def get_lfi_result(self, container, file_path):
#Terminate the string with NULL byte
if '\x00' in file_path:
file_path = file_path[:file_path.find('\x00')]
def get_lfi_result(self, file_path):
result = None
if file_path in self.whitelist:
with open(file_path) as lfile:
result = lfile.read()
return result
def get_file_path(self, path):
file_match = re.match(patterns.LFI_FILEPATH, path)
if file_match:
file_path_relative = file_match.group(1)
file_path_relative = os.path.normpath(os.path.join('/', file_path_relative))
file_path = os.path.join(self.vdoc_path, file_path_relative[1:])
else:
file_path = path
return file_path
cmd = 'cat {file}'.format(file= shlex.quote(file_path))
execute_result = await self.helper.execute_cmd(container, cmd)
#Nulls are not printable, so replace it with another line-ender
execute_result = execute_result.replace('\x00', '\n')
return execute_result
def setup_or_update_vdocs(self):
if not os.path.exists(self.vdoc_path):
os.makedirs(self.vdoc_path)
with open(config.TannerConfig.get('DATA', 'vdocs')) as vdf:
vdocs = json.load(vdf)
if vdocs:
for key, value in vdocs.items():
filename = os.path.join(self.vdoc_path, key)
if not os.path.exists(filename):
os.makedirs(os.path.dirname(filename), exist_ok=True)
with open(filename, 'w') as vd:
vd.write(value)
async def setup_virtual_env(self):
container_name = 'lfi_container'
container = await self.helper.create_container(container_name)
return container
def scan(self, value):
detection = None
@@ -57,8 +32,8 @@ def scan(self, value):
return detection
async def handle(self, attack_params, session=None):
if not self.whitelist:
self.available_files()
file_path = self.get_file_path(attack_params[0]['value'])
result = self.get_lfi_result(file_path)
result = None
container = await self.setup_virtual_env()
if container:
result = await self.get_lfi_result(container, attack_params[0]['value'])
return result
View
@@ -5,7 +5,7 @@
import uuid
from tanner.config import TannerConfig
from tanner.emulators import cmd_exec
from tanner.utils import docker_helper
from tanner.utils.mysql_db_helper import MySQLDBHelper
from tanner.utils.sqlite_db_helper import SQLITEDBHelper
@@ -75,7 +75,7 @@ def associate_env(self, env):
self.associated_env = env
async def remove_associated_env(self):
await cmd_exec.CmdExecEmulator().delete_env(self.associated_env)
await docker_helper.DockerHelper().delete_env(self.associated_env)
def get_uuid(self):
return str(self.sess_uuid)
@@ -15,7 +15,7 @@ def setUp(self):
'REDIS': {'host': 'localhost', 'port': '1337', 'poolsize': '40', 'timeout': '5'},
'EMULATORS': {'root_dir': '/tmp/user_tanner'},
'SQLI': {'type':'SQLITE', 'db_name': 'user_tanner_db', 'host':'localhost', 'user':'user_name', 'password':'user_pass'},
'CMD_EXEC': {'host_image': 'test_image'},
'DOCKER': {'host_image': 'test_image'},
'LOGGER': {'log_debug': '/opt/tanner/tanner.log', 'log_err': '/opt/tanner/tanner.err'},
'MONGO': {'enabled': 'False', 'URI': 'mongodb://localhost'},
'LOCALLOG': {'enabled': 'False', 'PATH': '/tmp/user_tanner_report.json'}
@@ -60,7 +60,7 @@ def test_get_when_file_dont_exists(self):
'REDIS': {'host': 'localhost', 'port': 6379, 'poolsize': 80, 'timeout': 1},
'EMULATORS': {'root_dir': '/opt/tanner'},
'SQLI': {'type':'SQLITE', 'db_name': 'tanner_db', 'host':'localhost', 'user':'root', 'password':'user_pass'},
'CMD_EXEC': {'host_image': 'busybox:latest'},
'DOCKER': {'host_image': 'busybox:latest'},
'LOGGER': {'log_debug': '/opt/tanner/tanner.log', 'log_err': '/opt/tanner/tanner.err'},
'MONGO': {'enabled': 'False', 'URI': 'mongodb://localhost'},
'LOCALLOG': {'enabled': 'False', 'PATH': '/tmp/tanner_report.json'}
Oops, something went wrong.

0 comments on commit 64fcf8d

Please sign in to comment.