
O Goot é uma estrutura de análise estática para GO. O Goot é fácil de aprender, fácil de usar e altamente extensível, permitindo que você desenvolva facilmente novas análises sobre ela.
Atualmente, o Goot fornece os seguintes componentes de análise principal (e mais análises estão a caminho):
Intall goot por
go get -u github.com/cokeBeer/goot
Escreva o código abaixo no projeto a ser analisado, por exemplo, 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 ()
} Execute o código e você receberá um passthrough.json no mesmo diretório, que contém informações de passagem de todas as funções em seu projeto
Você pode ver a chave fmt.Sprintf segurar um objeto de valor
{
"fmt.Sprintf" : {
"Recv" : null ,
"Results" : [
[ 0 , 1 ]
],
"Params" : [
[ 0 , 1 ],
[ 1 ]
]
}
}Isso significa três coisas
Além disso, você receberá um taintgraph.json no mesmo diretório
Você pode ver o arquivo JSON contém bordas de mancha de um parâmetro de chamada para outro parâmetro de chamada
{
"(*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
}
} Isso significa que existe uma borda de mancha da posição 0 do RunCmd (neste caso, o parâmetro é o próprio Receiver runner.Runner ) para a posição 0 de StdoutPipe (neste caso, o parâmetro é o recebedor exec.Cmd também)
Para visualizar melhor as bordas de mancha, você pode carregá -las no neo4j definindo esses parâmetros (para opções mais detalhadas, consulte as opções do corredor)
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 )
}
} Quando a análise é final, você pode encontrar nós e bordas manchas no seu banco de dados NEO4J
Por exemplo, executamos análises de manchas em gitlab.com/gitlab-org/[email protected], que tem uma vulnerabilidade RCE CVE-2021-22225
Usando a consulta abaixo para encontrar caminhos em mancal
MATCH (source:Source),(sink:Sink {name:"os/exec.CommandContext"}),p=(source)-[*7]->(sink) RETURN p
Podemos obter um gráfico como este: (os nós vermelhos são afundados, os nós marrons são funções intra e os nós verdes são fonte)
Que revela dois caminhos em mancha de fonte para afundar os/exec.CommandContext , o mesmo que CVE-2021-22225
Para usar o Goot como estrutura, primeiro crie duas estruturas implementando pkg/toolkits/scalar.FlowAnalysis Interface
// 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 )
} e pkg/golang/switcher.Switcher Interface separadamente
// 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 )
} Não se preocupe com essas APIs. Uma maneira fácil de implementá -los é usar composição como pkg/toolkits/scalar.BaseFlowAnalysis
// ConstantPropagationAnalysis represents a constant propagtion analysis
type ConstantPropagationAnalysis struct {
scalar. BaseFlowAnalysis
constantPropagationSwitcher * ConstantPropagationSwitcher
} e 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
} Isso pode fazer você se concentrar nos métodos principais que você realmente precisa para projetar cuidadosamente em análises específicas
Você pode aprender mais informações sobre como usar o Goot como uma estrutura e como executar uma análise de um pequeno exemplo que preparei para você em como usar e como executar que demonstra uma constant propagation analysis
*map[any]any fluxo e ssa.Instruction instrução como unidade, portanto, tenha cuidado com a afirmação do tipo