Boredom, Bugs and a Lawsuit: Reverse Engineering Artix Entertainment
Minad and I learnt programming by pulling apart AQWorlds and AQ3D, from packet proxies and Unity injectors to Artix's white-hat team and the exploit that got me sued.
In 2019, Artix Entertainment published a post about someone sending messages from a moderator account and deleting AQ3D characters. Their investigation involved more than a million requests, a broken authentication system and, eventually, a lawsuit.
I was the person they sued. In the community, I was known as Rothien.
When this story began, I could not program.
It started with !hello
I found AdventureQuest Worlds around 2009, then found the underground community surrounding it: trainers, packet editors and people who seemed to know things about the game that ordinary players did not.
Minad's man-in-the-middle proxy was the first tool that made it click. Instead of pressing a button and watching the game react, I could see the traffic passing between client and server. I could stop it, read it, change it and send it on.
The first command I added was !hello. It did almost nothing. Seeing AQWorlds respond to code I had written still felt impossible.
From there, Minad and I became a bad influence on each other. We would choose a language, rebuild a proxy or server in it and become productive within weeks. Then one of us would find something new and the other would have to catch up. It became less about any particular language and more about who could make the game do the most ridiculous thing next.
Networking was an unforgiving teacher. A proxy dragged us through sockets, threads, asynchronous I/O, buffering, binary data, protocol state, error handling and concurrency. There was no pretending we understood it. The connection either worked or it died silently at two in the morning.
Bugs that should not have existed
AQWorlds rewarded even basic curiosity. At one point, different parts of its authentication system disagreed about whether usernames were case-sensitive. Rothien, RoThIeN and rOtHiEn could be treated as separate logins and the same account at the same time.
The exploit was literally the capital letters in this packet:
<msg t="sys">
<body action="login" r="0">
<login z="zone_master">
<nick><![CDATA[RoThIeN]]></nick>
<pword><![CDATA[password]]></pword>
</login>
</body>
</msg>
Changing the capitalisation was enough to log my account in more than once. No memory corruption. No elaborate chain. Just two parts of a system with different ideas about what a username was.
Then there was what we called the XML bomb. The AQWorlds socket server accepted an external entity inside incoming XML. A small packet could tell the server to fetch a much larger file and expand it repeatedly:
<?xml version="1.0"?>
<!DOCTYPE external [
<!ENTITY ee SYSTEM "http://www.python.org/ftp/python/3.7.1/Python-3.7.1.tgz">
]>
<root>
ⅇⅇⅇⅇⅇⅇⅇⅇⅇⅇ
</root>
The original proof of concept repeatedly sent that payload followed by an ordinary version-check packet. The server would do far too much work because an unauthenticated client asked nicely enough. It was simple, ugly and effective.
Every discovery widened the target. The game was not only combat, quests and packets. It was parsers, login systems, databases, web endpoints and whatever assumptions connected them.
Somehow, we were the white hats
Artix eventually made us part of its white-hat team. That title suggests meetings, reports and adult supervision. The reality was Lamp nominally leading while, from what I remember, rarely being around. Minad and I carried on trying to outdo each other. Lamp carried on writing socket bots in PHP, which remains one of the more threatening sentences in this story.
We openly took the piss out of AE while speaking directly to its developers. Somehow, nobody saw a contradiction.
I once joked to Zhoom that AQ3D needed packet encryption. He went away and added it.
It was XOR.
Stripped of the key, the protection looked like this:
for (let index = 0; index < packet.length; index++) {
packet[index] ^= key[index % key.length];
}
The same three-byte key repeated across every packet. It could hide traffic from someone casually looking at it, but the client needed the key to decrypt it, and AQ3D was built in Unity.
That meant dnSpy, but it did not stop at reading decompiled code. We built Unity Mono injectors so we could load our own code into the running client, patch methods and change its behaviour while the game was running.
Packets had shown us what the client said. Decompiling its .NET assemblies showed us how it decided what to say. Injection let us interrupt that decision and replace it with our own.
One exploit came from combining two changes that seemed harmless on their own. I patched the client's death handler so my character would not die, then teleported to an absurdly large negative coordinate and back again. My character stretched into spaghetti and, for everyone in the map, the world turned black. It was the sort of result that made no sense until it worked, at which point it was impossible not to laugh.
I later gave the credit to another player who wanted to become an AQ3D tester. I had found the exploit, but I thought he would be good at the job and the credit might help him get there. That was how informal the whole scene was: a game-breaking discovery could also become somebody else's job reference.
XOR was not much of an obstacle when the key and algorithm had to ship inside the application. By then we were moving between network protocols, decompiled C#, runtime injection, Unity internals, web applications and backend behaviour, learning whatever was necessary to follow the next lead.
Then I crossed the line
Years later, I found a flaw in authentication infrastructure shared by AQWorlds and AQ3D. Tokens created under the same timing conditions could collide. One user's authenticated session could become another user's session.
Artix later documented the incident in "DELETED - A Game Dev Investigation Story", connecting the same underlying issue to messages sent through an AQWorlds moderator account and the deletion of AQ3D characters.
That was me.
First I used a moderator account to send server-wide messages. Then I moved to AQ3D and deleted player characters.
Artix published its investigation. Then it sued me.
I was not making a point or exposing the flaw responsibly. I was bored, immature and interested in seeing how far I could take it. People lost characters because I wanted to prove that I could. There is no version of that which makes me the hero.
What remains
Minad and I started with a Flash game and no formal plan. We ended up learning languages in weeks because waiting to understand everything first was never an option. We built the tool, watched it fail and kept going until it did not.
That approach taught me most of what became useful later: networking, concurrency, decompilation, Unity, debugging, web security and how to move through an unfamiliar system without a map.
It also taught me something less flattering. Technical ability and good judgement are separate skills. I developed one much faster than the other, and the lawsuit was the point at which that difference became impossible to ignore.
I have matured a lot since then. I no longer need to prove I can break something simply because I have found a way in. These days, knowing when to stop, report the problem and leave other people out of the blast radius feels as important as finding the bug in the first place. I wish I had understood that sooner.
The AE hacking scene is quieter now. The current white hats seem more interested in staying friendly with the company, and I no longer speak to them. Maybe that is healthier. It is definitely a long way from two bored people racing to see who could make a game break first.