BTAS

Blue Team Auxiliary Script

  1. // ==UserScript==
  2. // @name BTAS
  3. // @namespace https://github.com/Mr-Tree-S/BTAS
  4. // @homepageURL https://github.com/Mr-Tree-S/BTAS
  5. // @version 3.8.6
  6. // @description Blue Team Auxiliary Script
  7. // @author Barry, Jack, Xingyu, Mike
  8. // @license Apache-2.0
  9. // @match https://login.microsoftonline.com/*
  10. // @match https://security.microsoft.com/*
  11. // @include https://caas*.com/*
  12. // @include https://mss*mss.com/*
  13. // @icon https://avatars.githubusercontent.com/u/42169240?v=4
  14. // @require https://code.jquery.com/jquery-3.6.4.min.js
  15. // @require https://cdn.jsdelivr.net/npm/clipboard@2.0.11/dist/clipboard.min.js
  16. // @require https://unpkg.com/@popperjs/core@2/dist/umd/popper.min.js
  17. // @require https://unpkg.com/tippy.js@6/dist/tippy-bundle.umd.js
  18. // @require https://cdnjs.cloudflare.com/ajax/libs/dompurify/3.0.6/purify.min.js
  19. // @grant GM_registerMenuCommand
  20. // @grant GM_unregisterMenuCommand
  21. // @grant GM_xmlhttpRequest
  22. // @grant GM_openInTab
  23. // @grant GM_getValue
  24. // @grant GM_setValue
  25. // @connect raw.githubusercontent.com
  26. // @connect myqcloud.com
  27. // @connect 172.18.4.200
  28. // @run-at document-idle
  29. // @grant GM_addStyle
  30. // ==/UserScript==
  31.  
  32. var $ = window.jQuery;
  33.  
  34. /**
  35. * This function creates and displays a flag using AJS.flag function
  36. * @param {string} type - The type of flag, can be one of the following: "success", "info", "warning", "error"
  37. * @param {string} title - The title of the flag
  38. * @param {string} body - The body of the flag
  39. * @param {string} close - The close of flag, can be one of the following: "auto", "manual", "never"
  40. */
  41. function security_microsoft() {
  42. var queryString = window.location.search;
  43. var urlParams = new URLSearchParams(queryString);
  44. var current_domain = urlParams.get('current');
  45. var customers = {};
  46. const cachedWebsiteContent = GM_getValue('cachedWebsiteContent', null);
  47. console.log(cachedWebsiteContent);
  48. cachedWebsiteContent.forEach((item, index) => {
  49. if (item && item['category'] == 'mde' && item['url']) {
  50. customers[item['name']] = item['url'];
  51. }
  52. });
  53. var customer = customers[current_domain];
  54. if (customer) {
  55. console.log('account11', customer);
  56. } else {
  57. customer = current_domain;
  58. }
  59. if (current_domain == 'none') {
  60. let urls = localStorage.getItem('urls').toString().split(',');
  61. for (var i = 0; i < urls.length; i++) {
  62. if (i == 0) {
  63. window.location.href = urls[i];
  64. } else {
  65. GM_openInTab(urls[i], {
  66. active: false, // 设置为 false,以在后台打开,不激活新标签页
  67. insert: true // 设置为 true,将新标签页插入到当前标签页之后
  68. });
  69. }
  70. }
  71. localStorage.removeItem('urls');
  72. }
  73. setTimeout(() => {
  74. document.getElementById('O365_MainLink_Me').click();
  75. console.log('account1');
  76. }, 9000);
  77. setTimeout(() => {
  78. var account = document.getElementById('mectrl_currentAccount_secondary').textContent;
  79. console.log(account, customer);
  80. if (
  81. !account.includes(customer) &&
  82. !customer.includes(account.split('@')[1].split('.')[0]) &&
  83. current_domain != 'none'
  84. ) {
  85. let urls = [];
  86. urlParams.forEach(function (value, key) {
  87. if (key.includes('url')) {
  88. urls.push(value);
  89. }
  90. });
  91. localStorage.setItem('urls', urls);
  92. document.getElementById('mectrl_body_signOut').click();
  93. } else {
  94. urlParams.forEach(function (value, key) {
  95. if (key.includes('url')) {
  96. GM_openInTab(value, {
  97. active: false, // 设置为 false,以在后台打开,不激活新标签页
  98. insert: true // 设置为 true,将新标签页插入到当前标签页之后
  99. });
  100. }
  101. });
  102. window.close();
  103. }
  104. }, 9900);
  105. }
  106.  
  107. function switch_user_microsoft() {
  108. console.log('login.microsoft', $('#idDiv_SAOTCC_Title').text().trim());
  109. if ($('#login_workload_logo_text').text().trim() == '您已注销帐户') {
  110. window.location.href = 'https://security.microsoft.com/homepage?&current=none';
  111. }
  112. if (document.title == '登录到您的帐户' && $('#idDiv_SAOTCC_Title').text().trim() != '输入验证码') {
  113. setTimeout(() => {
  114. var inputElement = document.querySelectorAll('.form-control')[0];
  115. inputElement.addEventListener('input', function (event) {
  116. var inputValue = inputElement.value;
  117. if (inputValue.includes('@')) {
  118. $('#idSIButton9').click();
  119. setTimeout(() => {
  120. $('#idSIButton9').click();
  121. }, 1500);
  122. }
  123. });
  124. }, 1600);
  125. } else {
  126. setTimeout(() => {
  127. var inputElement = document.querySelectorAll('.form-control')[0];
  128. inputElement.addEventListener('keyup', function (event) {
  129. var inputValue = inputElement.value;
  130. console.log(inputValue); // 打印当输入框的内容在元素失去焦点时的值
  131. if (inputValue.length == 6) {
  132. $('#idSubmit_SAOTCC_Continue').click();
  133. }
  134. });
  135. }, 800);
  136. }
  137. }
  138.  
  139. function addCss() {
  140. const ss = $(`
  141. <style>
  142. .red_highlight{
  143. color:red;
  144. font-weight: bold;
  145. }
  146. .black_highlight{
  147. color:black;
  148. font-weight: bold;
  149. }
  150. .aui-dropdown2{
  151. max-width: 550px !important;
  152. }
  153. .aui-dropdown2 .aui-dropdown2-checkbox, .aui-dropdown2 .aui-dropdown2-radio, .aui-dropdown2 .aui-icon-container {
  154. padding-top: 10px;
  155. padding-left: 35px;
  156. }
  157. #reply{
  158. column-count: 2;
  159. }
  160. .aui-flag{
  161. border: 4px solid rgb(222,184,135) ;
  162. }
  163. .fix-button{
  164. background-color: rgb(222,184,135);
  165. color:white;
  166. z-index: 100;
  167. margin-right: 12px;
  168. }
  169. </style>
  170. `);
  171. $('head').append(ss);
  172.  
  173. function hideAllFlag() {
  174. $('.aui-flag').toggle();
  175. }
  176. const button = $('<div>')
  177. .attr('id', 'hide-reminder')
  178. .addClass('aui-button toolbar-trigger fix-button aui-button-primary')
  179. .append($('<span>').addClass('trigger-label').text('NOTICE'))
  180. .click(hideAllFlag);
  181.  
  182. const checkExist = setInterval(function () {
  183. const targetDiv = document.getElementById('aui-flag-container');
  184. const toolbar = $('.aui-header-secondary');
  185.  
  186. if (targetDiv) {
  187. toolbar.prepend(button);
  188. clearInterval(checkExist); // 停止检查
  189. }
  190. }, 100); // 每100毫秒检查一次
  191. }
  192.  
  193. function showFlag(type, title, body, close) {
  194. AJS.flag({
  195. type: type,
  196. title: DOMPurify.sanitize(title),
  197. body: DOMPurify.sanitize(body),
  198. close: close
  199. });
  200.  
  201. // addButton('hide-reminder', 'Hide Reminder', hideAllFlag);
  202.  
  203. // 为 flag 的内容区域添加滚动条样式
  204. const flagBody = $('#aui-flag-container > div > div');
  205. flagBody.css({
  206. 'overflow': 'auto',
  207. 'max-height': '150px' // 添加最大高度,超出部分将出现滚动条
  208. });
  209.  
  210. // 为 flag 的container区域添加滚动条样式
  211. const flagContainer = $('#aui-flag-container');
  212. flagContainer.css({
  213. 'overflow': 'auto',
  214. 'overflow-x': 'hidden', //隐藏水平滚动条
  215. 'max-height': '90%' // 添加最大高度,超出部分将出现滚动条
  216. });
  217. }
  218.  
  219. /**
  220. * This function shows alert message in dialog and create a copy button
  221. * @param {string} body - Alert Message String
  222. */
  223. function showDialog(body) {
  224. // avoid editor treat double backslash as breakline and avoid xss attack
  225. body = DOMPurify.sanitize(body.replace(/\\\\/g, '\\'));
  226.  
  227. // Create custom dialog style
  228. const customDialogContent = AJS.$(`<section
  229. id="custom-dialog"
  230. class="aui-dialog2 aui-dialog2-large aui-layer"
  231. role="dialog"
  232. tabindex="-1"
  233. data-aui-modal="true"
  234. data-aui-remove-on-hide="true"
  235. aria-labelledby="dialog-show-button--heading"
  236. aria-describedby="dialog-show-button--description"
  237. hidden
  238. >
  239. <header class="aui-dialog2-header">
  240. <h2 class="aui-dialog2-header-main" id="dialog-show-button--heading">Description</h2>
  241. </header>
  242. <div class="aui-dialog2-content" id="dialog-show-button--description">
  243. <p style="word-wrap: break-word; white-space: pre-line">${body}</p>
  244. </div>
  245. <footer class="aui-dialog2-footer">
  246. <div class="aui-dialog2-footer-actions">
  247. <button id="dialog-copy-button" class="aui-button aui-button-primary">Copy</button>
  248. <button id="dialog-close-button" class="aui-button aui-button-link">Close</button>
  249. </div>
  250. </footer>
  251. </section>`);
  252.  
  253. // Show the dialog
  254. AJS.dialog2(customDialogContent).show();
  255.  
  256. // Close the dialog
  257. AJS.$('#dialog-close-button').on('click', function (e) {
  258. e.preventDefault();
  259. AJS.dialog2(customDialogContent).hide();
  260. //tippy.destroy();
  261. });
  262.  
  263. // Init tippy instance
  264. tippy('#dialog-copy-button', {
  265. content: 'Copy Success',
  266. placement: 'bottom',
  267. trigger: 'click'
  268. });
  269.  
  270. // Copy description text
  271. AJS.$('#dialog-copy-button').on('click', function () {
  272. const textToCopy = customDialogContent.find('#dialog-show-button--description').text().trim();
  273.  
  274. // Create Clipboard instance
  275. const clipboard = new ClipboardJS('#dialog-copy-button', {
  276. text: function () {
  277. return textToCopy;
  278. }
  279. });
  280.  
  281. // Copy success
  282. clipboard.on('success', function (e) {
  283. clipboard.destroy();
  284. e.clearSelection();
  285. });
  286. });
  287. }
  288.  
  289. /**
  290. * This function registers a Tampermonkey search menu command
  291. * @param {Array} searchEngines - Search engines array containing the Jira, VT, AbuseIPDB
  292. */
  293. function registerSearchMenu() {
  294. console.log('#### Code registerSearchMenu run ####');
  295. const LogSourceDomain = $('#customfield_10223-val').text().trim() || '*';
  296. const Host = function () {
  297. let search = {
  298. 'Source IP(s) and Hostname(s)': $('#customfield_10206-val').text().trim(),
  299. 'Destination IP(s) and Hostname(s)': $('#customfield_10208-val').text().trim()
  300. };
  301. if (search['Source IP(s) and Hostname(s)']) {
  302. return `AND 'Source IP(s) and Hostname(s)' ~ '${search['Source IP(s) and Hostname(s)']}'`;
  303. } else if (search['Destination IP(s) and Hostname(s)']) {
  304. return `AND 'Destination IP(s) and Hostname(s)' ~ '${search['Destination IP(s) and Hostname(s)']}'`;
  305. } else {
  306. return '';
  307. }
  308. };
  309. let cachedEntry = GM_getValue('cachedEntry', null);
  310.  
  311. let url = `${
  312. cachedEntry['hk']
  313. }/issues/?jql=text ~ "%s" AND "Log Source Domain" ~ "%D" ${Host()} ORDER BY created DESC`;
  314. if (window.location.href.includes(cachedEntry['macao'].split('//')[1])) {
  315. url = `${cachedEntry['macao']}/issues/?jql=text ~ "%s" ORDER BY created DESC`;
  316. }
  317. console.log('===url', url);
  318.  
  319. const searchEngines = [
  320. {
  321. name: 'Jira',
  322. url: url
  323. },
  324. { name: 'VT', url: 'https://www.virustotal.com/gui/search/%s' },
  325. { name: 'AbuseIPDB', url: 'https://www.abuseipdb.com/check/%s' },
  326. {
  327. name: 'Base64 Decode',
  328. url: `https://icyberchef.com/#recipe=From_Base64('A-Za-z0-9%2B/%3D',true,false)&input=%b`
  329. }
  330. ];
  331. searchEngines.forEach((engine) => {
  332. GM_registerMenuCommand(engine.name, () => {
  333. const selectedText = window.getSelection().toString();
  334. const searchURL = engine.url
  335. .replace('%s', selectedText)
  336. .replace('%D', LogSourceDomain)
  337. .replace('%b', btoa(selectedText));
  338. if (selectedText.length === 0) {
  339. showFlag('error', 'No text selected', 'Please select some text and try again', 'auto');
  340. } else {
  341. window.open(searchURL, '_blank');
  342. }
  343. });
  344. });
  345. }
  346.  
  347. /**
  348. * This function registers custom add/remove quick reply menus in Tampermonkey
  349. * Add custom reply: input custom reply and store in local
  350. * Remove quick reply: remove all local storage custom replies
  351. */
  352. function registerCustomQuickReplyMenu() {
  353. GM_registerMenuCommand('Add Custom Quick Reply', () => {
  354. const userInput_name = prompt('Enter saved quick reply name (the name should be unique)').toString();
  355. const userInput_reply = prompt('Enter a custom quick reply (<br> is used for line break)').toString();
  356. if (userInput_name !== null && userInput_reply !== null) {
  357. const key = `customReply_${userInput_name}`;
  358. // local save
  359. localStorage.setItem(key, userInput_reply);
  360. }
  361. });
  362.  
  363. GM_registerMenuCommand('Remove Custom Quick Reply', () => {
  364. for (let i = 0; i < localStorage.length; i++) {
  365. const key = localStorage.key(i);
  366. if (key.startsWith('customReply_')) {
  367. localStorage.removeItem(key);
  368. }
  369. }
  370. showFlag('success', 'Cleared All Custom Replies', '', 'auto');
  371. });
  372. GM_registerMenuCommand('MDE Assist', () => {
  373. let MDE_Assist_ = localStorage.getItem('MDE_Assist');
  374. const MDE_Assist = prompt(
  375. 'Whether MDE Assist is enabled(Example:enable 1, disable 0)',
  376. MDE_Assist_
  377. ).toString();
  378. localStorage.setItem('MDE_Assist', MDE_Assist);
  379. });
  380. }
  381.  
  382. /**
  383. * This function create a Quick Reply button in editor
  384. */
  385. function QuickReply() {
  386. const replyButton = `<button class="aui-button aui-dropdown2-trigger" aria-controls="is-radio-checked">Quick Reply</button>
  387. <aui-dropdown-menu id="is-radio-checked">
  388. <aui-section id="reply">
  389. <aui-item-radio interactive>Close ticket</aui-item-radio>
  390. <aui-item-radio interactive>Monitor ticket</aui-item-radio>
  391. <aui-item-radio interactive>Waiting ticket</aui-item-radio>
  392. <aui-item-radio interactive>Waiting Full Scan</aui-item-radio>
  393. <aui-item-radio interactive>Ask for Whitelist</aui-item-radio>
  394. <aui-item-radio interactive>Whitelist Done</aui-item-radio>
  395. <aui-item-radio interactive>Agent recover</aui-item-radio>
  396. <aui-item-radio interactive>Leaked Credentials</aui-item-radio>
  397. <aui-item-radio interactive>Compromised Accounts</aui-item-radio>
  398. <aui-item-radio interactive>Log resume</aui-item-radio>
  399. <aui-item-radio interactive>关闭工单</aui-item-radio>
  400. <aui-item-radio interactive>Haeco high severity</aui-item-radio>
  401. <aui-item-radio interactive>Haeco medium severity</aui-item-radio>
  402. <aui-item-radio interactive>Haeco low severity</aui-item-radio>
  403. </aui-section>
  404. </aui-dropdown-menu>`;
  405. const commentBar = $($('.aui-toolbar2-primary')[1]);
  406. commentBar.append(replyButton);
  407.  
  408. const commentBarSection = document.querySelector('aui-section#reply');
  409. const replyComment = {
  410. 'Close ticket': 'Dear Customer,<br>Thanks for your reply, we will close this ticket.<br>Best Regards.',
  411. 'Monitor ticket': 'Dear Customer,<br>Thanks for your reply, we will keep monitor.<br>Best Regards.',
  412. 'Waiting ticket': 'Dear Customer,<br>Thanks, we look forward to hearing from you.',
  413. 'Waiting Full Scan':
  414. 'Dear Customer,<br>Full scan have been triggered , if suspicious files detected new MDE alert/ticket will be created.',
  415. 'Ask for Whitelist': 'Dear Customer,<br>Can we add the ticket to white list?<br>Best Regards.',
  416. 'Whitelist Done':
  417. 'Dear Customer,<br>We have informed the relevant parties to add this ticket to the white list and will close this ticket<br>Best Regards.',
  418. 'Haeco high severity':
  419. '<h2><strong><span style="color: red;" data-mce-style="color: red;"><samp>[The ticket is escalated to High Severity]</samp></span></strong></h2><br>',
  420. 'Haeco medium severity':
  421. '<h2><span style="color: rgb(255, 171, 0);" data-mce-style="color: #ffab00;"><strong><samp>[The ticket is escalated to Medium Severity]</samp></strong></span></h2><br>',
  422. 'Haeco low severity':
  423. '<h2><span style="color: rgb(76, 154, 255);" data-mce-style="color: #4c9aff;"><strong><samp>[The ticket is de-escalated to Low Severity]</samp></strong></span></h2><br>',
  424. 'Leaked Credentials':
  425. '<p>Dear Client,</p><p>Our Cyber Threat Intelligence investigated the incident and found &lt;Number&gt; leaked credentials related to your organization exposed in dark web. The credentials are listed below:</p><table width="962" class="mce-item-table"><tbody><tr><td width="137"><div><p><strong>EMAIL/USERNAME</strong></p></div></td><td width="137"><div><p><strong>PASSWORD TYPE</strong></p></div></td><td width="137"><div><p><strong>PASSWORD</strong></p></div></td><td width="137"><div><p><strong>SOURCE</strong></p></div></td><td width="137"><div><p><strong>PRICE</strong></p></div></td><td width="137"><div><p><strong>POSTED DATE</strong></p></div></td><td width="137"><div><p><strong>SERVICE</strong></p></div></td></tr><tr><td width="137"><br data-mce-bogus="1"></td><td width="137"><br data-mce-bogus="1"></td><td width="137"><br data-mce-bogus="1"></td><td width="137"><br data-mce-bogus="1"></td><td width="137"><br data-mce-bogus="1"></td><td width="137"><br data-mce-bogus="1"></td><td width="137"><br data-mce-bogus="1"></td></tr></tbody></table><p>[Source Detail from Kela]</p><p>&lt;SOURCE Details/Description&gt;</p><p>[Service if disclose need check]</p><p>As per our open-source investigation through passive means, we observe that:</p><p>&lt; SERVICE&gt; appear to be &lt;SERVICE USAGE&gt;</p><p>[Recommendation]</p><p>We recommend confirming that the service coverage is to customers only, or whether it also includes staff and/or third-party, and evaluate if accounts with administrative privileges require a password change. &nbsp;We also recommend to heighten monitoring of customer login to indicate anomalies in location or timing, and review password policies and evaluate if there is a need to strengthen (e.g., mandate password rotation regularly). A further recommendation is to reach out to these account holders if the accounts are still active, and request that they change their passwords.</p><p>Please do not hesitate to reach out to us if you have any queries. Thank you.</p><p>Best Regards,<br>Cyber Threat Intelligence Team</p>',
  426. 'Compromised Accounts':
  427. '<p>Dear Client,</p><p>Our Cyber Threat Intelligence investigated the incident and found&nbsp;&lt;Number&gt; compromised accounts related to your organisation exposed in dark web. The credentials are listed below:</p><table width="962" class="mce-item-table"><tbody><tr><td width="137"><div><p><strong>EMAIL/USERNAME</strong></p></div></td><td width="137"><div><p><strong>PASSWORD TYPE</strong></p></div></td><td width="137"><div><p><strong>PASSWORD</strong></p></div></td><td width="137"><div><p><strong>SOURCE</strong></p></div></td><td width="137"><div><p><strong>PRICE</strong></p></div></td><td width="137"><div><p><strong>POSTED DATE</strong></p></div></td><td width="137"><div><p><strong>SERVICE</strong></p></div></td></tr><tr><td width="137"><br data-mce-bogus="1"></td><td width="137"><br data-mce-bogus="1"></td><td width="137"><br data-mce-bogus="1"></td><td width="137"><br data-mce-bogus="1"></td><td width="137"><br data-mce-bogus="1"></td><td width="137"><br data-mce-bogus="1"></td><td width="137"><br data-mce-bogus="1"></td></tr></tbody></table><p>[Source Detail from Kela]</p><p>&lt;SOURCE Details/Description&gt;</p><p>[Service if disclose need check]</p><p>As per our open-source investigation through passive means, we observe that:</p><p>&lt; SERVICE&gt; appear to be &lt;SERVICE USAGE&gt;&nbsp;</p><p>[Recommendation]</p><p>We recommend confirming that the service coverage is to customers only, or whether it also includes staff and/or third-party, and evaluate if accounts with administrative privileges require a password change. &nbsp;We also recommend to heighten monitoring of customer login to indicate anomalies in location or timing, and review password policies and evaluate if there is a need to strengthen (e.g., mandate password rotation regularly). A further recommendation is to reach out to these account holders if the accounts are still active, and request that they change their passwords.</p><p>Please do not hesitate to reach out to us if you have any queries. Thank you.</p><p>Best Regards,<br>Cyber Threat Intelligence Team</p>',
  428. 'Log resume':
  429. 'Dear Customer,<br>Thanks for your reply, <br>Log resumed, we will close this ticket.<br>Best Regards.',
  430. 'Agent recover':
  431. 'Dear Customer,<br>Thanks for your reply,<br>The agent is now active and we will close this case<br>Best Regards.',
  432. '关闭工单': '尊敬的客户,<br>感谢您的回复,我们将关闭此工单。 <br>祝您生活愉快。<br>'
  433. };
  434.  
  435. // Check local storage at initialization time
  436. function getAllCustomReply() {
  437. for (let i = 0; i < localStorage.length; i++) {
  438. const key = localStorage.key(i);
  439. if (key.startsWith('customReply_')) {
  440. const storedReply = localStorage.getItem(key).toString();
  441. const storeReplyName = key.split('_')[1].toString();
  442. replyComment[storeReplyName] = storedReply;
  443. $('#reply').append(`<aui-item-radio interactive>${storeReplyName}</aui-item-radio>`);
  444. }
  445. }
  446. }
  447. getAllCustomReply();
  448.  
  449. try {
  450. if (commentBarSection !== null) {
  451. commentBarSection.addEventListener('change', function (e) {
  452. if (e.target.hasAttribute('checked')) {
  453. tinymce.activeEditor.setContent('');
  454. let replyValue = replyComment[e.target.textContent];
  455. tinymce.activeEditor.execCommand('mceInsertContent', false, replyValue);
  456. }
  457. });
  458. }
  459. } catch (error) {
  460. console.error(error);
  461. }
  462. }
  463.  
  464. /**jsonView */
  465. function jsonToTree(data) {
  466. let flag = false;
  467. let html = '<ul class="code-java" style="list-style-type: none;margin-top: 0px;padding-left: 20px;">';
  468. if (Array.isArray(data)) {
  469. let temp = '[';
  470. data.forEach((element) => {
  471. temp += jsonToTree(element);
  472. });
  473. html += temp + '],';
  474. } else if (data != null && typeof data === 'object' && Object.keys(data).length !== 0) {
  475. flag = true;
  476. for (let key in data) {
  477. if (data.hasOwnProperty(key)) {
  478. html += '<li class="code-quote">"' + key + '": ';
  479. if (Array.isArray(data[key])) {
  480. let temp = '[';
  481. data[key].forEach((element) => {
  482. temp += jsonToTree(element);
  483. });
  484. html += temp + '],';
  485. } else if (typeof data[key] === 'object') {
  486. try {
  487. if (Object.keys(data[key]).length == 0) {
  488. html += '{},';
  489. } else {
  490. const str = jsonToTree(data[key]);
  491. html += str;
  492. }
  493. } catch (TypeError) {
  494. html += '"",';
  495. }
  496. } else {
  497. html += '"' + data[key].toString() + '",';
  498. }
  499. html += '</li>';
  500. }
  501. }
  502. } else {
  503. html += '"' + data.toString() + '",';
  504. }
  505. if (flag === true) {
  506. html = '{' + html + '},';
  507. }
  508. html += '</ul>';
  509. return html;
  510. }
  511.  
  512. function ToWhitelist() {
  513. const summary = $('#summary-val').text().trim();
  514. var LogSourceDomain = $('#customfield_10223-val').text().trim();
  515. let DecoderName = $('#customfield_10807-val').text().trim().toLowerCase();
  516. let Component = 'Wazuh';
  517. if (DecoderName.includes('mde') || DecoderName.includes('m365')) {
  518. Component = 'MDE';
  519. }
  520. if (DecoderName.includes('cortex')) {
  521. Component = 'Cortex';
  522. }
  523. let whitelist = {
  524. summary: summary,
  525. LogSourceDomain: LogSourceDomain,
  526. Component: Component,
  527. MSS: window.location.href
  528. };
  529. localStorage.setItem('whitelist', JSON.stringify(whitelist));
  530. let cachedEntry = GM_getValue('cachedEntry', null);
  531. window.open(`${cachedEntry['hk']}/plugins/servlet/desk/portal/2/create/100`, '_blank');
  532. }
  533.  
  534. /**
  535. * This function registers two Tampermonkey exception menu command
  536. * Add Exception: adds the currently selected text to an exception list stored in local storage
  537. * Clear Exception: clears the exception list from local storage
  538. */
  539. let exceptionKey = localStorage.getItem('exceptionKey')?.split(',') || [];
  540. let notifyKey = [...exceptionKey];
  541. function registerExceptionMenu() {
  542. console.log('#### Code registerExceptionMenu run ####');
  543. GM_registerMenuCommand('Add Exception', () => {
  544. const selection = window.getSelection().toString().trim();
  545. if (!selection) {
  546. showFlag('error', 'No Issue Key selected', '', 'auto');
  547. return;
  548. }
  549. exceptionKey.push(selection);
  550. localStorage.setItem('exceptionKey', exceptionKey.toString());
  551. showFlag('success', '', `Added <strong>${selection}</strong> successfully`, 'auto');
  552. });
  553.  
  554. GM_registerMenuCommand('Clear Exception', () => {
  555. localStorage.setItem('exceptionKey', '');
  556. exceptionKey = notifyKey = [];
  557. showFlag('success', 'Cleared All Issue Key', '', 'auto');
  558. });
  559.  
  560. GM_registerMenuCommand('JsonViewer', () => {
  561. var isJson = function (str) {
  562. try {
  563. JSON.parse(str);
  564. } catch (e) {
  565. showFlag('error', 'Please select json format data', '', 'auto');
  566. return false;
  567. }
  568. return true;
  569. };
  570. let selection = window.getSelection().toString().trim();
  571. if (!selection) {
  572. showFlag('error', 'No Issue Key selected', '', 'auto');
  573. return;
  574. } else if (isJson(selection)) {
  575. var jsonData = jsonToTree(JSON.parse(selection));
  576. /** var jsonView = document.createElement('pre');
  577. jsonView.textContent = JSON.stringify(jsonData,null,2);
  578. **/
  579. showDialog(jsonData, 'Json Format');
  580. }
  581. });
  582. }
  583.  
  584. /**
  585. * This function creates audio and checkbox controls and adds them to the Jira share button's parent node
  586. * @returns {Object} Object containing references to the audio control and audio checkbox, keep checkbox, prompt checkbox
  587. */
  588. // ## In the future, the alert sound will be migrated to another server, and more fun music will be added.
  589. function createNotifyControls() {
  590. console.log('#### Code createNotifyControls run ####');
  591. const operationsBar = $('div.saved-search-operations.operations');
  592. const audioControl = $('<span></span>');
  593.  
  594. function createAudioControl(parentNode) {
  595. const currentDate = new Date();
  596. const audioURL =
  597. currentDate.getHours() >= 9 && currentDate.getHours() < 21
  598. ? 'https://gitee.com/aspirepig/aspirepig/raw/master/12221.wav'
  599. : 'https://gitee.com/aspirepig/aspirepig/raw/master/alerts.wav';
  600. audioControl.html(`<audio id="myAudio" src="${audioURL}" type="audio/mpeg" controls></audio>`);
  601. parentNode.prepend(audioControl);
  602. }
  603.  
  604. function createCheckbox(parentNode, localStorageKey, checkStatus) {
  605. const checkbox = $('<span></span>');
  606. const value = localStorage.getItem(localStorageKey);
  607. checkbox.html(
  608. `<input type="checkbox" name="${localStorageKey}" ${
  609. value == 'true' ? 'checked' : checkStatus ? 'checked' : ''
  610. }>${localStorageKey}`
  611. );
  612. checkbox.find('input').on('click', () => {
  613. localStorage.setItem(localStorageKey, checkbox.find('input').prop('checked'));
  614. });
  615. parentNode.prepend(checkbox);
  616. return checkbox;
  617. }
  618. createAudioControl(operationsBar);
  619. const audioCheckbox = createCheckbox(operationsBar, 'audioNotify', false);
  620. const keepCheckbox = createCheckbox(operationsBar, 'keepAudio', false);
  621. const promptCheckbox = createCheckbox(operationsBar, 'prompt', true);
  622.  
  623. return { audioControl, audioCheckbox, keepCheckbox, promptCheckbox };
  624. }
  625.  
  626. /**
  627. * Check for updates in the issues list and play a sound if new issues are found
  628. * @param {Object} NotifyControls - Object containing the audio control, audio checkbox, keep checkbox, prompt checkbox
  629. */
  630. function checkupdate(NotifyControls) {
  631. console.log('#### Code checkupdate run ####');
  632. const { audioControl, audioCheckbox, keepCheckbox, promptCheckbox } = NotifyControls;
  633. const table = $('tbody');
  634. if (!table.length) return;
  635. let cachedEntry = GM_getValue('cachedEntry', null);
  636.  
  637. let Tickets = '';
  638. table.find('tr').each(function () {
  639. const summary = $(this).find('.summary p').text().trim();
  640. const issuekey = $(this).find('.issuekey a.issue-link').attr('data-issue-key');
  641. if (!notifyKey.includes(issuekey)) {
  642. notifyKey.push(issuekey);
  643. Tickets += `${summary}==${issuekey}\n`;
  644. }
  645. });
  646. if (Tickets || keepCheckbox.find('input').prop('checked')) {
  647. if (audioCheckbox.find('input').prop('checked')) {
  648. audioControl.find('audio').get(0).currentTime = 0;
  649. audioControl.find('audio').get(0).play();
  650. }
  651. }
  652.  
  653. $('.aui-banner').remove();
  654. let overdueTickets = '';
  655. table.find('tr').each(function () {
  656. const issuekey = $(this).find('.issuekey a.issue-link').attr('data-issue-key');
  657. const datetime = new Date($(this).find('.updated time').attr('datetime'));
  658. const currentTime = new Date();
  659. const diffMs = currentTime - datetime;
  660. const diffMinutes = Math.floor(diffMs / 60000);
  661. if (diffMinutes > 30 && diffMinutes < 120) {
  662. overdueTickets += `<a href="${cachedEntry['hk']}/browse/${issuekey}" target="_blank">${issuekey}</a>, `;
  663. }
  664. });
  665. if (overdueTickets && promptCheckbox.find('input').prop('checked')) {
  666. GM_addStyle(`
  667. .aui-banner.aui-banner-warning {
  668. background-color: #ffab00 !important;
  669. color: black !important;
  670. }
  671. `);
  672. AJS.banner({
  673. body: `Ticket: ${overdueTickets}<br>30 minutes have passed since the ticket's status changed, please handle it as soon as possible`,
  674. type: 'warning'
  675. });
  676. }
  677. }
  678.  
  679. /**
  680. * This function checks for specific keywords within a string
  681. * Advises the user to double-check and contact L2 or TL if suspicious.
  682. */
  683. function checkKeywords() {
  684. console.log('#### Code checkKeywords run ####');
  685. function check(keywords) {
  686. const rawLog = $('#customfield_10219-val').text().trim().toLowerCase();
  687. const summary = $('#summary-val').text().trim().toLowerCase();
  688. let Raw_Crotex_alert = $('.code-java').text().trim().toLowerCase();
  689.  
  690. for (const keyword of keywords) {
  691. if (
  692. rawLog.includes(keyword['keyword'].toLowerCase()) ||
  693. Raw_Crotex_alert.includes(keyword['keyword'].toLowerCase()) ||
  694. summary.includes(keyword['keyword'].toLowerCase())
  695. ) {
  696. AJS.banner({
  697. body: `\"${keyword['keyword']}\" was found in the ticket, it is maybe used for "${keyword['remark']}", please double-check and contact L2 or TL if suspicious.`
  698. });
  699. }
  700. }
  701. }
  702. function fetchData(url, apiKey) {
  703. const cachedKeywordsContent = GM_getValue('cachedKeywordsContent', null);
  704. const cachedWebsiteContent = GM_getValue('cachedWebsiteContent', null);
  705. const cachedWhitehashContent = GM_getValue('cachedWhitehashContent', null);
  706. GM_xmlhttpRequest({
  707. method: 'GET',
  708. url: url,
  709. headers: {
  710. 'api-key': apiKey
  711. },
  712. timeout: 4000, // 超过4秒未获取到文件则使用缓存文件
  713. onload: function (response) {
  714. if (response.status === 200) {
  715. const data = JSON.parse(response.responseText)['data'];
  716.  
  717. console.log(data);
  718. if (cachedKeywordsContent == null) {
  719. GM_setValue('cachedKeywordsContent', data['keywords']);
  720. }
  721. if (cachedWebsiteContent == null) {
  722. GM_setValue('cachedWebsiteContent', data['website']);
  723. let cachedEntry = {};
  724. data['website'].forEach((item, index) => {
  725. if (item && item['name'] == 'hk' && item['url']) {
  726. cachedEntry['hk'] = item['url'];
  727. }
  728. if (item && item['name'] == 'macao' && item['url']) {
  729. cachedEntry['macao'] = item['url'];
  730. }
  731. GM_setValue('cachedEntry', cachedEntry);
  732. });
  733. }
  734. if (cachedWhitehashContent == null) {
  735. GM_setValue('cachedWhitehashContent', data['whitehash']);
  736. }
  737. } else {
  738. console.error('Error fetching cachedContent:', response.status);
  739. }
  740. },
  741. ontimeout: function () {
  742. if (cachedKeywordsContent == null || cachedWebsiteContent == null || cachedWhitehashContent == null) {
  743. showFlag('Error', 'BTAS缓存数据获取失败', '未连接到 VPN,请连接后刷新页面', 'auto');
  744. }
  745. },
  746. onerror: function (error) {
  747. console.error('Error:', error);
  748. }
  749. });
  750. }
  751.  
  752. const url = 'https://172.18.4.200/api/7vVKD9hF/message/';
  753. const apiKey = 'Tnznjha3yhJgA7YG';
  754. const cachedKeywordsContent = GM_getValue('cachedKeywordsContent', null);
  755. if (cachedKeywordsContent == null) {
  756. fetchData(url, apiKey);
  757. }
  758. check(cachedKeywordsContent);
  759. }
  760.  
  761. /**
  762. * This function is used for checking ATT&CK field
  763. */
  764. function checkATTCK() {
  765. const status = $('#opsbar-transitions_more > span').text().trim();
  766. const attck = $('#rowForcustomfield_10220 > div > strong > label').text();
  767. if (status == 'Waiting for customer' && attck == '') {
  768. AJS.banner({ body: `The ATT&CK field is not filled in` });
  769. }
  770. }
  771.  
  772. /**
  773. * This function is used for popping up MSS ticket considerations when clicked "Edit" and "Resolved" button or page loading.
  774. * Ticket Considerations file is store in cloud server
  775. * @param {Object} pageData - Gets the specified fields from the jira page
  776. */
  777. function ticketNotify(pageData) {
  778. console.log('#### Code ticketNotify run ####');
  779.  
  780. function fetchOrgNotifydict() {
  781. // 从本地存储获取缓存的文件内容和上次更新时间
  782. const cachedContent = GM_getValue('cachedFileContent', null);
  783.  
  784. GM_xmlhttpRequest({
  785. method: 'GET',
  786. url: 'https://172.18.4.200/api/7vVKD9hF/notifys/',
  787. headers: {
  788. 'api-key': 'Tnznjha3yhJgA7YG'
  789. },
  790. timeout: 4000, // 超过4秒未获取到文件则使用缓存文件
  791. onload: function (response) {
  792. if (response.status === 200) {
  793. const data = JSON.parse(response.responseText)['data'];
  794.  
  795. // 本地无缓存,第一次获取文件保存到本地
  796. if (cachedContent == null) {
  797. // 更新本地存储中的文件内容和更新时间
  798. GM_setValue('cachedFileContent', data);
  799.  
  800. checkNotify(data.items, pageData);
  801. }
  802.  
  803. // 如果本地存储中有缓存,并且文件内容有变化
  804. if (cachedContent !== null && JSON.stringify(cachedContent) !== JSON.stringify(data)) {
  805. // 更新本地存储中的文件内容
  806. GM_setValue('cachedFileContent', data);
  807.  
  808. // 使用最新文件
  809. checkNotify(data.items, pageData);
  810. }
  811.  
  812. // 本地存在缓存,且内容相同则使用缓存文件
  813. if (cachedContent !== null && JSON.stringify(cachedContent) == JSON.stringify(data)) {
  814. checkNotify(cachedContent.items, pageData);
  815. }
  816. } else {
  817. console.error('Error fetching orgNotifydict:', response.status);
  818. }
  819. },
  820. ontimeout: function () {
  821. if (cachedContent !== null) {
  822. checkNotify(cachedContent.items, pageData);
  823. } else {
  824. showFlag('Error', '文件获取失败', '未连接到 VPN,请连接后刷新页面', 'auto');
  825. }
  826. },
  827. onerror: function (error) {
  828. console.error('Error:', error);
  829. }
  830. });
  831. }
  832. fetchOrgNotifydict();
  833.  
  834. function checkNotify(Notifydict, pageData) {
  835. // get button path
  836. const buttonMap = {
  837. Edit: '#edit-issue',
  838. Resolve: '#action_id_761',
  839. None: ''
  840. };
  841. const searchStrings = [];
  842.  
  843. // 查找并高亮指定字符串的函数
  844. function highlightTextInElement(selector, searchStrings) {
  845. const element = $(selector);
  846. if (element.length === 0) {
  847. console.error('未找到指定的元素');
  848. return;
  849. }
  850.  
  851. // 获取元素文本内容
  852. let text = element.text().trim();
  853.  
  854. // 对每个字符串进行高亮处理
  855. searchStrings.forEach((searchString) => {
  856. // 在文本中查找并替换匹配的字符串
  857. text = text.replace(
  858. new RegExp(searchString, 'gi'),
  859. (match) => `<span style="background-color: yellow;">${match}</span>`
  860. );
  861. });
  862.  
  863. // 将替换后的文本重新设置为元素的 HTML 内容
  864. element.html(text);
  865. }
  866.  
  867. function checkProperties(properties, pageData, ticketname) {
  868. const condition = (property) => {
  869. const propertyArray = property.propertiesVal.split(',');
  870. let isAllConditionsMet = false;
  871. for (const val of propertyArray) {
  872. try {
  873. if (!property.conditionOptions) {
  874. let isTrue = pageData[property.propertiesKey]
  875. .toLowerCase()
  876. .includes(val.trim().toLowerCase().replace('!', ''));
  877. if (val.trim().toLowerCase().includes('!')) {
  878. isTrue = !isTrue;
  879. }
  880. if (isTrue) {
  881. if (property.propertiesKey == 'RawLog') {
  882. searchStrings.push(val.trim());
  883. }
  884. isAllConditionsMet = true; // 如果任何一个属性满足条件,返回 true
  885. }
  886. }
  887. switch (property.conditionOptions) {
  888. case 'contain':
  889. if (pageData[property.propertiesKey].toLowerCase().includes(val.trim().toLowerCase())) {
  890. isAllConditionsMet = true;
  891. }
  892. break;
  893. case 'not contain':
  894. if (
  895. !pageData[property.propertiesKey].toLowerCase().includes(val.trim().toLowerCase())
  896. ) {
  897. isAllConditionsMet = true;
  898. }
  899. break;
  900. case 'equal':
  901. if (pageData[property.propertiesKey].toLowerCase() === val.trim().toLowerCase()) {
  902. isAllConditionsMet = true;
  903. }
  904. break;
  905. case 'not equal':
  906. if (pageData[property.propertiesKey].toLowerCase() !== val.trim().toLowerCase()) {
  907. isAllConditionsMet = true;
  908. }
  909. break;
  910. default:
  911. console.log('Unknown.');
  912. }
  913. } catch (error) {
  914. if (
  915. error.name === 'TypeError' &&
  916. error.message == "Cannot read properties of undefined (reading 'includes')"
  917. ) {
  918. console.warn(`${ticketname} 提醒未加条件,请检查配置`);
  919. }
  920. }
  921. }
  922. return isAllConditionsMet; // 如果所有属性都不满足条件,则返回 false
  923. };
  924. properties = JSON.parse(properties);
  925. return properties.reduce((acc, property) => {
  926. return acc && condition(property);
  927. }, true);
  928. }
  929. let cachedEntry = GM_getValue('cachedEntry', null);
  930. let projectMap = {};
  931. projectMap[cachedEntry['hk'].split('//')[1]] = 'HK';
  932. projectMap[cachedEntry['macao'].split('//')[1]] = 'MO';
  933.  
  934. for (const notify of Notifydict) {
  935. const { ticketname, starttime, endtime, message, properties, button, status, project } = notify;
  936. const isInTimeRange =
  937. (!starttime || new Date() >= new Date(starttime)) && (!endtime || new Date() <= new Date(endtime));
  938. const clickButton = buttonMap[button];
  939.  
  940. if (status == 'Disable' || !isInTimeRange || projectMap[window.location.host] !== project) {
  941. continue;
  942. }
  943.  
  944. if (checkProperties(properties, pageData, ticketname)) {
  945. if (clickButton == '') {
  946. showFlag('warning', `${ticketname}`, `${message.replace(/\r?\n/g, '<br>')}`, 'manual');
  947. } else {
  948. $(clickButton).on('click', () => {
  949. showFlag('warning', `${ticketname}`, `${message.replace(/\r?\n/g, '<br>')}`, 'manual');
  950. });
  951. }
  952.  
  953. let selector;
  954. if (project == 'HK') {
  955. selector = '#field-customfield_10219 > div:first-child > div:nth-child(2)';
  956. } else if (project == 'MO') {
  957. selector = '#field-customfield_10904 > div.twixi-wrap.verbose > div';
  958. }
  959. highlightTextInElement(selector, searchStrings);
  960. }
  961. }
  962. }
  963. }
  964. /**
  965. * Creates a new button and adds it to the DOM.
  966. * @param {string} id - The ID attribute for the new button element.
  967. * @param {string} text - The text content to display on the new button.
  968. * @param {string} onClick - The function to call when the button is clicked.
  969. */
  970. function addButton(id, text, onClick) {
  971. console.log(`#### Add Button: ${text} ####`);
  972. const toolbar = $('.aui-toolbar2-primary');
  973. // 重复添加的按钮不会被显示
  974. if ($('#' + id).length === 0) {
  975. const button = $('<a>')
  976. .attr('id', id)
  977. .addClass('aui-button toolbar-trigger')
  978. .append($('<span>').addClass('trigger-label').text(text))
  979. .click(onClick);
  980. toolbar.append($('<div>').addClass('aui-buttons pluggable-ops').append(button));
  981. }
  982. }
  983.  
  984. function monitorList() {
  985. var summaryElements = document.querySelectorAll('.summary');
  986. summaryElements.forEach(function (element) {
  987. if (
  988. element.textContent.includes('WebAvailability') ||
  989. element.textContent.includes('SWIFT login activity and select activity detected')
  990. ) {
  991. var audio = document.getElementById('myAudio');
  992. audio.play();
  993. }
  994. });
  995. var time_to_first_response = document.querySelectorAll('.sla-tag.sla-tag-ongoing');
  996. time_to_first_response.forEach(function (element) {
  997. console.log(element.outerText.replace('min', ''), element.outerText.replace('min', '') < 30);
  998. if (element.outerText.includes('min') && element.outerText.replace('min', '') < 30) {
  999. var audio = document.getElementById('myAudio');
  1000. audio.play();
  1001. console.log('出现特殊情况');
  1002. }
  1003. });
  1004. }
  1005.  
  1006. /**
  1007. * Creates three buttons on a JIRA issue page to handle Cortex XDR alerts
  1008. * The buttons allow users to generate a description of the alerts, open the alert card page and timeline page
  1009. */
  1010. function cortexAlertHandler(...kwargs) {
  1011. console.log('#### Code cortexAlertHandler run ####');
  1012. const { LogSourceDomain, summary } = kwargs[0];
  1013. const rawLog = $('#field-customfield_10232 > div.twixi-wrap.verbose > div > div > div > pre').text();
  1014. /**
  1015. * Extracts the log information and organization name from the current JIRA issue page
  1016. * @param {Object} orgDict - A dictionary that maps organization name to navigator name
  1017. * @returns {Object} An object that contains the organization's name, organization's navigator URL, raw log information
  1018. */
  1019. let orgDict = {};
  1020. const cachedWebsiteContent = GM_getValue('cachedWebsiteContent', null);
  1021. console.log(cachedWebsiteContent);
  1022. if (cachedWebsiteContent != null) {
  1023. cachedWebsiteContent.forEach((item, index) => {
  1024. if (item && item['category'] == 'cortex' && item['url']) {
  1025. orgDict[item['name']] = item['url'];
  1026. }
  1027. });
  1028. console.log('===orgDict', orgDict);
  1029. } else {
  1030. alert('cachedWebsiteContent is empty,please connect VPN get information');
  1031. }
  1032. const orgNavigator = orgDict[LogSourceDomain];
  1033.  
  1034. /**
  1035. * Parse the relevant information from the raw log data
  1036. * @param {Array} rawLog - An array of JSON strings representing the raw log data
  1037. * @returns {Array} An array of objects containing the alert relevant information
  1038. */
  1039. function parseLog(rawLog) {
  1040. let alertInfo = [];
  1041. try {
  1042. const { timestamp, data, rule } = JSON.parse(rawLog);
  1043. let rule_description = rule['description'].split(':')[-1];
  1044. const { cortex_xdr } = data;
  1045. const { source, alert_id, name, description } = cortex_xdr;
  1046. const isPANNGFW = source === 'PAN NGFW';
  1047. let dotIndex = timestamp.lastIndexOf('.');
  1048.  
  1049. dateTimeStr = timestamp.slice(0, dotIndex) + '+0800';
  1050. const alert = { source, alert_id, name, description, dateTimeStr, rule_description };
  1051. if (isPANNGFW) {
  1052. const {
  1053. action_local_ip,
  1054. action_local_port,
  1055. action_remote_ip,
  1056. action_remote_port,
  1057. action_pretty,
  1058. alert_link
  1059. } = cortex_xdr;
  1060. alertInfo.push({
  1061. ...alert,
  1062. action_local_ip,
  1063. action_local_port,
  1064. action_remote_ip,
  1065. action_remote_port,
  1066. action_pretty,
  1067. alert_link
  1068. });
  1069. } else {
  1070. const {
  1071. action_local_ip,
  1072. action_file_macro_sha256,
  1073. action_file_name,
  1074. action_file_path,
  1075. action_file_sha256,
  1076. action_process_image_name,
  1077. action_process_image_sha256,
  1078. action_process_image_command_line,
  1079. action_external_hostname,
  1080. actor_process_image_name,
  1081. actor_process_image_path,
  1082. actor_process_image_sha256,
  1083. actor_process_command_line,
  1084. causality_actor_process_image_name,
  1085. causality_actor_process_command_line,
  1086. causality_actor_process_image_path,
  1087. causality_actor_process_image_sha256,
  1088. os_actor_process_image_name,
  1089. os_actor_process_image_path,
  1090. os_actor_process_command_line,
  1091. os_actor_process_image_sha256,
  1092. action_pretty,
  1093. host_name,
  1094. host_ip,
  1095. user_name,
  1096. alert_link
  1097. } = cortex_xdr;
  1098. const action_list = {
  1099. action_file_name,
  1100. action_file_path,
  1101. action_file_sha256,
  1102. action_process_image_name,
  1103. action_process_image_sha256,
  1104. action_process_image_command_line
  1105. };
  1106. const actor_list = {
  1107. actor_process_image_name,
  1108. actor_process_image_path,
  1109. actor_process_image_sha256,
  1110. actor_process_command_line
  1111. };
  1112. const causality_actor_list = {
  1113. causality_actor_process_image_name,
  1114. causality_actor_process_command_line,
  1115. causality_actor_process_image_path,
  1116. causality_actor_process_image_sha256
  1117. };
  1118. const os_actor_list = {
  1119. os_actor_process_image_name,
  1120. os_actor_process_image_path,
  1121. os_actor_process_command_line,
  1122. os_actor_process_image_sha256
  1123. };
  1124.  
  1125. function countValidProperties(obj) {
  1126. const validPropsCount = Object.keys(obj).reduce((count, key) => {
  1127. if (obj[key] !== undefined) {
  1128. count++;
  1129. }
  1130. return count;
  1131. }, 0);
  1132. return validPropsCount;
  1133. }
  1134.  
  1135. const actionPropsCount = countValidProperties(action_list) ? countValidProperties(action_list) + 1 : 0;
  1136. const actorPropsCount = countValidProperties(actor_list);
  1137. const causalityPropsCount = countValidProperties(causality_actor_list);
  1138. const osPropsCount = countValidProperties(os_actor_list);
  1139. const maxCount = Math.max(actionPropsCount, actorPropsCount, causalityPropsCount, osPropsCount);
  1140.  
  1141. const action_cmd_length = action_process_image_command_line
  1142. ? action_process_image_command_line.length
  1143. : 0;
  1144. const actor_cmd_length = actor_process_command_line ? actor_process_command_line.length : 0;
  1145. const causality_cmd_length = causality_actor_process_command_line
  1146. ? causality_actor_process_command_line.length
  1147. : 0;
  1148. const os_cmd_length = os_actor_process_command_line ? os_actor_process_command_line.length : 0;
  1149. const lengths = [action_cmd_length, actor_cmd_length, causality_cmd_length, os_cmd_length];
  1150. const maxLength = Math.max(...lengths);
  1151.  
  1152. let filename;
  1153. let filepath;
  1154. let sha256;
  1155. let cmd;
  1156.  
  1157. if (action_cmd_length === maxLength && actionPropsCount === maxCount) {
  1158. if (!WhiteFilehash(action_file_sha256 || action_process_image_sha256)) {
  1159. sha256 = action_file_sha256 || action_process_image_sha256;
  1160. }
  1161. filename = action_file_name || action_process_image_name;
  1162. filepath = action_file_path;
  1163. cmd = action_process_image_command_line;
  1164. } else if (actor_cmd_length === maxLength && actorPropsCount === maxCount) {
  1165. if (!WhiteFilehash(actor_process_image_sha256)) {
  1166. sha256 = actor_process_image_sha256;
  1167. }
  1168. filename = actor_process_image_name;
  1169. filepath = actor_process_image_path;
  1170. cmd = actor_process_command_line;
  1171. } else if (causality_cmd_length === maxLength && causalityPropsCount === maxCount) {
  1172. if (!WhiteFilehash(causality_actor_process_image_sha256)) {
  1173. sha256 = causality_actor_process_image_sha256;
  1174. }
  1175. filename = causality_actor_process_image_name;
  1176. filepath = causality_actor_process_image_path;
  1177. cmd = causality_actor_process_command_line;
  1178. } else if (os_actor_process_image_name && osPropsCount === maxCount) {
  1179. if (!WhiteFilehash(os_actor_process_image_sha256)) {
  1180. sha256 = os_actor_process_image_sha256;
  1181. }
  1182. filename = os_actor_process_image_name;
  1183. filepath = os_actor_process_image_path;
  1184. cmd = os_actor_process_command_line;
  1185. }
  1186.  
  1187. alertInfo.push({
  1188. ...alert,
  1189. host_name,
  1190. host_ip,
  1191. alert_link,
  1192. user_name,
  1193. filename,
  1194. filepath,
  1195. cmd,
  1196. sha256,
  1197. action_pretty,
  1198. action_local_ip,
  1199. action_file_macro_sha256,
  1200. action_external_hostname
  1201. });
  1202. }
  1203. } catch (error) {
  1204. console.error(`Error: ${error.message}`);
  1205. }
  1206.  
  1207. return alertInfo;
  1208. }
  1209. const alertInfo = parseLog(rawLog);
  1210.  
  1211. /**
  1212. * Define three functions for handling alert information:
  1213. * generateDescription creates a description for each alert, and displays the combined description in an alert box
  1214. * openCard opens a new window to display the alert card page for each alert
  1215. * openTimeline opens a new window to display the timeline page for each alert
  1216. */
  1217. function generateDescription() {
  1218. const alertDescriptions = [];
  1219. for (const info of alertInfo) {
  1220. let {
  1221. source,
  1222. name,
  1223. action_local_ip,
  1224. action_local_port,
  1225. action_remote_ip,
  1226. action_remote_port,
  1227. action_pretty,
  1228. description,
  1229. alert_link,
  1230. rule_description,
  1231. action_external_hostname
  1232. } = info;
  1233. let unPanNgfw = [
  1234. 'host_name',
  1235. 'host_ip',
  1236. 'sha256',
  1237. 'action_file_macro_sha256',
  1238. 'filepath',
  1239. 'filename',
  1240. 'cmd',
  1241. 'user_name',
  1242. 'action_local_ip'
  1243. ];
  1244. if (description && description.includes('xdr_data')) {
  1245. console.log(rule_description);
  1246. description = rule_description;
  1247. }
  1248. if (source === 'PAN NGFW') {
  1249. const desc = `Observed ${name}\ntimestamp: ${dateTimeStr}\nSrcip: ${action_local_ip} Srcport: ${action_local_port}\nDstip: ${action_remote_ip} Dstport: ${action_remote_port}\nAction: ${action_pretty}\n${
  1250. LogSourceDomain === 'cityu' ? 'Cortex Portal: ' + alert_link + '\n' : ''
  1251. }\n\nPlease help to verify if this activity is legitimate.\n`;
  1252. alertDescriptions.push(desc);
  1253. } else {
  1254. let comment = '\nPlease help to verify if this activity is legitimate.\n';
  1255. if (
  1256. summary.toLowerCase().includes('wildfire malware') ||
  1257. summary.toLowerCase().includes('local analysis malware')
  1258. ) {
  1259. comment = '\nPlease verify if the File is legitimate. IF NOT, please Remove the File.\n';
  1260. }
  1261. let desc = `Observed ${
  1262. description || name
  1263. }\ntimestamp: ${dateTimeStr} \n<span class="red_highlight">action_external_hostname: ${action_external_hostname}\n</span>action: ${action_pretty}\n`;
  1264. for (const key of unPanNgfw) {
  1265. console.log(key);
  1266. if (Object.hasOwnProperty.call(info, key)) {
  1267. const value = info[key];
  1268. console.log(key, value);
  1269. if (value !== undefined) {
  1270. if (key == 'event_evidence') {
  1271. desc += `${key}: ${value.replace(/</g, '&lt;').replace(/>/g, '&gt;')}\n`;
  1272. } else {
  1273. desc += `${key}: ${value}\n`;
  1274. }
  1275. }
  1276. }
  1277. }
  1278. if (info['action_file_macro_sha256'] || info['sha256']) {
  1279. desc += `<a href="https://www.virustotal.com/gui/file/${
  1280. info['action_file_macro_sha256'] || info['sha256']
  1281. }">https://www.virustotal.com/gui/file/${info['action_file_macro_sha256'] || info['sha256']}</a>\n`;
  1282. }
  1283. alertDescriptions.push(desc + comment);
  1284. }
  1285. }
  1286. const alertMsg = [...new Set(alertDescriptions)].join('\n');
  1287. showDialog(alertMsg);
  1288. }
  1289.  
  1290. function openCard() {
  1291. for (const info of alertInfo) {
  1292. const { source, alert_id } = info;
  1293. if (orgNavigator) {
  1294. let cardURL;
  1295. switch (source) {
  1296. case 'XDR Analytics':
  1297. cardURL = `${orgNavigator}card/analytics2/${alert_id}`;
  1298. break;
  1299. case 'Correlation':
  1300. cardURL = `${orgNavigator}alerts/${alert_id}`;
  1301. break;
  1302. default:
  1303. cardURL = `${orgNavigator}card/alert/${alert_id}`;
  1304. break;
  1305. }
  1306. window.open(cardURL, '_blank');
  1307. } else {
  1308. showFlag('error', '', `There is no <strong>${LogSourceDomain}</strong> Navigator on Cortex`, 'auto');
  1309. }
  1310. }
  1311. }
  1312. function openTimeline() {
  1313. for (const info of alertInfo) {
  1314. const { source, alert_id } = info;
  1315. if (orgNavigator) {
  1316. let timelineURL;
  1317. switch (source) {
  1318. case 'Correlation':
  1319. showFlag(
  1320. 'error',
  1321. '',
  1322. `Source of the Alert is <strong>${source}</strong>, There is no Timeline on Cortex`,
  1323. 'auto'
  1324. );
  1325. break;
  1326. default:
  1327. timelineURL = `${orgNavigator}forensic-timeline/alert_id/${alert_id}`;
  1328. break;
  1329. }
  1330. timelineURL && window.open(timelineURL, '_blank');
  1331. } else {
  1332. showFlag('error', '', `There is no <strong>${LogSourceDomain}</strong> Navigator on Cortex`, 'auto');
  1333. }
  1334. }
  1335. }
  1336. addButton('generateDescription', 'Description', generateDescription);
  1337. addButton('openCard', 'Card', openCard);
  1338. addButton('openTimeline', 'Timeline', openTimeline);
  1339. }
  1340.  
  1341. function HTSCAlertHandler(...kwargs) {
  1342. console.log('#### Code HTSCAlertHandler run ####');
  1343. const { rawLog } = kwargs[0];
  1344. function decodeHtml(encodedString) {
  1345. const tmpElement = document.createElement('span');
  1346. tmpElement.innerHTML = encodedString;
  1347. return tmpElement.innerText;
  1348. }
  1349.  
  1350. const parseLog = (rawLog) => {
  1351. const alertInfo = rawLog.reduce((acc, log) => {
  1352. try {
  1353. const formatJson = log.substring(log.indexOf('{')).trim();
  1354. // const logObj = JSON.parse(formatJson);
  1355. const logObj = JSON.parse(formatJson.replace(/\\\(n/g, '\\n('));
  1356. const eventEvidence = decodeHtml(logObj.event_evidence).split('End time')[0];
  1357. const alert = {
  1358. attackType: logObj.tag,
  1359. hostRisk: logObj.hostRisk,
  1360. srcIP: logObj.src_ip,
  1361. eventEvidence,
  1362. hostName: logObj.hostName,
  1363. dstIP: logObj.dst_ip
  1364. };
  1365. acc.push(alert);
  1366. } catch (error) {
  1367. console.error(`Error: ${error.message}`);
  1368. }
  1369. return acc;
  1370. }, []);
  1371. return alertInfo;
  1372. };
  1373. const alertInfo = parseLog(rawLog);
  1374. // console.info(`alertInfo: ${alertInfo}`);
  1375.  
  1376. function generateDescription() {
  1377. const alertDescriptions = [];
  1378. for (const info of alertInfo) {
  1379. const { attackType, hostRisk, srcIP, hostName, dstIP, eventEvidence } = info;
  1380. const desc = `Observed ${attackType} Attack\nhostRisk: ${hostRisk}\nSrc_IP: ${srcIP}\nhostname: ${hostName}\nDst_IP: ${dstIP}\nevent_evidence: ${eventEvidence}\n\nPlease help to verify if this activity is legitimate.\n`;
  1381. alertDescriptions.push(desc);
  1382. }
  1383. const alertMsg = [...new Set(alertDescriptions)].join('\n');
  1384. showDialog(alertMsg);
  1385. }
  1386. addButton('generateDescription', 'Description', generateDescription);
  1387. }
  1388.  
  1389. function VMCEFAlertHandler(...kwargs) {
  1390. const { rawLog } = kwargs[0];
  1391.  
  1392. function parseCefLog(rawLog) {
  1393. function cefToJson(cefLog) {
  1394. let json = {};
  1395. let fields = cefLog.split(' ');
  1396.  
  1397. for (let i = 0; i < fields.length; i++) {
  1398. let field = fields[i].split('=');
  1399. let key = field[0];
  1400. let value = field.slice(1).join('=');
  1401.  
  1402. if (value) {
  1403. if (key === 'filePath' || key === 'msg' || key === 'start' || key === 'rt') {
  1404. let nextFieldIndex = i + 1;
  1405. while (nextFieldIndex < fields.length && !fields[nextFieldIndex].includes('=')) {
  1406. value += ' ' + fields[nextFieldIndex];
  1407. nextFieldIndex++;
  1408. }
  1409. }
  1410. json[key] = value;
  1411. }
  1412. }
  1413. return json;
  1414. }
  1415.  
  1416. const alertInfo = rawLog.reduce((acc, log) => {
  1417. try {
  1418. // Determine whether the log is empty
  1419. if (Object.keys(log).length !== 0) {
  1420. // Split CEF log
  1421. let cef_log = log.split('|');
  1422. // Parsing CEF Header
  1423. const cef_log_header = cef_log.slice(1, 7);
  1424. // Parsing CEF Extends
  1425. const cef_log_extends = cefToJson(cef_log[7]);
  1426.  
  1427. acc.push({
  1428. Summary: cef_log_header[4],
  1429. // for some like "server error" tickets
  1430. HostName: cef_log_extends.dhost ? cef_log_extends.dhost : cef_log_extends.dvchost,
  1431. HostIp: cef_log_extends.dst,
  1432. UserName: cef_log_extends.duser,
  1433. FileName: cef_log_extends.fname,
  1434. FilePath: cef_log_extends.filePath,
  1435. Sha256: cef_log_extends.fileHash,
  1436. Msg: cef_log_extends.msg
  1437. });
  1438. }
  1439. return acc;
  1440. } catch (error) {
  1441. console.error(`Error: ${error.message}`);
  1442. }
  1443. }, []);
  1444. return alertInfo;
  1445. }
  1446. const alertInfo = parseCefLog(rawLog);
  1447.  
  1448. function generateDescription() {
  1449. const alertDescriptions = [];
  1450. for (const info of alertInfo) {
  1451. const { Summary } = info;
  1452. let desc = `Observed ${Summary}\n`;
  1453. Object.entries(info).forEach(([index, value]) => {
  1454. if (value !== undefined && index != 'Summary' && index != 'CBlink') {
  1455. desc += `${index}: ${value}\n`;
  1456. }
  1457. });
  1458. desc += `\nPlease verify if the activity is legitimate.\n`;
  1459. alertDescriptions.push(desc);
  1460. }
  1461. const alertMsg = [...new Set(alertDescriptions)].join('\n');
  1462. showDialog(alertMsg);
  1463. }
  1464.  
  1465. addButton('generateDescription', 'Description', generateDescription);
  1466. }
  1467.  
  1468. function CBAlertHandler(...kwargs) {
  1469. console.log('#### Code CBAlertHandler run ####');
  1470. const { rawLog } = kwargs[0];
  1471.  
  1472. function parseLeefLog(rawLog) {
  1473. const alertInfo = rawLog.reduce((acc, log) => {
  1474. const cb_log = {};
  1475. try {
  1476. const log_obj = log.split('\t');
  1477. log_obj.forEach((log_item) => {
  1478. try {
  1479. const [key, value] = log_item.split('=');
  1480. cb_log[key] = value;
  1481. } catch (error) {
  1482. console.error(`Error: ${error.message}`);
  1483. }
  1484. });
  1485. if (log.trim() !== '') {
  1486. acc.push({
  1487. Summary: cb_log.watchlist_name,
  1488. HostName: cb_log.computer_name,
  1489. HostIp: cb_log.interface_ip,
  1490. UserName: cb_log.username,
  1491. CmdLine: cb_log.cmdline,
  1492. CBlink: cb_log.link_process,
  1493. Filepath: cb_log.path,
  1494. Sha256: cb_log.process_sha256
  1495. });
  1496. }
  1497. } catch (error) {
  1498. console.error(`Error: ${error.message}`);
  1499. }
  1500. return acc;
  1501. }, []);
  1502. return alertInfo;
  1503. }
  1504.  
  1505. const alertInfo = parseLeefLog(rawLog);
  1506.  
  1507. function generateDescription() {
  1508. const alertDescriptions = [];
  1509. for (const info of alertInfo) {
  1510. const { Summary } = info;
  1511. let desc = `Observed ${Summary}\n`;
  1512. Object.entries(info).forEach(([index, value]) => {
  1513. if (value !== undefined && index != 'Summary' && index != 'CBlink') {
  1514. desc += `${index}: ${value}\n`;
  1515. }
  1516. });
  1517. desc += `\nPlease verify if the activity is legitimate.\n`;
  1518. alertDescriptions.push(desc);
  1519. }
  1520. const alertMsg = [...new Set(alertDescriptions)].join('\n');
  1521. showDialog(alertMsg);
  1522. }
  1523.  
  1524. function openCB() {
  1525. let CBURL = '';
  1526. for (const info of alertInfo) {
  1527. const { CBlink } = info;
  1528. if (CBlink) {
  1529. CBURL += `${CBlink}\n`;
  1530. }
  1531. }
  1532. showFlag('info', 'CB URL:', `${CBURL}`, 'manual');
  1533. }
  1534.  
  1535. addButton('generateDescription', 'Description', generateDescription);
  1536. addButton('openCB', 'CB', openCB);
  1537. }
  1538.  
  1539. function WineventAlertHandler(...kwargs) {
  1540. console.log('#### Code WineventAlertHandler run ####');
  1541. let { rawLog, summary } = kwargs[0];
  1542. var raw_alert = 0;
  1543. const num_alert = $('#customfield_10300-val').text().trim();
  1544. summary = summary.replace(/[\[(].*?[\])]/g, '');
  1545. function parseLog(rawLog) {
  1546. const alertInfo = rawLog.reduce((acc, log) => {
  1547. try {
  1548. const { win } = JSON.parse(log);
  1549. raw_alert += 1;
  1550. const { eventdata, system } = win;
  1551. const alertHost = system.computer;
  1552. const systemTime = system.systemTime;
  1553. acc.push({ systemTime, summary, alertHost, eventdata });
  1554. } catch (error) {
  1555. console.error(`Error: ${error.message}`);
  1556. }
  1557. return acc;
  1558. }, []);
  1559. return alertInfo;
  1560. }
  1561. const alertInfo = parseLog(rawLog);
  1562.  
  1563. function generateDescription() {
  1564. const alertDescriptions = [];
  1565. if (raw_alert < num_alert) {
  1566. let extra_message = `<span class="red_highlight">Number Of Alert : ${num_alert}, Raw Log Alert : ${raw_alert} Raw log information is Not Complete, Please Get More Alert Information From Elastic.</span>\n`;
  1567. alertDescriptions.push(extra_message);
  1568. }
  1569. for (const info of alertInfo) {
  1570. let desc = `Observed${info.summary}\nHost: ${info.alertHost}\n`;
  1571. const date = new Date(info.systemTime.split('.')[0]);
  1572. date.setHours(date.getHours() + 16);
  1573. desc += `systemTime(<span class="red_highlight">UTC+8</span>): ${date.toISOString().split('.')[0]}\n`;
  1574. for (const key in info.eventdata) {
  1575. if (Object.hasOwnProperty.call(info.eventdata, key)) {
  1576. const value = info.eventdata[key];
  1577. if (value !== undefined) {
  1578. desc += `${key}: ${value}\n`;
  1579. }
  1580. }
  1581. }
  1582. desc += '\n' + 'Please help to verify if this activity is legitimate.' + '\n';
  1583. alertDescriptions.push(desc);
  1584. }
  1585. const alertMsg = [...new Set(alertDescriptions)].join('\n');
  1586. showDialog(alertMsg);
  1587. }
  1588.  
  1589. addButton('generateDescription', 'Description', generateDescription);
  1590. }
  1591.  
  1592. function FortigateAlertHandler(...kwargs) {
  1593. let { rawLog, summary, LogSourceDomain } = kwargs[0];
  1594. var raw_alert = 0;
  1595. const num_alert = $('#customfield_10300-val').text().trim();
  1596. summary = summary.split(']')[1].trim();
  1597. function ParseFortigateLog(rawLog) {
  1598. const alertInfos = rawLog.reduce((acc, log) => {
  1599. if (log == '') {
  1600. return acc;
  1601. }
  1602. let jsonData = {};
  1603. const regex = /(\w+)=(["'].*?["']|\S+)/g;
  1604. let matchresult;
  1605. raw_alert += 1;
  1606. while ((matchresult = regex.exec(log)) !== null) {
  1607. let key = matchresult[1];
  1608. let value = matchresult[2];
  1609. if (value.startsWith('"') && value.endsWith('"')) {
  1610. value = value.slice(1, -1);
  1611. } else if (value.startsWith("'") && value.endsWith("'")) {
  1612. value = value.slice(1, -1);
  1613. }
  1614. jsonData[key] = value;
  1615. }
  1616. acc.push(jsonData);
  1617. return acc;
  1618. }, []);
  1619. return [...new Set(alertInfos)];
  1620. }
  1621.  
  1622. const alertInfos = ParseFortigateLog(rawLog);
  1623. function ExtractAlertInfo(ExtractAlertInfo) {
  1624. const extract_alert_infos = alertInfos.reduce((acc, alertInfo) => {
  1625. const {
  1626. date,
  1627. time,
  1628. srcip,
  1629. srcport,
  1630. srccountry,
  1631. dstip,
  1632. dstport,
  1633. dstcountry,
  1634. hostname,
  1635. url,
  1636. referralurl,
  1637. action,
  1638. devname,
  1639. user,
  1640. cfgattr,
  1641. msg,
  1642. forwardedfor,
  1643. analyticscksum,
  1644. from,
  1645. to,
  1646. remip
  1647. } = alertInfo;
  1648. let arr = [];
  1649. if (summary.toLowerCase().includes('infected file detected in fortigate')) {
  1650. let vt_url;
  1651. if (url) {
  1652. vt_url = 'https://www.virustotal.com/gui/domain/' + url.split('/')[2];
  1653. } else {
  1654. vt_url = 'https://www.virustotal.com/gui/ip-address/' + srcip;
  1655. }
  1656. let sum = 'https://www.virustotal.com/gui/search/' + analyticscksum;
  1657. arr.push(`<a href="${vt_url}">${vt_url}</a>`);
  1658. arr.push(`<a href="${sum}">${sum}</a>`);
  1659. } else if (summary.toLowerCase().includes('connection attempt')) {
  1660. let vt_url = 'https://www.virustotal.com/gui/ip-address/' + dstip;
  1661. arr.push(`<a href="${vt_url}">${vt_url}</a>`);
  1662. } else if (summary.toLowerCase().includes('connection to newly registered domain')) {
  1663. let vt_url = 'https://www.virustotal.com/gui/domain/' + hostname;
  1664. arr.push(`<a href="${vt_url}">${vt_url}</a>`);
  1665. } else if (summary.toLowerCase().includes('non-office hour successful vpn login')) {
  1666. let vt_url = 'https://www.virustotal.com/gui/ip-address/' + remip;
  1667. arr.push(`<a href="${vt_url}">${vt_url}</a>`);
  1668. }
  1669.  
  1670. const extract_alert_info = {
  1671. datetime: `${date} ${time}`,
  1672. srcip: srcip ? `${srcip}:${srcport}[${srccountry}]` : undefined,
  1673. dstip: dstip ? `${dstip}:${dstport}[${dstcountry}]` : undefined,
  1674. hostname: hostname,
  1675. devname: devname,
  1676. user: user,
  1677. url: url,
  1678. action: action,
  1679. cfgattr: cfgattr,
  1680. msg: msg,
  1681. referralurl: referralurl,
  1682. forwardedfor: forwardedfor || undefined,
  1683. analyticscksum: analyticscksum,
  1684. from: from,
  1685. to,
  1686. remip: remip,
  1687. VT: arr.length > 0 ? arr : undefined
  1688. };
  1689. acc.push(extract_alert_info);
  1690. return acc;
  1691. }, []);
  1692. return extract_alert_infos;
  1693. }
  1694. function ExtractAlertInfo_sonicwall(ExtractAlertInfo) {
  1695. const extract_alert_infos = alertInfos.reduce((acc, alertInfo) => {
  1696. acc.push({
  1697. time: alertInfo.time,
  1698. msg: alertInfo.msg,
  1699. src: alertInfo.src,
  1700. srcZone: alertInfo.srcZone,
  1701. natSrc: alertInfo.natSrc,
  1702. dst: alertInfo.dst,
  1703. dstZone: alertInfo.dstZone,
  1704. natDst: alertInfo.natDst,
  1705. proto: alertInfo.proto
  1706. });
  1707. return acc;
  1708. }, []);
  1709. return extract_alert_infos;
  1710. }
  1711. let extract_alert_infos = '';
  1712. if (LogSourceDomain == 'miramar') {
  1713. console.log('===miramar');
  1714. extract_alert_infos = ExtractAlertInfo_sonicwall(alertInfos);
  1715. } else {
  1716. extract_alert_infos = ExtractAlertInfo(alertInfos);
  1717. }
  1718.  
  1719. function generateDescription() {
  1720. const alertDescriptions = [];
  1721. if (raw_alert < num_alert) {
  1722. let extra_message = `<span class="red_highlight">Number Of Alert : ${num_alert}, Raw Log Alert : ${raw_alert} Raw log information is Not Complete, Please Get More Alert Information From Elastic.</span>\n`;
  1723. alertDescriptions.push(extra_message);
  1724. }
  1725. for (const info of extract_alert_infos) {
  1726. let desc = `Observed ${summary}\n`;
  1727. Object.entries(info).forEach(([index, value]) => {
  1728. if (value !== undefined) {
  1729. desc += `${index}: ${value}\n`;
  1730. }
  1731. });
  1732. let comment = '\nPlease help to verify if this activity is legitimate.\n';
  1733. if (summary.toLowerCase().includes('to malware ip(s)') || summary.toLowerCase().includes('to tor ip(s)')) {
  1734. comment = '\nPlease verify if the IP is legitimate. If NOT, please block the dst ip\n';
  1735. }
  1736. desc += comment;
  1737. alertDescriptions.push(desc);
  1738. }
  1739. const alertMsg = [...new Set(alertDescriptions)].join('\n');
  1740. showDialog(alertMsg);
  1741. }
  1742.  
  1743. addButton('generateDescription', 'Description', generateDescription);
  1744. }
  1745.  
  1746. function CSAlertHandler(...kwargs) {
  1747. let { rawLog } = kwargs[0];
  1748. var raw_alert = 0;
  1749. const num_alert = $('#customfield_10300-val').text().trim();
  1750. function parseCefLog(rawLog) {
  1751. function cefToJson(cefLog) {
  1752. let json = {};
  1753. let fields = cefLog.split(' ');
  1754.  
  1755. for (let i = 0; i < fields.length; i++) {
  1756. let field = fields[i].split('=');
  1757. let key = field[0];
  1758. let value = field.slice(1).join('=');
  1759.  
  1760. if (value) {
  1761. if (key === 'filePath' || key === 'msg' || key === 'cs5' || key === 'start' || key === 'rt') {
  1762. let nextFieldIndex = i + 1;
  1763. while (nextFieldIndex < fields.length && !fields[nextFieldIndex].includes('=')) {
  1764. value += ' ' + fields[nextFieldIndex];
  1765. nextFieldIndex++;
  1766. }
  1767. }
  1768. json[key] = value;
  1769. }
  1770. }
  1771. return json;
  1772. }
  1773.  
  1774. const alertInfo = rawLog.reduce((acc, log) => {
  1775. try {
  1776. // Determine whether the log is empty
  1777. if (Object.keys(log).length !== 0) {
  1778. // Split CEF log
  1779. let cef_log = log.split('|');
  1780. // Parsing CEF Header
  1781. const cef_log_header = cef_log.slice(1, 7);
  1782. // Parsing CEF Extends
  1783. const cef_log_extends = cefToJson(cef_log[7]);
  1784. raw_alert += 1;
  1785. acc.push({
  1786. CreateTime: cef_log[0].split(' localhost ')[0],
  1787. Summary: cef_log_header[4],
  1788. // for some like "server error" tickets
  1789. HostName: cef_log_extends.dhost ? cef_log_extends.dhost : cef_log_extends.dvchost,
  1790. HostIp: cef_log_extends.dst,
  1791. UserName: cef_log_extends.duser,
  1792. FileName: cef_log_extends.fname,
  1793. FilePath: cef_log_extends.filePath,
  1794. Command: cef_log_extends.cs5,
  1795. Sha256: cef_log_extends.fileHash,
  1796. Msg: cef_log_extends.msg,
  1797. CSLink: cef_log_extends.cs6 ? cef_log_extends.cs6 : cef_log_extends.cs1
  1798. });
  1799. }
  1800. return acc;
  1801. } catch (error) {
  1802. console.error(`Error: ${error.message}`);
  1803. }
  1804. }, []);
  1805. return alertInfo;
  1806. }
  1807.  
  1808. const alertInfo = parseCefLog(rawLog);
  1809.  
  1810. function generateDescription() {
  1811. const alertDescriptions = [];
  1812. if (raw_alert < num_alert) {
  1813. let extra_message = `<span class="red_highlight">Number Of Alert : ${num_alert}, Raw Log Alert : ${raw_alert} Raw log information is Not Complete, Please Get More Alert Information From Elastic.</span>\n`;
  1814. alertDescriptions.push(extra_message);
  1815. }
  1816. for (const info of alertInfo) {
  1817. const { Summary } = info;
  1818. let desc = `Observed ${Summary}\n`;
  1819. Object.entries(info).forEach(([index, value]) => {
  1820. if (value !== undefined && index != 'Summary' && index != 'CSLink') {
  1821. desc += `${index}: ${value}\n`;
  1822. }
  1823. });
  1824. desc += `\nPlease verify if the activity is legitimate.\n`;
  1825. alertDescriptions.push(desc);
  1826. }
  1827. const alertMsg = [...new Set(alertDescriptions)].join('\n');
  1828. showDialog(alertMsg);
  1829. }
  1830. function openCS() {
  1831. let CSURL = '';
  1832. let cs_url = [];
  1833. for (const info of alertInfo) {
  1834. const { CSLink } = info;
  1835. if (CSLink && !cs_url.includes(CSLink)) {
  1836. CSURL += `${CSLink.replace('hXXps', 'https').replace(/[\[\]]/g, '')}<br><br>`;
  1837. }
  1838. cs_url.push(CSLink);
  1839. }
  1840. showFlag('info', 'CS URL:', `${CSURL}`, 'manual');
  1841. }
  1842. addButton('generateDescription', 'Description', generateDescription);
  1843. addButton('openCS', 'CS', openCS);
  1844. }
  1845.  
  1846. function SophosAlertHandler(...kwargs) {
  1847. let { rawLog } = kwargs[0];
  1848. var raw_alert = 0;
  1849. const num_alert = $('#customfield_10300-val').text().trim();
  1850. function parseLog(rawLog) {
  1851. const alertInfo = rawLog.reduce((acc, log) => {
  1852. try {
  1853. log.replace(/[\[(].*?[\])]/g, '');
  1854. const { sophos, logsource } = JSON.parse(log);
  1855. raw_alert += 1;
  1856. const summary = sophos.name;
  1857. const createtime = sophos.rt.split('.')[0] + 'Z';
  1858. const alertHost = sophos.dhost;
  1859. const alertUser = sophos.suser;
  1860. const alertID = sophos.id;
  1861. const alertIP = sophos?.source_info?.ip || sophos?.data?.source_info?.ip || '';
  1862. const alertExtraInfo = {
  1863. 'Sha256': sophos.appSha256,
  1864. 'Filename': sophos?.data?.fileName ? sophos.data.fileName : undefined,
  1865. 'Processname': sophos?.data?.processName ? sophos.data.processName : undefined,
  1866. 'Process': sophos?.data?.process ? sophos.data.process : undefined,
  1867. 'Clean Up Result': sophos?.core_remedy_items?.items[0]?.result
  1868. };
  1869. acc.push({ summary, createtime, alertHost, alertIP, alertUser, alertID, logsource, alertExtraInfo });
  1870. } catch (error) {
  1871. console.log(`Error: ${error.message}`);
  1872. }
  1873. return acc;
  1874. }, []);
  1875. return alertInfo;
  1876. }
  1877. const alertInfo = parseLog(rawLog);
  1878.  
  1879. function generateDescription() {
  1880. const alertDescriptions = [];
  1881. if (raw_alert < num_alert) {
  1882. let extra_message = `<span class="red_highlight">Number Of Alert : ${num_alert}, Raw Log Alert : ${raw_alert} Raw log information is Not Complete, Please Get More Alert Information From Elastic.</span>\n`;
  1883. alertDescriptions.push(extra_message);
  1884. }
  1885. for (const info of alertInfo) {
  1886. let desc = `Observed ${info.summary}\nHost: ${info.alertHost} IP: ${info.alertIP || 'N/A'}\nUser: ${
  1887. info.alertUser
  1888. }\ncreatetime:(<span class="red_highlight">GMT</span>)${info.createtime}\n`;
  1889. for (const key in info.alertExtraInfo) {
  1890. if (Object.hasOwnProperty.call(info.alertExtraInfo, key)) {
  1891. const value = info.alertExtraInfo[key];
  1892. if (value !== undefined) {
  1893. desc += `${key}: ${value}\n`;
  1894. }
  1895. }
  1896. }
  1897. if (!info.summary.includes('Failed to protect computer')) {
  1898. desc += '\n' + 'Please help to verify if this activity is legitimate.' + '\n';
  1899. }
  1900. alertDescriptions.push(desc);
  1901. }
  1902. const alertMsg = [...new Set(alertDescriptions)].join('\n');
  1903. showDialog(alertMsg);
  1904. }
  1905.  
  1906. function openSophos() {
  1907. let searchID = '';
  1908. for (const info of alertInfo) {
  1909. const { alertHost, alertID, logsource } = info;
  1910. if (alertID || alertHost) {
  1911. searchID += `<strong>[${logsource}] ${alertHost}</strong>:<br>${alertID}<br><br>`;
  1912. }
  1913. }
  1914. showFlag('info', 'Host and Alert ID', `${searchID}`, 'manual');
  1915. GM_openInTab('https://cloud.sophos.com/manage/enterprise/alerts-list', {
  1916. active: false, // 设置为 false,以在后台打开,不激活新标签页
  1917. insert: true // 设置为 true,将新标签页插入到当前标签页之后
  1918. });
  1919. }
  1920.  
  1921. addButton('generateDescription', 'Description', generateDescription);
  1922. addButton('openSophos', 'Open Sophos', openSophos);
  1923. }
  1924.  
  1925. function SpemAlertHandler(...kwargs) {
  1926. const { rawLog, summary } = kwargs[0];
  1927.  
  1928. function parseLog(rawLog) {
  1929. let logObject = {};
  1930. const alertInfo = rawLog.reduce((acc, log) => {
  1931. try {
  1932. logArray = log.split(',');
  1933. logArray[10] = 'Action:' + logArray[10];
  1934. for (const index of logArray) {
  1935. const [key, value] = index.split(/:(.+)/, 2);
  1936. logObject[key] = value;
  1937. }
  1938. acc.push({
  1939. 'Summary': logObject['Event Description'] !== undefined ? logObject['Event Description'] : summary,
  1940. 'User Name': logObject['User Name'],
  1941. 'Local Host IP': logObject['Local Host IP'],
  1942. 'Local Port': logObject['Local Port'],
  1943. 'Remote Host IP': logObject['Remote Host IP'],
  1944. 'Remote Port': logObject['Remote Port'],
  1945. 'Application': logObject['Application'],
  1946. 'SHA-256': logObject['SHA-256'],
  1947. 'Intrusion URL': logObject['Intrusion URL'],
  1948. 'Action': logObject['Action']
  1949. });
  1950. } catch (error) {
  1951. console.log(`Error: ${error}`);
  1952. }
  1953. return acc;
  1954. }, []);
  1955. return alertInfo;
  1956. }
  1957.  
  1958. const alertInfo = parseLog(rawLog);
  1959.  
  1960. function generateDescription() {
  1961. const alertDescriptions = [];
  1962. for (const info of alertInfo) {
  1963. let desc = `Observed ${info['Summary']}\n`;
  1964. Object.entries(info).forEach(([index, value]) => {
  1965. if (value !== undefined && value !== ' ' && index != 'Summary') {
  1966. desc += `${index}: ${value}\n`;
  1967. }
  1968. });
  1969. desc += `\nPlease verify if the activity is legitimate.\n`;
  1970. alertDescriptions.push(desc);
  1971. }
  1972. const alertMsg = [...new Set(alertDescriptions)].join('\n');
  1973. showDialog(alertMsg);
  1974. }
  1975.  
  1976. addButton('generateDescription', 'Description', generateDescription);
  1977. }
  1978.  
  1979. function AwsAlertHandler(...kwargs) {
  1980. const { rawLog, summary } = kwargs[0];
  1981. var raw_alert = 0;
  1982. const DecoderName = $('#customfield_10807-val').text().trim().toLowerCase();
  1983. function parseLog(rawLog) {
  1984. const alertInfo = rawLog.reduce((acc, log) => {
  1985. try {
  1986. const { aws } = JSON.parse(log);
  1987. if (DecoderName == 'aws-guardduty') {
  1988. let EventTime = aws.service.eventFirstSeen.split('.')[0] + 'Z';
  1989. const action = aws.service.action;
  1990. if (action.actionType == 'AWS_API_CALL') {
  1991. acc.push({
  1992. EventTime: EventTime,
  1993. actionType: action.actionType,
  1994. Api_Name: action?.awsApiCallAction?.api,
  1995. userName: aws?.resource?.accessKeyDetails?.userName,
  1996. RemoteIP: action?.awsApiCallAction?.remoteIpDetails?.ipAddressV4,
  1997. RemoteIP_country: action?.awsApiCallAction?.remoteIpDetails?.country.countryName
  1998. });
  1999. } else if (action.actionType == 'KUBERNETES_API_CALL') {
  2000. acc.push({
  2001. EventTime: EventTime,
  2002. actionType: action.actionType,
  2003. userName: aws?.resource?.accessKeyDetails?.userName,
  2004. sourceIPs: action?.kubernetesApiCallAction?.sourceIPs,
  2005. requestUri: action?.kubernetesApiCallAction?.requestUri
  2006. });
  2007. } else if (action.actionType == 'PORT_PROBE') {
  2008. acc.push({
  2009. EventTime: EventTime,
  2010. actionType: action.actionType,
  2011. localPort: action?.portProbeAction?.portProbeDetails.localPortDetails.port,
  2012. RemoteIP: action?.portProbeAction?.portProbeDetails.remoteIpDetails.ipAddressV4,
  2013. RemoteIP_country:
  2014. action?.portProbeAction?.portProbeDetails.remoteIpDetails.country.countryName
  2015. });
  2016. } else if (action.actionType == 'NETWORK_CONNECTION') {
  2017. console.log('===', action);
  2018. acc.push({
  2019. EventTime: EventTime,
  2020. actionType: action.actionType,
  2021. localIp: action?.networkConnectionAction?.localIpDetails.ipAddressV4,
  2022. localPortDetails: action?.networkConnectionAction?.localPortDetails.port,
  2023. remoteIp: action?.networkConnectionAction?.remoteIpDetails.ipAddressV4,
  2024. remotePortDetails: action?.networkConnectionAction?.remotePortDetails.port,
  2025. instanceId: aws?.resource?.instanceDetails?.instanceId,
  2026. platform: aws?.resource?.instanceDetails?.platform,
  2027. remoteIpcountryName: action?.networkConnectionAction?.remoteIpDetails?.country?.countryName
  2028. });
  2029. }
  2030. } else if (summary.toLowerCase().includes('multiple sms request for same source ip')) {
  2031. let headers = aws.logEvents.message.httpRequest.headers;
  2032. let host, content;
  2033. headers.forEach((item) => {
  2034. if (item.name === 'host') {
  2035. host = item.value;
  2036. }
  2037. if (item.name == 'content-type') {
  2038. content = item.value;
  2039. }
  2040. });
  2041. acc.push({
  2042. log_file: aws.log_info.log_file,
  2043. clientIp: aws.logEvents.message.httpRequest.clientIp,
  2044. httpMethod: aws.logEvents.message.httpRequest.httpMethod,
  2045. uri: aws.logEvents.message.httpRequest.uri,
  2046. host: host,
  2047. content_type: content
  2048. });
  2049. } else {
  2050. acc.push({
  2051. EventTime: aws?.eventTime,
  2052. EventName: aws?.eventName,
  2053. SourceIP: aws?.sourceIPAddress || aws?.internal_ip,
  2054. ExternalIP: aws?.external_ip,
  2055. Domain: aws?.domain,
  2056. User: aws?.userIdentity?.arn,
  2057. UserAgent: aws?.userAgent,
  2058. PrincipalId: aws?.userIdentity?.principalId,
  2059. Result: aws?.errorCode,
  2060. QueryType: aws?.query_type,
  2061. Action: aws?.action,
  2062. requestParameters: JSON.stringify(aws?.requestParameters),
  2063. responseElements: JSON.stringify(aws?.responseElements)
  2064. });
  2065. }
  2066. raw_alert += 1;
  2067. } catch (error) {
  2068. console.log(`Error: ${error}`);
  2069. }
  2070. return acc;
  2071. }, []);
  2072. return alertInfo;
  2073. }
  2074.  
  2075. const alertInfo = parseLog(rawLog);
  2076. const num_alert = $('#customfield_10300-val').text().trim();
  2077. function generateDescription() {
  2078. const alertDescriptions = [];
  2079. if (raw_alert < num_alert) {
  2080. let extra_message = `<span class="red_highlight">Number Of Alert : ${num_alert}, Raw Log Alert : ${raw_alert} Raw log information is Not Complete, Please Get More Alert Information From Elastic.</span>\n`;
  2081. alertDescriptions.push(extra_message);
  2082. }
  2083. for (const info of alertInfo) {
  2084. let desc = `Observed ${summary.split(']')[1]}\n`;
  2085. Object.entries(info).forEach(([index, value]) => {
  2086. if (value !== undefined && value !== ' ' && index != 'Summary') {
  2087. if (index == 'EventTime') {
  2088. desc += `EventTime(<span class="red_highlight">GMT</span>): ${value}\n`;
  2089. } else {
  2090. desc += `${index}: ${value}\n`;
  2091. }
  2092. }
  2093. });
  2094. desc += `\nPlease verify if the activity is legitimate.\n`;
  2095. alertDescriptions.push(desc);
  2096. }
  2097. const alertMsg = [...new Set(alertDescriptions)].join('\n');
  2098. showDialog(alertMsg);
  2099. }
  2100.  
  2101. addButton('generateDescription', 'Description', generateDescription);
  2102. }
  2103.  
  2104. function AzureAlertHandler(...kwargs) {
  2105. const { rawLog } = kwargs[0];
  2106.  
  2107. function parseLog(rawLog) {
  2108. const alertInfo = rawLog.reduce((acc, log) => {
  2109. try {
  2110. const { eventhub, azure } = JSON.parse(log);
  2111. const { ExtendedProperties, Entities } = eventhub;
  2112. let entities = {};
  2113. if (Entities) {
  2114. Entities.forEach(function (entity) {
  2115. if (entity.Type === 'host') {
  2116. entities['host'] = entity['HostName'];
  2117. }
  2118. if (entity.Type === 'network-connection') {
  2119. entities['SourceIP'] = entity['SourceAddress']['Address'];
  2120. }
  2121. });
  2122. }
  2123. acc.push({
  2124. AlertType: eventhub['AlertType'],
  2125. StartTimeUtc: eventhub['StartTimeUtc'],
  2126. Severity: eventhub['Severity'],
  2127. Intent: eventhub['Intent'],
  2128. Description: eventhub['Description'],
  2129. summary: azure['ThreatDescription'] || eventhub['AlertDisplayName'],
  2130. Protocol: azure['Protocol'],
  2131. SourceIP: azure['SourceIp'],
  2132. SourcePort: azure['SourcePort'],
  2133. DestinationIp: azure['DestinationIp'],
  2134. DestinationPort: azure['DestinationPort'],
  2135. URL: azure['Url'],
  2136. Action: azure['Action'],
  2137. ExtendedProperties: JSON.stringify(ExtendedProperties, null, 4),
  2138. ...entities,
  2139. alerturi: eventhub['AlertUri']
  2140. });
  2141. } catch (error) {
  2142. console.log(`Error: ${error}`);
  2143. }
  2144. return acc;
  2145. }, []);
  2146. return alertInfo;
  2147. }
  2148.  
  2149. const alertInfo = parseLog(rawLog);
  2150.  
  2151. function generateDescription() {
  2152. const alertDescriptions = [];
  2153. for (const info of alertInfo) {
  2154. let desc = `Observed ${info.summary}\n`;
  2155. Object.entries(info).forEach(([index, value]) => {
  2156. if (value !== undefined && value !== '' && index !== 'summary') {
  2157. if (index == 'StartTimeUtc') {
  2158. desc += `StartTimeUtc(<span class="red_highlight">GMT</span>): ${value.split('.')[0]}\n`;
  2159. } else {
  2160. desc += `${index}: ${value}\n`;
  2161. }
  2162. }
  2163. });
  2164. desc += `\nPlease verify if the activity is legitimate.\n`;
  2165. alertDescriptions.push(desc);
  2166. }
  2167. const alertMsg = [...new Set(alertDescriptions)].join('\n');
  2168. showDialog(alertMsg);
  2169. }
  2170.  
  2171. function openAzure() {
  2172. let AzureURL = '';
  2173. for (const info of alertInfo) {
  2174. const { alerturi } = info;
  2175. if (alerturi) {
  2176. AzureURL += `${alerturi.replace('hXXps', 'https').replace(/\[|\]/g, '')}<br><br>`;
  2177. }
  2178. }
  2179. showFlag('info', 'Azure URL:', `${AzureURL}`, 'manual');
  2180. }
  2181.  
  2182. addButton('generateDescription', 'Description', generateDescription);
  2183. addButton('openAzure', 'Azure', openAzure);
  2184. }
  2185.  
  2186. function paloaltoAlertHandler(...kwargs) {
  2187. const { rawLog, summary } = kwargs[0];
  2188. var raw_alert = 0;
  2189. const num_alert = $('#customfield_10300-val').text().trim();
  2190. function parseLog(rawLog) {
  2191. const alertInfo = rawLog.reduce((acc, log) => {
  2192. try {
  2193. let logArray = log.split(',');
  2194. let logType = logArray[3];
  2195. if (logType == 'GLOBALPROTECT') {
  2196. acc.push({
  2197. 'Createtime': logArray[1],
  2198. 'src ip': logArray[15],
  2199. 'user': logArray[12]
  2200. });
  2201. }
  2202. if (logType == 'TRAFFIC') {
  2203. acc.push({
  2204. 'Createtime': logArray[1],
  2205. 'Summary': summary.split(']')[1],
  2206. 'Source IP': logArray[7],
  2207. 'Destination IP': logArray[8],
  2208. 'Destination Port': logArray[25],
  2209. 'Destination Location': logArray[42] != 0 ? logArray[42] : logArray[39]
  2210. });
  2211. }
  2212. if (logType == 'THREAT') {
  2213. let really = false,
  2214. malware_potential = [];
  2215. for (let i = 0; i < logArray.length; i++) {
  2216. if (logArray[i].includes('"') && i > 100) {
  2217. if (really) {
  2218. malware_potential.push(logArray[i]);
  2219. }
  2220. really = !really;
  2221. }
  2222. if (really) {
  2223. malware_potential.push(logArray[i]);
  2224. }
  2225. }
  2226. let vt_url = 'https://www.virustotal.com/gui/search/' + logArray[31].replace('"', '').split('/')[0];
  2227. let description = `</br>Timestamp: ${logArray[0].split(' ').slice(0, 3).join(' ')}</br>
  2228. Device: ${logArray[0].split(' ').slice(3, 5).join(' ')}</br>
  2229. Log Details:
  2230. <ul><li>Event Time: ${logArray[1]}</li>
  2231. <li>Log ID: ${logArray[2]}</li>
  2232. <li>Type: ${logArray[3]}(${logArray[4]})</li>
  2233. <li>Severity: ${logArray[34]}</li>
  2234. <li>Rule Triggered: ${logArray[11]}</li>
  2235. <li>Vulnerability: ${logArray[32]}</li>
  2236. <li>Threat ID: ${logArray[34]}</li></ul>
  2237. Network Information:
  2238. <ul><li>Source IP: ${logArray[7]}</li>
  2239. <li>Destination IP: ${logArray[8]}</li>
  2240. <li>URL/filename : ${logArray[31]}</li>
  2241. <li>VT : <a href="${vt_url}">${vt_url}</a></li>
  2242. <li>Source Zone: ${logArray[16]}</li>
  2243. <li>Destination Zone: ${logArray[17]}</li>
  2244. <li>Ingress Interface: ${logArray[18]}</li>
  2245. <li>Egress Interface: ${logArray[19]}</li></ul>
  2246. Traffic Details:
  2247. <ul><li>Protocol: ${logArray[29]}</li>
  2248. <li>Application: ${logArray[14]}</li>
  2249. <li>Direction: ${logArray[35]}</li>
  2250. <li>Session ID: ${logArray[36]}</li></ul>
  2251. Vulnerability Information:</br>
  2252. <ul><li>Exploit Type: ${logArray[69]}</li>
  2253. <li>Attack Vector: ${logArray[111]}</li>
  2254. <li>Affected Technology: ${logArray[112]},${logArray[113]}</li>
  2255. <li>Malware Potential:${malware_potential}</li>
  2256. </ul>`;
  2257. raw_alert += 1;
  2258. acc.push(description);
  2259. }
  2260. } catch (error) {
  2261. console.error(`Error:${error}`);
  2262. }
  2263. return acc;
  2264. }, []);
  2265. return alertInfo;
  2266. }
  2267.  
  2268. const alertInfo = parseLog(rawLog);
  2269.  
  2270. function generateDescription() {
  2271. const alertDescriptions = [];
  2272. if (raw_alert < num_alert) {
  2273. let extra_message = `<span class="red_highlight">Number Of Alert : ${num_alert}, Raw Log Alert : ${raw_alert} Raw log information is Not Complete, Please Get More Alert Information From Elastic.</span>\n`;
  2274. alertDescriptions.push(extra_message);
  2275. }
  2276. for (const info of alertInfo) {
  2277. let arr = summary.split(']');
  2278. let desc = `Observed ${arr[arr.length - 1]}\n`;
  2279. if (typeof info == 'string') {
  2280. desc += info;
  2281. } else {
  2282. Object.entries(info).forEach(([index, value]) => {
  2283. if (value !== undefined && value !== '' && index !== 'Summary') {
  2284. desc += `${index}: ${value}\n`;
  2285. }
  2286. });
  2287. }
  2288. let comment = '\nPlease help to verify if this activity is legitimate.\n</br>';
  2289. if (summary.toLowerCase().includes('to malware ip(s)') || summary.toLowerCase().includes('to tor ip(s)')) {
  2290. comment = '\nPlease verify if the IP is legitimate. If NOT, please block the dst ip\n';
  2291. }
  2292. desc += comment;
  2293. alertDescriptions.push(desc);
  2294. }
  2295. const alertMsg = [...new Set(alertDescriptions)].join('\n');
  2296. showDialog(alertMsg);
  2297. }
  2298.  
  2299. addButton('generateDescription', 'Description', generateDescription);
  2300. }
  2301.  
  2302. function ImpervaincCEFAlertHandler(...kwargs) {
  2303. const { rawLog } = kwargs[0];
  2304.  
  2305. function parseCefLog(rawLog) {
  2306. function cefToJson(cefLog) {
  2307. let json = {};
  2308. let fields = cefLog.split(' ');
  2309.  
  2310. for (let i = 0; i < fields.length; i++) {
  2311. let field = fields[i].split('=');
  2312. let key = field[0];
  2313. let value = field.slice(1).join('=');
  2314.  
  2315. if (value) {
  2316. if (key === 'filePath' || key === 'msg' || key === 'start' || key === 'rt' || key === 'cs1') {
  2317. let nextFieldIndex = i + 1;
  2318. while (nextFieldIndex < fields.length && !fields[nextFieldIndex].includes('=')) {
  2319. value += ' ' + fields[nextFieldIndex];
  2320. nextFieldIndex++;
  2321. }
  2322. }
  2323. if (value == 'n/a') {
  2324. json[key] = undefined;
  2325. } else {
  2326. json[key] = value;
  2327. }
  2328. }
  2329. }
  2330. return json;
  2331. }
  2332.  
  2333. const alertInfo = rawLog.reduce((acc, log) => {
  2334. try {
  2335. // Determine whether the log is empty
  2336. if (Object.keys(log).length !== 0) {
  2337. // Split CEF log
  2338. let cef_log = log.split('|');
  2339. let createtime = cef_log[0].split('CEF:')[0];
  2340. // Parsing CEF Header
  2341. const cef_log_header = cef_log.slice(1, 7);
  2342. // Parsing CEF Extends
  2343. const cef_log_extends = cefToJson(cef_log[7]);
  2344.  
  2345. acc.push({
  2346. summary: cef_log_extends.cs1,
  2347. // for some like "server error" tickets
  2348. createtime: createtime,
  2349. username: cef_log_extends.duser,
  2350. srcIP: cef_log_extends.src,
  2351. dstIP: cef_log_extends.dst,
  2352. dstPort: cef_log_extends.dpt,
  2353. protocol: cef_log_extends.proto
  2354. });
  2355. }
  2356. return acc;
  2357. } catch (error) {
  2358. console.error(`Error: ${error.message}`);
  2359. }
  2360. }, []);
  2361. return alertInfo;
  2362. }
  2363. const alertInfo = parseCefLog(rawLog);
  2364.  
  2365. function generateDescription() {
  2366. const alertDescriptions = [];
  2367. for (const info of alertInfo) {
  2368. const { summary } = info;
  2369. let desc = `Observed ${summary}\n`;
  2370. Object.entries(info).forEach(([index, value]) => {
  2371. if (value !== undefined && index != 'summary' && index != 'CBlink') {
  2372. desc += `${index}: ${value}\n`;
  2373. }
  2374. });
  2375. desc += `\nPlease verify if the activity is legitimate.\n`;
  2376. alertDescriptions.push(desc);
  2377. }
  2378. const alertMsg = [...new Set(alertDescriptions)].join('\n');
  2379. showDialog(alertMsg);
  2380. }
  2381.  
  2382. addButton('generateDescription', 'Description', generateDescription);
  2383. }
  2384.  
  2385. function AzureGraphAlertHandler(...kwargs) {
  2386. const { summary, rawLog } = kwargs[0];
  2387. var raw_alert = 0;
  2388. if (summary.toLowerCase().includes('successful azure/o365 login from malware-ip')) {
  2389. return;
  2390. }
  2391. function parseLog(rawLog) {
  2392. const alertInfo = rawLog.reduce((acc, log) => {
  2393. try {
  2394. const { azure } = JSON.parse(log);
  2395. let properties = {};
  2396. raw_alert += 1;
  2397. if (azure.targetResources) {
  2398. for (const resource of azure.targetResources) {
  2399. if (summary.toLowerCase().includes('conditional access policy updated')) {
  2400. const { initiatedBy, targetResources, activityDateTime, activityDisplayName, result } =
  2401. azure;
  2402.  
  2403. const alertExtraInfo = {
  2404. userPrincipalName: initiatedBy?.user?.userPrincipalName
  2405. ? initiatedBy?.user?.userPrincipalName
  2406. : undefined,
  2407. displayName: targetResources[0]?.displayName
  2408. ? targetResources[0]?.displayName
  2409. : undefined,
  2410. activityDateTime: activityDateTime ? activityDateTime : undefined,
  2411. activityDisplayName: activityDisplayName ? activityDisplayName : undefined,
  2412. result: result ? result : undefined
  2413. };
  2414. acc.push({ alertExtraInfo });
  2415. } else {
  2416. if (resource.type == 'User') {
  2417. const resourceProperties = { TargetUser: resource.userPrincipalName };
  2418. properties = { ...properties, ...resourceProperties };
  2419. }
  2420. for (const prop of resource.modifiedProperties) {
  2421. properties = { ...properties, [prop['displayName']]: prop['newValue'] };
  2422. }
  2423. const activityDateTime = azure.activityDateTime.split('.')[0] + 'Z';
  2424. acc.push({
  2425. activityDateTime: activityDateTime,
  2426. AppDisplayName: azure?.appDisplayName || azure?.initiatedBy?.app?.displayName,
  2427. SourceUser: azure?.userPrincipalName || azure?.initiatedBy?.user?.userPrincipalName,
  2428. IpAddress: azure?.ipAddress || azure?.initiatedBy?.user?.ipAddress,
  2429. Location:
  2430. azure?.location?.countryOrRegion && azure?.location?.state && azure?.location?.city
  2431. ? `${azure?.location?.countryOrRegion}\\${azure?.location?.state}\\${azure?.location?.city}`
  2432. : undefined,
  2433. ...properties,
  2434. Result: azure?.status?.failureReason || azure.result,
  2435. AdditionalInfo: azure?.additionalDetails[0]?.value
  2436. ? azure?.additionalDetails[0]?.value
  2437. : undefined
  2438. });
  2439. }
  2440. }
  2441. } else {
  2442. const activityDateTime = azure.createdDateTime;
  2443. acc.push({
  2444. activityDateTime: activityDateTime,
  2445. AppDisplayName: azure?.appDisplayName || azure?.initiatedBy?.app?.displayName,
  2446. SourceUser: azure?.userPrincipalName || azure?.initiatedBy?.user?.userPrincipalName,
  2447. IpAddress: azure?.ipAddress || azure?.initiatedBy?.user?.ipAddress,
  2448. Location:
  2449. azure?.location?.countryOrRegion && azure?.location?.state && azure?.location?.city
  2450. ? `${azure?.location?.countryOrRegion}\\${azure?.location?.state}\\${azure?.location?.city}`
  2451. : undefined,
  2452. ...properties,
  2453. DeviceName: azure.deviceDetail.displayName || 'N/A',
  2454. failureReason: azure?.status?.failureReason || azure.result
  2455. });
  2456. }
  2457. } catch (error) {
  2458. console.log(`Error: ${error}`);
  2459. }
  2460. return acc;
  2461. }, []);
  2462. return alertInfo;
  2463. }
  2464.  
  2465. const alertInfo = parseLog(rawLog);
  2466. const num_alert = $('#customfield_10300-val').text().trim();
  2467. function generateDescription() {
  2468. const alertDescriptions = [];
  2469. if (raw_alert < num_alert) {
  2470. let extra_message = `<span class="red_highlight">Number Of Alert : ${num_alert}, Raw Log Alert : ${raw_alert} Raw log information is Not Complete, Please Get More Alert Information From Elastic.</span>\n`;
  2471. alertDescriptions.push(extra_message);
  2472. }
  2473. if (summary.toLowerCase().includes('conditional access policy updated')) {
  2474. for (const info of alertInfo) {
  2475. console.log(info['alertExtraInfo']['userPrincipalName']);
  2476. let desc = `Observed the user "${
  2477. info['alertExtraInfo']['userPrincipalName']
  2478. }" was on (<span class="red_highlight">GMT</span>)${
  2479. info['alertExtraInfo']['activityDateTime'].split('.')[0]
  2480. }ZS Updated the conditional access policy "${info['alertExtraInfo']['displayName']}"\n\n`;
  2481. for (const key in info.alertExtraInfo) {
  2482. if (Object.hasOwnProperty.call(info.alertExtraInfo, key)) {
  2483. const value = info.alertExtraInfo[key];
  2484. if (
  2485. value !== undefined &&
  2486. key != 'userPrincipalName' &&
  2487. key != 'displayName' &&
  2488. key != 'activityDateTime'
  2489. ) {
  2490. desc += `${key}: ${value}\n`;
  2491. }
  2492. }
  2493. }
  2494. desc += `\nIt is recommended that you verify that the user has permission to change the conditional access policy and that the action is a legitimate update known to the user. Thanks!\n`;
  2495. alertDescriptions.push(desc);
  2496. }
  2497. } else {
  2498. for (const info of alertInfo) {
  2499. let desc = `Observed ${summary.split(']')[1]}\n`;
  2500. console.log(info);
  2501. for (const key in info) {
  2502. if (Object.hasOwnProperty.call(info, key)) {
  2503. const value = info[key];
  2504. if (value !== undefined && value !== '' && key != 'summary' && key != 'alerturi') {
  2505. if (key == 'activityDateTime') {
  2506. desc += `activityDateTime(<span class="red_highlight">GMT</span>): ${value}\n`;
  2507. } else {
  2508. desc += `${key}: ${value}\n`;
  2509. }
  2510. }
  2511. }
  2512. }
  2513. desc += `\nPlease verify if the activity is legitimate.\n`;
  2514. alertDescriptions.push(desc);
  2515. }
  2516. }
  2517. const alertMsg = [...new Set(alertDescriptions)].join('\n');
  2518. showDialog(alertMsg);
  2519. }
  2520.  
  2521. addButton('generateDescription', 'Description', generateDescription);
  2522. }
  2523.  
  2524. function ProofpointAlertHandler(...kwargs) {
  2525. const { summary, rawLog } = kwargs[0];
  2526. var raw_alert = 0;
  2527. function parseLog(rawLog) {
  2528. const alertInfo = rawLog.reduce((acc, log) => {
  2529. try {
  2530. const BraceIndex = log.toString().indexOf('{');
  2531. const lastBraceIndex = log.toString().lastIndexOf('}');
  2532. // If the braces are found
  2533. if (BraceIndex !== -1) {
  2534. raw_alert += 1;
  2535. console.log(`${raw_alert} iteration 'is being processed`);
  2536. // Intercepts a substring from the beginning of the brace to the end of the string
  2537. json_text = log.toString().substr(BraceIndex, lastBraceIndex);
  2538. try {
  2539. let json_alert = JSON.parse(json_text);
  2540. if (json_alert.hasOwnProperty('messagesDelivered')) {
  2541. for (const message of json_alert['messagesDelivered']) {
  2542. const { subject, sender, senderIP, recipient } = message;
  2543. const alertExtraInfo = {
  2544. subject: subject ? subject : undefined,
  2545. sender: sender ? sender : undefined,
  2546. recipient: recipient ? recipient : undefined,
  2547. senderIP: senderIP ? senderIP : undefined
  2548. };
  2549. acc.push({ alertExtraInfo });
  2550. }
  2551. } else if (json_alert['sourcetype'].includes('clicksPermitted')) {
  2552. json_alert['clickTime'] = json_alert['clickTime'].split('.')[0];
  2553. json_alert['threatTime'] = json_alert['threatTime'].split('.')[0];
  2554. acc.push({ alertExtraInfo: json_alert });
  2555. console.log('hellO');
  2556. } else {
  2557. const {
  2558. subject,
  2559. sender,
  2560. senderIP,
  2561. recipient,
  2562. headerFrom,
  2563. messageTime,
  2564. threatsInfoMap,
  2565. sourcetype,
  2566. spamScore,
  2567. phishScore,
  2568. cluster,
  2569. completelyRewritten,
  2570. id,
  2571. QID,
  2572. GUID
  2573. } = json_alert;
  2574. let alertExtraInfo = {
  2575. sourcetype: sourcetype ? sourcetype : undefined,
  2576. messageTime: messageTime ? messageTime : undefined,
  2577. subject: subject ? subject : undefined,
  2578. senderIP: senderIP ? senderIP : undefined,
  2579. sender: sender ? sender : undefined,
  2580. recipient: recipient ? recipient : undefined,
  2581. headerFrom: headerFrom ? headerFrom : undefined,
  2582. spamScore: spamScore ? spamScore : undefined,
  2583. phishScore: phishScore ? phishScore : undefined,
  2584. cluster: cluster ? cluster : undefined,
  2585. completelyRewritten: completelyRewritten ? completelyRewritten : undefined,
  2586. id: id ? id : undefined,
  2587. QID: QID ? QID : undefined,
  2588. GUID: GUID ? GUID : undefined
  2589. };
  2590. alertExtraInfo = Object.assign({}, alertExtraInfo, threatsInfoMap[0]);
  2591. acc.push({ alertExtraInfo });
  2592. }
  2593. } catch (error) {
  2594. console.log('Unable to parse JSON data, handling exception: ' + error);
  2595. var split_str = json_text
  2596. .split('"messagesDelivered" :')[1]
  2597. .split('"messagesBlocked" :')[0]
  2598. .slice(1, -2);
  2599. const json_alerts = JSON.parse(split_str);
  2600. for (const alert of json_alerts) {
  2601. const { subject, sender, senderIP, recipient } = alert;
  2602. console.log(subject, recipient);
  2603. const alertExtraInfo = {
  2604. subject: subject ? subject : undefined,
  2605. sender: sender ? sender : undefined,
  2606. recipient: recipient ? recipient : undefined,
  2607. senderIP: senderIP ? senderIP : undefined
  2608. };
  2609. acc.push({ alertExtraInfo });
  2610. }
  2611. }
  2612. }
  2613. } catch (error) {
  2614. console.log(`Error: ${error.message}`);
  2615. }
  2616. return acc;
  2617. }, []);
  2618. return alertInfo;
  2619. }
  2620.  
  2621. const alertInfo = parseLog(rawLog);
  2622. const num_alert = $('#customfield_10300-val').text().trim();
  2623. console.log('reduce the methods iterated altogether' + num_alert + ' times');
  2624. function generateDescription() {
  2625. const alertDescriptions = [];
  2626. if (raw_alert < num_alert) {
  2627. let extra_message = `<span class="red_highlight">Number Of Alert : ${num_alert}, Raw Log Alert : ${raw_alert} Raw log information is Not Complete, Please Get More Alert Information From Elastic.</span>\n`;
  2628. alertDescriptions.push(extra_message);
  2629. }
  2630. for (const info of alertInfo) {
  2631. let desc = `Observed ${summary.split(']')[1]}\n`;
  2632. for (const key in info.alertExtraInfo) {
  2633. if (Object.hasOwnProperty.call(info.alertExtraInfo, key)) {
  2634. const value = info.alertExtraInfo[key];
  2635. if (value !== undefined) {
  2636. if (key == 'messageTime' || key == 'clickTime' || key == 'threatTime') {
  2637. desc += `${key}(<span class="red_highlight">GMT</span>): ${value.split('.')[0]}\n`;
  2638. } else {
  2639. desc += `${key}: ${value}\n`;
  2640. }
  2641. }
  2642. }
  2643. }
  2644. desc += `\nPlease verify if the activity is legitimate.\n`;
  2645. alertDescriptions.push(desc);
  2646. }
  2647. const alertMsg = [...new Set(alertDescriptions)].join('\n');
  2648. showDialog(alertMsg);
  2649. }
  2650.  
  2651. addButton('generateDescription', 'Description', generateDescription);
  2652. }
  2653.  
  2654. function ZscalerAlertHandler(...kwargs) {
  2655. const { summary, rawLog } = kwargs[0];
  2656. var raw_alert = 0;
  2657. function parseLog(rawLog) {
  2658. const alertInfo = rawLog.reduce((acc, log) => {
  2659. try {
  2660. const BraceIndex = log.toString().indexOf('{');
  2661. const lastBraceIndex = log.toString().lastIndexOf('}');
  2662.  
  2663. // If the braces are found
  2664. if (BraceIndex !== -1) {
  2665. raw_alert += 1;
  2666. // Intercepts a substring from the beginning of the brace to the end of the string
  2667. json_text = log.toString().substr(BraceIndex, lastBraceIndex);
  2668. const json_alert = JSON.parse(json_text);
  2669. const { PrivateIP, PublicIP, Username, Customer, Hostname } = json_alert;
  2670. const alertExtraInfo = {
  2671. Hostname: Hostname ? Hostname : undefined,
  2672. PublicIP: PublicIP ? PublicIP : undefined,
  2673. PrivateIP: PrivateIP ? PrivateIP : undefined,
  2674. Username: Username ? Username : undefined,
  2675. Customer: Customer ? Customer : undefined
  2676. };
  2677. acc.push({ alertExtraInfo });
  2678. }
  2679. } catch (error) {
  2680. console.log(`Error: ${error.message}`);
  2681. }
  2682. return acc;
  2683. }, []);
  2684. return alertInfo;
  2685. }
  2686.  
  2687. const alertInfo = parseLog(rawLog);
  2688. const num_alert = $('#customfield_10300-val').text().trim();
  2689. function generateDescription() {
  2690. const alertDescriptions = [];
  2691. if (raw_alert < num_alert) {
  2692. let extra_message = `<span class="red_highlight">Number Of Alert : ${num_alert}, Raw Log Alert : ${raw_alert} Raw log information is Not Complete, Please Get More Alert Information From Elastic.</span>\n`;
  2693. alertDescriptions.push(extra_message);
  2694. }
  2695. for (const info of alertInfo) {
  2696. let desc = `Observed ${summary.split(']')[1]}\n`;
  2697. for (const key in info.alertExtraInfo) {
  2698. if (Object.hasOwnProperty.call(info.alertExtraInfo, key)) {
  2699. const value = info.alertExtraInfo[key];
  2700. if (value !== undefined) {
  2701. desc += `${key}: ${value}\n`;
  2702. }
  2703. }
  2704. }
  2705. desc += `\nPlease verify if the ip is legitimate.\n`;
  2706. alertDescriptions.push(desc);
  2707. }
  2708. const alertMsg = [...new Set(alertDescriptions)].join('\n'); //Can achieve automatic deduplication
  2709. showDialog(alertMsg);
  2710. }
  2711. addButton('generateDescription', 'Description', generateDescription);
  2712. }
  2713.  
  2714. function PulseAlertHandler(...kwargs) {
  2715. var { summary, rawLog } = kwargs[0];
  2716. var raw_alert = 0;
  2717. if (rawLog == '') {
  2718. var rawLog = $('#customfield_10219-val').text().trim().split('\n');
  2719. }
  2720. function parseLog(rawLog) {
  2721. const alertInfo = rawLog.reduce((acc, log) => {
  2722. try {
  2723. if (log.includes('PulseSecure')) {
  2724. var firstIndex = log.indexOf('PulseSecure:');
  2725. let time_text = '';
  2726. if (summary.toLowerCase().includes('suspicious geolocation ip login success')) {
  2727. time_text = log.toString().substr(0, firstIndex);
  2728. } else {
  2729. time_text = log.toString().substr(firstIndex + 13);
  2730. const first_bar = time_text.indexOf(':');
  2731. time_text = time_text.toString().substr(0, first_bar + 6);
  2732. }
  2733. const lastIndex = log.toString().lastIndexOf('Vendor)');
  2734. let alert_text = log
  2735. .toString()
  2736. .substr(lastIndex + 7)
  2737. .replace('[][] -', '');
  2738. const lastIndex_ = alert_text.toString().lastIndexOf(' - ');
  2739. alert_text = alert_text.substr(lastIndex_ + 2);
  2740. let first = log.indexOf('- ');
  2741. let second = log.indexOf(' - [');
  2742. let vpn_name = log.toString().substring(first + 2, second) + ' ';
  2743. const alert_content = '\n' + vpn_name + alert_text + ' On ' + time_text + '\n';
  2744. acc.push(alert_content);
  2745. raw_alert += 1;
  2746. }
  2747. } catch (error) {
  2748. console.log(`Error: ${error.message}`);
  2749. }
  2750. return acc;
  2751. }, []);
  2752. return alertInfo;
  2753. }
  2754. const alertInfo = parseLog(rawLog);
  2755. const num_alert = $('#customfield_10300-val').text().trim();
  2756. function generateDescription() {
  2757. const alertDescriptions = [];
  2758. if (raw_alert < num_alert) {
  2759. let extra_message = `<span class="red_highlight">Number Of Alert : ${num_alert}, Raw Log Alert : ${raw_alert} Raw log information is Not Complete, Please Get More Alert Information From Elastic.</span>\n`;
  2760. alertDescriptions.push(extra_message);
  2761. }
  2762. let desc = `Observed ${summary.split(']')[1]}\n`;
  2763. desc += alertInfo;
  2764. desc += `\n\nPlease verify if the login is legitimate.\n`;
  2765. alertDescriptions.push(desc);
  2766. const alertMsg = [...new Set(alertDescriptions)].join('\n'); //Can achieve automatic deduplication
  2767. showDialog(alertMsg);
  2768. }
  2769. addButton('generateDescription', 'Description', generateDescription);
  2770. }
  2771.  
  2772. function Risky_Countries_AlertHandler(...kwargs) {
  2773. var { summary, rawLog } = kwargs[0];
  2774. function parseLog(rawLog) {
  2775. const alertInfo = rawLog.reduce((acc, log) => {
  2776. try {
  2777. const json_alert = JSON.parse(log);
  2778. if (json_alert.hasOwnProperty('azure')) {
  2779. const {
  2780. createdDateTime,
  2781. userDisplayName,
  2782. userPrincipalName,
  2783. ipAddress,
  2784. appDisplayName,
  2785. deviceDetail,
  2786. status
  2787. } = json_alert['azure'];
  2788. const { failureReason, additionalDetails } = status;
  2789. const { displayName, operatingSystem } = deviceDetail;
  2790.  
  2791. const alertExtraInfo = {
  2792. createdEventDateTime: createdDateTime ? createdDateTime : undefined,
  2793. userDisplayName: userDisplayName ? userDisplayName : undefined,
  2794. userPrincipalName: userPrincipalName ? userPrincipalName : undefined,
  2795. appDisplayName: appDisplayName ? appDisplayName : undefined,
  2796. ipAddress: ipAddress ? ipAddress : undefined,
  2797. operatingSystem: operatingSystem ? operatingSystem : undefined,
  2798. DeviceName: displayName ? displayName : 'N/A',
  2799. failureReason: failureReason ? failureReason : undefined,
  2800. additionalDetails: additionalDetails ? additionalDetails : undefined
  2801. };
  2802. acc.push({ alertExtraInfo });
  2803. }
  2804. if (json_alert.hasOwnProperty('office_365')) {
  2805. let alertExtraInfo;
  2806. if (json_alert['office_365'].hasOwnProperty('Data')) {
  2807. console.log(JSON.parse(json_alert['office_365']['Data']));
  2808. let data = JSON.parse(json_alert['office_365']['Data']);
  2809. alertExtraInfo = {
  2810. CreationEventTime: data['wsrt'] ? data['wsrt'] : undefined,
  2811. Username: data['f3u'] ? data['f3u'] : undefined,
  2812. Workload: data['wl'] ? data['wl'] : undefined,
  2813. Reason: data['ad'] ? data['ad'] : undefined
  2814. };
  2815. } else if (!json_alert['office_365'].hasOwnProperty('ClientIP')) {
  2816. let data = json_alert['office_365'];
  2817. alertExtraInfo = {
  2818. CreationEventTime: data['CreationTime'] ? data['CreationTime'] : undefined,
  2819. Operation: data['Operation'] ? data['Operation'] : undefined,
  2820. ResultStatus: data['ResultStatus'] ? data['ResultStatus'] : undefined,
  2821. UserId: data['UserId'] ? data['UserId'] : undefined,
  2822. ObjectId: data['ObjectId'] ? data['ObjectId'] : undefined,
  2823. UserKey: data['UserKey'] ? data['UserKey'] : undefined
  2824. };
  2825. } else {
  2826. const {
  2827. CreationTime,
  2828. Operation,
  2829. Workload,
  2830. ClientIP,
  2831. UserId,
  2832. ResultStatusDetail,
  2833. UserAgent,
  2834. ActorIpAddress,
  2835. DeviceProperties,
  2836. UserKey
  2837. } = json_alert['office_365'];
  2838.  
  2839. let devicename = '';
  2840. DeviceProperties.forEach((item) => {
  2841. if (item.Name === 'DisplayName') {
  2842. devicename = item.Value;
  2843. }
  2844. });
  2845. alertExtraInfo = {
  2846. CreationEventTime: CreationTime ? CreationTime : undefined,
  2847. Operation: Operation ? Operation : undefined,
  2848. Workload: Workload ? Workload : undefined,
  2849. UserId: UserId ? UserId : undefined,
  2850. ClientIP: ClientIP ? ClientIP : undefined,
  2851. ActorIpAddress: ActorIpAddress ? ActorIpAddress : undefined,
  2852. UserAgent: UserAgent ? UserAgent : undefined,
  2853. DeviceName: devicename ? devicename : 'N/A',
  2854. UserKey: UserKey ? UserKey : undefined,
  2855. ResultStatusDetail: ResultStatusDetail ? ResultStatusDetail : undefined
  2856. };
  2857. }
  2858.  
  2859. acc.push({ alertExtraInfo });
  2860. }
  2861. } catch (error) {
  2862. console.log(`Error: ${error.message}`);
  2863. }
  2864. return acc;
  2865. }, []);
  2866. return alertInfo;
  2867. }
  2868. const alertInfo = parseLog(rawLog);
  2869. function generateDescription() {
  2870. const alertDescriptions = [];
  2871. console.log(alertInfo);
  2872. for (const info of alertInfo) {
  2873. const lastindex = summary.lastIndexOf(']');
  2874.  
  2875. let desc = `Observed ${summary.substr(lastindex + 1)}\n`;
  2876. for (const key in info.alertExtraInfo) {
  2877. if (Object.hasOwnProperty.call(info.alertExtraInfo, key)) {
  2878. const value = info.alertExtraInfo[key];
  2879. if (value !== undefined) {
  2880. if (key == 'CreationEventTime') {
  2881. desc += `CreationEventTime(<span class="red_highlight">GMT</span>): ${value}\n`;
  2882. } else {
  2883. desc += `${key}: ${value}\n`;
  2884. }
  2885. }
  2886. }
  2887. }
  2888. desc += `\nPlease verify if the activity is legitimate.\n`;
  2889. alertDescriptions.push(desc);
  2890. }
  2891. const alertMsg = [...new Set(alertDescriptions)].join('\n');
  2892. showDialog(alertMsg);
  2893. }
  2894.  
  2895. addButton('generateDescription', 'Description', generateDescription);
  2896. }
  2897.  
  2898. function Agent_Disconnect_AlertHandler(...kwargs) {
  2899. var { summary, rawLog } = kwargs[0];
  2900. const LogSource = $('#customfield_10204-val').text().trim().split('\n');
  2901. function parseLog(LogSource) {
  2902. const alertInfo = LogSource.reduce((acc, log) => {
  2903. try {
  2904. log = log.replace(/\s/g, '');
  2905. if (log == 'Show' || log == 'Hide' || log.length == 0) {
  2906. console.log('ss');
  2907. } else {
  2908. acc.push(log);
  2909. console.log(log);
  2910. }
  2911. } catch (error) {
  2912. console.log(`Error: ${error.message}`);
  2913. }
  2914. return acc;
  2915. }, []);
  2916. return alertInfo;
  2917. }
  2918. let alertInfo = [...new Set(parseLog(LogSource))];
  2919. function generateDescription() {
  2920. const alertDescriptions = [];
  2921.  
  2922. const lastindex = summary.lastIndexOf(']');
  2923. let desc = `Observed ${summary.substr(lastindex + 1)}, kindly please help to check it.\n`;
  2924. desc += `\nagent name: ${alertInfo.join(',')}`;
  2925. alertDescriptions.push(desc);
  2926. const alertMsg = [...new Set(alertDescriptions)].join('\n');
  2927. showDialog(alertMsg);
  2928. }
  2929. function openMDE() {
  2930. let KQL = '';
  2931. KQL += `name=${alertInfo.join(' or name=')} \n`;
  2932. showFlag('info', 'KQL:', `${KQL}`, 'manual');
  2933. }
  2934. addButton('generateDescription', 'Description', generateDescription);
  2935. addButton('openKQL', 'KQL', openMDE);
  2936. }
  2937.  
  2938. function MdbAlertHandler(...kwargs) {
  2939. var { summary, rawLog } = kwargs[0];
  2940. if (rawLog.length == 0 || rawLog.length == 1) {
  2941. rawLog = $('#customfield_10219-val').text().trim().split('\n');
  2942. }
  2943. function parseLog(rawLog) {
  2944. const alertInfo = rawLog.reduce((acc, log) => {
  2945. try {
  2946. if (log.length == 0) {
  2947. return acc;
  2948. }
  2949. if (summary.toLowerCase().includes('syslog: user missed the password more than one time')) {
  2950. let log_ = log.split(';')[1].split(' ');
  2951. let time_host = log.split(' sshd')[0].split(' ');
  2952. let user = '';
  2953. if (log_.length > 7) {
  2954. user = log_[8].split('=')[1];
  2955. }
  2956. let description = `Observed user<span class='black_highlight'> ${user}</span> multiple ssh login failed from ${
  2957. log_[6].split('=')[1]
  2958. }\nCreateTime: ${time_host
  2959. .slice(0, time_host.length - 1)
  2960. .join(' ')}\nHostname: <span class='black_highlight'> ${
  2961. time_host[time_host.length - 1]
  2962. }</span>\n`;
  2963.  
  2964. acc.push(description);
  2965. }
  2966. if (summary.toLowerCase().includes('sshd: insecure connection attempt')) {
  2967. let log_ = log.split(' ');
  2968. console.log('log', log_);
  2969. let description = `Observed insecure connection attempt from ${
  2970. log_[log_.length - 3]
  2971. }\nCreateTime: ${log_.slice(0, log_.length - 11).join(' ')}\n`;
  2972. acc.push(description);
  2973. }
  2974. if (
  2975. summary
  2976. .toLowerCase()
  2977. .includes('anomaly: suspected lateral movement - linux containing session opened')
  2978. ) {
  2979. let log_ = log.split('>')[1] + '\n';
  2980. console.log('log', log_);
  2981. acc.push(log_);
  2982. }
  2983. } catch (error) {
  2984. console.log(`Error: ${error.message}`);
  2985. }
  2986. return acc;
  2987. }, []);
  2988. return alertInfo;
  2989. }
  2990. const alertInfo = parseLog(rawLog);
  2991. function generateDescription() {
  2992. const alertDescriptions = [];
  2993. if (summary.toLowerCase().includes('anomaly: suspected lateral movement - linux containing session opened')) {
  2994. const Log_source = $('#customfield_10204-val').text().trim();
  2995. alertDescriptions.push(`Observed session opened on <span class='black_highlight'>${Log_source}</span>\n`);
  2996. }
  2997. for (const info of alertInfo) {
  2998. alertDescriptions.push(info);
  2999. }
  3000. if (summary.toLowerCase().includes('sshd: insecure connection attempt')) {
  3001. alertDescriptions.push('Kindly help to verify if the connection is legitimate\n');
  3002. }
  3003. if (summary.toLowerCase().includes('syslog: user missed the password more than one time')) {
  3004. alertDescriptions.push('Kindly help to verify if the login is legitimate\n');
  3005. }
  3006. if (summary.toLowerCase().includes('anomaly: suspected lateral movement - linux containing session opened')) {
  3007. alertDescriptions.push('Kindly help to verify if the session is legitimate\n');
  3008. }
  3009. const alertMsg = [...new Set(alertDescriptions)].join('\n');
  3010. showDialog(alertMsg);
  3011. }
  3012.  
  3013. addButton('generateDescription', 'Description', generateDescription);
  3014. }
  3015.  
  3016. function AlicloudAlertHandler(...kwargs) {
  3017. var { summary, rawLog } = kwargs[0];
  3018. var raw_alert = 0;
  3019. function parseLog(rawLog) {
  3020. const alertInfo = rawLog.reduce((acc, log) => {
  3021. try {
  3022. const BraceIndex = log.toString().indexOf('{');
  3023. const lastBraceIndex = log.toString().lastIndexOf('}');
  3024. if (BraceIndex !== -1) {
  3025. raw_alert += 1;
  3026. // Intercepts a substring from the beginning of the brace to the end of the string
  3027. json_text = log.toString().substr(BraceIndex, lastBraceIndex);
  3028. let time_1 = log.toString().substr(0, BraceIndex).split(' ');
  3029. let time = time_1.slice(time_1.length - 4, time_1.length - 2).join(' ');
  3030. time = time_1[0] + ' ' + time;
  3031. try {
  3032. const json_alert = JSON.parse(json_text);
  3033. let {
  3034. eventId,
  3035. uuid,
  3036. eventName,
  3037. resourceName,
  3038. sourceIpAddress,
  3039. userIdentity,
  3040. intranet_ip,
  3041. internet_ip,
  3042. instance_id,
  3043. extend_content,
  3044. detail,
  3045. requestParameters,
  3046. responseElements
  3047. } = json_alert['alicloud'];
  3048. let alertExtraInfo = {
  3049. createTime: time,
  3050. eventId: eventId ? eventId : undefined,
  3051. uuid: uuid ? uuid : undefined,
  3052. eventName: eventName ? eventName : undefined,
  3053. InstanceId: resourceName ? resourceName : undefined,
  3054. sourceIpAddress: sourceIpAddress ? sourceIpAddress : undefined,
  3055. userName: userIdentity?.userName ? userIdentity?.userName : undefined,
  3056. internet_ip: internet_ip ? internet_ip : undefined,
  3057. intranet_ip: intranet_ip ? intranet_ip : undefined,
  3058. instance_id: instance_id ? instance_id : undefined,
  3059. extend_content: extend_content ? extend_content : undefined,
  3060. responseElements: responseElements ? JSON.stringify(responseElements) : undefined
  3061. };
  3062. console.log('===', requestParameters, time);
  3063.  
  3064. if (detail != undefined) {
  3065. detail = JSON.parse(detail);
  3066. alertExtraInfo = Object.assign({}, alertExtraInfo, detail);
  3067. }
  3068. if (requestParameters != undefined) {
  3069. alertExtraInfo = Object.assign({}, alertExtraInfo, requestParameters);
  3070. }
  3071.  
  3072. console.log(alertExtraInfo);
  3073. acc.push({ alertExtraInfo });
  3074. } catch (error) {
  3075. console.log('Unable to parse JSON data, handling exception: ' + error);
  3076. }
  3077. }
  3078. } catch (error) {
  3079. console.log(`Error: ${error.message}`);
  3080. }
  3081. return acc;
  3082. }, []);
  3083. return alertInfo;
  3084. }
  3085.  
  3086. const alertInfo = parseLog(rawLog);
  3087. function generateDescription() {
  3088. const alertDescriptions = [];
  3089. for (const info of alertInfo) {
  3090. const lastindex = summary.lastIndexOf(']');
  3091. let desc = `Observed ${summary.substr(lastindex + 1)}\n`;
  3092. for (const key in info.alertExtraInfo) {
  3093. if (Object.hasOwnProperty.call(info.alertExtraInfo, key)) {
  3094. const value = info.alertExtraInfo[key];
  3095. if (value !== undefined) {
  3096. desc += `${key}: ${value}\n`;
  3097. }
  3098. }
  3099. }
  3100. desc += `\nPlease verify if the activity is legitimate.\n`;
  3101. alertDescriptions.push(desc);
  3102. }
  3103. const alertMsg = [...new Set(alertDescriptions)].join('\n');
  3104. showDialog(alertMsg);
  3105. }
  3106.  
  3107. addButton('generateDescription', 'Description', generateDescription);
  3108. }
  3109.  
  3110. function DstAlertHandler(...kwargs) {
  3111. var rawLog = $('#field-customfield_10904').text().trim().split('\n');
  3112. function parseLog(rawLog) {
  3113. const alertInfo = rawLog.reduce((acc, log) => {
  3114. try {
  3115. const json_alert = JSON.parse(log);
  3116. const { system, eventdata } = json_alert['win'];
  3117. const alertExtraInfo = {
  3118. computer: system?.computer ? system?.computer : undefined,
  3119. commandLine: eventdata?.commandLine ? eventdata?.commandLine : undefined
  3120. };
  3121. acc.push({ alertExtraInfo });
  3122. } catch (error) {
  3123. console.log(`Error: ${error.message}`);
  3124. }
  3125. return acc;
  3126. }, []);
  3127. return alertInfo;
  3128. }
  3129. const alertInfo = parseLog(rawLog);
  3130. function generateDescription() {
  3131. const alertDescriptions = [];
  3132. for (const info of alertInfo) {
  3133. let desc = ``;
  3134. for (const key in info.alertExtraInfo) {
  3135. if (Object.hasOwnProperty.call(info.alertExtraInfo, key)) {
  3136. const value = info.alertExtraInfo[key];
  3137. if (value !== undefined) {
  3138. desc += `${key}: ${value}\n`;
  3139. }
  3140. }
  3141. }
  3142. alertDescriptions.push(desc);
  3143. }
  3144. const alertMsg = [...new Set(alertDescriptions)].join('\n');
  3145. showDialog(alertMsg);
  3146. }
  3147.  
  3148. addButton('generateDescription', 'Description', generateDescription);
  3149. }
  3150.  
  3151. function ThreatMatrixAlertHandler(...kwargs) {
  3152. var { summary, rawLog } = kwargs[0];
  3153. function parseLog(rawLog) {
  3154. const alertInfo = rawLog.reduce((acc, log) => {
  3155. try {
  3156. const json_alert = JSON.parse(log);
  3157. console.log(json_alert['threatmatrix']);
  3158. const {
  3159. account_telephone,
  3160. account_login,
  3161. application_name,
  3162. customer_event_type,
  3163. input_ip_address,
  3164. event_datetime,
  3165. input_ip_city,
  3166. input_ip_geo,
  3167. input_ip_isp,
  3168. input_ip_organization,
  3169. policy,
  3170. tmx_risk_rating,
  3171. request_result
  3172. } = json_alert['threatmatrix'];
  3173. const alertExtraInfo = {
  3174. account_telephone: account_telephone ? account_telephone : undefined,
  3175. account_login: account_login ? account_login : undefined,
  3176. application_name: application_name ? application_name : undefined,
  3177. customer_event_type: customer_event_type ? customer_event_type : undefined,
  3178. input_ip_address: input_ip_address ? input_ip_address : undefined,
  3179. input_ip_city: input_ip_city ? input_ip_city : undefined,
  3180. input_ip_geo: input_ip_geo ? input_ip_geo : undefined,
  3181. input_ip_isp: input_ip_isp ? input_ip_isp : undefined,
  3182. input_ip_organization: input_ip_organization ? input_ip_organization : undefined,
  3183. policy: policy ? policy : undefined,
  3184. tmx_risk_rating: tmx_risk_rating ? tmx_risk_rating : undefined,
  3185. request_result: request_result ? request_result : undefined,
  3186. event_datetime: event_datetime ? event_datetime.split('.')[0] : undefined
  3187. };
  3188. acc.push({ alertExtraInfo });
  3189. } catch (error) {
  3190. console.log(`Error: ${error.message}`);
  3191. }
  3192. return acc;
  3193. }, []);
  3194. return alertInfo;
  3195. }
  3196. const alertInfo = parseLog(rawLog);
  3197. function generateDescription() {
  3198. const alertDescriptions = [];
  3199. for (const info of alertInfo) {
  3200. const lastindex = summary.lastIndexOf(']');
  3201. let desc = `Observed ${summary.substr(lastindex + 1)}\n`;
  3202. for (const key in info.alertExtraInfo) {
  3203. if (Object.hasOwnProperty.call(info.alertExtraInfo, key)) {
  3204. const value = info.alertExtraInfo[key];
  3205. if (value !== undefined) {
  3206. desc += `${key}: ${value}\n`;
  3207. }
  3208. }
  3209. }
  3210. desc += `\nPlease verify if the login is legitimate.\n`;
  3211. alertDescriptions.push(desc);
  3212. }
  3213. const alertMsg = [...new Set(alertDescriptions)].join('\n');
  3214. showDialog(alertMsg);
  3215. }
  3216.  
  3217. addButton('generateDescription', 'Description', generateDescription);
  3218. }
  3219.  
  3220. function DarktraceAlertHandler(...kwargs) {
  3221. var { summary, rawLog } = kwargs[0];
  3222. var raw_alert = 0;
  3223. var breach_Url;
  3224. function parseLog(rawLog) {
  3225. const alertInfo = rawLog.reduce((acc, log) => {
  3226. try {
  3227. const BraceIndex = log.toString().indexOf('{');
  3228. const lastBraceIndex = log.toString().lastIndexOf('}');
  3229. const logarray = log.toString().split(' ');
  3230. if (BraceIndex !== -1) {
  3231. raw_alert += 1;
  3232. // Intercepts a substring from the beginning of the brace to the end of the string
  3233. json_text = log.toString().substr(BraceIndex, lastBraceIndex);
  3234. const json_alert = JSON.parse(json_text);
  3235. let alertExtraInfo = {},
  3236. Resource_paths = [];
  3237. breach_Url = json_alert['breachUrl'] + '<br>' + json_alert['incidentEventUrl'];
  3238. let year = ' 20' + $('#created-val').text().trim().split('/')[2].split(' ')[0]; //动态产生工单的年份
  3239. let time_str = logarray.slice(0, 3).join(' ') + year;
  3240. if (!time_str.includes(':')) {
  3241. time_str = logarray.slice(0, 4).join(' ').replace(' ', ' ') + year;
  3242. }
  3243.  
  3244. if (json_alert.hasOwnProperty('model')) {
  3245. const { device, triggeredComponents, model } = json_alert;
  3246. let User_agent = '',
  3247. Message;
  3248. alertExtraInfo = {
  3249. AlertTime: formatCurrentDateTime(time_str),
  3250. hostname: device?.hostname ? device?.hostname : undefined,
  3251. ip: device?.ip ? device?.ip : undefined,
  3252. credentials: device?.credentials ? device?.credentials : undefined,
  3253. subnetlabel: device?.ips ? device?.ips[0].subnetlabel : undefined,
  3254. typename: device?.typename ? device?.typename : undefined,
  3255. User_agent: User_agent ? User_agent : undefined,
  3256. saas_info: device?.customFields?.saasinfo
  3257. ? device.customFields.saasinfo.saas_info
  3258. : undefined,
  3259. Message: Message ? Message : undefined,
  3260. description: model?.description ? model?.description.replace(/\\\n/g, ' ') : undefined
  3261. };
  3262. triggeredComponents[0]['triggeredFilters'].forEach((item) => {
  3263. if (item['filterType'] == 'User agent' && item['id'] == 'O') {
  3264. User_agent = item['arguments']['value'];
  3265. console.log('value', item['arguments']['value']);
  3266. } else if (item['id'] == 'C') {
  3267. Message = item['trigger']['value'];
  3268. } else if (
  3269. item['filterType'].includes('IP') ||
  3270. item['filterType'] == 'Resource Location' ||
  3271. item['filterType'] == 'Event' ||
  3272. item['filterType'] == 'Connection hostname'
  3273. ) {
  3274. alertExtraInfo[item['filterType']] = item['trigger']['value'];
  3275. }
  3276. });
  3277. } else {
  3278. const { summary, breachDevices, details } = json_alert;
  3279. let values;
  3280. alertExtraInfo = {
  3281. AlertTime: formatCurrentDateTime(time_str),
  3282. hostname: breachDevices[0]?.hostname ? breachDevices[0]?.hostname : undefined,
  3283. host_ip: breachDevices[0]?.ip ? breachDevices[0]?.ip : undefined,
  3284. summary: summary ? summary : undefined
  3285. };
  3286. details.forEach((item) => {
  3287. if (item[0].header == 'Endpoint Details') {
  3288. values = item[0].contents[0].values;
  3289. item[0].contents.forEach((i) => {
  3290. if (i.key == 'IP addresses associated with hostnames') {
  3291. console.log(i);
  3292. alertExtraInfo[i.type] = JSON.stringify(i.values);
  3293. }
  3294. });
  3295. }
  3296. item.forEach((ii) => {
  3297. if (
  3298. ii.header == 'Activity Details' ||
  3299. ii.header == 'Details of Accessing Users' ||
  3300. ii.header == 'Resource Access Details'
  3301. ) {
  3302. ii.contents.forEach((i) => {
  3303. if (i['key'] == 'Resource paths include' || i['key'] == 'Resource path') {
  3304. i['values'].forEach((iii) => {
  3305. Resource_paths.push(iii);
  3306. });
  3307. } else if (
  3308. i['key'].includes('Source IPs') ||
  3309. i['key'].includes('Actors include')
  3310. ) {
  3311. alertExtraInfo[i.key] = JSON.stringify(i.values);
  3312. }
  3313. });
  3314. }
  3315. });
  3316. });
  3317. Resource_paths = [...new Set(Resource_paths)].join('\n');
  3318. alertExtraInfo['Resource_paths'] = Resource_paths ? Resource_paths : undefined;
  3319. alertExtraInfo['Endpoint Details'] = values ? values : undefined;
  3320. }
  3321. acc.push({ alertExtraInfo });
  3322. }
  3323. } catch (error) {
  3324. console.log(`Error: ${error.message}`);
  3325. }
  3326. return acc;
  3327. }, []);
  3328. return alertInfo;
  3329. }
  3330. const alertInfo = parseLog(rawLog);
  3331. const num_alert = $('#customfield_10300-val').text().trim();
  3332. function generateDescription() {
  3333. const alertDescriptions = [];
  3334. if (raw_alert < num_alert) {
  3335. let extra_message = `<span class="red_highlight">Number Of Alert : ${num_alert}, Raw Log Alert : ${raw_alert} Raw log information is Not Complete, Please Get More Alert Information From Elastic.</span>\n`;
  3336. alertDescriptions.push(extra_message);
  3337. }
  3338. for (const info of alertInfo) {
  3339. const lastindex = summary.lastIndexOf(']');
  3340. let ss = summary.substr(lastindex + 1).split('::');
  3341. let desc = `Observed ${ss[ss.length - 1]}\n\n`;
  3342. for (const key in info.alertExtraInfo) {
  3343. if (Object.hasOwnProperty.call(info.alertExtraInfo, key)) {
  3344. const value = info.alertExtraInfo[key];
  3345. if (value !== undefined) {
  3346. desc += `${key}: ${value}\n`;
  3347. }
  3348. }
  3349. }
  3350. desc += `\nPlease help to verify if this activity is legitimate.\n`;
  3351. alertDescriptions.push(desc);
  3352. }
  3353. const alertMsg = [...new Set(alertDescriptions)].join('\n');
  3354. showDialog(alertMsg);
  3355. }
  3356. function breachUrl() {
  3357. showFlag('info', 'breach Url:', `${breach_Url.replace('hXXps[:]', 'https:')}`, 'manual');
  3358. }
  3359. addButton('generateDescription', 'Description', generateDescription);
  3360. addButton('breachUrl', 'breachUrl', breachUrl);
  3361. }
  3362.  
  3363. function SangforAlertHandler(...kwargs) {
  3364. var { summary, rawLog } = kwargs[0];
  3365. function parseLog(rawLog) {
  3366. const alertInfo = rawLog.reduce((acc, log) => {
  3367. try {
  3368. if (log.length == 0) {
  3369. return acc;
  3370. }
  3371. const regex = /(\b\w+=)([^=\s].*?)(?=\s+\w+=|$)/g;
  3372. let match;
  3373. const matches = {};
  3374. while ((match = regex.exec(log)) !== null) {
  3375. let item = match[0].split('=');
  3376. matches[item[0]] = item.slice(1, item.length).join('=');
  3377. }
  3378. console.log(matches);
  3379. var pattern = /event_evidence.*?(?=suffer_classify1_id_name)/g;
  3380. console.log(log.match(pattern));
  3381. let logArray = log.split(' ').filter((item) => item !== ''); //Remove extra whitespace from the string
  3382. const DecoderName = $('#customfield_10807-val').text().trim().toLowerCase();
  3383. if (DecoderName == 'cyberark_cef') {
  3384. let data_json = {
  3385. 'Event time': logArray.slice(0, 3).join(' '),
  3386. 'event_desc': matches.event_desc ? matches.event_desc : undefined,
  3387. 'dhost': matches.dhost ? matches.dhost : undefined,
  3388. 'dst': matches.dst ? matches.dst : undefined,
  3389. 'duser': matches.duser ? matches.duser : undefined,
  3390. 'shost': matches.shost ? matches.shost : undefined,
  3391. 'src': matches.src ? matches.src : undefined,
  3392. 'suser': matches.suser ? matches.suser : undefined
  3393. };
  3394. data_json[matches.cs3Label] = matches.cs3 ? matches.cs3 : undefined;
  3395. acc.push(data_json);
  3396. } else if (DecoderName == 'trellix_cef') {
  3397. let data_json = {
  3398. filePath: matches.filePath ? matches.filePath : undefined,
  3399. rt: matches.rt ? matches.rt : undefined,
  3400. duser: matches.duser ? matches.duser : undefined,
  3401. msg: matches.msg ? matches.msg : undefined,
  3402. act: matches.act ? matches.act : undefined,
  3403. suser: matches.suser ? matches.suser.replace(/[<>]/g, '') : undefined,
  3404. fileType: matches.fileType ? matches.fileType : undefined,
  3405. subject: matches.subject ? matches.subject : undefined
  3406. };
  3407. data_json[matches.cs1Label] = matches.cs1 ? matches.cs1 : undefined;
  3408. data_json[matches.cs4Label] = matches.cs4 ? matches.cs4 : undefined;
  3409. data_json[matches.flexString2Label] = matches.flexString2 ? matches.flexString2 : undefined;
  3410. acc.push(data_json);
  3411. } else if (DecoderName == 'impervainc_cef') {
  3412. console.log('===', matches);
  3413. console.log('===start ', formatCurrentDateTime(parseInt(matches.start), 'impervainc_cef'));
  3414. let data_json = {
  3415. start_time: matches.start
  3416. ? formatCurrentDateTime(parseInt(matches.start), 'impervainc_cef')
  3417. : undefined,
  3418. end_time: matches.end
  3419. ? formatCurrentDateTime(parseInt(matches.end), 'impervainc_cef')
  3420. : undefined,
  3421. dhost: matches.dhost ? matches.dhost : undefined,
  3422. AlertTime: matches.rt ? matches.rt : undefined,
  3423. src: matches.src ? matches.src : undefined,
  3424. sptPort: matches.spt ? matches.spt : undefined,
  3425. dstIP: matches.dst ? matches.dst : undefined,
  3426. dstPort: matches.dpt ? matches.dpt : undefined,
  3427. protocol: matches.proto ? matches.proto : undefined,
  3428. request: matches.request ? matches.request : undefined,
  3429. requestClientApplication: matches.requestClientApplication
  3430. ? matches.requestClientApplication
  3431. : undefined,
  3432. msg: matches.msg ? matches.msg : undefined
  3433. };
  3434. data_json[matches.cs1Label] = matches.cs1 ? matches.cs1 : undefined;
  3435. data_json[matches.cs2Label] = matches.cs2 ? matches.cs2 : undefined;
  3436. data_json[matches.cs3Label] = matches.cs3 ? matches.cs3 : undefined;
  3437. data_json[matches.cs4Label] = matches.cs4 ? matches.cs4 : undefined;
  3438. data_json[matches.cs5Label] = matches.cs5 ? matches.cs5 : undefined;
  3439. data_json[matches.cs6Label] = matches.cs6 ? matches.cs6 : undefined;
  3440. data_json[matches.cs7Label] = matches.cs7 ? matches.cs7 : undefined;
  3441. data_json[matches.cs8Label] = matches.cs8 ? matches.cs8 : undefined;
  3442. data_json[matches.cs9Label] = matches.cs9 ? matches.cs9 : undefined;
  3443.  
  3444. acc.push(data_json);
  3445. } else if (DecoderName == 'checkpoint_cef') {
  3446. let data_json = {
  3447. Signature: matches.Signature ? matches.Signature : undefined,
  3448. cp_severity: matches.cp_severity ? matches.cp_severity : undefined,
  3449. src: matches.src ? matches.src : undefined,
  3450. dst: matches.dst ? matches.dst : undefined,
  3451. origin: matches.origin ? matches.origin : undefined
  3452. };
  3453. data_json[matches.cs2Label] = matches.cs2 ? matches.cs2 : undefined;
  3454. data_json[matches.cs3Label] = matches.cs3 ? matches.cs3 : undefined;
  3455. data_json[matches.cs4Label] = matches.cs4 ? matches.cs4 : undefined;
  3456. data_json[matches.flexNumber1Label] = matches.flexNumber1 ? matches.flexNumber1 : undefined;
  3457. data_json[matches.flexNumber2Label] = matches.flexNumber2 ? matches.flexNumber2 : undefined;
  3458. data_json[matches.flexString2Label] = matches.flexString2 ? matches.flexString2 : undefined;
  3459. acc.push(data_json);
  3460. } else if (DecoderName == 'incapsula_cef') {
  3461. let data_json = {
  3462. requestClientApplication: matches.requestClientApplication
  3463. ? matches.requestClientApplication
  3464. : undefined,
  3465. request: matches.request ? matches.request : undefined,
  3466. requestMethod: matches.requestMethod ? matches.requestMethod : undefined,
  3467. postbody: matches.postbody ? matches.postbody : undefined,
  3468. qstr: matches.qstr ? matches.qstr : undefined,
  3469. act: matches.act ? matches.act : undefined,
  3470. sip: matches.sip ? matches.sip : undefined,
  3471. spt: matches.spt ? matches.spt : undefined,
  3472. xff: matches.xff ? matches.xff : undefined,
  3473. cpt: matches.cpt ? matches.cpt : undefined,
  3474. src: matches.src ? matches.src : undefined
  3475. };
  3476. data_json[matches.cs9Label] = matches.cs9 ? matches.cs9 : undefined;
  3477. acc.push(data_json);
  3478. } else if (window.location.href.includes('macaumss')) {
  3479. acc.push({
  3480. 'Event time': logArray.slice(0, 3).join(' '),
  3481. 'event_desc': matches.event_desc ? matches.event_desc : undefined,
  3482. 'dev_name': matches.dev_name ? matches.dev_name : undefined,
  3483. 'attack_ip': matches.attack_ip ? matches.attack_ip : undefined,
  3484. 'suffer_ip': matches.suffer_ip ? matches.suffer_ip : undefined,
  3485. 'suffer_port': matches.suffer_port ? matches.suffer_port : undefined,
  3486. 'status_code': matches.status_code ? matches.status_code : undefined,
  3487. 'x_forwarded_for': matches.x_forwarded_for ? matches.x_forwarded_for : undefined,
  3488. 'event_evidence': log.match(pattern) ? log.match(pattern)[0] : undefined,
  3489. 'attack_type_name': matches.attack_type_name ? matches.attack_type_name : undefined
  3490. });
  3491. } else {
  3492. acc.push({
  3493. 'Event time': logArray.slice(0, 3).join(' '),
  3494. 'event_desc': matches.event_desc ? matches.event_desc : undefined,
  3495. 'dev_name': matches.dev_name ? matches.dev_name : undefined,
  3496. 'suffer_ip': matches.suffer_ip ? matches.suffer_ip : undefined,
  3497. 'attack_ip': matches.attack_ip ? matches.attack_ip : undefined,
  3498. 'event_evidence': matches.event_evidence ? matches.event_evidence : undefined,
  3499. 'url': matches.url ? matches.url : undefined,
  3500. 'suggest': matches.suggest ? matches.suggest : undefined
  3501. });
  3502. }
  3503. } catch (error) {
  3504. console.log(`Error: ${error.message}`);
  3505. }
  3506. return acc;
  3507. }, []);
  3508. return alertInfo;
  3509. }
  3510. const alertInfo = parseLog(rawLog);
  3511. function generateDescription() {
  3512. const alertDescriptions = [];
  3513. for (const info of alertInfo) {
  3514. const lastindex = summary.lastIndexOf(']');
  3515. let desc;
  3516. if (summary.includes('-')) {
  3517. desc = `Observed ${summary.substr(lastindex + 1).split('-')[1]}\n`;
  3518. } else {
  3519. desc = `Observed ${summary.substr(lastindex + 1)}\n`;
  3520. }
  3521. for (const key in info) {
  3522. if (Object.hasOwnProperty.call(info, key)) {
  3523. const value = info[key];
  3524. if (value !== undefined) {
  3525. if (key == 'event_evidence') {
  3526. desc += `${key}: ${value.replace(/</g, '&lt;').replace(/>/g, '&gt;')}\n`;
  3527. } else if (key == 'start_time' || key == 'end_time' || key == 'AlertTime') {
  3528. desc += `${key}(<span class="red_highlight">GMT+8</span>): ${value.split('.')[0]}\n`;
  3529. } else {
  3530. desc += `${key}: ${value}\n`;
  3531. }
  3532. }
  3533. }
  3534. }
  3535. desc += `\nPlease verify if the activity is legitimate.\n`;
  3536. alertDescriptions.push(desc);
  3537. }
  3538. const alertMsg = [...new Set(alertDescriptions)].join('\n');
  3539. showDialog(alertMsg);
  3540. }
  3541. addButton('generateDescription', 'Description', generateDescription);
  3542. }
  3543.  
  3544. function RadwareAlertHandler(...kwargs) {
  3545. var { summary, rawLog } = kwargs[0];
  3546. function parseLog(rawLog) {
  3547. const alertInfo = rawLog.reduce((acc, log) => {
  3548. try {
  3549. const json_alert = JSON.parse(log);
  3550. const {
  3551. device_ip,
  3552. device_name,
  3553. device_abbr,
  3554. detected_by,
  3555. asset_name,
  3556. asset_type,
  3557. asset_ip,
  3558. account_uid,
  3559. account_name,
  3560. acc_site_name,
  3561. end_time,
  3562. start_time
  3563. } = json_alert['radware'];
  3564.  
  3565. alertExtraInfo = {
  3566. start_time: start_time._date_time ? start_time._date_time : undefined,
  3567. end_time: end_time._date_time ? end_time._date_time : undefined,
  3568. device_ip: device_ip ? device_ip : undefined,
  3569. device_name: device_name ? device_name : undefined,
  3570. device_abbr: device_abbr ? device_abbr : undefined,
  3571. detected_by: detected_by ? detected_by : undefined,
  3572. asset_name: asset_name ? asset_name : undefined,
  3573. asset_type: asset_type ? asset_type : undefined,
  3574. asset_ip: asset_ip ? asset_ip : undefined,
  3575. account_uid: account_uid ? account_uid : undefined,
  3576. account_name: account_name ? account_name : undefined,
  3577. acc_site_name: acc_site_name ? acc_site_name : undefined
  3578. };
  3579. acc.push({ alertExtraInfo });
  3580. } catch (error) {
  3581. console.log(`Error: ${error.message}`);
  3582. }
  3583. return acc;
  3584. }, []);
  3585. return alertInfo;
  3586. }
  3587. const alertInfo = parseLog(rawLog);
  3588. function generateDescription() {
  3589. const alertDescriptions = [];
  3590. for (const info of alertInfo) {
  3591. const lastindex = summary.lastIndexOf(']');
  3592. let desc = `Observed ${summary.substr(lastindex + 1)}\n`;
  3593. for (const key in info.alertExtraInfo) {
  3594. if (Object.hasOwnProperty.call(info.alertExtraInfo, key)) {
  3595. const value = info.alertExtraInfo[key];
  3596. if (value !== undefined) {
  3597. if (key == 'start_time' || key == 'end_time') {
  3598. desc += `${key}(<span class="red_highlight">GMT</span>): ${value.split('.')[0] + 'Z'}\n`;
  3599. } else {
  3600. desc += `${key}: ${value}\n`;
  3601. }
  3602. }
  3603. }
  3604. }
  3605. desc += `\nPlease verify if the activity is legitimate.\n`;
  3606. alertDescriptions.push(desc);
  3607. }
  3608. const alertMsg = [...new Set(alertDescriptions)].join('\n');
  3609. showDialog(alertMsg);
  3610. }
  3611. addButton('generateDescription', 'Description', generateDescription);
  3612. }
  3613.  
  3614. function CarbonAlertHandler(...kwargs) {
  3615. var { summary, rawLog } = kwargs[0];
  3616. var raw_alert = 0;
  3617. const num_alert = $('#customfield_10300-val').text().trim();
  3618. function parseLog(rawLog) {
  3619. const alertInfo = rawLog.reduce((acc, log) => {
  3620. try {
  3621. const BraceIndex = log.toString().indexOf('{');
  3622. const lastBraceIndex = log.toString().lastIndexOf('}');
  3623. if (BraceIndex !== -1) {
  3624. json_text = log.toString().substr(BraceIndex, lastBraceIndex);
  3625. const json_alert = JSON.parse(json_text);
  3626. const {
  3627. reason,
  3628. device_os_version,
  3629. device_username,
  3630. device_location,
  3631. device_external_ip,
  3632. device_internal_ip,
  3633. device_name,
  3634. process_pid,
  3635. process_name,
  3636. process_sha256,
  3637. process_guid,
  3638. process_cmdline,
  3639. process_username,
  3640. netconn_remote_ip,
  3641. netconn_remote_port,
  3642. parent_guid,
  3643. parent_pid,
  3644. parent_name,
  3645. parent_sha256,
  3646. parent_username,
  3647. netconn_local_ip,
  3648. netconn_local_port,
  3649. first_event_timestamp
  3650. } = json_alert;
  3651. alertExtraInfo = {
  3652. EventTime: first_event_timestamp.split('.')[0],
  3653. device_name: device_name ? device_name : undefined,
  3654. device_os_version: device_os_version ? device_os_version : undefined,
  3655. device_username: device_username ? device_username : undefined,
  3656. device_location: device_location ? device_location : undefined,
  3657. device_external_ip: device_external_ip ? device_external_ip : undefined,
  3658. device_internal_ip: device_internal_ip ? device_internal_ip : undefined,
  3659. process_guid: process_guid ? process_guid : undefined,
  3660. process_pid: process_pid ? process_pid : undefined,
  3661. process_name: process_name ? process_name : undefined,
  3662. process_sha256: process_sha256 ? process_sha256 : undefined,
  3663. process_cmdline: process_cmdline ? process_cmdline : undefined,
  3664. process_username: process_username ? process_username : undefined,
  3665. parent_guid: parent_guid ? parent_guid : undefined,
  3666. parent_pid: parent_pid ? parent_pid : undefined,
  3667. parent_name: parent_name ? parent_name : undefined,
  3668. parent_sha256: parent_sha256 ? parent_sha256 : undefined,
  3669. parent_username: parent_username ? parent_username : undefined,
  3670. netconn_remote_ip: netconn_remote_ip ? netconn_remote_ip : undefined,
  3671. netconn_remote_port: netconn_remote_port ? netconn_remote_port : undefined,
  3672. netconn_local_ip: netconn_local_ip ? netconn_local_ip : undefined,
  3673. netconn_local_port: netconn_local_port ? netconn_local_port : undefined,
  3674. reason: reason ? reason : undefined
  3675. };
  3676. raw_alert += 1;
  3677. acc.push({ alertExtraInfo });
  3678. }
  3679. } catch (error) {
  3680. console.log(`Error: ${error.message}`);
  3681. }
  3682. return acc;
  3683. }, []);
  3684. return alertInfo;
  3685. }
  3686. const alertInfo = parseLog(rawLog);
  3687. function generateDescription() {
  3688. const alertDescriptions = [];
  3689. if (raw_alert < num_alert) {
  3690. let extra_message = `<span class="red_highlight">Number Of Alert : ${num_alert}, Raw Log Alert : ${raw_alert} Raw log information is Not Complete, Please Get More Alert Information From Elastic.</span>\n`;
  3691. alertDescriptions.push(extra_message);
  3692. }
  3693. for (const info of alertInfo) {
  3694. const lastindex = summary.lastIndexOf(']');
  3695. let desc = `Observed ${summary.substr(lastindex + 1)}\n`;
  3696. for (const key in info.alertExtraInfo) {
  3697. if (Object.hasOwnProperty.call(info.alertExtraInfo, key)) {
  3698. const value = info.alertExtraInfo[key];
  3699. if (key == 'EventTime') {
  3700. desc += `EventTime(<span class="red_highlight">GMT</span>): ${value + 'Z'}\n`;
  3701. } else if (value !== undefined) {
  3702. desc += `${key}: ${value}\n`;
  3703. }
  3704. }
  3705. }
  3706. desc += `\nPlease verify if the activity is legitimate.\n`;
  3707. alertDescriptions.push(desc);
  3708. }
  3709. const alertMsg = [...new Set(alertDescriptions)].join('\n');
  3710. showDialog(alertMsg);
  3711. }
  3712.  
  3713. addButton('generateDescription', 'Description', generateDescription);
  3714. }
  3715.  
  3716. function MultipleAccountAlertHandler(...kwargs) {
  3717. var { summary, rawLog } = kwargs[0];
  3718. function parseLog(rawLog) {
  3719. const alertInfo = rawLog.reduce((acc, log) => {
  3720. try {
  3721. const json_alert = JSON.parse(log)['win'];
  3722. const { targetUserName, targetDomainName, subjectUserName, subjectDomainName, subjectLogonId } =
  3723. json_alert['eventdata'];
  3724. const { systemTime, computer, message } = json_alert['system'];
  3725. alertExtraInfo = {
  3726. Eventtime: systemTime ? systemTime : undefined,
  3727. computer: computer ? computer : undefined,
  3728. targetUserName: targetUserName ? targetUserName : undefined,
  3729. targetDomainName: targetDomainName ? targetDomainName : undefined,
  3730. subjectUserName: subjectUserName ? subjectUserName : undefined,
  3731. subjectDomainName: subjectDomainName ? subjectDomainName : undefined,
  3732. message: message ? message.split('\r\n\r\n')[0] : undefined
  3733. };
  3734. acc.push({ alertExtraInfo });
  3735. } catch (error) {
  3736. console.log(`Error: ${error.message}`);
  3737. }
  3738. return acc;
  3739. }, []);
  3740. return alertInfo;
  3741. }
  3742. const alertInfo = parseLog(rawLog);
  3743. function generateDescription() {
  3744. const alertDescriptions = [];
  3745. const single = [];
  3746. const lastindex = summary.lastIndexOf(']');
  3747. let desc = `Observed ${summary.substr(lastindex + 1)}\n`;
  3748. for (const info of alertInfo) {
  3749. let desc_ = '',
  3750. single_ = '';
  3751. for (const key in info.alertExtraInfo) {
  3752. if (Object.hasOwnProperty.call(info.alertExtraInfo, key)) {
  3753. const value = info.alertExtraInfo[key];
  3754. if (value !== undefined) {
  3755. if (key == 'Eventtime') {
  3756. desc_ += `${key}(<span class="red_highlight">GMT</span>): ${value.split('.')[0] + 'Z'}\n`;
  3757. } else if (
  3758. key == 'subjectUserName' ||
  3759. key == 'subjectDomainName' ||
  3760. key == 'computer' ||
  3761. key == 'message' ||
  3762. key == 'targetDomainName'
  3763. ) {
  3764. single_ += `${key}: ${value}\n`;
  3765. } else {
  3766. desc_ += `${key}: ${value}\n`;
  3767. }
  3768. }
  3769. }
  3770. }
  3771. alertDescriptions.push(desc_);
  3772. single.push(single_);
  3773. }
  3774. desc += [...new Set(single)].join('\n');
  3775. desc += '\n';
  3776. desc += [...new Set(alertDescriptions)].join('\n');
  3777. desc += `Please verify if the activity is legitimate.\n`;
  3778. showDialog(desc);
  3779. }
  3780. addButton('generateDescription', 'Description', generateDescription);
  3781. }
  3782.  
  3783. /**
  3784. * Create Description and Open MDE and MDE365 button
  3785. * @param {...any} kwargs - Include LogSourceDomain, Labels, LogSource, TicketAutoEscalate, Status, RawLog, Summary fields
  3786. */
  3787. function MDE365AlertHandler(...kwargs) {
  3788. console.log('#### Code MDE365lertHandler run ####');
  3789. const { rawLog, LogSourceDomain, summary } = kwargs[0];
  3790. var raw_alert = 0;
  3791. const num_alert = $('#customfield_10300-val').text().trim();
  3792. let alertInfo_MDE = [],
  3793. alertInfo_365 = [];
  3794. function GMT8(params) {
  3795. let date = new Date(params);
  3796. date.setHours(date.getHours() + 16); // 获取当前的小时数并加上8小时
  3797. const year = date.getUTCFullYear();
  3798. const month = String(date.getUTCMonth() + 1).padStart(2, '0');
  3799. const day = String(date.getUTCDate()).padStart(2, '0');
  3800. const hours = String(date.getUTCHours()).padStart(2, '0');
  3801. const minutes = String(date.getUTCMinutes()).padStart(2, '0');
  3802. const seconds = String(date.getUTCSeconds()).padStart(2, '0');
  3803.  
  3804. const formattedDate = `${year}-${month}-${day}T${hours}:${minutes}:${seconds}`;
  3805. return formattedDate;
  3806. }
  3807. function parseLog(rawLog) {
  3808. const alertInfo = rawLog.reduce((acc, log) => {
  3809. let logObj = '';
  3810. if (log != '') {
  3811. try {
  3812. if (log.charAt(log.length - 1) == '}') {
  3813. const formatJson = log.substring(log.indexOf('{')).trim();
  3814. logObj = JSON.parse(formatJson.replace(/\\\(n/g, '\\n('));
  3815. } else {
  3816. const formatJson = log.substring(log.indexOf('{')).trim() + '"}]}}';
  3817. logObj = JSON.parse(formatJson.replace(/\\\(n/g, '\\n('));
  3818. }
  3819. if (logObj['integration'] == 'Wazuh-MDE') {
  3820. raw_alert += 1;
  3821. const { mde } = logObj;
  3822. const { title, id, computerDnsName, relatedUser, evidence, alertCreationTime } = mde;
  3823. let dotIndex = alertCreationTime.lastIndexOf('.');
  3824.  
  3825. let dateTimeStr = GMT8(alertCreationTime.slice(0, dotIndex));
  3826. const alert = { title, id, computerDnsName, dateTimeStr };
  3827. const userName = relatedUser ? relatedUser.userName : 'N/A';
  3828. let extrainfo = '';
  3829. let processCommandLine = '';
  3830. if (evidence) {
  3831. const tmp = [];
  3832. for (const evidenceItem of evidence) {
  3833. let description = '';
  3834.  
  3835. if (evidenceItem.entityType === 'File') {
  3836. console.log('===', WhiteFilehash(evidenceItem.sha1));
  3837. if (WhiteFilehash(evidenceItem.sha1) || WhiteFilehash(evidenceItem.sha256)) {
  3838. description = `filename: ${evidenceItem.fileName}\nfilePath: ${evidenceItem.filePath}`;
  3839. tmp.push(description);
  3840. } else {
  3841. description = `filename: ${evidenceItem.fileName}\nfilePath: ${evidenceItem.filePath}\nsha1: ${evidenceItem.sha1}`;
  3842. tmp.push(description);
  3843. }
  3844. }
  3845. if (evidenceItem.entityType === 'Process') {
  3846. if (evidenceItem.processCommandLine !== undefined) {
  3847. processCommandLine = evidenceItem.processCommandLine.replace(
  3848. /\r\n\r\n+/g,
  3849. '\n'
  3850. );
  3851. console.log(processCommandLine);
  3852. }
  3853. if (
  3854. evidenceItem.processCommandLine !== undefined &&
  3855. evidenceItem.processCommandLine.includes('EncodedCommand')
  3856. ) {
  3857. let cmd_length = evidenceItem.processCommandLine.split(' ').length;
  3858. description = `Decode_Cmd: ${atob(
  3859. evidenceItem.processCommandLine
  3860. .split(' ')
  3861. [cmd_length - 1].replace(/['"]/g, '')
  3862. )}`;
  3863. tmp.push(description);
  3864. }
  3865. if (WhiteFilehash(evidenceItem.sha1) || WhiteFilehash(evidenceItem.sha256)) {
  3866. description = `cmd: ${processCommandLine}\naccount: ${evidenceItem.accountName}`;
  3867. tmp.push(description);
  3868. } else {
  3869. description = `cmd: ${processCommandLine}\naccount: ${evidenceItem.accountName}\nsha1: ${evidenceItem.sha1}`;
  3870. tmp.push(description);
  3871. }
  3872. }
  3873. if (evidenceItem.entityType === 'Url') {
  3874. description += `Url: ${evidenceItem.url}`;
  3875. tmp.push(description);
  3876. }
  3877. if (evidenceItem.entityType === 'Ip') {
  3878. description += `IP: ${evidenceItem.ipAddress}`;
  3879. tmp.push(description);
  3880. }
  3881. }
  3882. const uniqueDescriptions = Array.from(new Set(tmp));
  3883. extrainfo = uniqueDescriptions.join('\n');
  3884. }
  3885. alertInfo_MDE.push({ ...alert, userName, extrainfo });
  3886. } else {
  3887. raw_alert += 1;
  3888. const alerts = logObj['incidents']['alerts'][0];
  3889. console.log(alerts);
  3890. let entities = {};
  3891. if (alerts !== undefined) {
  3892. alerts['entities'].forEach(function (entity) {
  3893. if (entity.processCommandLine !== undefined) {
  3894. processCommandLine = entity.processCommandLine.replace(/\r\n\r\n+/g, '\n');
  3895. console.log(processCommandLine);
  3896. }
  3897. if (entity['entityType'] == 'User' || entity['entityType'] == 'Mailbox') {
  3898. entities['user'] = `${entity['domainName']}\\\\${entity['accountName']}`;
  3899. entities['userPrincipalName'] = entity['userPrincipalName'];
  3900. }
  3901. if (entity['entityType'] == 'CloudApplication') {
  3902. entities['applicationId'] = entity['applicationId'];
  3903. entities['applicationName'] = entity['applicationName'];
  3904. }
  3905. if (entity['entityType'] == 'Process') {
  3906. if (!entities['process']) {
  3907. entities['process'] = [];
  3908. }
  3909. const fileEntry = {
  3910. filename: entity['fileName'],
  3911. filePath: entity['filePath'],
  3912. cmd: processCommandLine
  3913. };
  3914. if (processCommandLine.includes('EncodedCommand')) {
  3915. let cmd_length = processCommandLine.split(' ').length;
  3916. fileEntry['Decode_Cmd'] = atob(
  3917. processCommandLine.split(' ')[cmd_length - 1].replace(/['"]/g, '')
  3918. );
  3919. }
  3920. if (
  3921. Object.keys(entity).includes('sha256') &&
  3922. (WhiteFilehash(entity['sha256']) || WhiteFilehash(entity['sha1']))
  3923. ) {
  3924. entities['process'].push(fileEntry);
  3925. } else {
  3926. fileEntry['sha256'] = entity['sha256'];
  3927. entities['process'].push(fileEntry);
  3928. }
  3929. }
  3930.  
  3931. if (entity['entityType'] == 'File') {
  3932. if (!entities['file']) {
  3933. entities['file'] = [];
  3934. }
  3935. const fileEntry = {
  3936. filename: entity['fileName'],
  3937. filePath: entity['filePath']
  3938. };
  3939. if (
  3940. Object.keys(entity).includes('sha256') &&
  3941. (WhiteFilehash(entity['sha256']) || WhiteFilehash(entity['sha1']))
  3942. ) {
  3943. entities['file'].push(fileEntry);
  3944. } else {
  3945. fileEntry['sha256'] = entity['sha256'];
  3946. entities['file'].push(fileEntry);
  3947. }
  3948. }
  3949.  
  3950. if (entity['entityType'] == 'Ip') {
  3951. if (!entities['ip']) {
  3952. entities['ip'] = [];
  3953. }
  3954. entities['ip'].push({
  3955. ip: entity['ipAddress']
  3956. });
  3957. }
  3958. if (entity['entityType'] == 'Url') {
  3959. if (!entities['url']) {
  3960. entities['url'] = [];
  3961. }
  3962. entities['url'].push({
  3963. url: entity['url']
  3964. });
  3965. }
  3966. });
  3967. }
  3968. let creationTime = GMT8(alerts.creationTime.split('.')[0]);
  3969. let title = alerts?.title;
  3970. if (summary.toLowerCase().includes(title.toLowerCase())) {
  3971. title = undefined;
  3972. }
  3973. alertInfo_365.push({
  3974. creationTime: creationTime,
  3975. Title: title,
  3976. summary: logObj['incidents'].incidentName,
  3977. host: alerts?.devices[0]?.deviceDnsName,
  3978. user: entities.user,
  3979. userPrincipalName: entities.userPrincipalName,
  3980. process: entities.process,
  3981. file: entities.file,
  3982. ip: entities.ip,
  3983. url: entities.url,
  3984. alertid: alerts?.alertId,
  3985. incidenturi: logObj['incidents'].incidentUri,
  3986. severity: logObj['incidents'].severity,
  3987. description: alerts['description'],
  3988. applicationId: entities.applicationId,
  3989. applicationName: entities.applicationName
  3990. });
  3991. }
  3992. } catch (error) {
  3993. console.error(`Error: ${error.message}`);
  3994. }
  3995. }
  3996. return acc;
  3997. }, []);
  3998. return alertInfo;
  3999. }
  4000. const alertDescriptions = [];
  4001. parseLog(rawLog);
  4002.  
  4003. function generateDescription_MDE() {
  4004. for (const info of alertInfo_MDE) {
  4005. const { title, computerDnsName, userName, extrainfo, dateTimeStr } = info;
  4006. const desc = `Observed ${title}\nalertCreationTime(<span class="red_highlight">GMT+8</span>): ${dateTimeStr}\nHost: ${computerDnsName}\nusername: ${userName}\n${extrainfo}\n\nPlease help to verify if it is legitimate.\n`;
  4007. alertDescriptions.push(desc);
  4008. }
  4009. }
  4010. function generateDescription_365() {
  4011. if (summary.includes('M365 Defender High Severity Alerts: Logon from a risky country involving one user')) {
  4012. const ticketnumber = $('#key-val').text();
  4013. for (const info of alertInfo) {
  4014. let desc = `Dear Customer,
  4015. Reasons for escalating:
  4016. Observed Logon from a risky country involving one user in [time]
  4017. Here is information about this login:
  4018. creationTime(<span class="red_highlight"">GMT</span>): ${info.creationTime}
  4019. source IP: ${info.ip[0].ip}
  4020. user: ${info.user}
  4021. active: Microsoft 365
  4022. userPrincipalName: ${info.userPrincipalName}
  4023. Device type:
  4024. UserAgent:
  4025. location:
  4026. logging status:
  4027. LoginStatus:
  4028. MfaRequired:
  4029. the user suddenly logged in from [Location1] but the user used to be logged in from [Location2], aberdeen. Please confirm whether the login behavior of the user is normal.if not, could block the ip.
  4030. Suggestion: We suggest to confirm whether the behavior of this customer logging in at ${info.ip[0].ip}: is normal or not, if not, we suggest to block the IP and change the user's password and perform a full scan on the user's commonly used PCs, thank you!
  4031. Severity: ${info.severity}
  4032. Correlation ticket: ${ticketnumber}
  4033. `;
  4034. alertDescriptions.push(desc);
  4035. }
  4036. } else {
  4037. for (const info of alertInfo_365) {
  4038. let desc = `Observed ${info.summary}\n`;
  4039. try {
  4040. for (let key in info) {
  4041. if (info.hasOwnProperty(key)) {
  4042. if (Array.isArray(info[key])) {
  4043. info[key].forEach((item) => {
  4044. for (let subKey in item) {
  4045. if (item.hasOwnProperty(subKey) && item[subKey] !== '') {
  4046. desc += `${subKey}: ${item[subKey]}\n`;
  4047. }
  4048. }
  4049. });
  4050. } else {
  4051. if (
  4052. info[key] !== undefined &&
  4053. info[key] !== ' ' &&
  4054. key !== 'summary' &&
  4055. key !== 'alertid' &&
  4056. key !== 'incidenturi' &&
  4057. key !== 'severity'
  4058. ) {
  4059. if (key == 'creationTime') {
  4060. desc += `creationTime(<span class="red_highlight">GMT+8</span>): ${info[key]}\n`;
  4061. } else {
  4062. desc += `${key}: ${info[key]}\n`;
  4063. }
  4064. }
  4065. }
  4066. }
  4067. }
  4068. } catch (error) {
  4069. console.error(`Error: ${error}`);
  4070. }
  4071. let MDEURL = '';
  4072. if (LogSourceDomain == 'wkcda') {
  4073. if (info.alertid && !MDEURL.includes(info.alertid)) {
  4074. MDEURL += `https://security.microsoft.com/alerts/${info.alertid}<br>`;
  4075. }
  4076. if (info.incidenturi) {
  4077. let incident_url = info.incidenturi.replace('hXXps[:]', 'https:') + '<br>';
  4078. MDEURL += incident_url;
  4079. }
  4080. desc += `MDE URL: \n${MDEURL}\n`;
  4081. }
  4082.  
  4083. desc += `\nPlease verify if the activity is legitimate.\n`;
  4084. alertDescriptions.push(desc);
  4085. }
  4086. }
  4087. }
  4088. function generateDescription() {
  4089. if (raw_alert < num_alert) {
  4090. let extra_message = `<span class="red_highlight">Number Of Alert : ${num_alert}, Raw Log Alert : ${raw_alert} Raw log information is Not Complete, Please Get More Alert Information From Elastic.</span>\n`;
  4091. alertDescriptions.push(extra_message);
  4092. }
  4093. generateDescription_MDE();
  4094. generateDescription_365();
  4095. const alertMsg = [...new Set(alertDescriptions)].join('\n');
  4096. showDialog(alertMsg);
  4097. }
  4098. function openMDE() {
  4099. let MDEURL = '';
  4100. for (const info of alertInfo_MDE) {
  4101. const { id } = info;
  4102. if (id) {
  4103. MDEURL += `https://security.microsoft.com/alerts/${id}<br>`;
  4104. }
  4105. }
  4106. for (const info of alertInfo_365) {
  4107. const { alertid, incidenturi } = info;
  4108. if (alertid && !MDEURL.includes(alertid)) {
  4109. MDEURL += `https://security.microsoft.com/alerts/${alertid}<br>`;
  4110. }
  4111. if (incidenturi) {
  4112. let incident_url = incidenturi.replace('hXXps[:]', 'https:') + '<br>';
  4113. MDEURL += incident_url;
  4114. }
  4115. }
  4116. showFlag('info', 'MDE URL:', `${MDEURL}`, 'manual');
  4117. let url = 'https://security.microsoft.com/homepage?&current=';
  4118. url += LogSourceDomain;
  4119. for (let i = 0; i < MDEURL.length; i++) {
  4120. let mde_url = `&url${i}=${MDEURL[i]}`;
  4121. url += mde_url;
  4122. console.log(MDEURL[i]);
  4123. }
  4124. let MDE_Assist_ = localStorage.getItem('MDE_Assist');
  4125. if (MDE_Assist_ != 0) {
  4126. GM_openInTab(url, {
  4127. active: false, // 设置为 false,以在后台打开,不激活新标签页
  4128. insert: true // 设置为 true,将新标签页插入到当前标签页之后
  4129. });
  4130. }
  4131. }
  4132. addButton('generateDescription', 'Description', generateDescription);
  4133. addButton('openMDE', 'MDE', openMDE);
  4134. }
  4135.  
  4136. function WindowsSysAlertHandler(...kwargs) {
  4137. var { summary, rawLog } = kwargs[0];
  4138. function parseLog(rawLog) {
  4139. const alertInfo = rawLog.reduce((acc, log) => {
  4140. try {
  4141. if (log != '') {
  4142. let log_data = {},
  4143. sub = '';
  4144. log.split('#010').forEach((element, index) => {
  4145. if (element.includes('#013')) {
  4146. element = element.replace(/#013/g, '');
  4147. }
  4148. if (element.includes('#009')) {
  4149. let e = element.replace(/#009/g, '').split(':');
  4150. log_data[e[0]] = e[1];
  4151. }
  4152. if (element.includes('=')) {
  4153. let e = element.replace(/#013/g, '').split('=');
  4154. log_data[e[0]] = e[1];
  4155. }
  4156. if (element.includes(':#013')) {
  4157. sub = element.split(':')[0];
  4158. }
  4159. if (
  4160. element.includes(':#009') &&
  4161. (element.includes('Account') ||
  4162. element.includes('Security ID') ||
  4163. element.includes('Logon ID'))
  4164. ) {
  4165. let e = element.replace(/#009/g, ' ').replace(/#013/g, '').split(': ');
  4166. log_data[sub + e[0].trim()] = e[1];
  4167. }
  4168. if (element.includes(':#009')) {
  4169. let e = element.replace(/#009/g, ' ').replace(/#013/g, '').split(': ');
  4170. log_data[e[0].trim()] = e[1];
  4171. }
  4172. });
  4173. const regex = /(\S+\s+\S+\s+\S+\s+\S+\s+)(.*)/g;
  4174. alertExtraInfo = {
  4175. Event_time: regex.exec(log.split('#010')[0])[2],
  4176. ComputerName: log_data.ComputerName ? log_data.ComputerName : undefined,
  4177. EventCode: log_data.EventCode ? log_data.EventCode : undefined,
  4178. SourceName: log_data.SourceName ? log_data.SourceName : undefined,
  4179. CreatorAccountDomain: log_data['Creator SubjectAccount Domain']
  4180. ? log_data['Creator SubjectAccount Domain']
  4181. : undefined,
  4182. CreatorAccountName: log_data['Creator SubjectAccount Name']
  4183. ? log_data['Creator SubjectAccount Name']
  4184. : undefined,
  4185. Type: log_data.Type ? log_data.Type : undefined,
  4186. Keywords: log_data.Keywords ? log_data.Keywords : undefined,
  4187. Message: log_data.Message ? log_data.Message : undefined,
  4188. CreatorProcessID: log_data['Creator Process ID'] ? log_data['Creator Process ID'] : undefined,
  4189. CreatorProcessName: log_data['Creator Process Name']
  4190. ? log_data['Creator Process Name']
  4191. : undefined,
  4192. NewProcessID: log_data['New Process ID'] ? log_data['New Process ID'] : undefined,
  4193. NewProcessName: log_data['New Process Name'] ? log_data['New Process Name'] : undefined,
  4194. ProcessCommandLine: log_data['Process Command Line']
  4195. ? log_data['Process Command Line']
  4196. : undefined,
  4197. ProcessCommandLine: log_data['Process Command Line']
  4198. ? log_data['Process Command Line']
  4199. : undefined,
  4200. SecurityID: log_data['Security ID'] ? log_data['Security ID'] : undefined,
  4201. ServiceAccount: log_data['Service Account'] ? log_data['Service Account'] : undefined,
  4202. ServiceFileName: log_data['Service File Name'] ? log_data['Service File Name'] : undefined,
  4203. ServiceName: log_data['Service Name'] ? log_data['Service Name'] : undefined,
  4204. ServiceStartType: log_data['Service Start Type'] ? log_data['Service Start Type'] : undefined,
  4205. ServiceType: log_data['Service Type'] ? log_data['Service Type'] : undefined
  4206. };
  4207. acc.push({ alertExtraInfo });
  4208. }
  4209. } catch (error) {
  4210. console.log(`Error: ${error.message}`);
  4211. }
  4212. return acc;
  4213. }, []);
  4214. return alertInfo;
  4215. }
  4216. const alertInfo = parseLog(rawLog);
  4217. function generateDescription() {
  4218. const alertDescriptions = [];
  4219. for (const info of alertInfo) {
  4220. const lastindex = summary.lastIndexOf(']');
  4221. let desc = `Observed ${summary.substr(lastindex + 1)}\n`;
  4222. for (const key in info.alertExtraInfo) {
  4223. if (Object.hasOwnProperty.call(info.alertExtraInfo, key)) {
  4224. const value = info.alertExtraInfo[key];
  4225. if (value !== undefined) {
  4226. if (key == 'start_time' || key == 'end_time') {
  4227. desc += `${key}(<span class="red_highlight">GMT</span>): ${value.split('.')[0] + 'Z'}\n`;
  4228. } else {
  4229. desc += `${key}: ${value}\n`;
  4230. }
  4231. }
  4232. }
  4233. }
  4234. desc += `\nPlease verify if the activity is legitimate.\n`;
  4235. alertDescriptions.push(desc);
  4236. }
  4237. const alertMsg = [...new Set(alertDescriptions)].join('\n');
  4238. showDialog(alertMsg);
  4239. }
  4240. addButton('generateDescription', 'Description', generateDescription);
  4241. }
  4242.  
  4243. function ClarotyAlertHandler(...kwargs) {
  4244. var { summary, rawLog } = kwargs[0];
  4245. var raw_alert = 0;
  4246. const num_alert = $('#customfield_10300-val').text().trim();
  4247. function parseLog(rawLog) {
  4248. const alertInfo = rawLog.reduce((acc, log) => {
  4249. try {
  4250. if (log.length == 0) {
  4251. return acc;
  4252. }
  4253. const regex = /(\b\w+=)([^=\s].*?)(?=\s+\w+=|$)/g;
  4254. let match;
  4255. const matches = {};
  4256. while ((match = regex.exec(log)) !== null) {
  4257. let item = match[0].split('=');
  4258. matches[item[0]] = item.slice(1, item.length).join('=');
  4259. }
  4260. raw_alert += 1;
  4261. console.log(matches);
  4262. let logArray = log.split(' ').filter((item) => item !== ''); //Remove extra whitespace from the string
  4263. acc.push({
  4264. 'Event time': logArray.slice(0, 3).join(' '),
  4265. 'Extra information': logArray.slice(3, 8).join(' '),
  4266. 'CtdSourceIp': matches.CtdSourceIp ? matches.CtdSourceIp : undefined,
  4267. 'CtdDestinationIp': matches.CtdDestinationIp ? matches.CtdDestinationIp : undefined,
  4268. 'CtdMessage': matches.CtdMessage ? matches.CtdMessage : undefined,
  4269. 'CtdCategory': matches.CtdCategory ? matches.CtdCategory : undefined,
  4270. 'CtdSourceZone': matches.CtdSourceZone ? matches.CtdSourceZone : undefined,
  4271. 'CtdDestinationZone': matches.CtdDestinationZone ? matches.CtdDestinationZone : undefined,
  4272. 'CtdAlertLink': matches.CtdAlertLink ? matches.CtdAlertLink : undefined
  4273. });
  4274. } catch (error) {
  4275. console.log(`Error: ${error.message}`);
  4276. }
  4277. return acc;
  4278. }, []);
  4279. return alertInfo;
  4280. }
  4281. const alertInfo = parseLog(rawLog);
  4282. function generateDescription() {
  4283. const alertDescriptions = [];
  4284. if (raw_alert < num_alert) {
  4285. let extra_message = `<span class="red_highlight">Number Of Alert : ${num_alert}, Raw Log Alert : ${raw_alert} Raw log information is Not Complete, Please Get More Alert Information From Elastic.</span>\n`;
  4286. alertDescriptions.push(extra_message);
  4287. }
  4288. for (const info of alertInfo) {
  4289. const lastindex = summary.lastIndexOf(']');
  4290. let desc = `Observed ${summary.substr(lastindex + 1)}\n`;
  4291. for (const key in info) {
  4292. if (Object.hasOwnProperty.call(info, key)) {
  4293. const value = info[key];
  4294. if (value !== undefined) {
  4295. desc += `${key}: ${value}\n`;
  4296. }
  4297. }
  4298. }
  4299. desc += `\nPlease verify if the activity is legitimate.\n`;
  4300. alertDescriptions.push(desc);
  4301. }
  4302. const alertMsg = [...new Set(alertDescriptions)].join('\n');
  4303. showDialog(alertMsg);
  4304. }
  4305. addButton('generateDescription', 'Description', generateDescription);
  4306. }
  4307.  
  4308. function FireeyeAlertHandler(...kwargs) {
  4309. var { summary, rawLog } = kwargs[0];
  4310. var raw_alert = 0;
  4311. const num_alert = $('#customfield_10300-val').text().trim();
  4312. function parseLog(rawLog) {
  4313. const alertInfo = rawLog.reduce((acc, log) => {
  4314. try {
  4315. if (log.length == 0) {
  4316. return acc;
  4317. }
  4318. const regex = /(\b\w+=)([^=\s].*?)(?=\s+\w+=|$)/g;
  4319. let match;
  4320. const matches = {};
  4321. while ((match = regex.exec(log)) !== null) {
  4322. let item = match[0].split('=');
  4323. matches[item[0]] = item.slice(1, item.length).join('=');
  4324. }
  4325. raw_alert += 1;
  4326. let logArray = log.split(' ').filter((item) => item !== ''); //Remove extra whitespace from the string
  4327. acc.push({
  4328. 'Event time': logArray.slice(0, 3).join(' '),
  4329. 'Vlan': matches.cn1 ? matches.cn1 : undefined,
  4330. 'Sid': matches.cn2 ? matches.cn2 : undefined,
  4331. 'CncHost': matches.cs5 ? matches.cs5 : undefined,
  4332. 'CncPort': matches.cn3 ? matches.cn3 : undefined,
  4333. 'Sname': matches.cs1 ? matches.cs1 : undefined,
  4334. 'anomaly': matches.cs2 ? matches.cs2 : undefined,
  4335. 'Link': matches.cs4 ? matches.cs4 : undefined,
  4336. 'Channel': matches.cs6 ? matches.cs6 : undefined,
  4337. 'request': matches.request ? matches.request : undefined,
  4338. 'requestClientApplication': matches.requestClientApplication
  4339. ? matches.requestClientApplication
  4340. : undefined,
  4341. 'requestMethod': matches.requestMethod ? matches.requestMethod : undefined,
  4342. 'dst': matches.dst ? matches.dst : undefined,
  4343. 'dpt': matches.dpt ? matches.dpt : undefined,
  4344. 'src': matches.src ? matches.src : undefined,
  4345. 'spt': matches.spt ? matches.spt : undefined,
  4346. 'dvchost': matches.dvchost ? matches.dvchost : undefined,
  4347. 'dvc': matches.dvc ? matches.dvc : undefined
  4348. });
  4349. } catch (error) {
  4350. console.log(`Error: ${error.message}`);
  4351. }
  4352. return acc;
  4353. }, []);
  4354. return alertInfo;
  4355. }
  4356. const alertInfo = parseLog(rawLog);
  4357. function generateDescription() {
  4358. const alertDescriptions = [];
  4359. if (raw_alert < num_alert) {
  4360. let extra_message = `<span class="red_highlight">Number Of Alert : ${num_alert}, Raw Log Alert : ${raw_alert} Raw log information is Not Complete, Please Get More Alert Information From Elastic.</span>\n`;
  4361. alertDescriptions.push(extra_message);
  4362. }
  4363. for (const info of alertInfo) {
  4364. const lastindex = summary.lastIndexOf(']');
  4365. let desc = `Observed ${summary.substr(lastindex + 1)}\n`;
  4366. for (const key in info) {
  4367. if (Object.hasOwnProperty.call(info, key)) {
  4368. const value = info[key];
  4369. if (value !== undefined) {
  4370. desc += `${key}: ${value}\n`;
  4371. }
  4372. }
  4373. }
  4374. desc += `\nPlease verify if the activity is legitimate.\n`;
  4375. alertDescriptions.push(desc);
  4376. }
  4377. const alertMsg = [...new Set(alertDescriptions)].join('\n');
  4378. showDialog(alertMsg);
  4379. }
  4380. addButton('generateDescription', 'Description', generateDescription);
  4381. }
  4382.  
  4383. function WebAccesslogAlertHandler(...kwargs) {
  4384. var { summary, rawLog } = kwargs[0];
  4385. var raw_alert = 0;
  4386. function parseLog(rawLog) {
  4387. const alertInfo = rawLog.reduce((acc, log) => {
  4388. try {
  4389. if (log.length == 0) {
  4390. return acc;
  4391. }
  4392. const regex = /(\b\w+=)"([^"]*?)"/g;
  4393. const regex_ = /"(.*?)"/g;
  4394. let match;
  4395. const matches = {};
  4396. while ((match = regex.exec(log)) !== null) {
  4397. let item = match[0].split('=');
  4398. matches[item[0]] = item.slice(1, item.length).join('=');
  4399. }
  4400. let match_;
  4401. const matches_ = [];
  4402. while ((match_ = regex_.exec(log)) !== null) {
  4403. matches_.push(match_[0]);
  4404. }
  4405. console.log(matches);
  4406. console.log(matches_);
  4407. let logArray = log.split(' ').filter((item) => item !== ''); //Remove extra whitespace from the string
  4408. console.log(logArray);
  4409. acc.push({
  4410. 'Event time': logArray.slice(3, 5).join(' '),
  4411. 'Source_IP': logArray[0] ? logArray[0] : undefined,
  4412. // 'request_uri': matches.request_uri ? matches.request_uri : undefined,
  4413. 'URL': matches_[0] ? matches_[0] : undefined,
  4414. 'User-Agent': matches_[2] ? matches_[2] : undefined,
  4415. 'upstream_status': logArray[8] ? logArray[8] : undefined,
  4416. 'upstream_addr': matches.upstream_addr ? matches.upstream_addr : undefined,
  4417. 'sn': matches.sn ? matches.sn : undefined,
  4418. 'http_referrer': matches.http_referrer ? matches.http_referrer : undefined,
  4419. 'http_cookie': matches.http_cookie ? matches.http_cookie : undefined,
  4420. 'location': matches.location ? matches.location : undefined
  4421. });
  4422. } catch (error) {
  4423. console.log(`Error: ${error.message}`);
  4424. }
  4425. return acc;
  4426. }, []);
  4427. return alertInfo;
  4428. }
  4429. const alertInfo = parseLog(rawLog);
  4430. console.log(alertInfo);
  4431. function generateDescription() {
  4432. const alertDescriptions = [];
  4433. for (const info of alertInfo) {
  4434. const lastindex = summary.lastIndexOf(']');
  4435. let desc = `Observed ${summary.substr(lastindex + 1)}\n`;
  4436. for (const key in info) {
  4437. if (Object.hasOwnProperty.call(info, key)) {
  4438. const value = info[key];
  4439. if (value !== undefined && value !== '-' && value !== '"-"') {
  4440. desc += `${key}: ${value}\n`;
  4441. }
  4442. }
  4443. }
  4444. desc += `\nPlease verify if the activity is legitimate.\n`;
  4445. alertDescriptions.push(desc);
  4446. }
  4447. const alertMsg = [...new Set(alertDescriptions)].join('\n');
  4448. showDialog(alertMsg);
  4449. }
  4450. addButton('generateDescription', 'Description', generateDescription);
  4451. }
  4452.  
  4453. function FireeyeEtpAlertHandler(...kwargs) {
  4454. const { rawLog, summary } = kwargs[0];
  4455. var raw_alert = 0;
  4456. function parseLog(rawLog) {
  4457. const alertInfo = rawLog.reduce((acc, log) => {
  4458. try {
  4459. const { meta, alert, email } = JSON.parse(log)['fireeye'];
  4460. acc.push({
  4461. timestamp: alert['timestamp'],
  4462. accepted: email['timestamp']['accepted'],
  4463. last_malware: meta['last_malware'],
  4464. alert_type: meta['alert_type'],
  4465. status: email['status'],
  4466. source_ip: email['source_ip'],
  4467. rcpt_to: email['smtp']['rcpt_to'],
  4468. mail_from: email['smtp']['mail_from'],
  4469. etp_message_id: email['etp_message_id'],
  4470. To: email['headers']['to'],
  4471. From: email['headers']['from'],
  4472. Subject: email['headers']['subject'],
  4473. attachment: email['attachment']
  4474. });
  4475. raw_alert += 1;
  4476. } catch (error) {
  4477. console.log(`Error: ${error}`);
  4478. }
  4479. return acc;
  4480. }, []);
  4481. return alertInfo;
  4482. }
  4483.  
  4484. const alertInfo = parseLog(rawLog);
  4485. const num_alert = $('#customfield_10300-val').text().trim();
  4486. function generateDescription() {
  4487. const alertDescriptions = [];
  4488. if (raw_alert < num_alert) {
  4489. let extra_message = `<span class="red_highlight">Number Of Alert : ${num_alert}, Raw Log Alert : ${raw_alert} Raw log information is Not Complete, Please Get More Alert Information From Elastic.</span>\n`;
  4490. alertDescriptions.push(extra_message);
  4491. }
  4492. for (const info of alertInfo) {
  4493. let desc = `Observed ${summary.split(']')[1]}\n`;
  4494. Object.entries(info).forEach(([index, value]) => {
  4495. if (value !== undefined && value !== ' ' && index != 'Summary') {
  4496. if (index == 'timestamp') {
  4497. desc += `timestamp(<span class="red_highlight">GMT</span>): ${value.split('.')[0]}Z\n`;
  4498. } else if (index == 'accepted') {
  4499. desc += `accepted(<span class="red_highlight">GMT</span>): ${value}Z\n`;
  4500. } else {
  4501. desc += `${index}: ${value}\n`;
  4502. }
  4503. }
  4504. });
  4505. desc += `\nPlease verify if the activity is legitimate.\n`;
  4506. alertDescriptions.push(desc);
  4507. }
  4508. const alertMsg = [...new Set(alertDescriptions)].join('\n');
  4509. showDialog(alertMsg);
  4510. }
  4511. addButton('generateDescription', 'Description', generateDescription);
  4512. }
  4513.  
  4514. function SentinelOneAlertHandler(...kwargs) {
  4515. const { rawLog, summary } = kwargs[0];
  4516. var raw_alert = 0;
  4517. function parseLog(rawLog) {
  4518. const alertInfo = rawLog.reduce((acc, log) => {
  4519. try {
  4520. console.log('===sentinel_one');
  4521. const sentinel_one = JSON.parse(log)['sentinel_one'];
  4522. acc.push({
  4523. timestamp: sentinel_one.threatInfo.createdAt.split('.')[0],
  4524. accountName: sentinel_one.accountName,
  4525. agentDomain: sentinel_one.agentDomain,
  4526. agentIpV4: sentinel_one.agentIpV4,
  4527. agentOsName: sentinel_one.agentOsName,
  4528. agentMitigationMode: sentinel_one.agentMitigationMode,
  4529. filePath: sentinel_one.threatInfo.filePath,
  4530. sha1: sentinel_one.threatInfo.sha1,
  4531. confidenceLevel: sentinel_one.threatInfo.filePath,
  4532. threatName: sentinel_one.threatInfo.threatName,
  4533. processUser: sentinel_one.threatInfo.processUser
  4534. });
  4535. raw_alert += 1;
  4536. } catch (error) {
  4537. console.log(`Error: ${error}`);
  4538. }
  4539. return acc;
  4540. }, []);
  4541. return alertInfo;
  4542. }
  4543.  
  4544. const alertInfo = parseLog(rawLog);
  4545. const num_alert = $('#customfield_10300-val').text().trim();
  4546. function generateDescription() {
  4547. const alertDescriptions = [];
  4548. if (raw_alert < num_alert) {
  4549. let extra_message = `<span class="red_highlight">Number Of Alert : ${num_alert}, Raw Log Alert : ${raw_alert} Raw log information is Not Complete, Please Get More Alert Information From Elastic.</span>\n`;
  4550. alertDescriptions.push(extra_message);
  4551. }
  4552. for (const info of alertInfo) {
  4553. let desc = `Observed ${summary.split(']')[1]}\n`;
  4554. Object.entries(info).forEach(([index, value]) => {
  4555. if (value !== undefined && value !== ' ' && index != 'Summary') {
  4556. if (index == 'timestamp') {
  4557. desc += `timestamp(<span class="red_highlight">GMT</span>): ${value.split('.')[0]}Z\n`;
  4558. } else {
  4559. desc += `${index}: ${value}\n`;
  4560. }
  4561. }
  4562. });
  4563. desc += `\nPlease verify if the activity is legitimate.\n`;
  4564. alertDescriptions.push(desc);
  4565. }
  4566. const alertMsg = [...new Set(alertDescriptions)].join('\n');
  4567. showDialog(alertMsg);
  4568. }
  4569. addButton('generateDescription', 'Description', generateDescription);
  4570. }
  4571.  
  4572. function LHG_CS_AlertHandler(DecoderName) {
  4573. let ORG = $('#customfield_10002-val').text().trim();
  4574. console.log(ORG.split(' ')[ORG.split(' ').length - 1]);
  4575. const elements = document.querySelectorAll('.user-hover.user-avatar');
  4576. const userList = ['kitty.li', 'anson.cho', 'ray.tan', 'philip.ng'];
  4577. console.log(elements[0].textContent.toLowerCase()); // 对每个元素执行操作
  4578. let ClientComment = false;
  4579. for (const dataItem of userList) {
  4580. if (elements[0].textContent.toLowerCase().includes(dataItem.toLowerCase())) {
  4581. ClientComment = true;
  4582. break;
  4583. }
  4584. }
  4585. //判断工单是否升级,
  4586. if (ORG.split(' ')[ORG.split(' ').length - 1] == 'None' && DecoderName == 'crowdstrike_cef') {
  4587. $('#opsbar-opsbar-transitions').on('click', () => {
  4588. let userConfirmed = confirm('LHG的所有 Crowdstrike 告警均需要升级,即使是误报也需要升级');
  4589. });
  4590. } else {
  4591. if (!ClientComment) {
  4592. $('#opsbar-opsbar-transitions').on('click', () => {
  4593. let userConfirmed = confirm(
  4594. '只有这四个客户回复philip.ng,ray.tan,anson.cho,kitty.li,才可关单,若以上四个客户已允许close,可忽略此提示'
  4595. );
  4596. });
  4597. }
  4598. }
  4599. }
  4600.  
  4601. function RealMonitorMe() {
  4602. let ORG = $('#customfield_10002-val').text().trim();
  4603. let status = $('#opsbar-transitions_more').text().trim();
  4604. if ($('#customfield_10302-val').text().trim().includes('\n')) {
  4605. let rules = $('#customfield_10302-val').text().trim().split(' \n')[1].split('\n');
  4606. if (rules.length - 1 >= 3 && status == 'Work in progress') {
  4607. confirm(
  4608. `检测到该工单的RuleName${
  4609. rules.length - 1
  4610. }个,(如果同一张tickets出现三个告警及以上,需要往cortex群里发,如果是误报请描述原因,谢谢)`
  4611. );
  4612. }
  4613. }
  4614. const intervalId = setInterval(() => {
  4615. var element_one = document.getElementById('opsbar-opsbar-transitions');
  4616. var first = element_one ? element_one.textContent || element_one.innerText : null;
  4617. if (first == 'Resolved') {
  4618. clearInterval(intervalId);
  4619. }
  4620. if (first == 'Waiting for customer' && ORG.split(' ')[ORG.split(' ').length - 1] == 'None') {
  4621. console.log('===发生了改变', first);
  4622. confirm('请注意,该工单变为Waiting for customer,请检查该工单是否已添加ORG');
  4623. first = 'Waiting for customer';
  4624. clearInterval(intervalId);
  4625. }
  4626. }, 500);
  4627. }
  4628.  
  4629. function formatCurrentDateTime(dateStr, decoder_name) {
  4630. if (dateStr) {
  4631. var date = new Date(dateStr);
  4632. var localOffset = date.getTimezoneOffset();
  4633. if (decoder_name == 'impervainc_cef') {
  4634. var targetDate = new Date(date.getTime() + (480 + localOffset) * 60000);
  4635. } else {
  4636. var targetDate = new Date(date.getTime() + (960 + localOffset) * 60000);
  4637. }
  4638. var year = targetDate.getFullYear();
  4639. var month = ('0' + (targetDate.getMonth() + 1)).slice(-2);
  4640. var day = ('0' + targetDate.getDate()).slice(-2);
  4641. var hours = ('0' + targetDate.getHours()).slice(-2);
  4642. var minutes = ('0' + targetDate.getMinutes()).slice(-2);
  4643. var seconds = ('0' + targetDate.getSeconds()).slice(-2);
  4644. return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
  4645. }
  4646. const pad = (num) => (num < 10 ? '0' : '') + num;
  4647. const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
  4648. const date_ = new Date();
  4649.  
  4650. const day_ = date_.getDate();
  4651. const month_ = months[date_.getMonth()];
  4652. const year_ = date_.getFullYear().toString().slice(-2); // 取最后两位
  4653. const hours_ = date_.getHours();
  4654. const minutes_ = date_.getMinutes();
  4655. const ampm = hours_ >= 12 ? 'PM' : 'AM';
  4656. const hour = hours_ % 12 || 12; // Convert to 12-hour format and handle 0 case
  4657.  
  4658. return `${pad(day_)}/${month_}/${year_} ${pad(hour)}:${pad(minutes_)} ${ampm}`;
  4659. }
  4660.  
  4661. function MonitorDev() {
  4662. function formatDate() {
  4663. const date = new Date();
  4664. const day = String(date.getDate()).padStart(2, '0'); // 日期补齐两位数
  4665. const month = date.toLocaleString('en-US', { month: 'short' }); // 获取月份缩写
  4666. const year = String(date.getFullYear()).slice(-2); // 取年份的后两位
  4667.  
  4668. let hours = date.getHours();
  4669. const minutes = String(date.getMinutes()).padStart(2, '0');
  4670. const ampm = hours >= 12 ? 'PM' : 'AM';
  4671.  
  4672. hours = hours % 12; // 将24小时制转换为12小时制
  4673. hours = hours ? hours : 12; // 如果是0点,将其转换为12
  4674. hours = String(hours).padStart(2, '0'); // 补齐小时为两位数
  4675.  
  4676. return `${day}/${month}/${year} ${hours}:${minutes} ${ampm}`;
  4677. }
  4678. let white = JSON.parse(localStorage.getItem('whitelist'));
  4679.  
  4680. if (window.location.href.includes('/portal/2/create/100')) {
  4681. const interval = setInterval(() => {
  4682. var iframe = document.getElementById('rw_iframe');
  4683. var iframeDocument = iframe.contentDocument || iframe.contentWindow.document;
  4684. var element = iframeDocument.getElementById('summary');
  4685. if (element) {
  4686. let summary = 'Whitelist ' + white['summary'].replace('Wazuh', white['LogSourceDomain']);
  4687. iframeDocument.getElementById('summary').value = summary;
  4688. iframeDocument.getElementById('s2id_labels').innerHTML =
  4689. `<ul class="select2-choices"> <li class="select2-search-choice"> <div>` +
  4690. white['LogSourceDomain'] +
  4691. `</div> <a href="#" class="select2-search-choice-close" tabindex="-1"></a></li><li class="select2-search-field"> <input type="text" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" class="select2-input" id="s2id_autogen1" style="width: 10px;"> </li></ul>`;
  4692. iframeDocument.getElementById('labels').value = white['LogSourceDomain'];
  4693. iframeDocument.getElementById('customfield_14601').value = formatDate();
  4694. iframeDocument.getElementById('customfield_14600').value = formatDate();
  4695. iframeDocument.getElementById('customfield_14610').value = 'Yes';
  4696. iframeDocument.getElementById('customfield_14609').value = 'Yes';
  4697. iframeDocument.getElementById('customfield_14608').value = 'Yes';
  4698. clearInterval(interval);
  4699. }
  4700. }, 600);
  4701. }
  4702. let cachedEntry = GM_getValue('cachedEntry', null);
  4703. if (window.location.href.includes('/servlet/desk/portal/2') && window.location.href.includes('DEV')) {
  4704. window.location.href = `${cachedEntry['hk']}/browse/` + window.location.href.split('portal/2/')[1];
  4705. localStorage.setItem('Dev_link', window.location.href.split('portal/2/')[1]);
  4706. }
  4707. if (window.location.href.includes(localStorage.getItem('Dev_link'))) {
  4708. document.getElementById('edit-issue').click();
  4709. const interval = setInterval(() => {
  4710. const components = document.querySelector('#components-textarea');
  4711. if (components) {
  4712. $('#components-textarea').val(white['Component']);
  4713. $('#components-textarea').click();
  4714. $('#issuelinks-issues-textarea').val(white['MSS'].split('browse/')[1]);
  4715. $('#tab-0').click();
  4716. localStorage.removeItem('Dev_link');
  4717. clearInterval(interval);
  4718. }
  4719. }, 500);
  4720. }
  4721. }
  4722.  
  4723. function WhiteFilehash(filehash) {
  4724. if (filehash == undefined) {
  4725. return 0;
  4726. }
  4727. const cachedWhitehashContent = GM_getValue('cachedWhitehashContent', null);
  4728. for (const f of cachedWhitehashContent) {
  4729. if (filehash.includes(f['hash'].toLowerCase())) {
  4730. console.log('命中了', filehash);
  4731. return true;
  4732. }
  4733. }
  4734. }
  4735.  
  4736. function RealTimeMonitoring() {
  4737. // Filter page: audio control registration and regular issues table update
  4738. if (
  4739. (window.location.href.includes('filter=15200') ||
  4740. window.location.href.includes('filter=26405') ||
  4741. window.location.href.includes('filter=13300')) &&
  4742. !window.location.href.includes('MSS')
  4743. ) {
  4744. console.log('#### Code includes filter run ####');
  4745. const NotifyControls = createNotifyControls();
  4746. if (window.location.href.includes('filter=15200') || window.location.href.includes('filter=26405')) {
  4747. setInterval(() => {
  4748. notifyKey = [];
  4749. $('.aui-button.aui-button-primary.search-button').click();
  4750. setTimeout(() => {
  4751. checkupdate(NotifyControls);
  4752. }, 10000);
  4753. }, 180000);
  4754. }
  4755. if (window.location.href.includes('filter=13300')) {
  4756. setInterval(() => {
  4757. notifyKey = [];
  4758. $('.aui-button.aui-button-primary.search-button').click();
  4759. setTimeout(() => {
  4760. monitorList();
  4761. }, 10000);
  4762. }, 60000);
  4763. }
  4764. }
  4765. if (window.location.href.includes('login.microsoftonline.com')) {
  4766. setTimeout(() => {
  4767. switch_user_microsoft();
  4768. }, 2000);
  4769. }
  4770. if (window.location.href.includes('security.microsoft.com/homepage?&current=')) {
  4771. setTimeout(() => {
  4772. security_microsoft();
  4773. }, 3000);
  4774. }
  4775. // Issue page: Alert Handler
  4776. const generation_description = setInterval(() => {
  4777. var LogSourceDomain = $('#customfield_10223-val').text().trim();
  4778. let rawLog = $('#field-customfield_10219 > div:first-child > div:nth-child(2)').text().trim().split('\n');
  4779. if (rawLog == '') {
  4780. rawLog = $('#field-customfield_10904 > div:first-child > div:nth-child(2)').text().trim().split('\n');
  4781. }
  4782. const summary = $('#summary-val').text().trim();
  4783. if ($('#issue-content').length && !$('#generateDescription').length) {
  4784. console.log('#### Code Issue page: Alert Handler ####');
  4785. const handlers = {
  4786. 'cortex-xdr-json': cortexAlertHandler,
  4787. 'mde-api-json': MDE365AlertHandler,
  4788. 'sangfor-ccom-json': HTSCAlertHandler,
  4789. 'carbonblack': CBAlertHandler,
  4790. 'carbonblack_cef': VMCEFAlertHandler,
  4791. 'windows_eventchannel': WineventAlertHandler,
  4792. 'fortigate-firewall-v5': FortigateAlertHandler,
  4793. 'crowdstrike_cef': CSAlertHandler,
  4794. 'sophos': SophosAlertHandler,
  4795. 'sepm-security': SpemAlertHandler,
  4796. 'sepm-traffic': SpemAlertHandler,
  4797. 'vmwarecarbonblack_cef': VMCEFAlertHandler,
  4798. 'aws-cloudtrail': AwsAlertHandler,
  4799. 'aws-cisco-umbrella': AwsAlertHandler,
  4800. 'm365-defender-json': MDE365AlertHandler,
  4801. 'azureeventhub': AzureAlertHandler,
  4802. 'azuregraphapi-json': AzureGraphAlertHandler,
  4803. 'paloalto-firewall': paloaltoAlertHandler,
  4804. 'impervainc_cef': SangforAlertHandler,
  4805. 'proofpoint_tap': ProofpointAlertHandler,
  4806. 'zscaler-zpa-json': ZscalerAlertHandler,
  4807. 'pulse-secure': PulseAlertHandler,
  4808. 'aws-guardduty': AwsAlertHandler,
  4809. 'alicloud-json': AlicloudAlertHandler,
  4810. 'darktrace-json': DarktraceAlertHandler,
  4811. 'sangfor_cef': SangforAlertHandler,
  4812. 'cyberark_cef': SangforAlertHandler,
  4813. 'radware-json': RadwareAlertHandler,
  4814. 'carbonblack_cloud': CarbonAlertHandler,
  4815. 'windows-syslog': WindowsSysAlertHandler,
  4816. 'claroty_cef': ClarotyAlertHandler,
  4817. 'office-365': Risky_Countries_AlertHandler,
  4818. 'fireeye': FireeyeAlertHandler,
  4819. 'web-accesslog': WebAccesslogAlertHandler,
  4820. 'checkpoint_cef': SangforAlertHandler,
  4821. 'incapsula_cef': SangforAlertHandler,
  4822. 'fireeye-etp-json': FireeyeEtpAlertHandler,
  4823. 'sentinelone-json': SentinelOneAlertHandler,
  4824. 'sonicwall': FortigateAlertHandler,
  4825. 'trellix_cef': SangforAlertHandler
  4826. };
  4827. let DecoderName = $('#customfield_10807-val').text().trim().toLowerCase();
  4828. if (DecoderName == '') {
  4829. DecoderName = $('#customfield_10906-val').text().trim().toLowerCase();
  4830. }
  4831. if (DecoderName.includes('m365-defender-json')) {
  4832. let decoder_name = [];
  4833. DecoderName.split(' ').forEach((element, index) => {
  4834. if (element != 'hide\n' && element != '' && element != 'show\n' && element != '\n') {
  4835. decoder_name.push(element);
  4836. }
  4837. });
  4838. if (decoder_name[0].includes('m365-defender-json\n')) {
  4839. DecoderName = 'm365-defender-json';
  4840. }
  4841. }
  4842. const handler = handlers[DecoderName];
  4843. if (handler) {
  4844. handler({ LogSourceDomain: LogSourceDomain, rawLog: rawLog, summary: summary });
  4845. }
  4846. const No_Decoder_handlers = {
  4847. 'detect aad, o365 sign-in from risky countries': Risky_Countries_AlertHandler,
  4848. 'successful azure/o365 login from malware-ip': Risky_Countries_AlertHandler,
  4849. 'rarely country signin from o365': Risky_Countries_AlertHandler,
  4850. 'agent disconnected': Agent_Disconnect_AlertHandler,
  4851. 'suspicious geolocation ip login success': PulseAlertHandler,
  4852. 'login success from malware ip(s)': ThreatMatrixAlertHandler,
  4853. 'multiple account being disabled or deleted in short period of time': MultipleAccountAlertHandler,
  4854. 'multiple sms request for same source ip': AwsAlertHandler
  4855. };
  4856. const Summary = $('#summary-val').text().trim();
  4857. let No_Decoder_handler = null;
  4858. Object.keys(No_Decoder_handlers).forEach((key) => {
  4859. if (Summary.toLowerCase().includes(key)) {
  4860. No_Decoder_handler = No_Decoder_handlers[key];
  4861. }
  4862. });
  4863. if (No_Decoder_handler !== null) {
  4864. No_Decoder_handler({ LogSourceDomain: LogSourceDomain, rawLog: rawLog, summary: Summary });
  4865. }
  4866. if (LogSourceDomain == '') {
  4867. LogSourceDomain = $('#customfield_10846-val').text().trim();
  4868. }
  4869. const Log_Domain_handlers = {
  4870. mdb: MdbAlertHandler, //这里面有点工单为decoder name:sshd
  4871. dst: DstAlertHandler
  4872. };
  4873. const Log_Domain_handler = Log_Domain_handlers[LogSourceDomain];
  4874. if (Log_Domain_handler) {
  4875. Log_Domain_handler({ LogSourceDomain: LogSourceDomain, rawLog: rawLog, summary: summary });
  4876. }
  4877. clearInterval(generation_description);
  4878. }
  4879. }, 1000);
  4880. // Issue page: check Keywords and ATT&CK and Org
  4881. setTimeout(() => {
  4882. if ($('#issue-content').length && !$('.aui-banner-error').length) {
  4883. console.log('#### Code Issue page: check Keywords ####');
  4884. checkKeywords();
  4885. checkATTCK();
  4886. }
  4887. }, 4500);
  4888.  
  4889. // Issue page: Edit Notify
  4890. setTimeout(() => {
  4891. let LogSourceDomain,
  4892. Source,
  4893. Labels,
  4894. LogSource,
  4895. DecoderName,
  4896. TicketAutoEscalate,
  4897. Status,
  4898. RawLog,
  4899. Summary,
  4900. AgentName;
  4901. let cachedEntry = GM_getValue('cachedEntry', null);
  4902. if (window.location.host === cachedEntry['hk'].split('//')[1]) {
  4903. // for HK
  4904. LogSourceDomain = $('#customfield_10223-val').text().trim();
  4905. Source = $('#customfield_10113-val').text().trim();
  4906. Labels = $('.labels-wrap .labels li a span').text();
  4907. LogSource = $('#customfield_10204-val').text().trim();
  4908. DecoderName = $('#customfield_10807-val').text().trim().toLowerCase();
  4909. TicketAutoEscalate = $('#customfield_12202-val').text().trim();
  4910. Status = $('#status-val > span').text().trim();
  4911. RawLog =
  4912. $('#field-customfield_10219 > div:first-child > div:nth-child(2)').text().trim() ||
  4913. $('#customfield_10219-val').text().trim() ||
  4914. $('#field-customfield_10232 > div.twixi-wrap.verbose > div > div > div > pre').text();
  4915. Summary = $('#summary-val').text().trim();
  4916. AgentName = $('#customfield_10805-val').text().trim();
  4917. } else if (window.location.host === cachedEntry['macao'].split('//')[1]) {
  4918. // for MO
  4919. LogSourceDomain = $('#customfield_10846-val').text().trim();
  4920. Source = $('#customfield_10872-val').text().trim();
  4921. Labels = $('#labels-212244-value').text().trim();
  4922. LogSource = $('#customfield_10854-val').text().trim();
  4923. DecoderName = $('#customfield_10906-val').text().trim();
  4924. TicketAutoEscalate = $('#customfield_10893-val').text().trim();
  4925. Status = $('#status-value > span').text().trim();
  4926. RawLog = $('#field-customfield_10904 > div.twixi-wrap.verbose > div').text().trim();
  4927. Summary = $('#summary-val').text().trim();
  4928. AgentName = $('#customfield_10802-val').text().trim();
  4929. }
  4930.  
  4931. const pageData = {
  4932. LogSourceDomain,
  4933. Source,
  4934. Labels,
  4935. LogSource,
  4936. DecoderName,
  4937. TicketAutoEscalate,
  4938. Status,
  4939. RawLog,
  4940. Summary,
  4941. AgentName
  4942. };
  4943.  
  4944. // If it pops up once, it will not be reminded again
  4945. if (
  4946. ($('#issue-content').length &&
  4947. !$('#generateTicketNotify').length &&
  4948. window.location.href.includes('MSS')) ||
  4949. window.location.href.includes('OPS')
  4950. ) {
  4951. addButton('towhitelist', 'WhiteList', ToWhitelist);
  4952. ticketNotify(pageData);
  4953. }
  4954. }, 1000);
  4955.  
  4956. // Issue page: Norm Alert
  4957. setTimeout(() => {
  4958. var LogSourceDomain = $('#customfield_10223-val').text().trim();
  4959. let DecoderName = $('#customfield_10807-val').text().trim().toLowerCase();
  4960. if (DecoderName == '') {
  4961. DecoderName = $('#customfield_10906-val').text().trim().toLowerCase();
  4962. }
  4963. if (LogSourceDomain.includes('lhg')) {
  4964. LHG_CS_AlertHandler(DecoderName);
  4965. }
  4966. }, 3500);
  4967.  
  4968. // Issue page: Quick Reply
  4969. setInterval(() => {
  4970. if (document.querySelector('#reply') == null) {
  4971. QuickReply();
  4972. }
  4973. }, 3000);
  4974. }
  4975.  
  4976. (function () {
  4977. ('use strict');
  4978. RealTimeMonitoring();
  4979.  
  4980. registerSearchMenu();
  4981. registerExceptionMenu();
  4982. registerCustomQuickReplyMenu();
  4983. addCss();
  4984. MonitorDev();
  4985. AJS.whenIType('zv').execute(function () {
  4986. document.getElementById('opsbar-transitions_more').click();
  4987. const interval = setInterval(() => {
  4988. const element = document.querySelector('#action_id_761');
  4989. if (element) {
  4990. document.getElementById('action_id_761').click();
  4991. clearInterval(interval);
  4992. }
  4993. }, 100); // 每100毫秒检查一次
  4994. });
  4995. AJS.whenIType('zx').execute(function () {
  4996. document.getElementById('edit-issue').click();
  4997. const interval = setInterval(() => {
  4998. const tabsMenu = document.querySelector('#horizontal');
  4999. const elements = tabsMenu.querySelectorAll('*');
  5000. const elementsArray = Array.from(elements);
  5001. const reviewElement = elementsArray.find((element) => element.outerText.trim() === 'Review');
  5002. if (reviewElement) {
  5003. const menuItem = reviewElement.querySelector('.menu-item a');
  5004. const idValue = menuItem.id;
  5005. const element = document.querySelector('#' + idValue);
  5006. if (element) {
  5007. document.getElementById(idValue).click();
  5008. $('#customfield_17201').val(formatCurrentDateTime());
  5009. const metaElement = document
  5010. .querySelector('meta[name="ajs-remote-user-fullname"]')
  5011. .getAttribute('content');
  5012. $('#customfield_17203-field').val(metaElement);
  5013. document.getElementById('customfield_17203-field').click();
  5014. clearInterval(interval);
  5015. }
  5016. }
  5017. }, 500);
  5018. const intervals = setInterval(() => {
  5019. const element1 = document.querySelector('#showing-1-of-1-matching-users');
  5020. console.log(element1);
  5021. if (element1) {
  5022. document.querySelector('#showing-1-of-1-matching-users li').click();
  5023. clearInterval(intervals);
  5024. }
  5025. }, 500);
  5026. });
  5027. RealMonitorMe();
  5028. })();