Нема описа

send-wazuh-proposal-required-events.sh 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. #!/usr/bin/env bash
  2. set -euo pipefail
  3. # Usage:
  4. # scripts/send-wazuh-proposal-required-events.sh [selector] [count] [delay_seconds]
  5. #
  6. # selector:
  7. # all | a1 | a2 | a3 | a4 | <usecase_id>
  8. # example usecase_id: A2-01, A3-05, A4-24
  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-required-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. FGT_DEVNAME="${FGT_DEVNAME:-FGT80F-Branch01}"
  34. FGT_DEVID="${FGT_DEVID:-FGT80FTK20000001}"
  35. WIN_HOST="${WIN_HOST:-win-dc01}"
  36. DNS_HOST="${DNS_HOST:-dns-fw-01}"
  37. SIM_VPN_USER="${SIM_VPN_USER:-remote.user}"
  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. rand_private_ip() {
  62. echo "10.$((RANDOM % 20 + 10)).$((RANDOM % 200 + 1)).$((RANDOM % 240 + 10))"
  63. }
  64. rand_domain() {
  65. echo "ioc-$((RANDOM % 9000 + 1000)).malicious.example"
  66. }
  67. emit_syslog() {
  68. local msg="$1"
  69. local sent="false"
  70. if [[ "${DRY_RUN}" == "1" ]]; then
  71. echo "[DRY_RUN $(date -u +'%Y-%m-%dT%H:%M:%SZ')] ${msg}"
  72. return 0
  73. fi
  74. if command -v nc >/dev/null 2>&1; then
  75. if printf "%s\n" "${msg}" | nc -u -w1 "${WAZUH_SYSLOG_HOST}" "${WAZUH_SYSLOG_PORT}"; then
  76. sent="true"
  77. fi
  78. fi
  79. if [[ "${sent}" != "true" ]]; then
  80. if printf "%s\n" "${msg}" >"/dev/udp/${WAZUH_SYSLOG_HOST}/${WAZUH_SYSLOG_PORT}" 2>/dev/null; then
  81. sent="true"
  82. fi
  83. fi
  84. if [[ "${sent}" != "true" ]]; then
  85. echo "error: failed to send syslog event to ${WAZUH_SYSLOG_HOST}:${WAZUH_SYSLOG_PORT}/udp"
  86. return 1
  87. fi
  88. echo "[$(date -u +'%Y-%m-%dT%H:%M:%SZ')] sent: ${msg}"
  89. }
  90. selector_matches() {
  91. local id="$1"
  92. local section="$2"
  93. local sel
  94. sel="$(echo "${SELECTOR}" | tr '[:upper:]' '[:lower:]')"
  95. local idl
  96. idl="$(echo "${id}" | tr '[:upper:]' '[:lower:]')"
  97. local sec
  98. sec="$(echo "${section}" | tr '[:upper:]' '[:lower:]')"
  99. [[ "${sel}" == "all" || "${sel}" == "${sec}" || "${sel}" == "${idl}" ]]
  100. }
  101. emit_fgt_usecase() {
  102. local id="$1"
  103. local section="$2"
  104. local severity="$3"
  105. local usecase="$4"
  106. local body="$5"
  107. selector_matches "${id}" "${section}" || return 0
  108. local tags
  109. if [[ "${PROFILE}" == "production" ]]; then
  110. tags="soc_mvp_test=true source=fortigate severity=${severity}"
  111. else
  112. tags="soc_mvp_test=true source=fortigate section=${section} usecase_id=${id} severity=${severity} usecase=\"${usecase}\""
  113. fi
  114. emit_syslog "<190>date=$(date '+%Y-%m-%d') time=$(date '+%H:%M:%S') devname=\"${FGT_DEVNAME}\" devid=\"${FGT_DEVID}\" eventtime=$(date +%s) vd=\"root\" ${tags} ${body}"
  115. sleep "${EVENT_DELAY}"
  116. }
  117. emit_dns_usecase() {
  118. local id="$1"
  119. local section="$2"
  120. local severity="$3"
  121. local usecase="$4"
  122. local body="$5"
  123. selector_matches "${id}" "${section}" || return 0
  124. local tags
  125. if [[ "${PROFILE}" == "production" ]]; then
  126. tags="soc_mvp_test=true source=dns severity=${severity}"
  127. else
  128. tags="soc_mvp_test=true source=dns section=${section} usecase_id=${id} severity=${severity} usecase=\"${usecase}\""
  129. fi
  130. emit_syslog "<189>$(date '+%b %d %H:%M:%S') ${DNS_HOST} ${tags} ${body}"
  131. sleep "${EVENT_DELAY}"
  132. }
  133. emit_windows_usecase() {
  134. local id="$1"
  135. local section="$2"
  136. local severity="$3"
  137. local usecase="$4"
  138. local body="$5"
  139. selector_matches "${id}" "${section}" || return 0
  140. local tags
  141. if [[ "${PROFILE}" == "production" ]]; then
  142. tags="soc_mvp_test=true source=windows severity=${severity}"
  143. else
  144. tags="soc_mvp_test=true source=windows section=${section} usecase_id=${id} severity=${severity} usecase=\"${usecase}\""
  145. fi
  146. emit_syslog "<182>$(date '+%b %d %H:%M:%S') ${WIN_HOST} ${tags} ${body}"
  147. sleep "${EVENT_DELAY}"
  148. }
  149. emit_a1() {
  150. local sip
  151. local domain
  152. local mip
  153. sip="$(rand_private_ip)"
  154. domain="$(rand_domain)"
  155. mip="$(rand_public_ip)"
  156. emit_dns_usecase "A1-01" "A1" "medium" \
  157. "DNS Network Traffic Communicate to Malicious Domain" \
  158. "event_type=ioc_dns_traffic src_ip=${sip} query=${domain} resolved_ip=${mip} action=blocked"
  159. emit_dns_usecase "A1-02" "A1" "medium" \
  160. "DNS Network Traffic Malicious Domain IOCs Detection" \
  161. "event_type=ioc_domain_match src_ip=${sip} ioc_type=domain ioc_value=${domain} feed=threatintel_main confidence=high action=alert"
  162. }
  163. emit_a2() {
  164. local pub
  165. local sip
  166. pub="$(rand_public_ip)"
  167. sip="$(rand_private_ip)"
  168. emit_fgt_usecase "A2-01" "A2" "high" "IPS IDS Network Traffic Allowed RDP from Public IPs" \
  169. "logid=\"0000000013\" type=\"traffic\" subtype=\"forward\" srcip=${pub} dstip=${sip} dstport=3389 service=\"RDP\" action=\"accept\" policyid=44"
  170. emit_fgt_usecase "A2-02" "A2" "high" "IPS IDS Firewall Account Admin Password Change" \
  171. "logid=\"0100044547\" type=\"event\" subtype=\"system\" user=\"admin\" action=\"password-change\" target_account=\"admin\""
  172. emit_fgt_usecase "A2-03" "A2" "high" "IPS IDS Firewall Account Create Add Admin Account" \
  173. "logid=\"0100044548\" type=\"event\" subtype=\"system\" user=\"admin\" action=\"create-admin\" target_account=\"secops_admin\""
  174. emit_fgt_usecase "A2-04" "A2" "high" "IPS IDS Firewall Configure Disabled Email Notification" \
  175. "logid=\"0100044551\" type=\"event\" subtype=\"system\" action=\"config-change\" config_item=\"alertemail\" config_value=\"disable\""
  176. emit_fgt_usecase "A2-05" "A2" "low" "IPS IDS Firewall Configure Download Configure FW" \
  177. "logid=\"0100044552\" type=\"event\" subtype=\"system\" action=\"download-config\" user=\"admin\""
  178. emit_fgt_usecase "A2-06" "A2" "medium" "IPS IDS IDS Alert Multiple Critical High" \
  179. "logid=\"0720018432\" type=\"utm\" subtype=\"ips\" action=\"detected\" attack=\"Multiple.Critical.High.Signatures\" severity=\"high\" count=7"
  180. emit_fgt_usecase "A2-07" "A2" "low" "IPS IDS Network Traffic Port Scanning" \
  181. "logid=\"0720018433\" type=\"utm\" subtype=\"anomaly\" attack=\"TCP.Port.Scan\" srcip=${pub} dstip=${sip} action=\"detected\""
  182. emit_fgt_usecase "A2-08" "A2" "medium" "IPS IDS Network Traffic IOC Detection" \
  183. "logid=\"0720018434\" type=\"utm\" subtype=\"ips\" ioc_type=ip ioc_value=$(rand_public_ip) action=\"blocked\""
  184. emit_fgt_usecase "A2-09" "A2" "medium" "IPS IDS Network Traffic Port Scanning from Private IP" \
  185. "logid=\"0720018435\" type=\"utm\" subtype=\"anomaly\" attack=\"Internal.Port.Scan\" srcip=$(rand_private_ip) dstip=$(rand_private_ip) action=\"detected\""
  186. emit_fgt_usecase "A2-10" "A2" "medium" "IPS IDS Network Traffic Communicate to Malicious IP" \
  187. "logid=\"0000000013\" type=\"traffic\" subtype=\"forward\" srcip=$(rand_private_ip) dstip=$(rand_public_ip) threat_label=\"known-c2\" action=\"accept\""
  188. }
  189. emit_a3() {
  190. local out_th
  191. out_th="$(rand_public_ip)"
  192. emit_fgt_usecase "A3-01" "A3" "high" "VPN Authentication Success from Guest Account" \
  193. "logid=\"0101037131\" type=\"event\" subtype=\"vpn\" action=\"ssl-login-success\" user=\"guest\" srcip=${out_th} country=\"TH\""
  194. emit_fgt_usecase "A3-02" "A3" "high" "VPN Authentication Success from Multiple Country" \
  195. "logid=\"0101037132\" type=\"event\" subtype=\"vpn\" action=\"ssl-login-success\" user=\"${SIM_VPN_USER}\" srcip=${out_th} country=\"US\" previous_country=\"TH\""
  196. emit_fgt_usecase "A3-03" "A3" "high" "VPN Authentication Brute Force Success" \
  197. "logid=\"0101037133\" type=\"event\" subtype=\"vpn\" action=\"ssl-login-success\" user=\"${SIM_VPN_USER}\" srcip=${out_th} failed_attempts_before_success=18"
  198. emit_fgt_usecase "A3-04" "A3" "low" "VPN Authentication Multiple Fail Many Accounts from One Source" \
  199. "logid=\"0101037134\" type=\"event\" subtype=\"vpn\" action=\"ssl-login-fail\" srcip=${out_th} failed_accounts=12"
  200. emit_fgt_usecase "A3-05" "A3" "high" "VPN Authentication Success from Outside Thailand" \
  201. "logid=\"0101037135\" type=\"event\" subtype=\"vpn\" action=\"ssl-login-success\" user=\"${SIM_VPN_USER}\" srcip=${out_th} country=\"US\" expected_country=\"TH\""
  202. }
  203. emit_a4() {
  204. emit_windows_usecase "A4-01" "A4" "medium" "Windows Authentication Multiple Fail from Privileged Account" \
  205. "event_id=4625 account=\"administrator\" src_ip=$(rand_private_ip) fail_count=9"
  206. emit_windows_usecase "A4-02" "A4" "medium" "Windows Authentication Multiple Fail from Service Account" \
  207. "event_id=4625 account=\"svc_backup\" src_ip=$(rand_private_ip) fail_count=11"
  208. emit_windows_usecase "A4-03" "A4" "medium" "Windows AD Enumeration with Malicious Tools" \
  209. "event_id=4688 process=\"adfind.exe\" user=\"user1\" host=\"${WIN_HOST}\""
  210. emit_windows_usecase "A4-04" "A4" "medium" "Windows Authentication Fail from Public IPs" \
  211. "event_id=4625 account=\"user1\" src_ip=$(rand_public_ip) fail_count=4"
  212. emit_windows_usecase "A4-05" "A4" "medium" "Windows File Share Enumeration to Single Destination" \
  213. "event_id=5145 account=\"user1\" src_ip=$(rand_private_ip) share=\"\\\\\\\\fileserver\\\\finance\" object_count=87"
  214. emit_windows_usecase "A4-06" "A4" "high" "Windows Authentication Success from Public IPs" \
  215. "event_id=4624 account=\"user2\" src_ip=$(rand_public_ip) logon_type=10"
  216. emit_windows_usecase "A4-07" "A4" "high" "Windows Authentication Privileged Account Impersonation" \
  217. "event_id=4624 account=\"administrator\" impersonation=true source_account=\"user2\""
  218. emit_windows_usecase "A4-08" "A4" "high" "Windows Authentication Successful Pass the Hash RDP" \
  219. "event_id=4624 account=\"administrator\" logon_type=10 auth_package=\"NTLM\" pth_indicator=true"
  220. emit_windows_usecase "A4-09" "A4" "high" "Windows Authentication Success from Guest Account" \
  221. "event_id=4624 account=\"guest\" logon_type=3"
  222. emit_windows_usecase "A4-10" "A4" "high" "Windows Authentication Interactive Logon Success by Service Account" \
  223. "event_id=4624 account=\"svc_backup\" logon_type=2"
  224. emit_windows_usecase "A4-11" "A4" "high" "Windows Account Added to Privileged Custom Group" \
  225. "event_id=4732 account=\"user3\" target_group=\"SOC-Privileged-Custom\""
  226. emit_windows_usecase "A4-12" "A4" "high" "Windows Account Added to Privileged Group" \
  227. "event_id=4728 account=\"user3\" target_group=\"Domain Admins\""
  228. emit_windows_usecase "A4-13" "A4" "high" "Windows Domain Configure DSRM Password Reset" \
  229. "event_id=4794 account=\"administrator\" action=\"dsrm-password-reset\""
  230. emit_windows_usecase "A4-14" "A4" "low" "Windows Authentication Multiple Fail One Account from Many Sources" \
  231. "event_id=4625 account=\"user4\" src_count=15 fail_count=28"
  232. emit_windows_usecase "A4-15" "A4" "low" "Windows Authentication Multiple Fail Many Accounts from One Source" \
  233. "event_id=4625 src_ip=$(rand_private_ip) account_count=18 fail_count=42"
  234. emit_windows_usecase "A4-16" "A4" "low" "Windows Authentication Multiple Fail from Guest Account" \
  235. "event_id=4625 account=\"guest\" fail_count=9"
  236. emit_windows_usecase "A4-17" "A4" "low" "Windows Authentication Multiple Fail One Account from One Source" \
  237. "event_id=4625 account=\"user5\" src_ip=$(rand_private_ip) fail_count=10"
  238. emit_windows_usecase "A4-18" "A4" "low" "Windows Authentication Multiple Interactive Logon Denied" \
  239. "event_id=4625 account=\"user6\" logon_type=2 fail_count=7"
  240. emit_windows_usecase "A4-19" "A4" "low" "Windows Authentication Password Spray" \
  241. "event_id=4625 spray=true src_ip=$(rand_public_ip) attempted_accounts=25"
  242. emit_windows_usecase "A4-20" "A4" "low" "Windows Authentication Attempt from Disabled Account" \
  243. "event_id=4625 account=\"disabled.user\" status=\"0xC0000072\""
  244. emit_windows_usecase "A4-21" "A4" "low" "Windows Domain Account Created" \
  245. "event_id=4720 account=\"new.domain.user\" account_type=\"domain\""
  246. emit_windows_usecase "A4-22" "A4" "low" "Windows Local Account Re Enabled" \
  247. "event_id=4722 account=\"local.user\" account_type=\"local\""
  248. emit_windows_usecase "A4-23" "A4" "low" "Windows Local Account Created" \
  249. "event_id=4720 account=\"local.new\" account_type=\"local\""
  250. emit_windows_usecase "A4-24" "A4" "low" "Windows Domain Account Re Enabled" \
  251. "event_id=4722 account=\"domain.reenabled\" account_type=\"domain\""
  252. }
  253. emit_selected_set() {
  254. local sel
  255. sel="$(echo "${SELECTOR}" | tr '[:upper:]' '[:lower:]')"
  256. case "${sel}" in
  257. all)
  258. emit_a1
  259. emit_a2
  260. emit_a3
  261. emit_a4
  262. ;;
  263. a1|a1-*)
  264. emit_a1
  265. ;;
  266. a2|a2-*)
  267. emit_a2
  268. ;;
  269. a3|a3-*)
  270. emit_a3
  271. ;;
  272. a4|a4-*)
  273. emit_a4
  274. ;;
  275. *)
  276. # Exact usecase selectors (e.g. A3-05) are handled by selector_matches.
  277. emit_a1
  278. emit_a2
  279. emit_a3
  280. emit_a4
  281. ;;
  282. esac
  283. }
  284. echo "starting proposal-required log simulator"
  285. echo "selector=${SELECTOR} count=${COUNT} delay=${DELAY}s event_delay=${EVENT_DELAY}s dry_run=${DRY_RUN} profile=${PROFILE}"
  286. echo "target=${WAZUH_SYSLOG_HOST}:${WAZUH_SYSLOG_PORT}/udp"
  287. if [[ "${FOREVER}" == "true" ]]; then
  288. echo "running forever with interval ${DELAY}s (Ctrl+C to stop)"
  289. trap 'echo; echo "stopped"; exit 0' INT TERM
  290. while true; do
  291. emit_selected_set
  292. sleep "${DELAY}"
  293. done
  294. else
  295. for ((i=1; i<=COUNT; i++)); do
  296. emit_selected_set
  297. if [[ "${i}" -lt "${COUNT}" ]]; then
  298. sleep "${DELAY}"
  299. fi
  300. done
  301. echo "done"
  302. fi