utils.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. package wafacquisition
  2. import (
  3. "fmt"
  4. "regexp"
  5. "time"
  6. "github.com/crowdsecurity/coraza/v3/collection"
  7. "github.com/crowdsecurity/coraza/v3/experimental"
  8. "github.com/crowdsecurity/coraza/v3/types/variables"
  9. "github.com/crowdsecurity/crowdsec/pkg/types"
  10. "github.com/crowdsecurity/crowdsec/pkg/waf"
  11. "github.com/prometheus/client_golang/prometheus"
  12. )
  13. func EventFromRequest(r waf.ParsedRequest) (types.Event, error) {
  14. evt := types.Event{}
  15. //we might want to change this based on in-band vs out-of-band ?
  16. evt.Type = types.LOG
  17. evt.ExpectMode = types.LIVE
  18. //def needs fixing
  19. evt.Stage = "s00-raw"
  20. evt.Process = true
  21. evt.Parsed = map[string]string{
  22. "source_ip": r.ClientIP,
  23. "target_host": r.Host,
  24. "target_uri": r.URI,
  25. "method": r.Method,
  26. "req_uuid": r.Tx.ID(),
  27. "source": "coraza",
  28. //TBD:
  29. //http_status
  30. //user_agent
  31. }
  32. evt.Line = types.Line{
  33. Time: time.Now(),
  34. //should we add some info like listen addr/port/path ?
  35. Labels: map[string]string{"type": "coraza-waf"},
  36. Process: true,
  37. Module: "waf",
  38. Src: "waf",
  39. Raw: "dummy-waf-data", //we discard empty Line.Raw items :)
  40. }
  41. evt.Waap = types.WaapEvent{}
  42. return evt, nil
  43. }
  44. func LogWaapEvent(evt *types.Event) {
  45. /*log.WithFields(log.Fields{
  46. "module": "waf",
  47. "source": evt.Parsed["source_ip"],
  48. "target_uri": evt.Parsed["target_uri"],
  49. }).Infof("%s triggered %d rules [%+v]", evt.Parsed["source_ip"], len(evt.Waap), evt.Waap.GetRuleIDs())*/
  50. //log.Infof("%s", evt.Waap)
  51. }
  52. /*
  53. how to configure variables to be kept:
  54. 1) full collection : tx.*
  55. 2) subvariables : tx.a*
  56. */
  57. func (r *WafRunner) AccumulateTxToEvent(tx experimental.FullTransaction, kind string, evt *types.Event) error {
  58. //log.Infof("tx addr: %p", tx)
  59. if tx.IsInterrupted() {
  60. r.logger.Infof("interrupted() = %t", tx.IsInterrupted())
  61. r.logger.Infof("interrupted.action = %s", tx.Interruption().Action)
  62. if evt.Meta == nil {
  63. evt.Meta = map[string]string{}
  64. }
  65. evt.Parsed["interrupted"] = "true"
  66. evt.Parsed["action"] = tx.Interruption().Action
  67. //log.Infof("action: %s", tx.Interruption().Action)
  68. evt.Meta["waap_interrupted"] = "1"
  69. evt.Meta["waap_action"] = tx.Interruption().Action
  70. }
  71. if evt.Waap.Vars == nil {
  72. evt.Waap.Vars = map[string]string{}
  73. }
  74. // collectionsToKeep := []string{
  75. // "toto",
  76. // "TX.allowed_methods",
  77. // "TX.*_score",
  78. // }
  79. tx.Variables().All(func(v variables.RuleVariable, col collection.Collection) bool {
  80. for _, variable := range col.FindAll() {
  81. key := ""
  82. if variable.Key() == "" {
  83. key = variable.Variable().Name()
  84. } else {
  85. key = variable.Variable().Name() + "." + variable.Key()
  86. }
  87. if variable.Value() == "" {
  88. continue
  89. }
  90. for _, collectionToKeep := range r.VariablesTracking {
  91. match, err := regexp.MatchString("(?i)"+collectionToKeep, key)
  92. if err != nil {
  93. r.logger.Warningf("error matching %s with %s: %s", key, collectionToKeep, err)
  94. continue
  95. }
  96. if match {
  97. evt.Waap.Vars[key] = variable.Value()
  98. r.logger.Infof("%s.%s = %s", variable.Variable().Name(), variable.Key(), variable.Value())
  99. } else {
  100. r.logger.Infof("%s.%s != %s (%s) (not kept)", variable.Variable().Name(), variable.Key(), collectionToKeep, variable.Value())
  101. }
  102. }
  103. }
  104. return true
  105. })
  106. r.logger.Infof("variables addr in AccumulateTxToEvent: %p", tx.Variables())
  107. //log.Infof("variables: %s", spew.Sdump(tx.Variables()))
  108. //log.Infof("tx variables: %+v", tx.Collection(variables.TX))
  109. //log.Infof("TX %s", spew.Sdump(tx.MatchedRules()))
  110. for _, rule := range tx.MatchedRules() {
  111. if rule.Message() == "" {
  112. continue
  113. }
  114. WafRuleHits.With(prometheus.Labels{"rule_id": fmt.Sprintf("%d", rule.Rule().ID()), "type": kind}).Inc()
  115. corazaRule := map[string]interface{}{
  116. "id": rule.Rule().ID(),
  117. "uri": evt.Parsed["uri"],
  118. "rule_type": kind,
  119. "method": evt.Parsed["method"],
  120. "disruptive": rule.Disruptive(),
  121. "tags": rule.Rule().Tags(),
  122. "file": rule.Rule().File(),
  123. "file_line": rule.Rule().Line(),
  124. "revision": rule.Rule().Revision(),
  125. "secmark": rule.Rule().SecMark(),
  126. "accuracy": rule.Rule().Accuracy(),
  127. "msg": rule.Message(),
  128. "severity": rule.Rule().Severity().String(),
  129. }
  130. evt.Waap.MatchedRules = append(evt.Waap.MatchedRules, corazaRule)
  131. }
  132. return nil
  133. }