mahldcat

BlackBeltPageWatch

Jun 2nd, 2020
118
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 5.97 KB | None | 0 0
  1. using Newtonsoft.Json;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.IO;
  5. using System.Linq;
  6. using System.Net;
  7. using System.Net.Mail;
  8. using System.Security.Cryptography;
  9. using System.Text;
  10. using System.Threading;
  11. using System.Threading.Tasks;
  12.  
  13. namespace BlackBeltWatcher
  14. {
  15.     /// <summary>
  16.     /// this is a super stripped down object that represents a discord message
  17.     /// that is used with the webhook API
  18.     /// </summary>
  19.     class WebHookMessage
  20.     {
  21.         public string username { get; set; }
  22.         public string content { get; set; }
  23.     }
  24.  
  25.     class Program
  26.     {
  27.         /// <summary>
  28.         /// used for calculating the hash of the website to monitor....
  29.         /// </summary>
  30.         static SHA256 shaHash;
  31.  
  32.         /// <summary>
  33.         /// static counter to track how many updates are detected
  34.         /// </summary>
  35.         static int changesDetected = 0;
  36.  
  37.         /// <summary>
  38.         /// the Discord webhook url to send message notifications to
  39.         /// </summary>
  40.         static string webHook = null;
  41.        
  42.         /// <summary>
  43.         /// Generate the message to post into my private discord channel using the Site Update Bot user...
  44.         /// </summary>
  45.         /// <param name="content"></param>
  46.         /// <returns></returns>
  47.         static byte[] GenerateDiscordMessage(string content)
  48.         {
  49.             WebHookMessage msg = new WebHookMessage
  50.             {
  51.                 username = "Site Update Bot",
  52.                 content = content
  53.             };
  54.  
  55.             string body = JsonConvert.SerializeObject(msg);
  56.             byte[] data = Encoding.ASCII.GetBytes(body);
  57.             return data;
  58.         }
  59.  
  60.         /// <summary>
  61.         /// wrapper function for the message to use when this detects a page update
  62.         /// </summary>
  63.         /// <param name="url"></param>
  64.         /// <param name="changeCount"></param>
  65.         /// <returns></returns>
  66.         static byte[] GenerateDiscordMessage(string url, int changeCount)
  67.         {
  68.             return GenerateDiscordMessage(string.Format("Page Update [changes:{0}]: {1}", changeCount, url));
  69.         }
  70.  
  71.  
  72.         /// <summary>
  73.         /// thank god for the webhooks API...there is a different API
  74.         /// for discord that I
  75.         /// </summary>
  76.         /// <param name="data"></param>
  77.         /// <returns></returns>
  78.         static HttpStatusCode SendDiscordMessage(byte[] data)
  79.         {
  80.  
  81.             WebRequest request = WebRequest.Create(webHook);
  82.             request.Method = "POST";
  83.             request.ContentType = "application/json";
  84.             request.ContentLength = data.Length;
  85.  
  86.             Stream stream = request.GetRequestStream();
  87.             stream.Write(data, 0, data.Length);
  88.             stream.Close();
  89.  
  90.             HttpWebResponse response = request.GetResponse() as HttpWebResponse;
  91.             stream = response.GetResponseStream();
  92.  
  93.             StreamReader sr = new StreamReader(stream);
  94.             string result = sr.ReadToEnd();
  95.             Console.WriteLine(result);
  96.  
  97.             sr.Close();
  98.             stream.Close();
  99.  
  100.             return response.StatusCode;
  101.         }
  102.  
  103.         static void GeneralDiscordAlert(string msg)
  104.         {
  105.             byte[] data = GenerateDiscordMessage(msg);
  106.             SendDiscordMessage(data);
  107.         }
  108.  
  109.  
  110.         static void DiscordAlert(string url, int changeCount)
  111.         {
  112.             byte[] data = GenerateDiscordMessage(url,changeCount);
  113.             SendDiscordMessage(data);
  114.         }
  115.  
  116.         static string ComputeHash(byte[] body)
  117.         {
  118.             byte[] hash = shaHash.ComputeHash(body);
  119.             return BitConverter.ToString(hash).Replace("-", "");
  120.         }
  121.  
  122.         /// <summary>
  123.         /// Look for any of the strings in the blacklist entries
  124.         /// if they are not found, we know the page has been updated...
  125.         /// </summary>
  126.         /// <param name="rawBody"></param>
  127.         /// <param name="blacklistEntries"></param>
  128.         /// <returns></returns>
  129.         static bool HasUpdatedBlackListCheck(byte[] rawBody, List<string> blacklistEntries)
  130.         {
  131.             string body = Encoding.ASCII.GetString(rawBody);
  132.  
  133.             foreach(string entry in blacklistEntries)
  134.             {
  135.                 if (!body.Contains(entry))
  136.                 {
  137.                     return true;
  138.                 }
  139.             }
  140.  
  141.             return false;
  142.         }
  143.        
  144.         /// <summary>
  145.         /// Simple webrequest wrapper that makes a GET request to the endPoint returns
  146.         /// the server response, and outputs the body of the response back as as a byte array....
  147.         /// </summary>
  148.         /// <param name="endPoint"></param>
  149.         /// <param name="responseBody"></param>
  150.         /// <returns></returns>
  151.         static HttpStatusCode FetchSite(string endPoint, out byte[] responseBody)
  152.         {
  153.             WebRequest r = WebRequest.Create(endPoint);
  154.             HttpWebResponse response = r.GetResponse() as HttpWebResponse;
  155.  
  156.             MemoryStream ms = new MemoryStream();
  157.             Stream s = response.GetResponseStream();
  158.             s.CopyTo(ms);
  159.  
  160.             responseBody = ms.ToArray();
  161.  
  162.             s.Close();
  163.             response.Close();
  164.  
  165.             return response.StatusCode;
  166.         }
  167.  
  168.  
  169.         /// <summary>
  170.         /// Here is where the magic happens for monitoring the page
  171.         /// </summary>
  172.         /// <param name="endPoint">the endpoint to monitor</param>
  173.         /// <param name="blEntries">entries that should not appear on the updated webpage </param>
  174.         /// <param name="intervalSec">how often to check the website for updated</param>
  175.         static void WatchEndPoint(string endPoint,List<string> blEntries,int intervalSec)
  176.         {
  177.             string currentHash = string.Empty;
  178.             bool firstCheck = true;
  179.             byte[] rawBody = null;
  180.                        
  181.             while (true) {
  182.                 HttpStatusCode responseCode = FetchSite(endPoint, out rawBody);
  183.  
  184.                 // checking the http response because I <did> get some 500 error codes here
  185.                 if (responseCode == HttpStatusCode.OK)
  186.                 {
  187.                     string hash = ComputeHash(rawBody);
  188.  
  189.                     // if this is the first time checking the site
  190.                     // use this to preload the hash
  191.                     if (firstCheck)
  192.                     {
  193.                         Console.WriteLine("First Check");
  194.                         GeneralDiscordAlert("Starting Check");
  195.                         firstCheck = false;
  196.                         currentHash = hash;
  197.                         continue;
  198.                     }
  199.  
  200.                     // Not sure why I was getting false positives with the hash check
  201.                     // earlier....the black list check should help mitigate this for now
  202.                     // as well as the response check
  203.                     //
  204.                     if (!currentHash.Equals(hash) && HasUpdatedBlackListCheck(rawBody, blEntries))
  205.                     {
  206.                         // ok so the hash of the site content is different && we have some missing names
  207.                         //
  208.                         ++changesDetected;
  209.  
  210.                         DiscordAlert(endPoint, changesDetected);
  211.                         Console.WriteLine("Changes:{0} (Check The Site)", changesDetected);
  212.  
  213.                         //update the original
  214.                         currentHash = hash;
  215.                     }
  216.                     else
  217.                     {
  218.                         Console.WriteLine("Changes:{0} Not Yet...", changesDetected);
  219.                     }
  220.                 }
  221.                 else
  222.                 {
  223.                     Console.Error.WriteLine("Status Back: {0}", responseCode);
  224.                 }
  225.  
  226.                 // goto sleep until we do a new check
  227.                 Thread.Sleep(intervalSec * 1000);
  228.             }
  229.         }
  230.  
  231.         /// <summary>
  232.         /// TODO: endpoint, make the data values used here config/args driven....
  233.         /// </summary>
  234.         /// <param name="args"></param>
  235.         static void Main(string[] args)
  236.         {          
  237.             shaHash = SHA256.Create();
  238.  
  239.             webHook="https://discordapp.com/api/webhooks/<redacted>/<redacted";
  240.             string endPoint = "http://www.<redacted>.com/page/black-belt-exam";
  241.  
  242.             // Names of folks I know have not tested...but are showing on the current page
  243.             //
  244.             // This specific check <will> fail once the page itself gets cleared....
  245.             // (and YES this check will fail once the page itself gets cleared)....
  246.             List<string> blEntries = new List<string>();
  247.             blEntries.Add("<redacted>");
  248.             blEntries.Add("<redacted>");
  249.  
  250.             WatchEndPoint(endPoint, blEntries, 30);
  251.         }
  252.     }
  253. }
Add Comment
Please, Sign In to add comment