
Goot ist ein statischer Analyse -Framework für GO. Goot ist leicht zu lernend, benutzerfreundlich und hoch erweiterbar, sodass Sie problemlos neue Analysen entwickeln können.
Derzeit stellt GoOT die folgenden Hauptanalysekomponenten an (und weitere Analysen sind unterwegs):
Intall Goot von
go get -u github.com/cokeBeer/goot
Schreiben Sie den folgenden Code im zu analysierenden Projekt, z. B. cmd/taint/main.go
package main
import "github.com/cokeBeer/goot/pkg/example/dataflow/taint"
func main () {
// if this file is cmd/taint/main.go
// and you want to analyse package pkg
// the path should be "../../pkg"
// or "../../pkg..." for all packages under pkg
runner := taint . NewRunner ( "relative/path/to/package" )
// for this project, is "github.com/cokeBeer/goot"
runner . ModuleName = "module-name"
runner . PassThroughDstPath = "passthrough.json"
runner . TaintGraphDstPath = "taintgraph.json"
runner . Run ()
} Führen Sie den Code aus, und Sie erhalten einen passthrough.json in demselben Verzeichnis, das verdichtete Pass -Through -Informationen über alle Funktionen in Ihrem Projekt enthält
Sie können fmt.Sprintf
{
"fmt.Sprintf" : {
"Recv" : null ,
"Results" : [
[ 0 , 1 ]
],
"Params" : [
[ 0 , 1 ],
[ 1 ]
]
}
}Das bedeutet drei Dinge
Außerdem erhalten Sie einen taintgraph.json im selben Verzeichnis
Sie können sehen, dass die JSON -Datei verdichtete Kanten von einem Anrufparameter zu einem anderen Anrufparameter enthält
{
"(*github.com/example/runnner.Runner).RunCmd#0#(*os/exec.Cmd).StdoutPipe#0" : {
"From" : " (*github.com/example/runnner.Runner).RunCmd " ,
"FromIndex" : 0 ,
"To" : " (*os/exec.Cmd).StdoutPipe " ,
"ToIndex" : 0 ,
"ToIsMethod" : false ,
"ToIsSink" : true ,
"ToIsSignature" : false ,
"ToIsStatic" : true
}
} Dies bedeutet, StdoutPipe es eine verdammte Kante von Position 0 0 RunCmd gibt (in diesem Fall ist der Parameter der runner.Runner exec.Cmd
Um verdichtete Kanten besser anzuzeigen, können Sie sie durch festlegen, indem Sie diese Parameter festlegen (detailliertere Optionen finden Sie unter Optionen des Läufers).
func main () {
runner := taint . NewRunner ( "../../internal..." )
runner . ModuleName = "gitlab.com/gitlab-org/gitlab-workhorse"
// parameters about neo4j
runner . PersistToNeo4j = true
runner . Neo4jURI = "bolt://localhost:7687"
runner . Neo4jUsername = "neo4j"
runner . Neo4jPassword = "password"
err := runner . Run ()
if err != nil {
log . Fatal ( err )
}
} Wenn die Analyse endet
Zum Beispiel führen wir eine Taint-Analyse unter gitlab.com/gitlab-org/[email protected] , durch
Verwenden der Abfrage unten, um verdammte Pfade zu finden
MATCH (source:Source),(sink:Sink {name:"os/exec.CommandContext"}),p=(source)-[*7]->(sink) RETURN p
Wir können ein Diagramm wie folgt erhalten: (Die roten Knoten sind sinken, die braunen Knoten sind Intra -Funktionen und die grünen Knoten sind Quelle)
Dies enthüllt zwei versierte Pfade von Quelle zum Sink os/exec.CommandContext , das gleich wie CVE-2021-22225
Um GoOT als Framework zu verwenden, erstellen Sie zunächst zwei Strukturen, die pkg/toolkits/scalar.FlowAnalysis -Schnittstelle implementieren
// FlowAnalysis represents a flow analysis
type FlowAnalysis interface {
GetGraph () * graph. UnitGraph
IsForward () bool
Computations () int
FlowThrougth ( inMap * map [ any ] any , unit ssa. Instruction , outMap * map [ any ] any )
NewInitalFlow () * map [ any ] any
EntryInitalFlow () * map [ any ] any
Copy ( srcMap * map [ any ] any , dstMap * map [ any ] any )
MergeInto ( Unit ssa. Instruction , inout * map [ any ] any , in * map [ any ] any )
End ( universe [] * entry. Entry )
} und pkg/golang/switcher.Switcher -Schnittstelle separat
// Switcher represents a ssa instruction switcher
type Switcher interface {
CaseAlloc ( inst * ssa. Alloc )
CasePhi ( inst * ssa. Phi )
CaseCall ( inst * ssa. Call )
CaseBinOp ( inst * ssa. BinOp )
CaseUnOp ( inst * ssa. UnOp )
...
CaseGo ( inst * ssa. Go )
CaseDefer ( inst * ssa. Defer )
CaseSend ( inst * ssa. Send )
CaseStore ( inst * ssa. Store )
CaseMapUpdate ( inst * ssa. MapUpdate )
CaseDebugRef ( inst * ssa. DebugRef )
} Mach dir keine Sorgen um diese APIs. Eine einfache Möglichkeit, sie zu implementieren pkg/toolkits/scalar.BaseFlowAnalysis besteht darin
// ConstantPropagationAnalysis represents a constant propagtion analysis
type ConstantPropagationAnalysis struct {
scalar. BaseFlowAnalysis
constantPropagationSwitcher * ConstantPropagationSwitcher
} und pkg/golang/switcher.BaseSwitcher
// ConstantPropagationSwitcher represents a constant propagtion switcher
type ConstantPropagationSwitcher struct {
switcher. BaseSwitcher
constanctPropagationAnalysis * ConstantPropagationAnalysis
inMap * map [ any ] any
outMap * map [ any ] any
} Diese können Sie dazu bringen, sich auf die Kernmethoden zu konzentrieren, die Sie wirklich in bestimmten Analysen sorgfältig entwerfen müssen
Weitere Informationen darüber erfahren Sie, wie Sie Goot als Framework verwenden und wie Sie eine Analyse aus einem winzigen Beispiel ausführen, das ich für Sie in der Verwendung und zum Ausführen einer constant propagation analysis vorbereitet habe
*map[any]any As Flow und ssa.Instruction als Einheit. Achten Sie daher vorsichtig mit der Art der Typbehandlung