event.go 7.8 KB

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