WebWormWatch.Mod 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. (* Aos, Copyright 2001, Pieter Muller, ETH Zurich *)
  2. MODULE WebWormWatch; (** AUTHOR "TF"; PURPOSE "HTTP plugin to catch worms"; *)
  3. IMPORT
  4. Streams, WebHTTP, AosLog := TFLog, Files, WebHTTPServer, Modules, Clock,
  5. IP, DNS, Kernel, Mail, AosSMTPClient := SMTPClient;
  6. CONST
  7. ShowWormOffals = FALSE;
  8. (* virus capture files *)
  9. CodeRedVar = "Virus.CodeRedVar.Bin";
  10. UnknownWorm = "Virus.Unknown.Bin";
  11. NimdaWorm = "Virus.Nimda.Bin";
  12. WormLog = "Virus.Log"; (* ASCII log file *)
  13. WormCache = "Virus.Cache"; (* binary cache file storing virus name and source address *)
  14. (* mail parameters *)
  15. ToName1 = "Thomas Frey"; ToAddr1 = "frey@inf.ethz.ch";
  16. FromName = "Worm Watch"; FromAddr = "frey@inf.ethz.ch";
  17. SMTPServer = "lillian.inf.ethz.ch";
  18. SMTPClient = "eth20853.ethz.ch";
  19. LocalPrefix = "129.132.";
  20. VAR log : AosLog.Log;
  21. nofNimda*, nofCodeRedVar*:LONGINT;
  22. lastWormIP*, lastWormName*, lastWormOrigin*: ARRAY 64 OF CHAR;
  23. TYPE
  24. CodeRedPlugin = OBJECT(WebHTTPServer.HTTPPlugin)
  25. PROCEDURE CanHandle(host: WebHTTPServer.Host; VAR h : WebHTTP.RequestHeader; secure : BOOLEAN): BOOLEAN;
  26. VAR i : LONGINT;
  27. BEGIN
  28. WHILE (h.uri[i] # 0X) & (i < LEN(h.uri)) DO INC(i) END;
  29. RETURN (i>100)
  30. END CanHandle;
  31. PROCEDURE Handle(host: WebHTTPServer.Host; VAR request: WebHTTP.RequestHeader; VAR reply: WebHTTP.ResponseHeader;
  32. VAR in: Streams.Reader; VAR out: Streams.Writer);
  33. VAR fn, vn : ARRAY 32 OF CHAR;
  34. BEGIN
  35. IF MyMatch(request.uri, "/default.ida") THEN
  36. vn := "Code Red variant"; fn := CodeRedVar; INC(nofCodeRedVar)
  37. ELSE
  38. vn := "Unknown"; fn := UnknownWorm
  39. END;
  40. MyHandle(vn, fn, in, out, request, reply)
  41. END Handle;
  42. END CodeRedPlugin;
  43. TYPE
  44. NimdaPlugin = OBJECT(WebHTTPServer.HTTPPlugin)
  45. PROCEDURE CanHandle(host: WebHTTPServer.Host; VAR h : WebHTTP.RequestHeader; secure : BOOLEAN): BOOLEAN;
  46. BEGIN
  47. RETURN h.uri = "/scripts/root.exe"
  48. END CanHandle;
  49. PROCEDURE Handle(host: WebHTTPServer.Host; VAR request: WebHTTP.RequestHeader; VAR reply: WebHTTP.ResponseHeader;
  50. VAR in: Streams.Reader; VAR out: Streams.Writer);
  51. BEGIN
  52. INC(nofNimda);
  53. MyHandle("Nimda", NimdaWorm, in, out, request, reply)
  54. END Handle;
  55. END NimdaPlugin;
  56. VAR
  57. crp : CodeRedPlugin;
  58. np : NimdaPlugin;
  59. PROCEDURE MyMatch(VAR uri :ARRAY OF CHAR; y: ARRAY OF CHAR) : BOOLEAN;
  60. VAR i : LONGINT;
  61. BEGIN
  62. WHILE (i < LEN(uri)) & (i < LEN(y)) & (uri[i] = y[i]) &(y[i] # 0X) DO INC(i) END;
  63. RETURN (i < LEN(uri)) & (i < LEN(y)) & (y[i] = 0X)
  64. END MyMatch;
  65. PROCEDURE Cached(vn, adr: ARRAY OF CHAR): BOOLEAN;
  66. VAR f: Files.File; n: ARRAY 64 OF CHAR; a: ARRAY 16 OF CHAR; r: Files.Reader; w: Files.Writer; cached: BOOLEAN;
  67. BEGIN {EXCLUSIVE}
  68. cached := FALSE;
  69. f := Files.Old(WormCache);
  70. IF f = NIL THEN f := Files.New(WormCache) END;
  71. IF f # NIL THEN (* search cache *)
  72. Files.OpenReader(r, f, 0);
  73. LOOP
  74. r.RawString(n); r.RawString(a);
  75. IF r.res # 0 THEN EXIT END;
  76. IF (n = vn) & (a = adr) THEN cached := TRUE; EXIT END
  77. END;
  78. IF ~cached THEN (* add to cache *)
  79. Files.OpenWriter(w, f, f.Length());
  80. w.RawString(vn); w.RawString(adr);
  81. w.Update;
  82. Files.Register(f)
  83. END
  84. END;
  85. RETURN cached
  86. END Cached;
  87. PROCEDURE MyHandle(vn, fn: ARRAY OF CHAR; VAR in: Streams.Reader; VAR out: Streams.Writer;
  88. VAR header : WebHTTP.RequestHeader; VAR reply: WebHTTP.ResponseHeader);
  89. VAR
  90. f: Files.File; w : Files.Writer; res: WORD; i, time, date: LONGINT;
  91. ch :CHAR;
  92. md : ARRAY 32 OF CHAR;
  93. origin : ARRAY 64 OF CHAR;
  94. ipstr:ARRAY 16 OF CHAR;
  95. timer : Kernel.Timer;
  96. msg : Mail.Message;
  97. smtpSession: AosSMTPClient.SMTPSession;
  98. str: Streams.StringWriter;
  99. BEGIN
  100. IP.AdrToStr(header.fadr, ipstr);
  101. DNS.HostByNumber(header.fadr, origin, res);
  102. COPY(ipstr, lastWormIP); COPY(origin, lastWormOrigin); COPY(vn, lastWormName);
  103. log.Enter; log.TimeStamp; log.String("Worm Alert : "); log.String(vn); log.String(" ");
  104. log.String(ipstr); IF res = DNS.Ok THEN log.String("("); log.String(origin); log.String(")") END;
  105. IF Cached(vn, ipstr) THEN
  106. log.Enter; log.TimeStamp;
  107. log.String("Worm Cache : "); log.String(vn); log.String(" "); log.String(ipstr);
  108. log.Exit;
  109. RETURN
  110. END;
  111. IF MyMatch(ipstr, LocalPrefix) THEN (* ETH infection: send a Mail *)
  112. log.Ln; i := 0 ;
  113. NEW(msg);
  114. msg.AddTo(ToName1, ToAddr1);
  115. msg.SetFrom(FromName, FromAddr);
  116. NEW(str, 64);
  117. Clock.Get(time, date); str.Date822(time, date, 0);
  118. str.Get(md); msg.SetDate(md);
  119. msg.SetSubject("Worm Infection report");
  120. IP.AdrToStr(header.fadr, ipstr);
  121. msg.AddLine("Infected IP");
  122. msg.AddLine(ipstr);
  123. msg.AddLine(origin);
  124. msg.AddLine(vn);
  125. NEW(smtpSession);
  126. smtpSession.Open(SMTPServer, SMTPClient, 25, res);
  127. IF res = AosSMTPClient.Ok THEN
  128. smtpSession.Send(msg, res)
  129. END;
  130. smtpSession.Close
  131. END;
  132. f := Files.New(fn); Files.OpenWriter(w, f, 0);
  133. NEW(timer);
  134. WHILE in.Available() > 0 DO
  135. ch := in.Get();
  136. IF ShowWormOffals THEN log.Hex(ORD(ch), -3); INC(i); IF i MOD 16 = 0 THEN log.Ln END END;
  137. IF in.Available() = 0 THEN timer.Sleep(2000) END;
  138. w.Char(ch);
  139. END;
  140. w.Update;
  141. Files.Register(f);
  142. log.Exit;
  143. IF header.method IN {WebHTTP.GetM, WebHTTP.HeadM} THEN
  144. WebHTTP.WriteStatus(reply, out);
  145. out.String("Content-Type: "); out.String("text/html"); out.Ln;
  146. out.Ln;
  147. IF (header.method = WebHTTP.GetM) THEN
  148. out.String("<HTML>");
  149. out.String("Your request seems to be a worm attack. Failed."); out.Ln;
  150. out.String("</HTML>");
  151. out.Ln
  152. END
  153. ELSE
  154. reply.statuscode := WebHTTP.NotImplemented;
  155. WebHTTP.WriteStatus(reply, out)
  156. END;
  157. out.Update
  158. END MyHandle;
  159. PROCEDURE Install*;
  160. VAR hl: WebHTTPServer.HostList;
  161. BEGIN
  162. IF crp = NIL THEN
  163. NEW(crp, "CodeRed-Plugin");
  164. NEW(np, "Nimda-Plugin");
  165. hl := WebHTTPServer.FindHosts("*");
  166. WHILE (hl # NIL) DO
  167. hl.host.AddPlugin(crp);
  168. hl.host.AddPlugin(np);
  169. hl := hl.next
  170. END;
  171. log.Enter; log.String("Worm Watch Plugin installed"); log.Exit;
  172. ELSE
  173. log.Enter; log.String("Worm Watch Plugin already installed"); log.Exit;
  174. END;
  175. END Install;
  176. PROCEDURE Close;
  177. VAR h: WebHTTPServer.HostList;
  178. BEGIN
  179. IF crp # NIL THEN
  180. h := WebHTTPServer.FindHosts("*");
  181. WHILE (h # NIL) DO
  182. h.host.RemovePlugin(crp);
  183. h.host.RemovePlugin(np);
  184. h := h.next
  185. END;
  186. log.Enter; log.String("Worm Watch Plugin removed"); log.Exit; log.Close;
  187. crp := NIL; np := NIL;
  188. END
  189. END Close;
  190. BEGIN
  191. lastWormOrigin := "No last worm origin";
  192. lastWormIP := "No last worm IP";
  193. lastWormName := "No last worm name";
  194. NEW(log, "Worm Watch");
  195. log.SetLogFile(WormLog);
  196. Modules.InstallTermHandler(Close)
  197. END WebWormWatch.
  198. System.Free WebWormWatch ~
  199. Aos.Call WebWormWatch.Install ~