Example 1: From source to sink
In the following code sample, the main method calls a method, getVulnerableSource
,
that returns a string. Note that, although the method reads data from
a completely unknown file, it never checks the validity of the returned
data. The main method then passes this tainted data into writeToVulnerableSink
.
The writeToVulnerableSink
method writes the data
out to the file, never checking its validity.
import java.io.*;
public class TestCase_IOT_Static {
public static void main(String[] args) {
try {
writeToVulnerableSink(getVulnerableSource(args[0]));
} catch (Exception e) {
}
}
public static String getVulnerableSource(String file)
throws java.io.IOException, java.io.FileNotFoundException {
FileInputStream fis = new FileInputStream(file);
byte[] buf = new byte[100];
fis.read(buf);
String ret = new String(buf);
fis.close();
return ret;
}
public static void writeToVulnerableSink(String str)
throws java.io.FileNotFoundException {
FileOutputStream fos = new FileOutputStream(str);
PrintWriter writer = new PrintWriter(fos);
writer.write(str);
}
}
The code sample produces this trace:
The pane shows the input stack where main
calls getVulnerableSource
which
calls FileInputStream.read
- and the output stack
where main
calls writeToVulnerableSink
,
which calls PrintWriter.write
. The graph displays
how the data flows from the read method to the write method, with main
joining
the two call stacks. The Data Flow section shows the line numbers
in the operations in the main
method that pass the
taint. In this example, both method calls exist on the same line (line
15) within the method (in the sample code above, this translates to
line number 7 - in the screen capture, the file includes 8 lines of
commenting).