Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[PHP] Improve Echoed Requests #3353

Merged
merged 5 commits into from
Apr 24, 2024
Merged

Conversation

shellz-n-stuff
Copy link
Contributor

@shellz-n-stuff shellz-n-stuff commented Apr 15, 2024

Description

This PR aims two improve the echoed requests PHP injection rule by doing the followings:

  1. Splitting out Print and Echo into seperate rules to allow for Fixes/Autofixes
  2. Adding additional sanitisation functions to reduce the number of false positives associated with the rules
  3. Remove a false negative associated with "empty" (more on this below)

False Negative

The empty function by itself isn't really a sanitiser as it returns a boolean output rather than an empty string. In theory we could add a sanitiser similar to:
pattern: if(empty($...VARS))

However, this is likely to be just as noisy/false negative heavy. There may be a smart way to check this with metavariable comparisons. If someone wants to try further improve this rule.

Notes

I couldn't find any way to use fix-regex to keep these rules combined but if would love to simplify this if you have any suggestions.

@CLAassistant
Copy link

CLAassistant commented Apr 15, 2024

CLA assistant check
All committers have signed the CLA.

@shellz-n-stuff
Copy link
Contributor Author

Arguably isset should also be removed as a sanitisation function.

@kurt-r2c
Copy link
Contributor

@shellz-n-stuff I suspect isset is a sanitizer here because the return type is a boolean and standard propagation would consider the return value tainted (which is false, as it's a boolean not the user input)

@shellz-n-stuff
Copy link
Contributor Author

shellz-n-stuff commented Apr 15, 2024

@shellz-n-stuff I suspect isset is a sanitizer here because the return type is a boolean and standard propagation would consider the return value tainted (which is false, as it's a boolean not the user input)

@kurt-r2c,

I'll update this rule later today to remove isset. I think a pattern like the below would be a fairly common false negative. I can't think of many cases where this would meaningfully increase false positives either

if(isset($VAR)){ echo $VAR; }

I'll also sort out the test failures.

@shellz-n-stuff
Copy link
Contributor Author

@kurt-r2c updated 🙏

Copy link
Contributor

@kurt-r2c kurt-r2c left a comment

Choose a reason for hiding this comment

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

@shellz-n-stuff removal of isset here will cause false positives as the taint must flow through the function to the sink to be considered sanitized - the sanitizer is not by side effect here.

without isset this will (incorrectly) flag echo isset($VAR)
https://semgrep.dev/playground/s/JDold

the correct behavior is:
https://semgrep.dev/playground/s/5rz6W

note that even with the sanitizer we are still flagging line 13 because an unsanitized reference of $VAR makes it into the sink

Similarly, empty(...) should not be removed.

Please revert these changes and this should be good to merge.

@shellz-n-stuff
Copy link
Contributor Author

shellz-n-stuff commented Apr 24, 2024

@shellz-n-stuff removal of isset here will cause false positives as the taint must flow through the function to the sink to be considered sanitized - the sanitizer is not by side effect here.

without isset this will (incorrectly) flag echo isset($VAR) https://semgrep.dev/playground/s/JDold

the correct behavior is: https://semgrep.dev/playground/s/5rz6W

note that even with the sanitizer we are still flagging line 13 because an unsanitized reference of $VAR makes it into the sink

Similarly, empty(...) should not be removed.

Please revert these changes and this should be good to merge.

Howdy Kurt,

Happy to make the change, but I think in terms of optimising the rule having this as a valid sanitiser is far more likely to increase false negatives than false positives.

It strikes me as a fairly common coding convention to check a variable isn't null before echoing it out e.g.:

if(isset($VAR)){ 
  echo "your name is" + $VAR; 
}

Whereas the pattern you described where you are echoing out a function that returns a boolean seems less common/likely. Obviously I'm happy to make the change if you disagree as I firmly believe you're in a better position to assess the noise/data quality of these rules ❤️

@kurt-r2c
Copy link
Contributor

kurt-r2c commented Apr 24, 2024

@shellz-n-stuff totally understand your concern - you'll note that in the correct behavior with the isset sanitizer (https://semgrep.dev/playground/s/5rz6W) line 9 is flagged (as it should be) which exercises the if(isset(...)){...} pattern you are concerned about.

<?php

function minimalexample() {
    $VAR = $_GET['someval']
    if(isset($VAR)){ 
        // ok: echoed-request
        echo isset($VAR);
        // ruleid: echoed-request
        echo $VAR; 
        //ok: echoed-request
        echo isset($VAR) . "something";
        // ruleid: echoed-request
        echo isset($VAR) . $VAR;
    }

}

@shellz-n-stuff
Copy link
Contributor Author

@shellz-n-stuff totally understand your concern - you'll note that in the correct behavior with the isset sanitizer (https://semgrep.dev/playground/s/5rz6W) line 9 is flagged (as it should be) which exercises the if(isset(...)){...} pattern you are concerned about.

<?php

function minimalexample() {
    $VAR = $_GET['someval']
    if(isset($VAR)){ 
        // ok: echoed-request
        echo isset($VAR);
        // ruleid: echoed-request
        echo $VAR; 
        //ok: echoed-request
        echo isset($VAR) . "something";
        // ruleid: echoed-request
        echo isset($VAR) . $VAR;
    }

}

Wow, so semgrep's taint tracker mode tracks assignment. That's absolutely unreal. I'll fix this now, I'm super interested in how y'all got that to work in pass by value vs pass by reference.

Apologies for my misunderstanding!

@kurt-r2c kurt-r2c enabled auto-merge April 24, 2024 15:59
@kurt-r2c
Copy link
Contributor

String interpolation tests are failing - investigating. Not sure why the removal of the parentheses cause this test to start failing.

php/lang/security/injection/echoed-request.php Outdated Show resolved Hide resolved
php/lang/security/injection/printed-request.php Outdated Show resolved Hide resolved
php/lang/security/injection/printed-request.php Outdated Show resolved Hide resolved
php/lang/security/injection/echoed-request.php Outdated Show resolved Hide resolved
@kurt-r2c kurt-r2c dismissed their stale review April 24, 2024 20:33

applied suggestions via web UI

@shellz-n-stuff
Copy link
Contributor Author

Oh good catch. Thank you @kurt-r2c, my apologies!

@kurt-r2c kurt-r2c merged commit 2c0ea0a into semgrep:develop Apr 24, 2024
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants