event.go 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. package types
  2. import (
  3. "fmt"
  4. "regexp"
  5. "strings"
  6. "time"
  7. log "github.com/sirupsen/logrus"
  8. "github.com/antonmedv/expr/vm"
  9. "github.com/crowdsecurity/crowdsec/pkg/models"
  10. )
  11. const (
  12. LOG = iota
  13. OVFLW
  14. )
  15. /*
  16. 1. If user triggered a rule that is for a CVE, that has high confidence and that is blocking, ban
  17. 2. If user triggered 3 distinct rules with medium confidence accross 3 different requests, ban
  18. any(evt.Waf.ByTag("CVE"), {.confidence == "high" && .action == "block"})
  19. len(evt.Waf.ByTagRx("*CVE*").ByConfidence("high").ByAction("block")) > 1
  20. */
  21. type MatchedRules []map[string]interface{}
  22. type WaapEvent struct {
  23. MatchedRules
  24. Vars map[string]string
  25. }
  26. type Field string
  27. func (f Field) String() string {
  28. return fmt.Sprintf("%s", f)
  29. }
  30. const (
  31. ID Field = "id"
  32. RuleType Field = "rule_type"
  33. Tags Field = "tags"
  34. File Field = "file"
  35. Confidence Field = "confidence"
  36. Revision Field = "revision"
  37. SecMark Field = "secmark"
  38. Accuracy Field = "accuracy"
  39. Msg Field = "msg"
  40. Severity Field = "severity"
  41. Kind Field = "kind"
  42. )
  43. func (w WaapEvent) GetVar(varName string) string {
  44. if w.Vars == nil {
  45. return ""
  46. }
  47. parsed := strings.Split(varName, ".")
  48. if len(parsed) == 1 {
  49. //no subkey
  50. return w.Vars[varName]
  51. } else if len(parsed) == 2 {
  52. //subkey
  53. if w.Vars[parsed[0]] == "" {
  54. return ""
  55. }
  56. //return w.Vars[parsed[0]][parsed[1]]
  57. }
  58. log.Warningf("invalid variable name %s", varName)
  59. return ""
  60. }
  61. // getters
  62. func (w MatchedRules) GetField(field Field) []interface{} {
  63. ret := make([]interface{}, 0)
  64. for _, rule := range w {
  65. ret = append(ret, rule[field.String()])
  66. }
  67. return ret
  68. }
  69. func (w MatchedRules) GetURI() string {
  70. for _, rule := range w {
  71. return rule["uri"].(string)
  72. }
  73. return ""
  74. }
  75. func (w MatchedRules) GetMethod() string {
  76. for _, rule := range w {
  77. return rule["method"].(string)
  78. }
  79. return ""
  80. }
  81. func (w MatchedRules) GetRuleIDs() []int {
  82. ret := make([]int, 0)
  83. for _, rule := range w {
  84. ret = append(ret, rule["id"].(int))
  85. }
  86. return ret
  87. }
  88. func (w MatchedRules) Kinds() []string {
  89. ret := make([]string, 0)
  90. for _, rule := range w {
  91. exists := false
  92. for _, val := range ret {
  93. if val == rule["kind"] {
  94. exists = true
  95. break
  96. }
  97. }
  98. if !exists {
  99. ret = append(ret, rule["kind"].(string))
  100. }
  101. }
  102. return ret
  103. }
  104. // filters
  105. func (w MatchedRules) ByID(id int) MatchedRules {
  106. waap := MatchedRules{}
  107. for _, rule := range w {
  108. if rule["id"] == id {
  109. waap = append(waap, rule)
  110. }
  111. }
  112. return waap
  113. }
  114. func (w MatchedRules) ByKind(kind string) MatchedRules {
  115. waap := MatchedRules{}
  116. for _, rule := range w {
  117. if rule["kind"] == kind {
  118. waap = append(waap, rule)
  119. }
  120. }
  121. return waap
  122. }
  123. func (w MatchedRules) ByTags(match []string) MatchedRules {
  124. waap := MatchedRules{}
  125. for _, rule := range w {
  126. for _, tag := range rule["tags"].([]string) {
  127. for _, match_tag := range match {
  128. if tag == match_tag {
  129. waap = append(waap, rule)
  130. break
  131. }
  132. }
  133. }
  134. }
  135. return waap
  136. }
  137. func (w MatchedRules) ByTag(match string) MatchedRules {
  138. waap := MatchedRules{}
  139. for _, rule := range w {
  140. for _, tag := range rule["tags"].([]string) {
  141. if tag == match {
  142. waap = append(waap, rule)
  143. break
  144. }
  145. }
  146. }
  147. return waap
  148. }
  149. func (w MatchedRules) ByTagRx(rx string) MatchedRules {
  150. waap := MatchedRules{}
  151. re := regexp.MustCompile(rx)
  152. if re == nil {
  153. return waap
  154. }
  155. for _, rule := range w {
  156. for _, tag := range rule["tags"].([]string) {
  157. log.Infof("ByTagRx: %s = %s -> %t", rx, tag, re.MatchString(tag))
  158. if re.MatchString(tag) {
  159. waap = append(waap, rule)
  160. break
  161. }
  162. }
  163. }
  164. return waap
  165. }
  166. func (w MatchedRules) ByDisruptiveness(is bool) MatchedRules {
  167. log.Infof("%s", w)
  168. wap := MatchedRules{}
  169. for _, rule := range w {
  170. if rule["disruptive"] == is {
  171. wap = append(wap, rule)
  172. }
  173. }
  174. log.Infof("ByDisruptiveness(%t) -> %d", is, len(wap))
  175. return wap
  176. }
  177. func (w MatchedRules) BySeverity(severity string) MatchedRules {
  178. wap := MatchedRules{}
  179. for _, rule := range w {
  180. if rule["severity"] == severity {
  181. wap = append(wap, rule)
  182. }
  183. }
  184. log.Infof("BySeverity(%s) -> %d", severity, len(wap))
  185. return wap
  186. }
  187. func (w MatchedRules) ByAccuracy(accuracy string) MatchedRules {
  188. wap := MatchedRules{}
  189. for _, rule := range w {
  190. if rule["accuracy"] == accuracy {
  191. wap = append(wap, rule)
  192. }
  193. }
  194. log.Infof("ByAccuracy(%s) -> %d", accuracy, len(wap))
  195. return wap
  196. }
  197. // Event is the structure representing a runtime event (log or overflow)
  198. type Event struct {
  199. /* is it a log or an overflow */
  200. Type int `yaml:"Type,omitempty" json:"Type,omitempty"` //Can be types.LOG (0) or types.OVFLOW (1)
  201. ExpectMode int `yaml:"ExpectMode,omitempty" json:"ExpectMode,omitempty"` //how to buckets should handle event : types.TIMEMACHINE or types.LIVE
  202. Whitelisted bool `yaml:"Whitelisted,omitempty" json:"Whitelisted,omitempty"`
  203. WhitelistReason string `yaml:"WhitelistReason,omitempty" json:"whitelist_reason,omitempty"`
  204. //should add whitelist reason ?
  205. /* the current stage of the line being parsed */
  206. Stage string `yaml:"Stage,omitempty" json:"Stage,omitempty"`
  207. /* original line (produced by acquisition) */
  208. Line Line `yaml:"Line,omitempty" json:"Line,omitempty"`
  209. /* output of groks */
  210. Parsed map[string]string `yaml:"Parsed,omitempty" json:"Parsed,omitempty"`
  211. /* output of enrichment */
  212. Enriched map[string]string `yaml:"Enriched,omitempty" json:"Enriched,omitempty"`
  213. /* output of Unmarshal */
  214. Unmarshaled map[string]interface{} `yaml:"Unmarshaled,omitempty" json:"Unmarshaled,omitempty"`
  215. /* Overflow */
  216. Overflow RuntimeAlert `yaml:"Overflow,omitempty" json:"Alert,omitempty"`
  217. Time time.Time `yaml:"Time,omitempty" json:"Time,omitempty"` //parsed time `json:"-"` ``
  218. StrTime string `yaml:"StrTime,omitempty" json:"StrTime,omitempty"`
  219. StrTimeFormat string `yaml:"StrTimeFormat,omitempty" json:"StrTimeFormat,omitempty"`
  220. MarshaledTime string `yaml:"MarshaledTime,omitempty" json:"MarshaledTime,omitempty"`
  221. Process bool `yaml:"Process,omitempty" json:"Process,omitempty"` //can be set to false to avoid processing line
  222. Waap WaapEvent `yaml:"Waap,omitempty" json:"Waap,omitempty"`
  223. /* Meta is the only part that will make it to the API - it should be normalized */
  224. Meta map[string]string `yaml:"Meta,omitempty" json:"Meta,omitempty"`
  225. }
  226. func (e *Event) GetType() string {
  227. if e.Type == OVFLW {
  228. return "overflow"
  229. } else if e.Type == LOG {
  230. return "log"
  231. } else {
  232. log.Warningf("unknown event type for %+v", e)
  233. return "unknown"
  234. }
  235. }
  236. func (e *Event) GetMeta(key string) string {
  237. if e.Type == OVFLW {
  238. for _, alert := range e.Overflow.APIAlerts {
  239. for _, event := range alert.Events {
  240. if event.GetMeta(key) != "" {
  241. return event.GetMeta(key)
  242. }
  243. }
  244. }
  245. } else if e.Type == LOG {
  246. for k, v := range e.Meta {
  247. if k == key {
  248. return v
  249. }
  250. }
  251. }
  252. return ""
  253. }
  254. // Move in leakybuckets
  255. const (
  256. Undefined = ""
  257. Ip = "Ip"
  258. Range = "Range"
  259. Filter = "Filter"
  260. Country = "Country"
  261. AS = "AS"
  262. )
  263. // Move in leakybuckets
  264. type ScopeType struct {
  265. Scope string `yaml:"type"`
  266. Filter string `yaml:"expression"`
  267. RunTimeFilter *vm.Program
  268. }
  269. type RuntimeAlert struct {
  270. Mapkey string `yaml:"MapKey,omitempty" json:"MapKey,omitempty"`
  271. BucketId string `yaml:"BucketId,omitempty" json:"BucketId,omitempty"`
  272. Whitelisted bool `yaml:"Whitelisted,omitempty" json:"Whitelisted,omitempty"`
  273. Reprocess bool `yaml:"Reprocess,omitempty" json:"Reprocess,omitempty"`
  274. Sources map[string]models.Source `yaml:"Sources,omitempty" json:"Sources,omitempty"`
  275. Alert *models.Alert `yaml:"Alert,omitempty" json:"Alert,omitempty"` //this one is a pointer to APIAlerts[0] for convenience.
  276. //APIAlerts will be populated at the end when there is more than one source
  277. APIAlerts []models.Alert `yaml:"APIAlerts,omitempty" json:"APIAlerts,omitempty"`
  278. }
  279. func (r RuntimeAlert) GetSources() []string {
  280. ret := make([]string, 0)
  281. for key := range r.Sources {
  282. ret = append(ret, key)
  283. }
  284. return ret
  285. }