@@ -876,39 +876,39 @@ module TaintedPath {
876
876
}
877
877
878
878
/**
879
- * Holds if there is a step `src -> dst ` mapping `srclabel ` to `dstlabel ` relevant for path traversal vulnerabilities.
879
+ * Holds if there is a step `node1 -> node2 ` mapping `state1 ` to `state2 ` relevant for path traversal vulnerabilities.
880
880
*/
881
881
predicate isAdditionalFlowStep (
882
- DataFlow:: Node src , FlowState srclabel , DataFlow:: Node dst , FlowState dstlabel
882
+ DataFlow:: Node node1 , FlowState state1 , DataFlow:: Node node2 , FlowState state2
883
883
) {
884
- isPosixPathStep ( src , srclabel , dst , dstlabel )
884
+ isPosixPathStep ( node1 , state1 , node2 , state2 )
885
885
or
886
886
// Ignore all preliminary sanitization after decoding URI components
887
- srclabel instanceof FlowState:: PosixPath and
888
- dstlabel instanceof FlowState:: PosixPath and
887
+ state1 instanceof FlowState:: PosixPath and
888
+ state2 instanceof FlowState:: PosixPath and
889
889
(
890
- TaintTracking:: uriStep ( src , dst )
890
+ TaintTracking:: uriStep ( node1 , node2 )
891
891
or
892
892
exists ( DataFlow:: CallNode decode |
893
893
decode .getCalleeName ( ) = "decodeURIComponent" or decode .getCalleeName ( ) = "decodeURI"
894
894
|
895
- src = decode .getArgument ( 0 ) and
896
- dst = decode
895
+ node1 = decode .getArgument ( 0 ) and
896
+ node2 = decode
897
897
)
898
898
)
899
899
or
900
- TaintTracking:: persistentStorageStep ( src , dst ) and srclabel = dstlabel
900
+ TaintTracking:: persistentStorageStep ( node1 , node2 ) and state1 = state2
901
901
or
902
- exists ( DataFlow:: PropRead read | read = dst |
903
- src = read .getBase ( ) and
902
+ exists ( DataFlow:: PropRead read | read = node2 |
903
+ node1 = read .getBase ( ) and
904
904
read .getPropertyName ( ) != "length" and
905
- srclabel = dstlabel and
905
+ state1 = state2 and
906
906
not AccessPath:: DominatingPaths:: hasDominatingWrite ( read )
907
907
)
908
908
or
909
909
// string method calls of interest
910
910
exists ( DataFlow:: MethodCallNode mcn , string name |
911
- srclabel = dstlabel and dst = mcn and mcn .calls ( src , name )
911
+ state1 = state2 and node2 = mcn and mcn .calls ( node1 , name )
912
912
|
913
913
name = StringOps:: substringMethodName ( ) and
914
914
// to avoid very dynamic transformations, require at least one fixed index
@@ -926,49 +926,49 @@ module TaintedPath {
926
926
)
927
927
or
928
928
// A `str.split()` call can either split into path elements (`str.split("/")`) or split by some other string.
929
- exists ( StringSplitCall mcn | dst = mcn and mcn .getBaseString ( ) = src |
929
+ exists ( StringSplitCall mcn | node2 = mcn and mcn .getBaseString ( ) = node1 |
930
930
if mcn .getSeparator ( ) = "/"
931
931
then
932
- srclabel .( FlowState:: PosixPath ) .canContainDotDotSlash ( ) and
933
- dstlabel instanceof FlowState:: SplitPath
934
- else srclabel = dstlabel
932
+ state1 .( FlowState:: PosixPath ) .canContainDotDotSlash ( ) and
933
+ state2 instanceof FlowState:: SplitPath
934
+ else state1 = state2
935
935
)
936
936
or
937
937
// array method calls of interest
938
- exists ( DataFlow:: MethodCallNode mcn , string name | dst = mcn and mcn .calls ( src , name ) |
938
+ exists ( DataFlow:: MethodCallNode mcn , string name | node2 = mcn and mcn .calls ( node1 , name ) |
939
939
(
940
940
name = "pop" or
941
941
name = "shift"
942
942
) and
943
- srclabel instanceof FlowState:: SplitPath and
944
- dstlabel .( FlowState:: PosixPath ) .canContainDotDotSlash ( )
943
+ state1 instanceof FlowState:: SplitPath and
944
+ state2 .( FlowState:: PosixPath ) .canContainDotDotSlash ( )
945
945
or
946
946
(
947
947
name = "slice" or
948
948
name = "splice" or
949
949
name = "concat"
950
950
) and
951
- dstlabel instanceof FlowState:: SplitPath and
952
- srclabel instanceof FlowState:: SplitPath
951
+ state2 instanceof FlowState:: SplitPath and
952
+ state1 instanceof FlowState:: SplitPath
953
953
or
954
954
name = "join" and
955
955
mcn .getArgument ( 0 ) .mayHaveStringValue ( "/" ) and
956
- srclabel instanceof FlowState:: SplitPath and
957
- dstlabel .( FlowState:: PosixPath ) .canContainDotDotSlash ( )
956
+ state1 instanceof FlowState:: SplitPath and
957
+ state2 .( FlowState:: PosixPath ) .canContainDotDotSlash ( )
958
958
)
959
959
or
960
960
// prefix.concat(path)
961
961
exists ( DataFlow:: MethodCallNode mcn |
962
- mcn .getMethodName ( ) = "concat" and mcn .getAnArgument ( ) = src
962
+ mcn .getMethodName ( ) = "concat" and mcn .getAnArgument ( ) = node1
963
963
|
964
- dst = mcn and
965
- dstlabel instanceof FlowState:: SplitPath and
966
- srclabel instanceof FlowState:: SplitPath
964
+ node2 = mcn and
965
+ state2 instanceof FlowState:: SplitPath and
966
+ state1 instanceof FlowState:: SplitPath
967
967
)
968
968
or
969
969
// reading unknown property of split path
970
- exists ( DataFlow:: PropRead read | read = dst |
971
- src = read .getBase ( ) and
970
+ exists ( DataFlow:: PropRead read | read = node2 |
971
+ node1 = read .getBase ( ) and
972
972
not read .getPropertyName ( ) = "length" and
973
973
not exists ( read .getPropertyNameExpr ( ) .getIntValue ( ) ) and
974
974
// split[split.length - 1]
@@ -977,135 +977,137 @@ module TaintedPath {
977
977
binop .getAnOperand ( ) .getIntValue ( ) = 1 and
978
978
binop .getAnOperand ( ) .( PropAccess ) .getPropertyName ( ) = "length"
979
979
) and
980
- srclabel instanceof FlowState:: SplitPath and
981
- dstlabel .( FlowState:: PosixPath ) .canContainDotDotSlash ( )
980
+ state1 instanceof FlowState:: SplitPath and
981
+ state2 .( FlowState:: PosixPath ) .canContainDotDotSlash ( )
982
982
)
983
983
or
984
984
exists ( API:: CallNode call | call = API:: moduleImport ( "slash" ) .getACall ( ) |
985
- src = call .getArgument ( 0 ) and
986
- dst = call and
987
- srclabel = dstlabel
985
+ node1 = call .getArgument ( 0 ) and
986
+ node2 = call and
987
+ state1 = state2
988
988
)
989
989
or
990
990
exists ( HtmlSanitizerCall call |
991
- src = call .getInput ( ) and
992
- dst = call and
993
- srclabel = dstlabel
991
+ node1 = call .getInput ( ) and
992
+ node2 = call and
993
+ state1 = state2
994
994
)
995
995
or
996
996
exists ( DataFlow:: CallNode join |
997
997
// path.join() with spread argument
998
998
join = NodeJSLib:: Path:: moduleMember ( "join" ) .getACall ( ) and
999
- src = join .getASpreadArgument ( ) and
1000
- dst = join and
999
+ node1 = join .getASpreadArgument ( ) and
1000
+ node2 = join and
1001
1001
(
1002
- srclabel .( FlowState:: PosixPath ) .canContainDotDotSlash ( )
1002
+ state1 .( FlowState:: PosixPath ) .canContainDotDotSlash ( )
1003
1003
or
1004
- srclabel instanceof FlowState:: SplitPath
1004
+ state1 instanceof FlowState:: SplitPath
1005
1005
) and
1006
- dstlabel .( FlowState:: PosixPath ) .isNormalized ( ) and
1006
+ state2 .( FlowState:: PosixPath ) .isNormalized ( ) and
1007
1007
if isRelative ( join .getArgument ( 0 ) .getStringValue ( ) )
1008
- then dstlabel .( FlowState:: PosixPath ) .isRelative ( )
1009
- else dstlabel .( FlowState:: PosixPath ) .isAbsolute ( )
1008
+ then state2 .( FlowState:: PosixPath ) .isRelative ( )
1009
+ else state2 .( FlowState:: PosixPath ) .isAbsolute ( )
1010
1010
)
1011
1011
}
1012
1012
1013
1013
/**
1014
- * Holds if we should include a step from `src -> dst ` with labels `srclabel -> dstlabel `, and the
1015
- * standard taint step `src -> dst ` should be suppressed.
1014
+ * Holds if we should include a step from `node1 -> node2 ` with labels `state1 -> state2 `, and the
1015
+ * standard taint step `node1 -> node2 ` should be suppressed.
1016
1016
*/
1017
1017
private predicate isPosixPathStep (
1018
- DataFlow:: Node src , FlowState:: PosixPath srclabel , DataFlow:: Node dst ,
1019
- FlowState:: PosixPath dstlabel
1018
+ DataFlow:: Node node1 , FlowState:: PosixPath state1 , DataFlow:: Node node2 ,
1019
+ FlowState:: PosixPath state2
1020
1020
) {
1021
1021
// path.normalize() and similar
1022
1022
exists ( NormalizingPathCall call |
1023
- src = call .getInput ( ) and
1024
- dst = call .getOutput ( ) and
1025
- dstlabel = srclabel .toNormalized ( )
1023
+ node1 = call .getInput ( ) and
1024
+ node2 = call .getOutput ( ) and
1025
+ state2 = state1 .toNormalized ( )
1026
1026
)
1027
1027
or
1028
1028
// path.resolve() and similar
1029
1029
exists ( ResolvingPathCall call |
1030
- src = call .getInput ( ) and
1031
- dst = call .getOutput ( ) and
1032
- dstlabel .isAbsolute ( ) and
1033
- dstlabel .isNormalized ( )
1030
+ node1 = call .getInput ( ) and
1031
+ node2 = call .getOutput ( ) and
1032
+ state2 .isAbsolute ( ) and
1033
+ state2 .isNormalized ( )
1034
1034
)
1035
1035
or
1036
1036
// path.relative() and similar
1037
1037
exists ( NormalizingRelativePathCall call |
1038
- src = call .getInput ( ) and
1039
- dst = call .getOutput ( ) and
1040
- dstlabel .isRelative ( ) and
1041
- dstlabel .isNormalized ( )
1038
+ node1 = call .getInput ( ) and
1039
+ node2 = call .getOutput ( ) and
1040
+ state2 .isRelative ( ) and
1041
+ state2 .isNormalized ( )
1042
1042
)
1043
1043
or
1044
1044
// path.dirname() and similar
1045
1045
exists ( PreservingPathCall call |
1046
- src = call .getInput ( ) and
1047
- dst = call .getOutput ( ) and
1048
- srclabel = dstlabel
1046
+ node1 = call .getInput ( ) and
1047
+ node2 = call .getOutput ( ) and
1048
+ state1 = state2
1049
1049
)
1050
1050
or
1051
1051
// foo.replace(/\./, "") and similar
1052
1052
exists ( DotRemovingReplaceCall call |
1053
- src = call .getInput ( ) and
1054
- dst = call .getOutput ( ) and
1055
- srclabel .isAbsolute ( ) and
1056
- dstlabel .isAbsolute ( ) and
1057
- dstlabel .isNormalized ( )
1053
+ node1 = call .getInput ( ) and
1054
+ node2 = call .getOutput ( ) and
1055
+ state1 .isAbsolute ( ) and
1056
+ state2 .isAbsolute ( ) and
1057
+ state2 .isNormalized ( )
1058
1058
)
1059
1059
or
1060
1060
// foo.replace(/(\.\.\/)*/, "") and similar
1061
1061
exists ( DotDotSlashPrefixRemovingReplace call |
1062
- src = call .getInput ( ) and
1063
- dst = call .getOutput ( )
1062
+ node1 = call .getInput ( ) and
1063
+ node2 = call .getOutput ( )
1064
1064
|
1065
- // the 4 possible combinations of normalized + relative for `srclabel `, and the possible values for `dstlabel ` in each case.
1066
- srclabel .isNonNormalized ( ) and srclabel .isRelative ( ) // raw + relative -> any()
1065
+ // the 4 possible combinations of normalized + relative for `state1 `, and the possible values for `state2 ` in each case.
1066
+ state1 .isNonNormalized ( ) and state1 .isRelative ( ) // raw + relative -> any()
1067
1067
or
1068
- srclabel .isNormalized ( ) and srclabel .isAbsolute ( ) and srclabel = dstlabel // normalized + absolute -> normalized + absolute
1068
+ state1 .isNormalized ( ) and state1 .isAbsolute ( ) and state1 = state2 // normalized + absolute -> normalized + absolute
1069
1069
or
1070
- srclabel .isNonNormalized ( ) and srclabel .isAbsolute ( ) and dstlabel .isAbsolute ( ) // raw + absolute -> raw/normalized + absolute
1070
+ state1 .isNonNormalized ( ) and state1 .isAbsolute ( ) and state2 .isAbsolute ( ) // raw + absolute -> raw/normalized + absolute
1071
1071
// normalized + relative -> none()
1072
1072
)
1073
1073
or
1074
1074
// path.join()
1075
1075
exists ( DataFlow:: CallNode join , int n |
1076
1076
join = NodeJSLib:: Path:: moduleMember ( "join" ) .getACall ( )
1077
1077
|
1078
- src = join .getArgument ( n ) and
1079
- dst = join and
1078
+ node1 = join .getArgument ( n ) and
1079
+ node2 = join and
1080
1080
(
1081
1081
// If the initial argument is tainted, just normalize it. It can be relative or absolute.
1082
1082
n = 0 and
1083
- dstlabel = srclabel .toNormalized ( )
1083
+ state2 = state1 .toNormalized ( )
1084
1084
or
1085
1085
// For later arguments, the flow label depends on whether the first argument is absolute or relative.
1086
1086
// If in doubt, we assume it is absolute.
1087
1087
n > 0 and
1088
- srclabel .canContainDotDotSlash ( ) and
1089
- dstlabel .isNormalized ( ) and
1088
+ state1 .canContainDotDotSlash ( ) and
1089
+ state2 .isNormalized ( ) and
1090
1090
if isRelative ( join .getArgument ( 0 ) .getStringValue ( ) )
1091
- then dstlabel .isRelative ( )
1092
- else dstlabel .isAbsolute ( )
1091
+ then state2 .isRelative ( )
1092
+ else state2 .isAbsolute ( )
1093
1093
)
1094
1094
)
1095
1095
or
1096
1096
// String concatenation - behaves like path.join() except without normalization
1097
- exists ( DataFlow:: Node operator , int n | StringConcatenation:: taintStep ( src , dst , operator , n ) |
1097
+ exists ( DataFlow:: Node operator , int n |
1098
+ StringConcatenation:: taintStep ( node1 , node2 , operator , n )
1099
+ |
1098
1100
// use ordinary taint flow for the first operand
1099
1101
n = 0 and
1100
- srclabel = dstlabel
1102
+ state1 = state2
1101
1103
or
1102
1104
n > 0 and
1103
- srclabel .canContainDotDotSlash ( ) and
1104
- dstlabel .isNonNormalized ( ) and // The ../ is no longer at the beginning of the string.
1105
+ state1 .canContainDotDotSlash ( ) and
1106
+ state2 .isNonNormalized ( ) and // The ../ is no longer at the beginning of the string.
1105
1107
(
1106
1108
if isRelative ( StringConcatenation:: getOperand ( operator , 0 ) .getStringValue ( ) )
1107
- then dstlabel .isRelative ( )
1108
- else dstlabel .isAbsolute ( )
1109
+ then state2 .isRelative ( )
1110
+ else state2 .isAbsolute ( )
1109
1111
)
1110
1112
)
1111
1113
}
0 commit comments