Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
language: python
python:
- "3.5"
script: cd tests && python test.py
- "3.6"
script: python -m tests
55 changes: 54 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
[![Build Status](https://travis-ci.org/python-security/pyt.svg?branch=master)](https://travis-ci.org/python-security/pyt)

# PyT - Python Taint

Static analysis of Python web applications based on theoretical foundations (Control flow graphs, fixed point, dataflow analysis)
Expand All @@ -8,11 +10,62 @@ Features planned:
- Detect XSS
- Detect directory traversal

Using it like a user:
`python -m pyt -f example/vulnerable_code/XSS_call.py save -du`

Running the tests: `python -m tests`

Running an individual test file: `python -m unittest tests.import_test`

Running an individual test: `python -m unittest tests.import_test.ImportTest.test_import`

Work in progress

# Contributions
Join our slack group: https://pyt-dev.slack.com/

[Guidelines](https://github.com/python-security/pyt/blob/master/CONTRIBUTIONS.md)

[![Build Status](https://travis-ci.org/python-security/pyt.svg?branch=master)](https://travis-ci.org/python-security/pyt)
## Virtual env setup guide

Create a directory to hold the virtual env and project

`mkdir ~/a_folder`

`cd ~/a_folder`

Clone the project into the directory

`git clone https://github.com/python-security/pyt.git`

Create the virtual environment

`python3 -m venv ~/a_folder/`

Check that you have the right versions

`python --version` sample output `Python 3.6.0`

`pip --version` sample output `pip 9.0.1 from /Users/kevinhock/a_folder/lib/python3.6/site-packages (python 3.6)`

Change to project directory

`cd pyt`

Install dependencies

`pip install -r requirements.txt`

`pip list` sample output

```
gitdb (0.6.4)
GitPython (2.0.8)
graphviz (0.4.10)
pip (9.0.1)
requests (2.10.0)
setuptools (28.8.0)
smmap (0.9.0)
```

In the future, just type `source ~/pyt/bin/activate` to start developing.
6 changes: 1 addition & 5 deletions example/cfg_example.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
import os
import sys

sys.path.insert(0, os.path.abspath('../pyt'))
from cfg import CFG, print_CFG, generate_ast
from ..pyt.cfg import CFG, print_CFG, generate_ast


ast = generate_ast('example_inputs/example.py')

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great to get rid of this

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Expand Down
9 changes: 3 additions & 6 deletions func_counter.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
"""Module used for counting number of functions
to get an estimate og how big the CFG should be"""

import ast
import sys
import os

sys.path.insert(0, os.path.abspath('pyt'))
from cfg import get_call_names_as_string, generate_ast
from project_handler import get_python_modules
from pyt.cfg import get_call_names_as_string, generate_ast
from pyt.project_handler import get_python_modules


function_calls = list()
functions = dict()
Expand Down
12 changes: 7 additions & 5 deletions profiling/fine_timer.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import pstats
import os
from subprocess import run as sub_run, PIPE
import pstats
from subprocess import PIPE, run as sub_run


KERNPROF = 'kernprof-3.5'
LINE_PROFILER_FILE = 'pyt.py.lprof'
PYTHON = 'python3'
PYT_PATH = '../pyt/pyt.py'
STATS_FILENAME = 'stats.prof'
SNAKEVIZ = 'snakeviz'
KERNPROF = 'kernprof-3.5'
LINE_PROFILER_FILE = 'pyt.py.lprof'
STATS_FILENAME = 'stats.prof'


def clean_up():
if os.path.isfile(STATS_FILENAME):
Expand Down
3 changes: 2 additions & 1 deletion profiling/profiler.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import argparse

import fine_timer
from . import fine_timer


parser = argparse.ArgumentParser()

Expand Down
12 changes: 7 additions & 5 deletions profiling/profiling_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,21 @@

Saves the result for future reference.
"""
from subprocess import Popen
from datetime import datetime
from shutil import which
from subprocess import Popen

TRAVIS_PYTHON = 'python'

FIXED_POINT_FLAG = '-fp'
KERNPROF = 'kernprof-3.5'
PROFILER = 'profiler.py'
PROFILING_DB = 'db.txt'
TEST_PROJECT_1 = 'test_projects/flaskbb_lite_1/flaskbb/app.py'
TEST_PROJECT_2 = 'test_projects/flaskbb_lite_2/flaskbb/app.py'
TEST_PROJECT_3 = 'test_projects/flaskbb_lite_3/flaskbb/app.py'
TEST_PROJECTS = [TEST_PROJECT_1, TEST_PROJECT_2, TEST_PROJECT_3]
FIXED_POINT_FLAG = '-fp'
PROFILING_DB = 'db.txt'
KERNPROF = 'kernprof-3.5'
TRAVIS_PYTHON = 'python'


if which(KERNPROF) is None:
print('You need "kernprof" to run this script. Install: "pip3 install line_profiler".')
Expand Down
2 changes: 1 addition & 1 deletion pydocstyle.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import subprocess
import re
import subprocess
import sys
import os

Expand Down
1 change: 1 addition & 0 deletions pyt/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import pyt


def main():
pyt.main()
54 changes: 30 additions & 24 deletions pyt/pyt.py → pyt/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,35 @@
import argparse
import os
from datetime import date
from pprint import pprint

from .argument_helpers import valid_date
from .ast_helper import generate_ast
from .draw import draw_cfgs, draw_lattices
from .constraint_table import initialize_constraint_table, print_table
from .fixed_point import analyse
from .flask_adaptor import FlaskAdaptor
from .github_search import scan_github, set_github_api_token
from .interprocedural_cfg import interprocedural
from .intraprocedural_cfg import intraprocedural
from .lattice import print_lattice
from .liveness import LivenessAnalysis
from .project_handler import get_directory_modules, get_python_modules
from .reaching_definitions import ReachingDefinitionsAnalysis
from .reaching_definitions_taint import ReachingDefinitionsTaintAnalysis
from .repo_runner import get_repos
from .save import (
cfg_to_file,
create_database,
def_use_chain_to_file,
lattice_to_file,
Output,
use_def_chain_to_file,
verbose_cfg_to_file,
vulnerabilities_to_file
)
from .vulnerabilities import find_vulnerabilities

from ast_helper import generate_ast
from interprocedural_cfg import interprocedural
from intraprocedural_cfg import intraprocedural
from draw import draw_cfgs, draw_lattices
from reaching_definitions_taint import ReachingDefinitionsTaintAnalysis
from liveness import LivenessAnalysis
from reaching_definitions import ReachingDefinitionsAnalysis
from fixed_point import analyse
from flask_adaptor import FlaskAdaptor
from vulnerabilities import find_vulnerabilities
from project_handler import get_python_modules, get_directory_modules
from save import create_database, def_use_chain_to_file,\
use_def_chain_to_file, cfg_to_file, verbose_cfg_to_file,\
lattice_to_file, vulnerabilities_to_file
from constraint_table import initialize_constraint_table
from github_search import scan_github, set_github_api_token
from argument_helpers import valid_date

parser = argparse.ArgumentParser()
parser.set_defaults(which='')
Expand Down Expand Up @@ -118,7 +129,7 @@
help='Output everything to file.',
action='store_true')

search_parser = subparsers.add_parser('github_search',
search_parser = subparsers.add_parser('github_search',
help='Searches through github and runs PyT'
' on found repositories. This can take some time.')
search_parser.set_defaults(which='search')
Expand Down Expand Up @@ -159,7 +170,6 @@ def main():

cfg_list = list()
if args.git_repos:
from repo_runner import get_repos
repos = get_repos(args.git_repos)
for repo in repos:
repo.clone()
Expand All @@ -171,7 +181,7 @@ def main():

if args.which == 'search':
set_github_api_token()
if args.start_date:
if args.start_date:
scan_github(args.search_string, args.start_date,
analysis, analyse_repo, args.csv_path)
else:
Expand Down Expand Up @@ -220,10 +230,8 @@ def main():
else:
draw_cfgs(cfg_list)
if args.print:
from lattice import print_lattice
l = print_lattice(cfg_list, analysis)

from constraint_table import print_table
print_table(l)
for i, e in enumerate(cfg_list):
print('############## CFG number: ', i)
Expand All @@ -234,7 +242,6 @@ def main():
print(repr(e))

if args.print_project_modules:
from pprint import pprint
print('############## PROJECT MODULES ##############')
pprint(project_modules)

Expand All @@ -246,7 +253,6 @@ def main():
# Output to file
if args.which == 'save':
if args.filename_prefix:
from save import Output
Output.filename_prefix = args.filename_prefix
if args.save_all:
def_use_chain_to_file(cfg_list)
Expand Down
4 changes: 2 additions & 2 deletions pyt/analysis_base.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"""Thos module contains a base class for the analysis component used in PyT."""
from abc import abstractmethod, ABCMeta
"""This module contains a base class for the analysis component used in PyT."""
from abc import ABCMeta, abstractmethod


class AnalysisBase(metaclass=ABCMeta):
Expand Down
3 changes: 2 additions & 1 deletion pyt/argument_helpers.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from datetime import datetime
from argparse import ArgumentTypeError
from datetime import datetime


def valid_date(s):
date_format = "%Y-%m-%d"
Expand Down
4 changes: 2 additions & 2 deletions pyt/ast_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,9 @@ def get_call_names(node):
return reversed(get_call_names_helper(node, result))


class Arguments(object):
class Arguments():
"""Represents arguments of a function."""

def __init__(self, args):
"""Create an Argument container class.

Expand Down
Loading