Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit a2d7634

Browse files
Merge pull request #167 from bcaller/method-propagation
Taint propagates from methods of tainted objects
2 parents d2a8189 + 8811343 commit a2d7634

File tree

2 files changed

+29
-17
lines changed

2 files changed

+29
-17
lines changed

‎pyt/cfg/stmt_visitor.py

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
)
1212
from ..core.ast_helper import (
1313
generate_ast,
14+
get_call_names,
1415
get_call_names_as_string
1516
)
1617
from ..core.module_definitions import (
@@ -472,14 +473,6 @@ def assignment_call_node(self, left_hand_label, ast_node):
472473
call = self.visit(ast_node.value)
473474
call_label = call.left_hand_side
474475

475-
if isinstance(call, BBorBInode):
476-
# Necessary to know e.g.
477-
# `image_name = image_name.replace('..', '')`
478-
# is a reassignment.
479-
vars_visitor = VarsVisitor()
480-
vars_visitor.visit(ast_node.value)
481-
call.right_hand_side_variables.extend(vars_visitor.result)
482-
483476
call_assignment = AssignmentCallNode(
484477
left_hand_label + ' = ' + call_label,
485478
left_hand_label,
@@ -572,7 +565,7 @@ def visit_While(self, node):
572565

573566
return self.loop_node_skeleton(test, node)
574567

575-
def add_blackbox_or_builtin_call(self, node, blackbox):
568+
def add_blackbox_or_builtin_call(self, node, blackbox):# noqa: C901
576569
"""Processes a blackbox or builtin function when it is called.
577570
Nothing gets assigned to ret_func_foo in the builtin/blackbox case.
578571
@@ -597,14 +590,14 @@ def add_blackbox_or_builtin_call(self, node, blackbox):
597590
saved_function_call_index = self.function_call_index
598591
self.undecided = False
599592

600-
call_label = LabelVisitor()
601-
call_label.visit(node)
593+
call_label_visitor = LabelVisitor()
594+
call_label_visitor.visit(node)
602595

603-
index = call_label.result.find('(')
596+
call_function_label = call_label_visitor.result[:call_label_visitor.result.find('(')]
604597

605598
# Create e.g. ~call_1 = ret_func_foo
606599
LHS = CALL_IDENTIFIER + 'call_' + str(saved_function_call_index)
607-
RHS = 'ret_' + call_label.result[:index] + '('
600+
RHS = 'ret_' + call_function_label + '('
608601

609602
call_node = BBorBInode(
610603
label='',
@@ -613,7 +606,7 @@ def add_blackbox_or_builtin_call(self, node, blackbox):
613606
right_hand_side_variables=[],
614607
line_number=node.lineno,
615608
path=self.filenames[-1],
616-
func_name=call_label.result[:index]
609+
func_name=call_function_label
617610
)
618611
visual_args = list()
619612
rhs_vars = list()
@@ -657,6 +650,11 @@ def add_blackbox_or_builtin_call(self, node, blackbox):
657650
# `scrypt.outer(scrypt.inner(image_name), scrypt.other_inner(image_name))`
658651
last_return_value_of_nested_call.connect(call_node)
659652

653+
call_names = list(get_call_names(node.func))
654+
if len(call_names) > 1:
655+
# taint is a RHS variable (self) of taint.lower()
656+
rhs_vars.append(call_names[0])
657+
660658
if len(visual_args) > 0:
661659
for arg in visual_args:
662660
RHS = RHS + arg + ", "
@@ -667,7 +665,6 @@ def add_blackbox_or_builtin_call(self, node, blackbox):
667665
call_node.label = LHS + " = " + RHS
668666

669667
call_node.right_hand_side_variables = rhs_vars
670-
# Used in get_sink_args, not using right_hand_side_variables because it is extended in assignment_call_node
671668
rhs_visitor = RHSVisitor()
672669
rhs_visitor.visit(node)
673670
call_node.args = rhs_visitor.result

‎tests/vulnerabilities/vulnerabilities_test.py

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,9 @@ def test_build_sanitiser_node_dict(self):
111111

112112
self.assertEqual(sanitiser_dict['escape'][0], cfg.nodes[3])
113113

114-
def run_analysis(self, path):
115-
self.cfg_create_from_file(path)
114+
def run_analysis(self, path=None):
115+
if path:
116+
self.cfg_create_from_file(path)
116117
cfg_list = [self.cfg]
117118

118119
FrameworkAdaptor(cfg_list, [], [], is_flask_route_function)
@@ -468,6 +469,20 @@ def test_yield(self):
468469

469470
self.assertAlphaEqual(str(vuln), EXPECTED_VULNERABILITY_DESCRIPTION)
470471

472+
def test_method_of_taint(self):
473+
def assert_vulnerable(fixture):
474+
tree = ast.parse('TAINT = request.args.get("")\n' + fixture + '\nexecute(result)')
475+
self.cfg_create_from_ast(tree)
476+
vulnerabilities = self.run_analysis()
477+
self.assert_length(vulnerabilities, expected_length=1, msg=fixture)
478+
479+
assert_vulnerable('result = TAINT')
480+
assert_vulnerable('result = TAINT.lower()')
481+
assert_vulnerable('result = str(TAINT)')
482+
assert_vulnerable('result = str(TAINT.lower())')
483+
assert_vulnerable('result = repr(str("%s" % TAINT.lower().upper()))')
484+
assert_vulnerable('result = repr(str("{}".format(TAINT.lower())))')
485+
471486

472487
class EngineDjangoTest(VulnerabilitiesBaseTestCase):
473488
def run_analysis(self, path):

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /