Skip to content

Commit 1b41c5c

Browse files
committed
Additional BotFuckery
1 parent 6b88bfa commit 1b41c5c

7 files changed

Lines changed: 95 additions & 39 deletions

File tree

src/Atlasd/Battlenet/Protocols/Game/ChatCommands/AdminBotFuckeryCommand.cs

Lines changed: 74 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public override bool CanInvoke(ChatCommandContext context)
2424

2525
public override void Invoke(ChatCommandContext context)
2626
{
27-
var t = Arguments.Count == 0 ? "" : Arguments[0]; // target
27+
var t = Arguments.Count == 0 ? string.Empty : Arguments[0]; // target
2828
string r; // reply
2929

3030
if (t.Length == 0 || !Battlenet.Common.GetClientByOnlineName(t, out var target) || target == null)
@@ -38,15 +38,6 @@ public override void Invoke(ChatCommandContext context)
3838
Arguments.RemoveAt(0); // remove target
3939
// Calculates and removes (target+' ') from (raw) which prints into (newRaw):
4040
RawBuffer = RawBuffer[(Encoding.UTF8.GetByteCount(t) + (Arguments.Count > 0 ? 1 : 0))..];
41-
var type = string.Join(' ', Arguments);
42-
43-
if (string.IsNullOrEmpty(type))
44-
{
45-
r = Resources.AdminBotFuckeryCommandInvalid;
46-
foreach (var line in r.Split(Environment.NewLine))
47-
new ChatEvent(ChatEvent.EventIds.EID_ERROR, context.GameState.ChannelFlags, context.GameState.Client.RemoteIPAddress, context.GameState.Ping, context.GameState.OnlineName, line).WriteTo(context.GameState.Client);
48-
return;
49-
}
5041

5142
var realmName = Settings.GetString(new string[] { "battlenet", "realm", "name" }, Resources.Battlenet);
5243
var targetEnv = new Dictionary<string, string>()
@@ -65,33 +56,85 @@ public override void Invoke(ChatCommandContext context)
6556
{ "username", target.OnlineName },
6657
{ "userName", target.OnlineName },
6758
};
68-
var env = targetEnv.Concat(context.Environment);
6959

70-
SID_AUTH_CHECK.Statuses status = type.ToLowerInvariant().Replace(" ", string.Empty) switch
71-
{
72-
"bannedkey" => SID_AUTH_CHECK.Statuses.GameKeyBanned,
73-
"bannedkey2" => SID_AUTH_CHECK.Statuses.GameKeyBanned | SID_AUTH_CHECK.Statuses.GameKeyExpansion,
74-
"inusekey" => SID_AUTH_CHECK.Statuses.GameKeyInUse,
75-
"inusekey2" => SID_AUTH_CHECK.Statuses.GameKeyInUse | SID_AUTH_CHECK.Statuses.GameKeyExpansion,
76-
"invalidkey" => SID_AUTH_CHECK.Statuses.GameKeyInvalid,
77-
"invalidkey2" => SID_AUTH_CHECK.Statuses.GameKeyInvalid | SID_AUTH_CHECK.Statuses.GameKeyExpansion,
78-
"invalidversion" => SID_AUTH_CHECK.Statuses.InvalidVersion,
79-
"success" => SID_AUTH_CHECK.Statuses.Success,
80-
"toonew" => SID_AUTH_CHECK.Statuses.VersionTooNew,
81-
"tooold" => SID_AUTH_CHECK.Statuses.VersionTooOld,
82-
"wronggamekey" => SID_AUTH_CHECK.Statuses.GameKeyProductMismatch,
83-
"wronggamekey2" => SID_AUTH_CHECK.Statuses.GameKeyProductMismatch | SID_AUTH_CHECK.Statuses.GameKeyExpansion,
84-
_ => SID_AUTH_CHECK.Statuses.InvalidVersion,
85-
};
60+
var random = new Random();
61+
int choice1 = (Arguments.Count > 0 ? int.Parse(Arguments[0]) : random.Next(0, 4));
8662

87-
new SID_AUTH_CHECK().Invoke(new MessageContext(target.Client, MessageDirection.ServerToClient, new Dictionary<string, dynamic>(){
88-
{ "status", status }, { "info", Array.Empty<byte>() }
89-
}));
63+
switch (choice1)
64+
{
65+
case 0: // What if the server sent client out-of-sequence spoofed SID_AUTH_CHECK result?
66+
{
67+
int choice2 = (Arguments.Count > 1 ? int.Parse(Arguments[1]) : random.Next(0, 12));
68+
context.Environment["message"] = "SID_AUTH_CHECK";
69+
SID_AUTH_CHECK.Statuses status = choice2 switch
70+
{
71+
0 => SID_AUTH_CHECK.Statuses.Success,
72+
1 => SID_AUTH_CHECK.Statuses.GameKeyBanned,
73+
2 => SID_AUTH_CHECK.Statuses.GameKeyBanned | SID_AUTH_CHECK.Statuses.GameKeyExpansion,
74+
3 => SID_AUTH_CHECK.Statuses.GameKeyInUse,
75+
4 => SID_AUTH_CHECK.Statuses.GameKeyInUse | SID_AUTH_CHECK.Statuses.GameKeyExpansion,
76+
5 => SID_AUTH_CHECK.Statuses.GameKeyInvalid,
77+
6 => SID_AUTH_CHECK.Statuses.GameKeyInvalid | SID_AUTH_CHECK.Statuses.GameKeyExpansion,
78+
7 => SID_AUTH_CHECK.Statuses.GameKeyProductMismatch,
79+
8 => SID_AUTH_CHECK.Statuses.GameKeyProductMismatch | SID_AUTH_CHECK.Statuses.GameKeyExpansion,
80+
9 => SID_AUTH_CHECK.Statuses.InvalidVersion,
81+
10 => SID_AUTH_CHECK.Statuses.VersionTooNew,
82+
11 => SID_AUTH_CHECK.Statuses.VersionTooOld,
83+
_ => SID_AUTH_CHECK.Statuses.InvalidVersion,
84+
};
85+
new SID_AUTH_CHECK().Invoke(new MessageContext(target.Client, MessageDirection.ServerToClient, new Dictionary<string, dynamic>(){
86+
{ "status", status }, { "info", Array.Empty<byte>() }
87+
}));
88+
break;
89+
}
90+
case 1: // What if server sent client unsolicited SID_QUERYREALMS2 with fake realm names?
91+
{
92+
context.Environment["message"] = "SID_QUERYREALMS2";
93+
var rand20HumanBytes = new byte[20];
94+
for (int i = 0; i < rand20HumanBytes.Length; i++) rand20HumanBytes[i] = (byte)random.Next((byte)'A', 1 + (byte)'Z');
95+
new SID_QUERYREALMS2().Invoke(new MessageContext(target.Client, MessageDirection.ServerToClient, new Dictionary<string, dynamic>(){
96+
{ "realms", new Dictionary<byte[], byte[]>(){{ Encoding.UTF8.GetBytes("Botfuckery"), rand20HumanBytes }} }
97+
}));
98+
break;
99+
}
100+
case 2: // What if server sent client out-of-sequence spoofed SID_LOGONRESPONSE2 result?
101+
{
102+
int choice2 = (Arguments.Count > 1 ? int.Parse(Arguments[1]) : random.Next(0, 4));
103+
context.Environment["message"] = "SID_LOGONRESPONSE2";
104+
SID_LOGONRESPONSE2.Statuses status = choice2 switch
105+
{
106+
0 => SID_LOGONRESPONSE2.Statuses.Success,
107+
1 => SID_LOGONRESPONSE2.Statuses.BadPassword,
108+
2 => SID_LOGONRESPONSE2.Statuses.AccountNotFound,
109+
3 => SID_LOGONRESPONSE2.Statuses.AccountClosed,
110+
_ => SID_LOGONRESPONSE2.Statuses.AccountNotFound,
111+
};
112+
var rand20HumanBytes = new byte[20];
113+
for (int i = 0; i < rand20HumanBytes.Length; i++) rand20HumanBytes[i] = (byte)random.Next((byte)'A', 1 + (byte)'Z');
114+
byte[] info = status == SID_LOGONRESPONSE2.Statuses.AccountClosed ? rand20HumanBytes : Array.Empty<byte>();
115+
new SID_LOGONRESPONSE2().Invoke(new MessageContext(target.Client, MessageDirection.ServerToClient, new Dictionary<string, dynamic>(){
116+
{ "status", status }, { "info", info }
117+
}));
118+
break;
119+
}
120+
case 3: // What if server asked for some registry info?
121+
{
122+
context.Environment["message"] = "SID_REGISTRY";
123+
new SID_REGISTRY().Invoke(new MessageContext(target.Client, MessageDirection.ServerToClient, new Dictionary<string, dynamic>(){
124+
{ "cookie", (UInt32)random.Next(-0x80000000, 0x7FFFFFFF) },
125+
{ "hiveKeyId", (UInt32)0x80000001 }, // HKEY_CURRENT_USER
126+
{ "keyPath", (string)"Software\\Battle.net\\Configuration" },
127+
{ "keyName", (string)"Battle.net gateways" },
128+
}));
129+
break;
130+
}
131+
}
90132

91133
r = Resources.AdminBotFuckeryCommand;
92-
foreach (var kv in env) r = r.Replace("{" + kv.Key + "}", kv.Value);
134+
foreach (var kv in targetEnv.Concat(context.Environment)) r = r.Replace("{" + kv.Key + "}", kv.Value);
93135
foreach (var line in r.Split(Battlenet.Common.NewLine))
94136
new ChatEvent(ChatEvent.EventIds.EID_INFO, context.GameState.ChannelFlags, context.GameState.Client.RemoteIPAddress, context.GameState.Ping, context.GameState.OnlineName, line).WriteTo(context.GameState.Client);
95137
}
96138
}
97139
}
140+

src/Atlasd/Battlenet/Protocols/Game/Messages/SID_LOGONRESPONSE.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ namespace Atlasd.Battlenet.Protocols.Game.Messages
99
{
1010
class SID_LOGONRESPONSE : Message
1111
{
12-
protected enum Statuses : UInt32
12+
public enum Statuses : UInt32
1313
{
1414
Failure = 0,
1515
Success = 1,

src/Atlasd/Battlenet/Protocols/Game/Messages/SID_LOGONRESPONSE2.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ namespace Atlasd.Battlenet.Protocols.Game.Messages
1010
{
1111
class SID_LOGONRESPONSE2 : Message
1212
{
13-
protected enum Statuses : UInt32
13+
public enum Statuses : UInt32
1414
{
1515
Success = 0,
1616
AccountNotFound = 1,

src/Atlasd/Battlenet/Protocols/Game/Messages/SID_QUERYREALMS2.cs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System.Collections.Generic;
55
using System.IO;
66
using System.Linq;
7+
using System.Text;
78

89
namespace Atlasd.Battlenet.Protocols.Game.Messages
910
{
@@ -41,6 +42,8 @@ public override bool Invoke(MessageContext context)
4142
}
4243
case MessageDirection.ServerToClient:
4344
{
45+
Dictionary<byte[], byte[]> realms = context.Arguments.ContainsKey("realms") ? (Dictionary<byte[], byte[]>)context.Arguments["realms"] : new Dictionary<byte[], byte[]>();
46+
4447
/**
4548
* (UINT32) Unknown (0)
4649
* (UINT32) Count
@@ -50,13 +53,21 @@ public override bool Invoke(MessageContext context)
5053
* (STRING) Realm description
5154
*/
5255

53-
Buffer = new byte[8];
56+
int count = 8;
57+
foreach (var pair in realms) count += pair.Key.Length + pair.Value.Length + 6;
58+
Buffer = new byte[count];
5459

5560
using var m = new MemoryStream(Buffer);
5661
using var w = new BinaryWriter(m);
5762

5863
w.Write((UInt32)0);
59-
w.Write((UInt32)0);
64+
w.Write((UInt32)realms.Count);
65+
foreach (var pair in realms)
66+
{
67+
w.Write((UInt32)1);
68+
w.WriteByteString(pair.Key);
69+
w.WriteByteString(pair.Value);
70+
}
6071

6172
Logging.WriteLine(Logging.LogLevel.Debug, Logging.LogType.Client_Game, context.Client.RemoteEndPoint, $"[{Common.DirectionToString(context.Direction)}] {MessageName(Id)} ({4 + Buffer.Length} bytes)");
6273
context.Client.Send(ToByteArray(context.Client.ProtocolType));

src/Atlasd/Battlenet/Protocols/Game/Messages/SID_REGISTRY.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ public override bool Invoke(MessageContext context)
4848
var cookie = r.ReadUInt32();
4949
var value = r.ReadByteString();
5050

51+
Logging.WriteLine(Logging.LogLevel.Info, Logging.LogType.Client_Game, context.Client.RemoteEndPoint, $"Requested registry cookie [0x{cookie:X8}] value [{Encoding.UTF8.GetString(value)}]");
5152
return true;
5253
}
5354
case MessageDirection.ServerToClient:
@@ -67,6 +68,7 @@ public override bool Invoke(MessageContext context)
6768
w.Write((string)keyPath);
6869
w.Write((string)keyName);
6970

71+
Logging.WriteLine(Logging.LogLevel.Info, Logging.LogType.Client_Game, context.Client.RemoteEndPoint, $"Requesting registry cookie [0x{cookie}:X8] hive [0x{hiveKeyId:X8}] key path [{keyPath}] name [{keyName}]");
7072
Logging.WriteLine(Logging.LogLevel.Debug, Logging.LogType.Client_Game, context.Client.RemoteEndPoint, $"[{Common.DirectionToString(context.Direction)}] {MessageName(Id)} ({4 + Buffer.Length} bytes)");
7173
context.Client.Send(ToByteArray(context.Client.ProtocolType));
7274
return true;

src/Atlasd/Localization/Resources.Designer.cs

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Atlasd/Localization/Resources.resx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,10 +127,10 @@
127127
<value>Who do you want to add?</value>
128128
</data>
129129
<data name="AdminBotFuckeryCommand" xml:space="preserve">
130-
<value>Sent spoofed SID_AUTH_CHECK result to {user}.</value>
130+
<value>Sent spoofed {message} result to {user}.</value>
131131
</data>
132132
<data name="AdminBotFuckeryCommandInvalid" xml:space="preserve">
133-
<value>Invalid parameters for SID_AUTH_CHECK.</value>
133+
<value>Invalid parameters for {message}.</value>
134134
</data>
135135
<data name="AdminClanListCommand" xml:space="preserve">
136136
<value>Registered clans:</value>

0 commit comments

Comments
 (0)