@@ -15,12 +15,28 @@ import python
1515import semmle.python.security.Paths
1616
1717import semmle.python.security.TaintTracking
18+ import semmle.python.security.strings.Basic
1819
1920/** A TaintKind to represent open tarfile objects. That is, the result of calling `tarfile.open(...)` */
2021class OpenTarFile extends TaintKind {
2122 OpenTarFile ( ) {
2223 this = "tarfile.open"
2324 }
25+
26+ override TaintKind getTaintOfMethodResult ( string name ) {
27+ name = "getmember" and result instanceof TarFileInfo
28+ or
29+ name = "getmembers" and result .( SequenceKind ) .getItem ( ) instanceof TarFileInfo
30+ }
31+
32+ override ClassValue getType ( ) {
33+ result = Module:: named ( "tarfile" ) .attr ( "TarFile" )
34+ }
35+
36+ override TaintKind getTaintForIteration ( ) {
37+ result instanceof TarFileInfo
38+ }
39+
2440}
2541
2642/** The source of open tarfile objects. That is, any call to `tarfile.open(...)` */
@@ -41,13 +57,29 @@ class TarfileOpen extends TaintSource {
4157
4258}
4359
44- /* Any call to an extract method */
45- class ExtractionSink extends TaintSink {
60+ class TarFileInfo extends TaintKind {
61+
62+ TarFileInfo ( ) {
63+ this = "tarfile.entry"
64+ }
65+
66+ override TaintKind getTaintOfMethodResult ( string name ) {
67+ name = "next" and result = this
68+ }
69+
70+ override TaintKind getTaintOfAttribute ( string name ) {
71+ name = "name" and result instanceof TarFileInfo
72+ }
73+ }
74+
75+
76+ /* Any call to an extractall method */
77+ class ExtractAllSink extends TaintSink {
4678
4779 CallNode call ;
4880
49- ExtractionSink ( ) {
50- this = call .getFunction ( ) .( AttrNode ) .getObject ( extract ( ) )
81+ ExtractAllSink ( ) {
82+ this = call .getFunction ( ) .( AttrNode ) .getObject ( "extractall" )
5183 }
5284
5385 override predicate sinks ( TaintKind kind ) {
@@ -56,21 +88,59 @@ class ExtractionSink extends TaintSink {
5688
5789}
5890
59- private string extract ( ) {
60- result = "extract" or result = "extractall"
91+ /* Argument to extract method */
92+ class ExtractSink extends TaintSink {
93+
94+ CallNode call ;
95+
96+ ExtractSink ( ) {
97+ call .getFunction ( ) .( AttrNode ) .getName ( ) = "extract" and
98+ this = call .getArg ( 0 )
99+ }
100+
101+ override predicate sinks ( TaintKind kind ) {
102+ kind instanceof TarFileInfo
103+ }
104+
61105}
62106
107+ class TarFileInfoSanitizer extends Sanitizer {
108+
109+ TarFileInfoSanitizer ( ) {
110+ this = "TarInfo sanitizer"
111+ }
112+
113+ override predicate sanitizingEdge ( TaintKind taint , PyEdgeRefinement test ) {
114+ path_sanitizing_test ( test .getTest ( ) ) and
115+ taint instanceof TarFileInfo
116+ }
117+ }
118+
119+ private predicate path_sanitizing_test ( ControlFlowNode test ) {
120+ checks_not_absolute ( test ) and
121+ test .getAChild + ( ) .getNode ( ) .( StrConst ) .getText ( ) = ".."
122+ }
123+
124+ private predicate checks_not_absolute ( ControlFlowNode test ) {
125+ test .getAChild + ( ) .( CallNode ) .getFunction ( ) .pointsTo ( Module:: named ( "os.path" ) .attr ( "absfile" ) )
126+ or
127+ test .getAChild + ( ) .getNode ( ) .( StrConst ) .getText ( ) = "/"
128+ }
63129
64- //evil = [e for e in members if os.path.relpath(e).startswith(('/', '..'))]
65130
66131class TarSlipConfiguration extends TaintTracking:: Configuration {
67132
68133 TarSlipConfiguration ( ) { this = "TarSlip configuration" }
69134
70135 override predicate isSource ( TaintTracking:: Source source ) { source instanceof TarfileOpen }
71136
72- override predicate isSink ( TaintTracking:: Sink sink ) { sink instanceof ExtractionSink }
137+ override predicate isSink ( TaintTracking:: Sink sink ) {
138+ sink instanceof ExtractSink or sink instanceof ExtractAllSink
139+ }
73140
141+ override predicate isSanitizer ( Sanitizer sanitizer ) {
142+ sanitizer instanceof TarFileInfoSanitizer
143+ }
74144}
75145
76146
0 commit comments