mirror of
https://github.com/raphaeIl/Novaria.git
synced 2025-12-12 14:34:38 +01:00
more generic crypto + packet encode + decode, hardcoded key in both client and server for now, first two req + resp works and GOT IN
This commit is contained in:
@@ -4,6 +4,7 @@ using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
//using Mono.Security.Cryptography;
|
||||
using NSec.Cryptography;
|
||||
using static System.Runtime.InteropServices.JavaScript.JSType;
|
||||
|
||||
@@ -55,8 +56,10 @@ namespace Novaria.Common.Crypto
|
||||
// assume AesGcm not supported (frida log)
|
||||
associatedData[associatedData.Length - 1] = 1;
|
||||
|
||||
|
||||
//byte[] testkey = Encoding.ASCII.GetBytes("#$*;1H&x*)0!@,/OcIe4VbiL[~fLyE7t"); // apprently key different for pc
|
||||
|
||||
//[75,49,239,215,37,193,247,16,183,230,183,161,235,3,201,156,64,192,54,208,139,46,144,123,142,80,149,85,161,26,15,195]
|
||||
|
||||
//Console.WriteLine("test key" + testkey.Length);
|
||||
//Utils.Utils.PrintByteArray(testkey);
|
||||
//Console.WriteLine();
|
||||
@@ -67,6 +70,9 @@ namespace Novaria.Common.Crypto
|
||||
|
||||
PS_REQUEST_NONCE[0] = 42;
|
||||
PS_REQUEST_NONCE[11] = 42;
|
||||
|
||||
key3[0] = 111;
|
||||
key3[31] = 111;
|
||||
}
|
||||
|
||||
public static bool Dencrypt_ChaCha20(Span<byte> result, ReadOnlySpan<byte> key, ReadOnlySpan<byte> nonce, ReadOnlySpan<byte> data, ReadOnlySpan<byte> associatedData)
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -14,43 +14,104 @@ using Novaria.Common.Core;
|
||||
using Proto;
|
||||
using Google.Protobuf;
|
||||
using System.Collections;
|
||||
using System.Reflection;
|
||||
using System.Net.Sockets;
|
||||
//using Mono.Security.Cryptography;
|
||||
|
||||
namespace Novaria.SDKServer.Controllers.Api
|
||||
{
|
||||
[Route("/agent-zone-1")]
|
||||
public class GatewayController : ControllerBase
|
||||
{
|
||||
public int req_count;
|
||||
|
||||
private byte[] key3 = new byte[32];
|
||||
|
||||
[HttpPost]
|
||||
public IActionResult PostRequest()
|
||||
{
|
||||
//var memoryStream = new MemoryStream();
|
||||
Log.Information("Received Gateway Post Request, Payload");
|
||||
|
||||
//Request.Body.CopyTo(memoryStream);
|
||||
//byte[] requestBodyBytes = memoryStream.ToArray();
|
||||
//Log.Information("Received Gateway Post Request, Payload: ");
|
||||
//Utils.PrintByteArray(requestBodyBytes);
|
||||
using var memoryStream = new MemoryStream();
|
||||
Request.Body.CopyTo(memoryStream); // Copy request body to MemoryStream
|
||||
byte[] rawPayload = memoryStream.ToArray(); // Get raw bytes from MemoryStream
|
||||
|
||||
Response.Headers.Add("Date", DateTime.UtcNow.ToString("R"));
|
||||
Response.Headers.Add("Content-Length", "171");
|
||||
Response.Headers.Add("Connection", "keep-alive");
|
||||
Utils.PrintByteArray(rawPayload);
|
||||
|
||||
Response.Headers.Append("Set-Cookie", "SERVERID=eef797ff9d3671d413582d7dc2f39f29|1736422941|1736422941;Path=/");
|
||||
Response.Headers.Append("Set-Cookie", "SERVERCORSID=eef797ff9d3671d413582d7dc2f39f29|1736422941|1736422941;Path=/;SameSite=None;Secure");
|
||||
Packet requestPacket = ParseRequest(rawPayload);
|
||||
|
||||
string filePath = "E:\\documents\\Decompiling\\Extracted\\NOVA\\Novaria\\Novaria.SDKServer\\response1"; // Replace with the actual file path
|
||||
Console.WriteLine();
|
||||
|
||||
if (req_count == 1)
|
||||
Console.WriteLine("msgs body: ");
|
||||
Utils.PrintByteArray(requestPacket.msgBody.ToArray());
|
||||
Log.Information("Sucessfully parsed request packet, id: " + requestPacket.msgId);
|
||||
|
||||
byte[] responsePackeBytes = null;
|
||||
|
||||
switch (requestPacket.msgId)
|
||||
{
|
||||
filePath = "E:\\documents\\Decompiling\\Extracted\\NOVA\\Novaria\\Novaria.SDKServer\\response2"; // Replace with the actual file path
|
||||
case 4:
|
||||
{
|
||||
LoginReq loginreq = DecodePacket<LoginReq>(requestPacket);
|
||||
|
||||
Log.Information("login_req received, contents: " + JsonSerializer.Serialize(loginreq));
|
||||
|
||||
Log.Information("Building login resp...");
|
||||
|
||||
LoginResp loginResp = new LoginResp()
|
||||
{
|
||||
Token = "seggstoken",
|
||||
};
|
||||
|
||||
Packet responsePacket = new Packet()
|
||||
{
|
||||
msgId = 5,
|
||||
msgBody = loginResp.ToByteArray()
|
||||
};
|
||||
|
||||
responsePackeBytes = BuildResponse(responsePacket);
|
||||
|
||||
Log.Information("Sending login_resp packet: " + JsonSerializer.Serialize(loginResp));
|
||||
|
||||
break;
|
||||
}
|
||||
case 1001:
|
||||
{
|
||||
Nil nilReq = DecodePacket<Nil>(requestPacket);
|
||||
Log.Information("nil_req received, contents: " + JsonSerializer.Serialize(nilReq));
|
||||
|
||||
Log.Information("Building nil resp...");
|
||||
|
||||
Nil nilResp = new Nil()
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
Packet responsePacket = new Packet()
|
||||
{
|
||||
msgId = 10001,
|
||||
msgBody = nilResp.ToByteArray()
|
||||
};
|
||||
|
||||
responsePackeBytes = BuildResponse(responsePacket);
|
||||
|
||||
Log.Information("Sending nil_resp packet: " + JsonSerializer.Serialize(nilResp));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
Log.Information("That packet has no handler!");
|
||||
break;
|
||||
}
|
||||
|
||||
byte[] fileBytes = System.IO.File.ReadAllBytes(filePath);
|
||||
if (responsePackeBytes == null)
|
||||
{
|
||||
throw new InvalidOperationException("something went wrong during building the response packet!");
|
||||
}
|
||||
|
||||
Response.Body.WriteAsync(fileBytes, 0, fileBytes.Length);
|
||||
|
||||
req_count++;
|
||||
Console.WriteLine("Built bytes: ");
|
||||
Utils.PrintByteArray(responsePackeBytes);
|
||||
|
||||
Response.Body.Write(responsePackeBytes, 0, responsePackeBytes.Length);
|
||||
|
||||
return new EmptyResult();
|
||||
}
|
||||
@@ -75,7 +136,7 @@ namespace Novaria.SDKServer.Controllers.Api
|
||||
|
||||
IKEResp ikeResponse = new IKEResp()
|
||||
{
|
||||
PubKey = ByteString.CopyFrom(AeadTool.PS_PUBLIC_KEY),
|
||||
PubKey = ByteString.CopyFrom(AeadTool.CLIENT_PUBLIC_KEY),
|
||||
Token = AeadTool.TOKEN
|
||||
};
|
||||
|
||||
@@ -91,24 +152,8 @@ namespace Novaria.SDKServer.Controllers.Api
|
||||
Console.WriteLine("Built bytes: ");
|
||||
Utils.PrintByteArray(responsePayload);
|
||||
|
||||
//// Set response headers
|
||||
//Response.Headers.Add("Date", DateTime.UtcNow.ToString("R"));
|
||||
//Response.Headers.Add("Content-Length", "251");
|
||||
//Response.Headers.Add("Connection", "keep-alive");
|
||||
|
||||
//// Set cookies
|
||||
//Response.Headers.Append("Set-Cookie", "acw_tc=cb6df452e3196d1ec00d2fcdf7726b25ed2accbaa45e1066701a61d2da90b384;path=/;HttpOnly;Max-Age=1800");
|
||||
//Response.Headers.Append("Set-Cookie", "SERVERID=eef797ff9d3671d413582d7dc2f39f29|1736422941|1736422941;Path=/");
|
||||
//Response.Headers.Append("Set-Cookie", "SERVERCORSID=eef797ff9d3671d413582d7dc2f39f29|1736422941|1736422941;Path=/;SameSite=None;Secure");
|
||||
|
||||
//// Set binary content as the response body
|
||||
//string filePath = "E:\\documents\\Decompiling\\Extracted\\NOVA\\Novaria\\Novaria.SDKServer\\options_response"; // Replace with the actual file path
|
||||
//byte[] fileBytes = System.IO.File.ReadAllBytes(filePath);
|
||||
|
||||
//// Write bytes directly to response body
|
||||
Response.Body.Write(responsePayload, 0, responsePayload.Length);
|
||||
|
||||
//// Return no content since the body is written manually
|
||||
return new EmptyResult();
|
||||
}
|
||||
|
||||
@@ -142,6 +187,102 @@ namespace Novaria.SDKServer.Controllers.Api
|
||||
return ((MemoryStream)rawResponseWriter.BaseStream).ToArray();
|
||||
}
|
||||
|
||||
public static T DecodePacket<T>(Packet packet) where T : IMessage
|
||||
{
|
||||
Assembly assembly = Assembly.GetAssembly(typeof(LoginReq));
|
||||
Type targetType = typeof(T);
|
||||
|
||||
PropertyInfo parserProperty = targetType.GetProperty("Parser", BindingFlags.Static | BindingFlags.Public);
|
||||
object parserInstance = parserProperty.GetValue(null);
|
||||
MethodInfo parseFromMethod = parserInstance.GetType().GetMethod("ParseFrom", new[] { typeof(byte[]) });
|
||||
|
||||
IMessage parsedMessage = (IMessage)parseFromMethod.Invoke(parserInstance, new object[] { packet.msgBody });
|
||||
|
||||
if (parsedMessage == null)
|
||||
{
|
||||
throw new InvalidOperationException("Failed to parse message.");
|
||||
}
|
||||
|
||||
return (T)parsedMessage;
|
||||
}
|
||||
|
||||
public static byte[] BuildResponse(Packet packet)
|
||||
{
|
||||
BinaryWriter packetWriter = new BinaryWriter(new MemoryStream());
|
||||
|
||||
byte[] msgIdBytes = BitConverter.GetBytes(packet.msgId);
|
||||
|
||||
if (BitConverter.IsLittleEndian)
|
||||
{
|
||||
Array.Reverse<byte>(msgIdBytes);
|
||||
}
|
||||
|
||||
packetWriter.Write(msgIdBytes.AsSpan<byte>());
|
||||
packetWriter.Write(packet.msgBody.AsSpan<byte>());
|
||||
|
||||
byte[] packetData = ((MemoryStream)packetWriter.BaseStream).ToArray();
|
||||
Span<byte> encryptedPacketData = (new byte[packetData.Length + 16]).AsSpan();
|
||||
|
||||
AeadTool.Encrypt_ChaCha20(encryptedPacketData, AeadTool.key3, AeadTool.PS_REQUEST_NONCE, packetData, false);
|
||||
|
||||
Console.WriteLine("build: encrypted data:");
|
||||
Utils.PrintByteArray(encryptedPacketData.ToArray());
|
||||
|
||||
BinaryWriter rawResponseWriter = new BinaryWriter(new MemoryStream());
|
||||
rawResponseWriter.Write(AeadTool.PS_REQUEST_NONCE);
|
||||
rawResponseWriter.Write(encryptedPacketData);
|
||||
|
||||
return ((MemoryStream)rawResponseWriter.BaseStream).ToArray();
|
||||
}
|
||||
|
||||
public static Packet ParseRequest(byte[] encryptedRawPayload)
|
||||
{
|
||||
BinaryReader reader = new BinaryReader(new MemoryStream(encryptedRawPayload));
|
||||
|
||||
byte[] nonceBytes = new byte[12]; // nonce 12 bytes length
|
||||
reader.Read(nonceBytes);
|
||||
|
||||
int packetSize = encryptedRawPayload.Length - nonceBytes.Length; // skip nonce length (12)
|
||||
|
||||
byte[] packetBytes = new byte[packetSize];
|
||||
reader.Read(packetBytes);
|
||||
|
||||
if (reader.BaseStream.Position != encryptedRawPayload.Length)
|
||||
{
|
||||
Log.Error("something went wrong, not all the bytes were read");
|
||||
Log.Error("reader pos: " + reader.BaseStream.Position);
|
||||
Log.Error("original len:" + encryptedRawPayload.Length);
|
||||
}
|
||||
|
||||
Span<byte> decrypt_result = new Span<byte>(new byte[packetSize - 16]); // for chacha20 decrypt, the result is 16 bytes less than the input data
|
||||
|
||||
Span<byte> nonce = nonceBytes.AsSpan();
|
||||
Span<byte> packet_data = packetBytes.AsSpan();
|
||||
|
||||
bool success = AeadTool.Dencrypt_ChaCha20(decrypt_result, AeadTool.key3, nonce, packet_data, null);
|
||||
|
||||
if (!success)
|
||||
{
|
||||
Log.Error("something went wrong when chacha20 decrypting the data");
|
||||
}
|
||||
|
||||
byte[] decrypted_bytes = decrypt_result.ToArray();
|
||||
|
||||
// might wanna use reader here
|
||||
byte[] msgid_bytes = decrypted_bytes[10..12]; // two bytes before msg data is msgid
|
||||
Array.Reverse<byte>(msgid_bytes); // should check BitConverter.IsLittleEndian (if true -> reverse, was true on my pc)
|
||||
|
||||
short msgId = BitConverter.ToInt16(msgid_bytes);
|
||||
|
||||
Packet packet = new Packet()
|
||||
{
|
||||
msgId = msgId,
|
||||
msgBody = decrypted_bytes[12..], // 2 + 2 (seqid) + 8 (timestamp)
|
||||
};
|
||||
|
||||
return packet;
|
||||
}
|
||||
|
||||
// used for parsing ike requests in ps (or any request ig) client -> server
|
||||
public static IKEReq ParseIkeRequest(byte[] encryptedRawPayload)
|
||||
{
|
||||
|
||||
@@ -107,6 +107,34 @@ namespace Novaria.SDKServer
|
||||
//Utils.PrintByteArray(Encoding.ASCII.GetBytes("Di9OhjFgkabvOO26XfjOzQ4/IcQ6yaFuK23tE2yw9Q7yYs5B53Zffs1e4DygW4IFgCFBtDKwAJtddxYmPfnjCfpCGk5UOAdLCH1/0NLHf+tl/Qc4GuG7jaK0Lcs75gHcSmRUkA"));
|
||||
//return;
|
||||
|
||||
byte[] firstReq = new byte[] { 90, 118, 89, 105, 76, 78, 54, 66, 118, 90, 97, 118, 69, 106, 227, 29, 185, 133, 2, 13, 102, 246, 198, 128, 110, 183, 97, 177, 211, 238, 130, 14, 32, 18, 36, 207, 124, 183, 86, 150, 155, 206, 31, 224, 74, 248, 142, 124, 168, 12, 179, 96, 157, 140, 21, 1, 223, 64, 54, 118, 137, 202, 12, 11, 229, 151, 82, 48, 229, 8, 170, 35, 236, 196, 247, 249, 235, 178, 227, 252, 146, 54, 17, 205, 93, 175, 7, 196, 123, 136, 204, 154, 60, 33, 179, 87, 206, 138, 76, 87, 64, 109, 147, 254, 148, 70, 26, 195, 231, 190, 186, 118, 218, 247, 13, 63, 240, 89, 41, 17, 56, 151, 5, 211, 4 };
|
||||
|
||||
Packet requestPacket = GatewayController.ParseRequest(firstReq);
|
||||
Console.WriteLine("---");
|
||||
Utils.PrintByteArray(requestPacket.msgBody);
|
||||
Console.WriteLine("---");
|
||||
Log.Information("Sucessfully parsed request packet, id: " + requestPacket.msgId);
|
||||
LoginReq loginreq = GatewayController.DecodePacket<LoginReq>(requestPacket);
|
||||
|
||||
Log.Information("login_req received, contents: " + JsonSerializer.Serialize(loginreq));
|
||||
|
||||
Log.Information("Building login resp...");
|
||||
|
||||
LoginResp loginResp = new LoginResp()
|
||||
{
|
||||
Token = "seggstoken",
|
||||
};
|
||||
|
||||
Packet responsePacket = new Packet()
|
||||
{
|
||||
msgId = 5,
|
||||
msgBody = loginResp.ToByteArray()
|
||||
};
|
||||
|
||||
byte[] responsePackeBytes = GatewayController.BuildResponse(requestPacket);
|
||||
|
||||
Utils.PrintByteArray(responsePackeBytes);
|
||||
//return;
|
||||
Log.Information("Starting SDK Server...");
|
||||
try
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user