Repository navigation
FIX: Check the default SSTIOutputScorer template-body patterns in linear time - #4296
Open
Jaafer Rahmani (bIackr0se) wants to merge 1 commit into
Open
Jaafer Rahmani (bIackr0se) wants to merge 1 commit into
Jaafer Rahmani (bIackr0se) wants to merge 1 commit into
Conversation
…ear time
The Python Gadget Chain, Twig Execution Filter, FreeMarker Gadget and SpEL
default patterns scan from every template opener to the next closer, so a
reply that repeats an opener without a closer takes quadratic time (26 s for
32 KB of unclosed {{ on main). Keep the default pattern strings and, when a
default is in use, check its match condition in one pass over the openers.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
SSTIOutputScorer()runs four default patterns that span a template body: "Python Gadget Chain", "Twig Execution Filter", "FreeMarker Gadget" and "SpEL / Java Type Expression". Each one starts at a template opener such as{{,{%,${,*{or<#, and reads ahead until either the exploit marker (__class__,|filter('system'), ...) or the closer of that expression. When neither a marker nor a closer follows,re.searchreads to the end of the reply again from every opener, so scoring takes quadratic time on repeated openers: a 32 KB reply that repeats{{takes 26 s on main. This PR checks those four patterns in linear time with the same verdict, as #3966 did for the default Markdown image patterns._opener_reaches_targetwalks the openers once, in order, and keeps the nearest closer and marker found for the previous opener while they are still ahead. A new search runs only when its cached match has fallen behind the current opener, so the search positions only move forward.{%inside{{%}are still considered, as the regex considers them.re.search.Default
SSTIOutputScorer().score_text_async(reply)withinitialize_pyrit_async(memory_db_type=IN_MEMORY), Python 3.12, on a warmed scoring path. The 8,000-character times were checked against three timed runs after one untimed scoring call; each remaining row was checked once after earlier timed scoring calls:Each new check gives the same verdict as
re.searchwith its default pattern on 300,194 strings (the 194 string literals oftest_ssti_output_scorer.pyplus 300,000 random sequences of template tokens such as{{,-,}},%},${,*{,<#,[=,],__class__,|FILTER('SYSTEM'),_self.envandT(System).getenv(), with no difference; about 10% to 16% of them match each pattern.Tests:
test_ssti_scorer_scales_on_unclosed_openers(10 s timeout; all seven cases time out on main),test_ssti_scorer_verdict_matches_default_pattern,test_ssti_scorer_custom_pattern_under_default_name_uses_regex, andtest_ssti_linear_checks_were_written_for_the_default_patterns, which fails when a default pattern changes without its linear check, intests/unit/score/regex/test_ssti_output_scorer.py.