public static void DoCommand(Socket peer, Stream input, Stream output, Dictionary <string, string> fileMappings, Dictionary <Regex, string> colorMappings) { using (input) { var crash = false; try { var line = ReadLine(input); var i3 = line.LastIndexOf((char)3); if (i3 != -1) { line = line.Substring(i3 + 1); } var lineOrig = line; line = line.ToLowerInvariant(); switch (line) { case "age": { var serverPath = ReadServerPath(ReadLine(input), fileMappings); var server = serverPath.Item1; var path = serverPath.Item2; var ms = new MemoryStream(); FileTailer.Tail(server, path, 1, false, ms); var str = Encoding.ASCII.GetString(ms.ToArray()); str = str.Substring(0, Math.Min(str.Length, 100)).Replace(",", "."); string os = null; var endsWithU = false; while (str.Length > 0) { DateTime dt; if (DateTime.TryParse(str, CultureInfo.InvariantCulture, endsWithU ? DateTimeStyles.AssumeUniversal : DateTimeStyles.AssumeLocal, out dt)) { os = ((long)(DateTime.Now - dt).TotalSeconds).ToString(); break; } endsWithU = str.EndsWith("U") && !str.EndsWith(" U"); str = str.Substring(0, str.Length - 1); } Write(os ?? "null", output); break; } case "apppools": { Shell.Do(peer, input, output, @"c:\windows\system32\inetsrv\appcmd", "list apppool /config /xml", false); break; } case "bend": { Remote.Do(peer, input, output); break; } case "buildtime": { Write(Environment.MachineName + " " + Date(BuildDate.RetrieveLinkerTimestamp()) + "\r\n", output); break; } case "crash": { crash = true; throw new InvalidOperationException(); } case "date": { var serverPath = ReadServerPath(ReadLine(input), fileMappings); var server = serverPath.Item1; var path = serverPath.Item2; var pattern = ReadLine(input); DateFinder.Find(new LogStream(server, path), output, pattern); break; } case "download": { var path = ReadLine(input); Zip.Download(path, output); break; } case "downloadzip": { var path = ReadLine(input); Zip.Zipit(path, output); break; } case "dump": { var path = ReadLine(input); var process = ReadLine(input); DumpFile.Create(path, process); break; } case "filecount": { var serverPath = ReadServerPath(ReadLine(input), fileMappings); var path = Path.GetDirectoryName(serverPath.Item2); var pattern = Path.GetFileName(serverPath.Item2); Write(Directory.GetFiles(path, pattern).Length.ToString(CultureInfo.InvariantCulture), output); break; } case "fulldump": { var enable = int.Parse(ReadLine(input)); DumpConfig.Enable(enable != 0); break; } case "fulldumpenabled": { var enabled = DumpConfig.IsEnabled(); Write(enabled ? "1" : "0", output); break; } case "isonline": { Write(Environment.MachineName + " ", output); FetchUri.FetchHeaders("http://localhost/IsOnline.aspx", output); Write($" {Path.GetFileName(Path.GetDirectoryName(DetermineVersion.DetermineWebSiteFolder()))} \r\n", output); break; } case "isonline2": { FetchUri.FetchHeaders("http://localhost/IsOnline.aspx", output); break; } case "ls": { foreach (var fi in LogStream.GetLocalFileInfos(ReadLine(input))) { Write($"- 1 root root {fi.Size} {fi.Modification.ToUniversalTime().ToString("o", CultureInfo.InvariantCulture)} {fi.Name}\n", output); } break; } case "mem": { MEMORYSTATUSEX memStatus = new MEMORYSTATUSEX(); if (GlobalMemoryStatusEx(memStatus)) { Write($"{Math.Round((double)memStatus.ullTotalPhys / (1024 * 1024 * 1024))} GB", output); } break; } case "netrelease": { var release = Convert.ToInt64(Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full", "Release", null)); Write(release.ToString(CultureInfo.InvariantCulture), output); break; } case "ntp": { Shell.Do(peer, input, output, "ntpq.exe", "-np", false); break; } case "offline": { Online.Do(false); break; } case "online": { Online.Do(true); break; } case "patch": { List <string> args = new List <string>(); string arg; while ((arg = ReadLine(input)).Length > 0) { args.Add(arg); } bool rebootIfNeeded = args.Contains("reboot"); bool onlyList = args.Contains("onlylist"); Patch patch = new Patch(); patch.InstallPatches(rebootIfNeeded, onlyList, output); break; } case "pc": { var counter = ReadLine(input); Write(PerformanceCounter.GetValue(counter).ToString(CultureInfo.InvariantCulture), output); break; } case "post / http/1.0": case "post / http/1.1": { Http.Do(input, fileMappings, colorMappings); break; } case "powershell": { List <string> scripts = new List <string>(); string arg; while ((arg = ReadLine(input)).Length > 0) { scripts.Add(arg); } foreach (string script in scripts) { Shell.Do(peer, input, output, "powershell.exe", $"-file {script}", false); } break; } case "rpc": { var counter = ReadLine(input); var specs = (ReadLine(input) ?? "0").Split('|'); var index = int.Parse(specs[0]); if (index == 4) { Write(Date(PerformanceCounterClient.GetDate(counter)), output); } else { var value = PerformanceCounterClient.GetValue(counter, index); Write(value.ToString(CultureInfo.InvariantCulture), output); if (specs.Length == 2) { Write("\n", output); switch (specs[1].ToLowerInvariant()) { case "timespan": Write(TimeSpan.FromSeconds(value) + "\n", output); break; } } } break; } case "shell": { Shell.Do(peer, input, output); break; } case "sites": { Shell.Do(peer, input, output, @"c:\windows\system32\inetsrv\appcmd", "list site /config /xml", false); break; } case "stacktrace": case "stacktracenative": case "verifyheap": { var pidOrSpec = GetPid2(ReadLine(input)); switch (line) { case "stacktrace": StackTrace.DoManaged(peer, output, pidOrSpec); break; case "stacktracenative": StackTrace.DoNative(peer, output, pidOrSpec); break; case "verifyheap": StackTrace.VerifyHeap(peer, output, pidOrSpec); break; } break; } case "systeminfo": { Shell.Do(peer, input, output, "systeminfo.exe", "", false); break; } case "tail": { var serverPath = ReadServerPath(ReadLine(input), fileMappings); var server = serverPath.Item1; var path = serverPath.Item2; var countLine = ReadLine(input); int count = 0; if (!string.IsNullOrEmpty(countLine)) { count = int.Parse(countLine); } line = ReadLine(input); bool tail = false; if (!string.IsNullOrEmpty(line)) { tail = int.Parse(line) != 0; } FileTailer.Tail(server, path, count, tail, output); break; } case "tailc": { using (var fs = new FileStream(ReadLine(input), FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { fs.Position = long.Parse(ReadLine(input)); fs.CopyTo(output); } break; } case "tasklist": { Shell.Do(peer, input, output, "tasklist.exe", "", false); break; } case "tasklistj": { Tasklist.JavaScript(output); break; } case "tasklistl": { Shell.Do(peer, input, output, "tasklist.exe", "/FO LIST", false); break; } case "tickcount": { var tc = Environment.TickCount; var now = DateTime.Now; var prev = -(long)int.MinValue + tc; var next = (long)int.MaxValue - tc; var bytes = Encoding.ASCII.GetBytes(Environment.MachineName + " Environment.TickCount is " + Environment.TickCount + " previous " + Date(now - TimeSpan.FromMilliseconds(prev)) + " next " + Date(now + TimeSpan.FromMilliseconds(next)) + " uptime " + GetUpTime() + "\r\n"); output.Write(bytes, 0, bytes.Length); break; } case "tickcount2": { Write(Environment.TickCount.ToString(CultureInfo.InvariantCulture), output); break; } case "tickcounts": { var tc = Environment.TickCount; var secs = ((double)int.MaxValue - tc) / 1000.0; Write(secs.ToString(CultureInfo.InvariantCulture) + "\n", output); Write(Date(DateTime.UtcNow.AddSeconds(secs)) + "\n", output); break; } case "time": { Write(Environment.MachineName + " " + Date() + "\r\n", output); break; } case "time2": { Write(Date(), output); break; } case "update": { var sourcePath = ReadLine(input); var destPath = Path.GetDirectoryName(Uri.UnescapeDataString(new UriBuilder(Assembly.GetExecutingAssembly().CodeBase).Path)); var arguments = string.Format("/C net stop \"{0}\" && timeout /t 5 /nobreak && move /y \"{1}\\*\" \"{2}\" && net start \"{0}\"", Program.ServiceName, sourcePath, destPath); Shell.Spawn(arguments); break; } case "upload": { var path = ReadLine(input); Zip.Upload(path, input); break; } case "uploadzip": { var path = ReadLine(input); Zip.Unzipit(path, input); break; } case "uptime": { Write(GetUpTime().ToString(), output); break; } case "uptime2": { var tc = GetTickCount64(); Write((tc / 1000.0).ToString(CultureInfo.InvariantCulture) + "\n", output); Write(TimeSpan.FromMilliseconds(tc) + "\n", output); break; } case "uri": { var path = ReadLine(input); FetchUri.Fetch(path, output); break; } case "users": { Shell.Do(peer, input, output, "query.exe", "user", false); break; } case "version": case "version2": case "version3": { var pid = GetPid(ReadLine(input)); if (pid != -1) { DetermineVersion.Do(pid, output, line == "version" ? " " : (line == "version2" ? null : "\n")); } break; } case "wertrace": { var process = ReadLine(input); StackTrace.OpenWerDump(peer, output, process); break; } default: if (line.StartsWith("get /")) { Http.Do(lineOrig, input, fileMappings, colorMappings); } else { throw new InvalidOperationException($"Unknown command {line}."); } break; } } catch (Exception e) { if (crash) { throw; } if (!(e is IOException)) { LogError(e); } } } }
public static void Do(string getLine, Stream net, Dictionary <string, string> fileMappings, Dictionary <Regex, string> colorMappings) { var ns = net as NetworkStream; if (ns != null) { ns.ReadTimeout = 30 * 1000; } bool methodKnown = true; using (net) { while (true) { List <string> headers = null; byte[] body; int cl = -1; bool readAnything = methodKnown; try { var type = string.Empty; while (true) { var line = Bender.ReadLine(net); if (string.IsNullOrEmpty(line)) { break; } readAnything = true; if (line.StartsWith("Get ", StringComparison.OrdinalIgnoreCase)) { getLine = line; methodKnown = true; } else if (line.StartsWith("Post ", StringComparison.OrdinalIgnoreCase)) { getLine = null; methodKnown = true; } if (line.StartsWith("Content-Length:", StringComparison.OrdinalIgnoreCase)) { cl = int.Parse(line.Substring(15)); } if (line.StartsWith("Content-Type:", StringComparison.OrdinalIgnoreCase)) { type = line.Substring(14); } if (headers == null && methodKnown && !string.IsNullOrEmpty(getLine)) { headers = new List <string> { getLine }; } else if (headers != null) { headers.Add(line); } } if (!readAnything) { return; } } catch (IOException) { return; } string contentType; try { string commandString = string.Empty; if (!string.IsNullOrEmpty(getLine)) { commandString = HttpUtility.UrlDecode(getLine.Substring(4, getLine.Length - 13)); } if (cl != -1) { var contents = new byte[cl]; var offset = 0; while (cl > 0) { var cl2 = net.Read(contents, offset, cl); if (cl2 <= 0) { throw new InvalidOperationException($"Unable to read {cl} bytes of input data. Read {cl2}."); } cl -= cl2; offset += cl2; } commandString = Encoding.UTF8.GetString(contents); } if (!methodKnown) { throw new InvalidOperationException("Illegal method"); } if (headers == null) { JavaScriptSerializer ser = new JavaScriptSerializer(); var commands = ser.DeserializeObject(commandString) as Dictionary <string, object>; var tasks = new List <Task <Tuple <string, MemoryStream> > >(); foreach (var command in commands) { var cmds = command.Value as object[]; var ms = new MemoryStream(); var serializer = new StreamWriter(ms); foreach (var cmd in cmds) { serializer.WriteLine(cmd as string); } serializer.Flush(); ms.Position = 0; var key = command.Key; var task = Task.Factory.StartNew(() => { var rs = new MemoryStream(); Bender.DoCommand(null, ms, rs, fileMappings, colorMappings); return(Tuple.Create(key, rs)); }); tasks.Add(task); } var js = string.Empty; var result = new Dictionary <string, List <string> >(); foreach (var task in tasks) { var key = task.Result.Item1; var stm = task.Result.Item2; stm = new MemoryStream(stm.ToArray()); var lines = new List <string>(); using (var rdr = new StreamReader(stm)) { while (true) { var l = rdr.ReadLine(); if (l == null) { break; } lines.Add(l); } } if (key.Equals("tasklistj", StringComparison.InvariantCultureIgnoreCase) && lines.Count == 1) { js = lines[0]; } result.Add(key, lines); if (result.Count > 1) { js = string.Empty; } } if (string.IsNullOrEmpty(js)) { js = ser.Serialize(result); } contentType = "Content-Type: application/json; charset=UTF-8"; body = Encoding.UTF8.GetBytes(js); } else { body = null; contentType = null; var index = commandString.IndexOf('?'); var paramString = string.Empty; if (index != -1) { paramString = commandString.Substring(index + 1); commandString = commandString.Substring(0, index); } if (commandString.Equals("/log", StringComparison.OrdinalIgnoreCase)) { const string defaults = "lines=80&tail=0&scroll=1&bw=1&newlines=1&text=0"; var appendLocation = string.Empty; if (!ParseParams(paramString, string.Empty).Keys.Intersect(ParseParams(defaults, string.Empty).Keys).Any()) { appendLocation = "&" + defaults; } var param = ParseParams(paramString, defaults); var bw = param["bw"] != "0"; var scroll = param["scroll"] != "0"; var file = param.ContainsKey("file") ? param["file"] : null; var lines = param.ContainsKey("val") ? param["val"] : param["lines"]; var tail = param["tail"]; var text = param["text"] != "0"; var newLines = param["newlines"] != "0"; if (lines == "-f") { lines = "40"; tail = "1"; } var serverPath = Bender.ReadServerPath(file, fileMappings); var server = param.ContainsKey("server") ? param["server"] : serverPath.Item1; var path = serverPath.Item2; var logOut = new LogOutput(net, new LogOutput.Format { AppendLocation = appendLocation, ColorMappings = bw ? null : colorMappings, Scroll = scroll, NewLine = newLines, Title = path, PlainText = text }); FileTailer.Tail(server, path, int.Parse(lines), int.Parse(tail) > 0, (bytes, i) => { logOut.Add(bytes, 0, i); }); logOut.End(); } else { var output = new MemoryStream(); var title = string.Empty; var param = ParseParams(paramString, string.Empty); if (commandString.Equals("/stack", StringComparison.OrdinalIgnoreCase)) { StackTrace.DoManaged(null, output, Bender.GetPid2(param["exe"])); title = $"Stacktrace for {param["exe"]}"; } else if (commandString.Equals("/wer", StringComparison.OrdinalIgnoreCase)) { StackTrace.OpenWerDump(null, output, param["exe"]); title = $"Werstack for {param["exe"]}"; } else if (commandString.Equals("/get", StringComparison.OrdinalIgnoreCase)) { var serverPath = Bender.ReadServerPath(param["uri"], fileMappings); // var server = serverPath.Item1; var path = serverPath.Item2; FetchUri.Fetch(path, output); title = $"GET {path}"; } var arr = output.ToArray(); if (arr.Length > 0) { var str = Encoding.UTF8.GetString(arr); var logOut = new LogOutput(net, new LogOutput.Format { Title = title, PlainText = true }); logOut.Add(str); logOut.End(); } else { contentType = "Content-Type: text/plain; charset=UTF-8"; var sb = new StringBuilder(); foreach (var h in headers) { sb.AppendLine(h); } body = Encoding.UTF8.GetBytes(sb.ToString()); } } } } catch (Exception) { Write(net, "HTTP/1.1 500 Internal server error\nConnection: Close\n\n", null); throw; } if (contentType != null && body != null) { var header = $"HTTP/1.1 200 OK\nAccess-Control-Allow-Origin: *\n{contentType}\nContent-Length: {body.Length}\n\n"; Write(net, header, body); } methodKnown = false; } } }