Plus Emulator Security Fixes

⚠️
Self Deleted
Joined
Jul 29, 2010
Messages
707
Reaction score
507
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 **** some **** 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 **** some **** up send me a PM :sleep:

 
Last edited by a moderator:
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!
 
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.
 
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.
 
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.
 
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 }} ?>
 
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.
 
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.
 
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.
 
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
 
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).
 
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();
 
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());
                        }
?
 
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.
 
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 retard 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 "retard developer for the month" if you were to suggest otherwise.
 
Back