123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224 |
- (* Aos, Copyright 2001, Pieter Muller, ETH Zurich *)
- MODULE WebWormWatch; (** AUTHOR "TF"; PURPOSE "HTTP plugin to catch worms"; *)
- IMPORT
- Streams, WebHTTP, AosLog := TFLog, Files, WebHTTPServer, Modules, Clock,
- IP, DNS, Kernel, Mail, AosSMTPClient := SMTPClient;
- CONST
- ShowWormOffals = FALSE;
- (* virus capture files *)
- CodeRedVar = "Virus.CodeRedVar.Bin";
- UnknownWorm = "Virus.Unknown.Bin";
- NimdaWorm = "Virus.Nimda.Bin";
- WormLog = "Virus.Log"; (* ASCII log file *)
- WormCache = "Virus.Cache"; (* binary cache file storing virus name and source address *)
- (* mail parameters *)
- ToName1 = "Thomas Frey"; ToAddr1 = "frey@inf.ethz.ch";
- FromName = "Worm Watch"; FromAddr = "frey@inf.ethz.ch";
- SMTPServer = "lillian.inf.ethz.ch";
- SMTPClient = "eth20853.ethz.ch";
- LocalPrefix = "129.132.";
- VAR log : AosLog.Log;
- nofNimda*, nofCodeRedVar*:LONGINT;
- lastWormIP*, lastWormName*, lastWormOrigin*: ARRAY 64 OF CHAR;
- TYPE
- CodeRedPlugin = OBJECT(WebHTTPServer.HTTPPlugin)
- PROCEDURE CanHandle(host: WebHTTPServer.Host; VAR h : WebHTTP.RequestHeader; secure : BOOLEAN): BOOLEAN;
- VAR i : LONGINT;
- BEGIN
- WHILE (h.uri[i] # 0X) & (i < LEN(h.uri)) DO INC(i) END;
- RETURN (i>100)
- END CanHandle;
- PROCEDURE Handle(host: WebHTTPServer.Host; VAR request: WebHTTP.RequestHeader; VAR reply: WebHTTP.ResponseHeader;
- VAR in: Streams.Reader; VAR out: Streams.Writer);
- VAR fn, vn : ARRAY 32 OF CHAR;
- BEGIN
- IF MyMatch(request.uri, "/default.ida") THEN
- vn := "Code Red variant"; fn := CodeRedVar; INC(nofCodeRedVar)
- ELSE
- vn := "Unknown"; fn := UnknownWorm
- END;
- MyHandle(vn, fn, in, out, request, reply)
- END Handle;
- END CodeRedPlugin;
- TYPE
- NimdaPlugin = OBJECT(WebHTTPServer.HTTPPlugin)
- PROCEDURE CanHandle(host: WebHTTPServer.Host; VAR h : WebHTTP.RequestHeader; secure : BOOLEAN): BOOLEAN;
- BEGIN
- RETURN h.uri = "/scripts/root.exe"
- END CanHandle;
- PROCEDURE Handle(host: WebHTTPServer.Host; VAR request: WebHTTP.RequestHeader; VAR reply: WebHTTP.ResponseHeader;
- VAR in: Streams.Reader; VAR out: Streams.Writer);
- BEGIN
- INC(nofNimda);
- MyHandle("Nimda", NimdaWorm, in, out, request, reply)
- END Handle;
- END NimdaPlugin;
- VAR
- crp : CodeRedPlugin;
- np : NimdaPlugin;
- PROCEDURE MyMatch(VAR uri :ARRAY OF CHAR; y: ARRAY OF CHAR) : BOOLEAN;
- VAR i : LONGINT;
- BEGIN
- WHILE (i < LEN(uri)) & (i < LEN(y)) & (uri[i] = y[i]) &(y[i] # 0X) DO INC(i) END;
- RETURN (i < LEN(uri)) & (i < LEN(y)) & (y[i] = 0X)
- END MyMatch;
- PROCEDURE Cached(vn, adr: ARRAY OF CHAR): BOOLEAN;
- VAR f: Files.File; n: ARRAY 64 OF CHAR; a: ARRAY 16 OF CHAR; r: Files.Reader; w: Files.Writer; cached: BOOLEAN;
- BEGIN {EXCLUSIVE}
- cached := FALSE;
- f := Files.Old(WormCache);
- IF f = NIL THEN f := Files.New(WormCache) END;
- IF f # NIL THEN (* search cache *)
- Files.OpenReader(r, f, 0);
- LOOP
- r.RawString(n); r.RawString(a);
- IF r.res # 0 THEN EXIT END;
- IF (n = vn) & (a = adr) THEN cached := TRUE; EXIT END
- END;
- IF ~cached THEN (* add to cache *)
- Files.OpenWriter(w, f, f.Length());
- w.RawString(vn); w.RawString(adr);
- w.Update;
- Files.Register(f)
- END
- END;
- RETURN cached
- END Cached;
- PROCEDURE MyHandle(vn, fn: ARRAY OF CHAR; VAR in: Streams.Reader; VAR out: Streams.Writer;
- VAR header : WebHTTP.RequestHeader; VAR reply: WebHTTP.ResponseHeader);
- VAR
- f: Files.File; w : Files.Writer; res: WORD; i, time, date: LONGINT;
- ch :CHAR;
- md : ARRAY 32 OF CHAR;
- origin : ARRAY 64 OF CHAR;
- ipstr:ARRAY 16 OF CHAR;
- timer : Kernel.Timer;
- msg : Mail.Message;
- smtpSession: AosSMTPClient.SMTPSession;
- str: Streams.StringWriter;
- BEGIN
- IP.AdrToStr(header.fadr, ipstr);
- DNS.HostByNumber(header.fadr, origin, res);
- COPY(ipstr, lastWormIP); COPY(origin, lastWormOrigin); COPY(vn, lastWormName);
- log.Enter; log.TimeStamp; log.String("Worm Alert : "); log.String(vn); log.String(" ");
- log.String(ipstr); IF res = DNS.Ok THEN log.String("("); log.String(origin); log.String(")") END;
- IF Cached(vn, ipstr) THEN
- log.Enter; log.TimeStamp;
- log.String("Worm Cache : "); log.String(vn); log.String(" "); log.String(ipstr);
- log.Exit;
- RETURN
- END;
- IF MyMatch(ipstr, LocalPrefix) THEN (* ETH infection: send a Mail *)
- log.Ln; i := 0 ;
- NEW(msg);
- msg.AddTo(ToName1, ToAddr1);
- msg.SetFrom(FromName, FromAddr);
- NEW(str, 64);
- Clock.Get(time, date); str.Date822(time, date, 0);
- str.Get(md); msg.SetDate(md);
- msg.SetSubject("Worm Infection report");
- IP.AdrToStr(header.fadr, ipstr);
- msg.AddLine("Infected IP");
- msg.AddLine(ipstr);
- msg.AddLine(origin);
- msg.AddLine(vn);
- NEW(smtpSession);
- smtpSession.Open(SMTPServer, SMTPClient, 25, res);
- IF res = AosSMTPClient.Ok THEN
- smtpSession.Send(msg, res)
- END;
- smtpSession.Close
- END;
- f := Files.New(fn); Files.OpenWriter(w, f, 0);
- NEW(timer);
- WHILE in.Available() > 0 DO
- ch := in.Get();
- IF ShowWormOffals THEN log.Hex(ORD(ch), -3); INC(i); IF i MOD 16 = 0 THEN log.Ln END END;
- IF in.Available() = 0 THEN timer.Sleep(2000) END;
- w.Char(ch);
- END;
- w.Update;
- Files.Register(f);
- log.Exit;
- IF header.method IN {WebHTTP.GetM, WebHTTP.HeadM} THEN
- WebHTTP.WriteStatus(reply, out);
- out.String("Content-Type: "); out.String("text/html"); out.Ln;
- out.Ln;
- IF (header.method = WebHTTP.GetM) THEN
- out.String("<HTML>");
- out.String("Your request seems to be a worm attack. Failed."); out.Ln;
- out.String("</HTML>");
- out.Ln
- END
- ELSE
- reply.statuscode := WebHTTP.NotImplemented;
- WebHTTP.WriteStatus(reply, out)
- END;
- out.Update
- END MyHandle;
- PROCEDURE Install*;
- VAR hl: WebHTTPServer.HostList;
- BEGIN
- IF crp = NIL THEN
- NEW(crp, "CodeRed-Plugin");
- NEW(np, "Nimda-Plugin");
- hl := WebHTTPServer.FindHosts("*");
- WHILE (hl # NIL) DO
- hl.host.AddPlugin(crp);
- hl.host.AddPlugin(np);
- hl := hl.next
- END;
- log.Enter; log.String("Worm Watch Plugin installed"); log.Exit;
- ELSE
- log.Enter; log.String("Worm Watch Plugin already installed"); log.Exit;
- END;
- END Install;
- PROCEDURE Close;
- VAR h: WebHTTPServer.HostList;
- BEGIN
- IF crp # NIL THEN
- h := WebHTTPServer.FindHosts("*");
- WHILE (h # NIL) DO
- h.host.RemovePlugin(crp);
- h.host.RemovePlugin(np);
- h := h.next
- END;
- log.Enter; log.String("Worm Watch Plugin removed"); log.Exit; log.Close;
- crp := NIL; np := NIL;
- END
- END Close;
- BEGIN
- lastWormOrigin := "No last worm origin";
- lastWormIP := "No last worm IP";
- lastWormName := "No last worm name";
- NEW(log, "Worm Watch");
- log.SetLogFile(WormLog);
- Modules.InstallTermHandler(Close)
- END WebWormWatch.
- System.Free WebWormWatch ~
- Aos.Call WebWormWatch.Install ~
|