Hello guys,
I am quite new into gremlin, after a few trials and errors and grasping the rough ideas, I find gremlin fascinating ! Congrats guys !
My question is around enforcing order in my traversals
g.addV("machine").property("ip","127.0.0.1").property("role","attacker").as("attacker")
.addV("machine").property("ip","127.0.0.2").property("role","userLambda").as("userLambda")
.addV("machine").property("ip","127.0.0.3").property("type","oracle").property("role","oracleAttacked").as("oracleAttacked")
.addV("machine").property("ip","127.0.0.4").property("type","oracle").property("role","oracleNoProblemo").as("oracleNoProblemo")
.addV("machine").property("ip","127.0.0.5").property("role","bastion1").as("bastion1")
.addV("machine").property("ip","127.0.0.6").property("type","bastion2").as("bastion2")
.addV("machine").property("ip","127.0.0.7").property("type","bastion3").as("bastion3")
.addV("machine").property("ip","127.0.0.8").property("type","bastion4").as("bastion4")
// attack via multiple bastion rebounds
.addE("jdbc").from("attacker").to("oracleAttacked")
.property("state","REFUSED")
.addE("ssh").from("attacker").to("oracleAttacked")
.property("state","REFUSED")
.addE("ssh").from("attacker").to("bastion1")
.property("state","OK")
.addE("ssh").from("bastion1").to("bastion2")
.property("state","OK")
.addE("ssh").from("bastion2").to("bastion3")
.property("state","OK")
.addE("ssh").from("bastion3").to("bastion4")
.property("state","OK")
.addE("ssh").from("bastion4").to("oracleAttacked")
.property("state","OK")
.addE("jdbc").from("oracleAttacked").to("oracleAttacked")
.property("state","OK")
// user lambda
.addE("jdbc").from("userLambda").to("oracleAttacked")
.property("state","OK")
.addE("ssh").from("userLambda").to("oracleAttacked")
.property("state","REFUSED")
.addE("jdbc").from("userLambda").to("oracleNoProblemo")
.property("state","OK")
I want to look for machines that are attacked. Basically it's detecting the machine which has been compromised:
- a user tried to connect with jdbc without success,
- a user tried ssh directly without success,
- a user logged in db locally using a series of bastions.
g.V().match(
__.as("potentialAttacked").hasLabel("machine").has("type","oracle"),
__.as("potentialAttacked").inE("jdbc").has("state","OK").outV().where(eq("potentialAttacked")),
__.as("potentialAttacked").inE("ssh").has("state","REFUSED").outV().as("potentialAttacker")
)
.select("potentialAttacker")
.repeat(outE("ssh").has("state","OK").inV()).until(where(eq("potentialAttacked")))
All is fine and good: we have our match.
g.addV("machine").property("ip","127.0.0.1").property("role","attacker").as("attacker")
.addV("machine").property("ip","127.0.0.2").property("role","userLambda").as("userLambda")
.addV("machine").property("ip","127.0.0.3").property("type","oracle").property("role","oracleAttacked").as("oracleAttacked")
.addV("machine").property("ip","127.0.0.4").property("type","oracle").property("role","oracleNoProblemo").as("oracleNoProblemo")
.addV("machine").property("ip","127.0.0.5").property("role","bastion1").as("bastion1")
.addV("machine").property("ip","127.0.0.6").property("type","bastion2").as("bastion2")
.addV("machine").property("ip","127.0.0.7").property("type","bastion3").as("bastion3")
.addV("machine").property("ip","127.0.0.8").property("type","bastion4").as("bastion4")
// attack via multiple bastion rebounds
.addE("jdbc").from("attacker").to("oracleAttacked")
.property("state","REFUSED")
.property("date",1)
.addE("ssh").from("attacker").to("oracleAttacked")
.property("state","REFUSED")
.property("date",2)
.addE("ssh").from("attacker").to("bastion1")
.property("state","OK")
.property("date",3)
.addE("ssh").from("bastion1").to("bastion2")
.property("state","OK")
.property("date",4)
.addE("ssh").from("bastion2").to("bastion3")
.property("state","OK")
.property("date",5)
.addE("ssh").from("bastion3").to("bastion4")
.property("state","OK")
.property("date",6)
.addE("ssh").from("bastion4").to("oracleAttacked")
.property("state","OK")
.property("date",7)
.addE("jdbc").from("oracleAttacked").to("oracleAttacked")
.property("state","OK")
.property("date",8)
// user lambda
.addE("jdbc").from("userLambda").to("oracleAttacked")
.property("state","OK")
.property("date",1)
.addE("ssh").from("userLambda").to("oracleAttacked")
.property("state","REFUSED")
.property("date",2)
.addE("jdbc").from("userLambda").to("oracleNoProblemo")
.property("state","OK")
.property("date",3)
All the edges dates are sequential to simplify things.
Now I want to change the expression "a user logged in db locally using a series of bastions" into "a user logged in db locally using a series of bastions which edges are in chronological order"
I tried -without success- many variations of this :
g.V().match(
__.as("potentialAttacked").hasLabel("machine").has("type","oracle"),
__.as("potentialAttacked").inE("jdbc").has("state","OK").as("jdbcOk").outV().where(eq("potentialAttacked")),
__.as("potentialAttacked").inE("ssh").has("state","REFUSED").as("sshKo").outV().as("potentialAttacker")
)
.select("potentialAttacker")
.repeat(
outE("ssh").match(
__.as("ok").has("state","OK").inV().as("nextMachine"),
__.as("ok").has("date", lte(select("nextMachine").inE("ssh").values("date")))
)
).until(
where(eq("potentialAttacked"))
)
Do you guys have hints/references on this matter ?
Cheers !
Florent