Welcome!

Join our community of MMO enthusiasts and game developers! By registering, you'll gain access to discussions on the latest developments in MMO server files and collaborate with like-minded individuals. Join us today and unlock the potential of MMO server development!

Join Today!

Plus Emulator Security Fixes

Joined
Jul 29, 2010
Messages
720
Reaction score
515
Hi,

When I was checking Plus I found a exploit which makes it possible to send queries, drop tables, whatever you like. I noticed that someone finally found out the exploit and I decided to release the fix because this guys just want duck some poop up.

Open the source and follow me.

1). HabboHotel\Items\Wired\Boxes\Effects\BotChangesClothesBox.cs

Find:
using (IQueryAdapter dbClient = PlusEnvironment.GetDatabaseManager().GetQueryReactor())
{
dbClient.RunQuery("UPDATE `bots` SET `look` = '" + User.BotData.Look + "', `gender` = '" + User.BotData.Gender + "' WHERE `id` = '" + User.BotData.Id + "' LIMIT 1");
}

Replace:
using (IQueryAdapter dbClient = PlusEnvironment.GetDatabaseManager().GetQueryReactor()) {
dbClient.SetQuery("UPDATE `bots` SET `look` = @look, `gender` = '" + User.BotData.Gender + "' WHERE `id` = '" + User.BotData.Id + "' LIMIT 1");
dbClient.AddParameter("look", User.BotData.Look);
dbClient.RunQuery();
}

And to be sure:

2). Communication\Packets\Incoming\Rooms\AI\Bots\SaveBotActionEvent.cs

Find:
using (IQueryAdapter dbClient = PlusEnvironment.GetDatabaseManager().GetQueryReactor())
{
dbClient.RunQuery("UPDATE `bots` SET `look` = '" + Session.GetHabbo().Look + "', `gender` = '" + Session.GetHabbo().Gender + "' WHERE `id` = '" + Bot.BotData.Id + "' LIMIT 1");
}

Replace:
using (IQueryAdapter dbClient = PlusEnvironment.GetDatabaseManager().GetQueryReactor())
{
dbClient.SetQuery("UPDATE `bots` SET `look` = @look, `gender` = '" + Session.GetHabbo().Gender + "' WHERE `id` = '" + Bot.BotData.Id + "' LIMIT 1");
dbClient.AddParameter("look", Session.GetHabbo().Look);
dbClient.RunQuery();
}

Replace the stuff as seen above in your source and recompile. I'm not going to explain how to execute the exploit because no one has this fixed yet.

More fixes

1). Communication\Packets\Incoming\Rooms\Furni\Wired\SaveWiredConfigEvent.cs

Find:
Room Room = Session.GetHabbo().CurrentRoom;
if (Room == null)
return;

Replace:
Room Room = Session.GetHabbo().CurrentRoom;
if (Room == null)
return;

if (!Room.CheckRights(Session, false) && !Room.CheckRights(Session, true))
return;

There is a way to change someone elses Wired settings so the code above is the fix.

2). Communication\Packets\Incoming\Catalog\CheckGnomeNameEvent.cs (Thanks to @Damien Jolly & thanks to @Shorty for sending me:love:)

Find:
if (Item == null || Item.Data == null)
return;

Replace:
if (Item == null || Item.Data == null || Item.UserID != Session.GetHabbo().Id || Item.Data.InteractionType != InteractionType.GNOME_BOX)
return;

The code above will fix the furni which change in Gnomes & duplicate furni in db.

3). HabboHotel\Users\UserData\UserDataFactory.cs (Thanks to @Damien Jolly)

Find:
dbClient.SetQuery("SELECT `id`,`username`,`rank`,`motto`,`look`,`gender`,`last_online`,`credits`,`activity_points`,`home_room`,`block_newfriends`,`hide_online`,`hide_inroom`,`vip`,`account_created`,`vip_points`,`machine_id`,`volume`,`chat_preference`,`focus_preference`, `pets_muted`,`bots_muted`,`advertising_report_blocked`,`last_change`,`gotw_points`,`ignore_invites`,`time_muted`,`allow_gifts`,`friend_bar_state`,`disable_forced_effects`,`allow_mimic`,`rank_vip` FROM `users` WHERE `auth_ticket` = @sso LIMIT 1");

Replace:
dbClient.SetQuery("SELECT users.id,users.username,users.rank,users.motto,users.look,users.gender,users.last_online,users.credits,users.activity_points,users.home_room,users.block_newfriends,users.hide_online,users.hide_inroom,users.vip,users.account_created,users.vip_points,users.machine_id,users.volume,users.chat_preference,users.focus_preference,users.pets_muted,users.bots_muted,users.advertising_report_blocked,users.last_change,users.gotw_points,users.ignore_invites,users.time_muted,users.allow_gifts,users.friend_bar_state,users.disable_forced_effects,users.allow_mimic,users.rank_vip " +
"FROM users " +
"JOIN user_auth_ticket " +
"ON users.id = user_auth_ticket.user_id " +
"WHERE user_auth_ticket.auth_ticket = @sso " +
"LIMIT 1");

Find:
dbClient.RunQuery("UPDATE `users` SET `online` = '1', `auth_ticket` = '' WHERE `id` = '" + UserId + "' LIMIT 1");

Replace:
dbClient.RunQuery("UPDATE `users` SET `online` = '1' WHERE `id` = '" + UserId + "' LIMIT 1");
dbClient.RunQuery("DELETE FROM `user_auth_ticket` WHERE `user_id` = '" + UserId + "' LIMIT 1");

PlusEnviroment.cs

Find:
dbClient.RunQuery("UPDATE `users` SET online = '0', `auth_ticket` = NULL");

Replace:
dbClient.RunQuery("TRUNCATE `user_auth_ticket`");
dbClient.RunQuery("UPDATE `users` SET online = '0'");

Finally run this database query:

-- ----------------------------
-- Table structure for `user_auth_ticket`
-- ----------------------------
DROP TABLE IF EXISTS `user_auth_ticket`;
CREATE TABLE `user_auth_ticket` (
`user_id` int(11) NOT NULL,
`auth_ticket` varchar(60) NOT NULL,
PRIMARY KEY (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

The code above will fix logging in someone elses account without password.

There's more, and I will release more fixes later. If you have troubles with someone who is duck some poop up send me a PM :sleep:

 
Last edited by a moderator:
Joined
Apr 24, 2013
Messages
1,682
Reaction score
1,124
IMO More fixes > 1 should be

Code:
Room Room = Session.GetHabbo().CurrentRoom;
if (Room == null)
return;




if (Room.CheckRights(Session, false))
return;

and not

Code:
Room Room = Session.GetHabbo().CurrentRoom;
if (Room == null)
return;




if (Room.OwnerId != Session.GetHabbo().Id && Room.CheckRights(Session, false))
return;

Otherwise you only allow the actual room owner to make changes to the wired, while everybody with rights should have this ability. Thanks for releasing these fixes, you've done a great job for the Plus using-community!
 
Newbie Spellweaver
Joined
Apr 29, 2014
Messages
89
Reaction score
59
Number 2 is the exact fix I posted a while back on another forum, yet you credited Shorty? hmm ;)

Either way, I doubt this is the last of these exploits, they seem to be popping up out of nowhere all of a sudden. Thank you for the bot fixes, it's a shame people have been abusing it and some hotels have suffered from it.

+1 from me.
 
Newbie Spellweaver
Joined
Apr 29, 2014
Messages
89
Reaction score
59
Here's another exploit while we're at it.

In PurchaseFromCatalogEvent.cs

Change:
Code:
if (Amount < 1 || Amount > 100)

To:
Code:
if (Amount < 1 || Amount > 100 || !Item.HaveOffer)

To stop people scripting unlimited credits.
 
Retired
Joined
Apr 15, 2015
Messages
715
Reaction score
238
A lot of people have had their db dropped using plus emulator, madness to think its possible but ay. These fixes will sure help people out that are using this emulator.
 
Initiate Mage
Joined
May 28, 2016
Messages
1
Reaction score
0
Oh, for the one who keep stuck at 76% after adding the fixes, you have to change your SSO ticket in client.php(?) to something like:



or normal mysql:

okey
i don't exactly know what to do
Please helpme
this is my client
PHP:
<?phprequire_once ('heliocms/core.php');if (isset($_SESSION['id'])) {if (isset($_GET['hash'])) {$client_a = mysql_query("SELECT * FROM heliocms_hotel");$client_q = mysql_fetch_assoc($client_a);mysql_query("UPDATE users SET auth_ticket = '', auth_ticket = '".GenerateTicket()."', ip_last = '', ip_last = '".$ip."' WHERE id = '".$user_q['id']."'");$ticketsql = mysql_query("SELECT * FROM users WHERE id = '".$user_q['id']."'");$ticketrow = mysql_fetch_assoc($ticketsql);?><!DOCTYPE HTML><html><head>    <meta content="text/html;charset=utf-8" http-equiv="Content-Type">    <link rel="stylesheet" href="<?php echo $aka; ?>/habbo-web/america/pt/app.css">    <link rel="stylesheet" type="text/css" href="<?php echo $aka; ?>/game-data-server-static//./hotel.css">    <script type="text/javascript" src="<?php echo $aka; ?>/game-data-server-static//./habboapi.js"></script></head> <script type="text/javascript">    var flashvars = {        "external.texts.txt": "<?php echo $client_q['external_flash_texts']; ?>",        "connection.info.port": "<?php echo $client_q['port']; ?>",        "furnidata.load.url": "<?php echo $client_q['furnidata']; ?>",        "external.variables.txt": "<?php echo $client_q['external_variables']; ?>",        "client.allow.cross.domain": "1",        "url.prefix": "<?php echo $site; ?>",        "external.override.texts.txt": "<?php echo $client_q['external_flash_override_texts']; ?>",        "supersonic_custom_css": "<?php echo $aka; ?>\/game-data-server-static\/\/.\/hotel.css",        "external.figurepartlist.txt": "<?php echo $client_q['figuredata']; ?>",        "flash.client.origin": "popup",        "client.starting": "Por favor aguarde! O <?php echo $sitename; ?> est\u00E1 carregando...",        "processlog.enabled": "1",        "has.identity": "1",        "productdata.load.url": "<?php echo $client_q['productdata']; ?>",        "client.starting.revolving": "Cuando menos te lo esperes... terminarĆ” de cargar...\/Cargando mensaje divertido! Por favor espera.\/ĀæQuieres papas fritas para acompaƱar?\/Siga al pato amarillo.\/El tiempo \u00E9 es una ilus\u00E3Ć³n.\/J\u00E1 chegamos?!\/Me gusta tu camiseta\/Mira para un lado, mira para el otro... parpadea dos veces. Listo\/No eres tĆŗ... soy yo\/Shhh! Estoy intentando pensar aquĆ­\/Cargando universo de pixeles...",        "external.override.variables.txt": "<?php echo $client_q['external_override_variables']; ?>",        "spaweb": "1",        "supersonic_application_key": "2c63c535",        "connection.info.host": "<?php echo $client_q['host']; ?>",        "sso.ticket": "<?php echo $ticketrow['auth_ticket']; ?>",        "client.notify.cross.domain": "0",        "account_id": "<?php echo $user_q['id']; ?>",        "flash.client.url": "<?php echo $client_q['base']; ?>",        "unique_habbo_id": "<?php echo $w; ?>",    };    </script>    <script>    var params = {    "base": "<?php echo $client_q['base']; ?>",    "allowScriptAccess": "always",    "menu": "false",    "wmode": "opaque"    };    swfobject.embedSWF('<?php echo $client_q['habbo_swf']; ?>', 'flash-container', '100%', '100%', '11.1.0', '//habboo-a.akamaihd.net/habboweb/63_1d5d8853040f30be0cc82355679bba7c/3630/web-gallery/flash/expressInstall.swf', flashvars, params, null, null);    if (!(HabbletLoader.needsFlashKbWorkaround())) {    params["wmode"] = "opaque";    }    FlashExternalInterface.signoutUrl = "<?php echo $site; ?>/logout";    </script><body id="client" class="flashclient">  <div id="overlay"></div><div id="client-ui" >    <div id="flash-wrapper">    <div id="flash-container">    <div ng-if="isOpen && !flashEnabled" class="client-error">    <div class="client-error__text">        <h1 class="client-error__title" translate="CLIENT_ERROR_TITLE">Ops, sem Flash, sem <?php echo $sitename; ?>!</h1>        <p translate="CLIENT_ERROR_FLASH">Se vocĆŖ estĆ” utilizando um PC, vocĆŖ precisa <a href="http://www.adobe.com/go/getflashplayer" target="_blank">atualizar ou instalar o Flash player</a>.</p>        <div class="client-error__downloads">            <a href="http://www.adobe.com/go/getflashplayer" ng-href="http://www.adobe.com/go/getflashplayer" target="_blank" class="client-error__flash"></a>        </div>        <p translate="CLIENT_ERROR_MOBILE">Se vocĆŖ estĆ” utilizando um iPad, iPhone ou um dispositivo Android vocĆŖ deve baixar o <a href="https://itunes.apple.com/app/id794866182" target="_blank"><?php echo $sitename; ?> para iOS</a> na App Store ou <a href="https://play.google.com/store/apps/details?id=air.com.sulake.habboair" target="_blank"><?php echo $sitename; ?> para Android</a> na Google PlayStore.</p>        <div class="client-error__downloads">            <a href="https://itunes.apple.com/app/id794866182" ng-href="https://itunes.apple.com/app/id794866182" target="_blank" class="client-error__appstore"></a>            <a href="https://play.google.com/store/apps/details?id=air.com.sulake.habboair" ng-href="https://play.google.com/store/apps/details?id=air.com.sulake.habboair" target="_blank" class="client-error__googleplay"></a>        </div>    </div></div>    </div>    </div></div> </body></html><?php }} ?>
 
Newbie Spellweaver
Joined
Apr 12, 2016
Messages
13
Reaction score
3
Good job! Sure that many people will appreciate it :)

However, I'm not using atm Plus Emulator, but yh i'm planning to use it soon.
 
Elite Diviner
Joined
Aug 4, 2013
Messages
466
Reaction score
169
This is a very beneficial thread for the community, especially because a majority of the community is now using the Plus Emulator that Sledmore released. Kudos to you for providing the community with this information rather than causing havoc. Not something a lot of people in the community would do.
 
Newbie Spellweaver
Joined
Apr 29, 2014
Messages
89
Reaction score
59
IMO More fixes > 1 should be

Code:
Room Room = Session.GetHabbo().CurrentRoom;
if (Room == null)
return;




if (Room.CheckRights(Session, false))
return;

and not

Code:
Room Room = Session.GetHabbo().CurrentRoom;
if (Room == null)
return;




if (Room.OwnerId != Session.GetHabbo().Id && Room.CheckRights(Session, false))
return;

Otherwise you only allow the actual room owner to make changes to the wired, while everybody with rights should have this ability. Thanks for releasing these fixes, you've done a great job for the Plus using-community!

Isn't it supposed to be..
Code:
if (!Room.CheckRights(Session, false))
return;

Otherwise you're allowing everyone BUT users with rights to use and save wired.
 
Junior Spellweaver
Joined
Dec 12, 2015
Messages
103
Reaction score
5
Your inbox is full. I editted the fix with the 'IQueryAdapter' instead of 'QueryAdapter'.

Thread updated.

Ye I already figured out that part, but my client isn't working, check your inbox.
 
Newbie Spellweaver
Joined
Sep 16, 2013
Messages
69
Reaction score
6
Need replacable code for revcms for sso ticket 76% loaded and stuck


tis log

Error in query:
SELECT users.id,users.username,users.rank,users.motto,users.look,users.gender,users.last_online,users.credits,users.activity_points,users.home_room,users.block_newfriends,users.hide_online,users.hide_inroom,users.vip,users.account_created,users.vip_points,users.machine_id,users.volume,users.chat_preference,users.focus_preference,users.pets_muted,users.bots_muted,users.advertising_report_blocked,users.last_change,users.gotw_points,users.ignore_invites,users.time_muted,users.allow_gifts,users.friend_bar_state,users.disable_forced_effects,users.allow_mimic,users.rank_vip FROM users JOIN user_auth_ticket ON users.id = user_auth_ticket.user_id WHERE user_auth_ticket.auth_ticket = @sso LIMIT 1
MySql.Data.MySqlClient.MySqlException (0x80004005): Fatal error encountered during command execution. ---> MySql.Data.MySqlClient.MySqlException (0x80004005): Parameter '@sso' must be defined.
bij MySql.Data.MySqlClient.Statement.SerializeParameter(MySqlParameterCollection parameters, MySqlPacket packet, String parmName, Int32 parameterIndex)
bij MySql.Data.MySqlClient.Statement.InternalBindParameters(String sql, MySqlParameterCollection parameters, MySqlPacket packet)
bij MySql.Data.MySqlClient.Statement.BindParameters()
bij MySql.Data.MySqlClient.PreparableStatement.Execute()
bij MySql.Data.MySqlClient.MySqlCommand.ExecuteReader(CommandBehavior behavior)
bij MySql.Data.MySqlClient.MySqlCommand.ExecuteReader(CommandBehavior behavior)
bij System.Data.Common.DbDataAdapter.FillInternal(DataSet dataset, DataTable[] datatables, Int32 startRecord, Int32 maxRecords, String srcTable, IDbCommand command, CommandBehavior behavior)
bij System.Data.Common.DbDataAdapter.Fill(DataSet dataSet, Int32 startRecord, Int32 maxRecords, String srcTable, IDbCommand command, CommandBehavior behavior)
bij System.Data.Common.DbDataAdapter.Fill(DataSet dataSet)
bij Plus.Database.Adapter.QueryAdapter.getRow() in C:\Users\Remco\Desktop\PlusEMU\Database\Adapter\QueryAdapter.cs:regel 77
 
Skilled Illusionist
Joined
Mar 26, 2013
Messages
371
Reaction score
280
I have found another SQL injection some times ago,

On HabboHotel/Moderation/ModerationManager.cs change

Code:
dbClient.SetQuery("REPLACE INTO `bans` (`bantype`, `value`, `reason`, `expire`, `added_by`,`added_date`) VALUES ('" + BanType + "', '" + BanValue + "', [USER=2000164457]ReasoN[/USER], " + ExpireTimestamp + ", '" + Mod + "', '" + PlusEnvironment.GetUnixTimestamp() + "');");
dbClient.AddParameter("reason", Reason);
dbClient.RunQuery();

To

Code:
dbClient.SetQuery("REPLACE INTO `bans` (`bantype`, `value`, `reason`, `expire`, `added_by`,`added_date`) VALUES ('" + BanType + "', @value, [USER=2000164457]ReasoN[/USER], " + ExpireTimestamp + ", '" + Mod + "', '" + PlusEnvironment.GetUnixTimestamp() + "');");
dbClient.AddParameter("reason", Reason);
dbClient.AddParameter("value", BanValue);
dbClient.RunQuery();

Since there is no check on machine ID format (look like a hash), an attacker can inject a query on it and ask for a mban (or insult staff to get a mban for example).
 
Skilled Illusionist
Joined
Mar 26, 2013
Messages
371
Reaction score
280
I have no idea or it's possible to generate a fake 'machineid' but if it's possible, woah we're fucked. Thank you for posting this :love:

Is possible and is easy, using a Bot or a Packetlogger you just need send the UniqueIDMessageEvent with a custom string and inject packet to server.

And maybe other SQL injection issue here :

On HabboHotel/Rooms/Chat/Commands/User/Fun/FacelessCommand.cs


Change


Code:
dbClient.RunQuery("UPDATE `users` SET `look` = '" + Session.GetHabbo().Look + "' WHERE `id` = '" + Session.GetHabbo().Id + "' LIMIT 1");


To


Code:
dbClient.SetQuery( "UPDATE `users` SET `look` = [USER=1333417016]Look[/USER] WHERE `id` = '" + Session.GetHabbo().Id + "' LIMIT 1");
dbClient.AddParameter("look", Session.GetHabbo().Look);
dbClient.RunQuery();
 
Junior Spellweaver
Joined
Jul 31, 2012
Messages
188
Reaction score
5
Maybe another sql injection in inventory component (idk)
Code:
  dbClient.RunQuery("UPDATE `items` SET `room_id` = '0', `user_id` = '" + _userId + "' WHERE `id` = '" + Id + "' LIMIT 1");
to
Code:
  dbClient.RunQuery("UPDATE `items` SET `room_id` = '0', `user_id` =   [USER=1335]user[/USER]id WHERE `id` = [USER=19862]id[/USER] LIMIT 1");
                        dbClient.AddParameter("userid", _userId);
                        dbClient.AddParameter("id", Id);
                        dbClient.RunQuery();
idk if it works. I'm not a coder.

UPDATE: maybe samething in:
Code:
  if (Id > 0)
                            dbClient.RunQuery("INSERT INTO `items` (`id`,`base_item`, `user_id`, `limited_number`, `limited_stack`) VALUES ('" + Id + "', '" + BaseItem + "', '" + _userId + "', '" + LimitedNumber + "', '" + LimitedStack + "')");
                        else
                        {
                            dbClient.SetQuery("INSERT INTO `items` (`base_item`, `user_id`, `limited_number`, `limited_stack`) VALUES ('" + BaseItem + "', '" + _userId + "', '" + LimitedNumber + "', '" + LimitedStack + "')");
                            Id = Convert.ToInt32(dbClient.InsertQuery());
                        }
?
 
Skilled Illusionist
Joined
Mar 26, 2013
Messages
371
Reaction score
280
Maybe another sql injection in inventory component (idk)
Code:
  dbClient.RunQuery("UPDATE `items` SET `room_id` = '0', `user_id` = '" + _userId + "' WHERE `id` = '" + Id + "' LIMIT 1");
to
Code:
  dbClient.RunQuery("UPDATE `items` SET `room_id` = '0', `user_id` =   @[I][B][URL="http://forum.ragezone.com/members/1335.html"]user[/URL][/B][/I]id WHERE `id` = @[I][B][URL="http://forum.ragezone.com/members/19862.html"]id[/URL][/B][/I] LIMIT 1");
                        dbClient.AddParameter("userid", _userId);
                        dbClient.AddParameter("id", Id);
                        dbClient.RunQuery();
idk if it works. I'm not a coder.

UPDATE: maybe samething in:
Code:
  if (Id > 0)
                            dbClient.RunQuery("INSERT INTO `items` (`id`,`base_item`, `user_id`, `limited_number`, `limited_stack`) VALUES ('" + Id + "', '" + BaseItem + "', '" + _userId + "', '" + LimitedNumber + "', '" + LimitedStack + "')");
                        else
                        {
                            dbClient.SetQuery("INSERT INTO `items` (`base_item`, `user_id`, `limited_number`, `limited_stack`) VALUES ('" + BaseItem + "', '" + _userId + "', '" + LimitedNumber + "', '" + LimitedStack + "')");
                            Id = Convert.ToInt32(dbClient.InsertQuery());
                        }
?

No, the injected value are integer, isn't possible to inject on it.
I already checked all query of emulator, there is no longer SQL injection on it if you apply all patch of this thread.

And your code is wrong, RunQuery execute the query, you can't AddParameter after that, you need use SetQuery, add params and finally RunQuery.
 
Retired
Loyal Member
Joined
May 5, 2007
Messages
497
Reaction score
665
No, the injected value are integer, isn't possible to inject on it.

While it is correct the code doesn't allow sqlis, it creates technical debt in that sense someone can modify the code with minor changes, making it exploitable. For example, in the future, some Special person may change this to a string and doesn't realize the query doesn't use prepared statement and oops you have an sqli. This is why you should - always - use prepared statement and you are entitled to "Special person developer for the month" if you were to suggest otherwise.
 
Back
Top