@@ -876,39 +876,39 @@ module TaintedPath {
876876 }
877877
878878 /**
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.
880880 */
881881 predicate isAdditionalFlowStep (
882- DataFlow:: Node src , FlowState srclabel , DataFlow:: Node dst , FlowState dstlabel
882+ DataFlow:: Node node1 , FlowState state1 , DataFlow:: Node node2 , FlowState state2
883883 ) {
884- isPosixPathStep ( src , srclabel , dst , dstlabel )
884+ isPosixPathStep ( node1 , state1 , node2 , state2 )
885885 or
886886 // 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
889889 (
890- TaintTracking:: uriStep ( src , dst )
890+ TaintTracking:: uriStep ( node1 , node2 )
891891 or
892892 exists ( DataFlow:: CallNode decode |
893893 decode .getCalleeName ( ) = "decodeURIComponent" or decode .getCalleeName ( ) = "decodeURI"
894894 |
895- src = decode .getArgument ( 0 ) and
896- dst = decode
895+ node1 = decode .getArgument ( 0 ) and
896+ node2 = decode
897897 )
898898 )
899899 or
900- TaintTracking:: persistentStorageStep ( src , dst ) and srclabel = dstlabel
900+ TaintTracking:: persistentStorageStep ( node1 , node2 ) and state1 = state2
901901 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
904904 read .getPropertyName ( ) != "length" and
905- srclabel = dstlabel and
905+ state1 = state2 and
906906 not AccessPath:: DominatingPaths:: hasDominatingWrite ( read )
907907 )
908908 or
909909 // string method calls of interest
910910 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 )
912912 |
913913 name = StringOps:: substringMethodName ( ) and
914914 // to avoid very dynamic transformations, require at least one fixed index
@@ -926,49 +926,49 @@ module TaintedPath {
926926 )
927927 or
928928 // 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 |
930930 if mcn .getSeparator ( ) = "/"
931931 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
935935 )
936936 or
937937 // 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 ) |
939939 (
940940 name = "pop" or
941941 name = "shift"
942942 ) and
943- srclabel instanceof FlowState:: SplitPath and
944- dstlabel .( FlowState:: PosixPath ) .canContainDotDotSlash ( )
943+ state1 instanceof FlowState:: SplitPath and
944+ state2 .( FlowState:: PosixPath ) .canContainDotDotSlash ( )
945945 or
946946 (
947947 name = "slice" or
948948 name = "splice" or
949949 name = "concat"
950950 ) and
951- dstlabel instanceof FlowState:: SplitPath and
952- srclabel instanceof FlowState:: SplitPath
951+ state2 instanceof FlowState:: SplitPath and
952+ state1 instanceof FlowState:: SplitPath
953953 or
954954 name = "join" and
955955 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 ( )
958958 )
959959 or
960960 // prefix.concat(path)
961961 exists ( DataFlow:: MethodCallNode mcn |
962- mcn .getMethodName ( ) = "concat" and mcn .getAnArgument ( ) = src
962+ mcn .getMethodName ( ) = "concat" and mcn .getAnArgument ( ) = node1
963963 |
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
967967 )
968968 or
969969 // 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
972972 not read .getPropertyName ( ) = "length" and
973973 not exists ( read .getPropertyNameExpr ( ) .getIntValue ( ) ) and
974974 // split[split.length - 1]
@@ -977,135 +977,137 @@ module TaintedPath {
977977 binop .getAnOperand ( ) .getIntValue ( ) = 1 and
978978 binop .getAnOperand ( ) .( PropAccess ) .getPropertyName ( ) = "length"
979979 ) and
980- srclabel instanceof FlowState:: SplitPath and
981- dstlabel .( FlowState:: PosixPath ) .canContainDotDotSlash ( )
980+ state1 instanceof FlowState:: SplitPath and
981+ state2 .( FlowState:: PosixPath ) .canContainDotDotSlash ( )
982982 )
983983 or
984984 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
988988 )
989989 or
990990 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
994994 )
995995 or
996996 exists ( DataFlow:: CallNode join |
997997 // path.join() with spread argument
998998 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
10011001 (
1002- srclabel .( FlowState:: PosixPath ) .canContainDotDotSlash ( )
1002+ state1 .( FlowState:: PosixPath ) .canContainDotDotSlash ( )
10031003 or
1004- srclabel instanceof FlowState:: SplitPath
1004+ state1 instanceof FlowState:: SplitPath
10051005 ) and
1006- dstlabel .( FlowState:: PosixPath ) .isNormalized ( ) and
1006+ state2 .( FlowState:: PosixPath ) .isNormalized ( ) and
10071007 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 ( )
10101010 )
10111011 }
10121012
10131013 /**
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.
10161016 */
10171017 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
10201020 ) {
10211021 // path.normalize() and similar
10221022 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 ( )
10261026 )
10271027 or
10281028 // path.resolve() and similar
10291029 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 ( )
10341034 )
10351035 or
10361036 // path.relative() and similar
10371037 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 ( )
10421042 )
10431043 or
10441044 // path.dirname() and similar
10451045 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
10491049 )
10501050 or
10511051 // foo.replace(/\./, "") and similar
10521052 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 ( )
10581058 )
10591059 or
10601060 // foo.replace(/(\.\.\/)*/, "") and similar
10611061 exists ( DotDotSlashPrefixRemovingReplace call |
1062- src = call .getInput ( ) and
1063- dst = call .getOutput ( )
1062+ node1 = call .getInput ( ) and
1063+ node2 = call .getOutput ( )
10641064 |
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()
10671067 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
10691069 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
10711071 // normalized + relative -> none()
10721072 )
10731073 or
10741074 // path.join()
10751075 exists ( DataFlow:: CallNode join , int n |
10761076 join = NodeJSLib:: Path:: moduleMember ( "join" ) .getACall ( )
10771077 |
1078- src = join .getArgument ( n ) and
1079- dst = join and
1078+ node1 = join .getArgument ( n ) and
1079+ node2 = join and
10801080 (
10811081 // If the initial argument is tainted, just normalize it. It can be relative or absolute.
10821082 n = 0 and
1083- dstlabel = srclabel .toNormalized ( )
1083+ state2 = state1 .toNormalized ( )
10841084 or
10851085 // For later arguments, the flow label depends on whether the first argument is absolute or relative.
10861086 // If in doubt, we assume it is absolute.
10871087 n > 0 and
1088- srclabel .canContainDotDotSlash ( ) and
1089- dstlabel .isNormalized ( ) and
1088+ state1 .canContainDotDotSlash ( ) and
1089+ state2 .isNormalized ( ) and
10901090 if isRelative ( join .getArgument ( 0 ) .getStringValue ( ) )
1091- then dstlabel .isRelative ( )
1092- else dstlabel .isAbsolute ( )
1091+ then state2 .isRelative ( )
1092+ else state2 .isAbsolute ( )
10931093 )
10941094 )
10951095 or
10961096 // 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+ |
10981100 // use ordinary taint flow for the first operand
10991101 n = 0 and
1100- srclabel = dstlabel
1102+ state1 = state2
11011103 or
11021104 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.
11051107 (
11061108 if isRelative ( StringConcatenation:: getOperand ( operator , 0 ) .getStringValue ( ) )
1107- then dstlabel .isRelative ( )
1108- else dstlabel .isAbsolute ( )
1109+ then state2 .isRelative ( )
1110+ else state2 .isAbsolute ( )
11091111 )
11101112 )
11111113 }
0 commit comments