Jump to content
Maximilian

Gem level up Combining script exploit - explanation and fix

Recommended Posts

Hello everybody.

Recently, a very damaging bug came to my attention, it's possible with a bit of manipulation to combine gems without destroying any in the process.
I will not exactly explain how to fully reproduce it so if people were to notice this before server-owners did.

The bug works this way: while the inventory is locked, no items can be deleted from it. This is usually not a problem because GiveItem does not work either, it will just give you an error.
This is an example in said situation:
immagine.png.3819aa09ccb6bd6c1bb7f8ca831511de.png

When analyzing items while the inventory is locked, no abuse is possible because while no items are deleted from the player's inventory, no items can be added to it either, thus "operation failed" being added to the system message.

However, if we were to look at the combining function : "begin_unite_item"
 

function begin_unite_item (...)
	local arg = {...}
	
	local Check_CanUnite = 0
	Check_CanUnite = can_unite_item_main ( arg )
	if Check_CanUnite == 0 then
		return 0
	end
	
	local role = 0
	local ItemBag = {}
	local ItemCount = {}
	local ItemBagCount = {}	
	local Get_Count = 4
	local ItemReadCount = 0
	local ItemReadNow = 1
	local ItemReadNext = 0
	local ItemBag_Now = 0
	local ItemCount_Now = 0
	local ItemBagCount_Num = 0

	role , ItemBag , ItemCount , ItemBagCount , ItemBag_Now , ItemCount_Now , ItemBagCount_Num = Read_Table ( arg )

	
	local BagItem1 = ItemBag [0]
	local BagItem2 = ItemBag [1]
	local BagItem3 = ItemBag [2]
	
	local BagItem1 = arg [3]
	local BagItem2 = arg [6]
	local BagItem3 = arg [9]

	local Item1 = GetChaItem ( role , 2 , BagItem1 )
	local Item2 = GetChaItem ( role , 2 , BagItem2 )
	local Item3 = GetChaItem ( role , 2 , BagItem3 )
	
	local ItemID1 = GetItemID ( Item1 )
	local ItemID2 = GetItemID ( Item2 )
	local ItemID3 = GetItemID ( Item3 )

	local ItemType2 = GetItemType ( Item2 )

	local Item2_Lv = Get_StoneLv ( Item2 )
	local Item3_Lv = Get_StoneLv ( Item3 )

	local i = 0
	local j = 0

	i = RemoveChaItem ( role , ItemID1 , 1 , 2 , BagItem1 , 2 , 1 , 0)		
	j = RemoveChaItem ( role , ItemID3 , 1 , 2 , BagItem3 , 2 , 1 , 0)		

	if i == 0 or j == 0 then -- important part
		LG( "Hecheng_BS" , "Delete item failed" ) 
	end
	
	Item2_Lv =Item2_Lv + 1 -- important part 2
	
	Set_StoneLv ( Item2 , Item2_Lv ) -- important part 3
	
	local Money_Need = getunite_money_main ( arg )
	local Money_Have = GetChaAttr ( role , ATTR_GD )
  
	Money_Have = Money_Have - Money_Need
	SetCharaAttr ( Money_Have , role , ATTR_GD )
	ALLExAttrSet( role )
	
	local Sklv = 1
	local StateLv = GetChaStateLv ( role , STATE_HCGLJB )
	
	Sklv = Sklv + StateLv


	local b = Check_CG_HechengBS ( Item2_Lv , ItemType2 , Sklv )
	if b == 0 then  -- important part 3
		i = RemoveChaItem ( role , ItemID2 , 1 , 2 , BagItem2 , 2 , 1 , 0)	
		if i == 0 then
			LG( "Hecheng_BS" , "Delete item failed" )
		end
		local cha_name = GetChaDefaultName ( role )
		LG( "JingLian_ShiBai" , "Player"..cha_name.."Gem combining failed" )
		SystemNotice( role , "Very sorry, combining has failed. Gem has vanished...")

		return 2	
	end
	local cha_name = GetChaDefaultName ( role )
	LG( "JingLian_ShiBai" , "Player"..cha_name.."Gem combining successful" )
	return 1
end

As you can see, this script does not "give" any item, it sets the gem level to 1 higher than it originally was.
Therefore, if people were able to lock their inventory. They would prevent the deletion of their gem, and get one of their gems upgraded.

Furthermore, this would work even if the combining were to fail given that the deletion of the gem due to failure happens *after* the gem level is increased, and items are not deleted when inventory is locked.


The fix is trivially simple, just have the function stop when items are supposed to get deleted, like this :
Or whatever suits your code-base, interrupt the function when items that should be deleted aren't.


    if i == 0 or j == 0 then

        LG( "Hecheng_BS" , "Delete item failed" )
        return 0

   end



If any site admin wants any further proof I will oblige, however I will not go into detail on the process a player can use to lock their inventory in such a way.

I would suggest to also check other functions which have the same behavior when items aren't deleted, I don't think any is susceptible to this same exploitation, but you never know.


A screenshot of the bug in action:
immagine.png.969bc47e0c69400322700779732abc86.png

Before this I had 1 refining gem level 2 and two level 1 in my inventory, after I had two level two and one level one.


immagine.png.1ad560f7c3badaaac33c87eae1622b5f.png

And now one is level three one is level two and one is level one

Neither the level 2 nor the level 1 of previous gem combinings got deleted

Edited by Maximilian
  • Like 1
  • Thanks 1

Share this post


Link to post
Share on other sites
1 hour ago, squaller said:

combining while trade?

No that's checked by the server, this kind of inventory-locking is non-trivial to acquire, I'm sorry but I do not want to disclose any more information on how that's achievable since this bug will likely be exploitable in several major servers untill this gets more attention.

Share this post


Link to post
Share on other sites
1 hour ago, Maximilian said:

No that's checked by the server, this kind of inventory-locking is non-trivial to acquire, I'm sorry but I do not want to disclose any more information on how that's achievable since this bug will likely be exploitable in several major servers untill this gets more attention.

This looks like CO files based on the client? If you are using CO server files, take a look at lua\plugin\gem.lua. That is where they load forge/combine function.


Nissan-GT-R.gif

Share this post


Link to post
Share on other sites
11 hours ago, Dan said:

This looks like CO files based on the client? If you are using CO server files, take a look at lua\plugin\gem.lua. That is where they load forge/combine function.

The screenshots are taken in a server that alleges to use CO server files, so there's empirical evidence of this working.

Furthermore not every server is using the custom gem.lua function, most are likely using the vulnerable one.

@Dan I checked the function in gem.lua 
I think that there's a problem on it too

 

	if i == 0 or j == 0 or k == 0 then
		LG( "Hecheng_BS" , "Delete item failed" )
		return -- does not return a value
	end

-- this part of the function should probably be the following:

	if i == 0 or j == 0 or k == 0 then
		LG( "Hecheng_BS" , "Delete item failed" )
		return 0
	end

 

Edited by Maximilian
updated information

Share this post


Link to post
Share on other sites

@Maximilian This is an issue caused from the “exploit” or “missing code” at lua side which is related to the gem stack feature that CO has.

Ex: keep like 2 or any amount of lv 1 gem (any gem) on invertory and extract a gem lv 2 or higher from equips (same gem that you have as lv 1 on invertory).

Ex:  if you extracted a lv 5 gem of rage and you had 20x lv 1 or more in invertory then all those 20x will turn lv 5.

This fix is already shared on forum on CO community topics by Angelix or Fritt one of them.

 

This would probably fix the issue you mentioned (Not tested).

 

Edit: If your not able to find the fix, let me know i’ll share it here.

Edited by Rinor

Share this post


Link to post
Share on other sites
36 minutes ago, Rinor said:

@Maximilian This is an issue caused from the “exploit” or “missing code” at lua side which is related to the gem stack feature that CO has.

Ex: keep like 2 or any amount of lv 1 gem (any gem) on invertory and extract a gem lv 2 or higher from equips (same gem that you have as lv 1 on invertory).

Ex:  if you extracted a lv 5 gem of rage and you had 20x lv 1 or more in invertory then all those 20x will turn lv 5.

This fix is already shared on forum on CO community topics by Angelix or Fritt one of them.

 

This would probably fix the issue you mentioned (Not tested).

 

Edit: If your not able to find the fix, let me know i’ll share it here.

Honestly, I do not see how they are related. The issue I am talking about stems from the fact that locked inventories prevent items from being deleted from the inventory, and the vanilla lua "begin_unite_item" function does not interrupt when items fail to be deleted. 
CO files have nothing to do with it, do not get confused by the fact that the screenshots show that the server I tested this on - with the GM's permission - has a CO-based client.

If I read CO's sourcecode correctly this exploit does not work when CO's begin_unite_item is used, because CO uses an AddItem function which in the server c++ code checks for the inventory being locked or not, however the vanilla function doesn't add any item, it just increases the level attribute of one of the two gems used in combining. 
Having the function return 0 when item deletion files fixes the issue.

Share this post


Link to post
Share on other sites

Another fix that came to my attention: the forcible flag:

i = RemoveChaItem ( role , ItemID1 , 1 , 2 , BagItem1 , 2 , 1 , 0)

the last attribute of this function is "0" which sets forcible deletion to false, when the function is set as:

i = RemoveChaItem ( role , ItemID1 , 1 , 2 , BagItem1 , 2 , 1 , 1)

Forcible deletion is set to true, which means that items are deleted even when the character's inventory is locked.

Share this post


Link to post
Share on other sites

@Maximilian you already sharing the fix, means you should give an example how you did it so people here can test to know if this exploits works in their files and apply the fix you shared, as diff devs uses diff files/extensions/addons.

Edited by Rinor

Share this post


Link to post
Share on other sites
21 hours ago, Rinor said:

@Maximilian you already sharing the fix, means you should give an example how you did it so people here can test to know if this exploits works in their files and apply the fix you shared, as diff devs uses diff files/extensions/addons.

Use gm commands to lock inventory and try.  

 

Note: the main C++ function checks for some locks, so you can either disable the checks temporary for testing purposes or set the lock that's not checked which is the bLock boolean value.

 

I will not explain how a non-gm can acquire the particular lock because probably a lot of servers are unsafe.

You should have all the information needed if you actually own a server and have access to GM level commands.

Share this post


Link to post
Share on other sites

😅 so much drama for such old bugs tho?

but you mentioned that for combine only so you should know its also called as gold hack as other name?

 and can use same method for the rest of any process ingame as most checks in top base on client side
and they were so dumb to check one type of locks
top have 4 type of locks:
1- inventory > most codes check it<
2- trade locks >GetTradeData() < most codes doesn't check it in server side, just in client
3- stall locks > GetStallData() < most codes check that in client side, not checked on sell items/ forge/combine analyze 

4- item lock stone Block states 
so if you server owner and wrote a code you should start with small check for item itself if locked or not 

item =GetChaItem(role,2,slot)
if(IsItemLocked(item))

 then create new code for check all states at one function 
 

inline int lua_IsChaLocked(lua_State* L) {
	BOOL bValid = lua_gettop(L) == 1 && lua_islightuserdata(L, 1);
	if (!bValid) {
		E_LUAPARAM;
		return 0;
	}

	CCharacter* pChar = (CCharacter*)lua_touserdata(L, 1);
	if (!pChar) {
		E_LUANULL;
		return 0;
	}
	if (pChar->GetPlyMainCha()->m_CKitbag.IsPwdLocked() || pChar->GetPlyMainCha()->GetStallData() || pChar->GetPlyMainCha()->GetTradeData()) {
		lua_pushnumber(L, LUA_TRUE);
	} else {
		lua_pushnumber(L, LUA_FALSE);
	}
	return 1;
}

or just create it in lus side and use in your codes 

 

function IsChaLocked(character)
		if KitbagLock(character, 1) == LUA_TRUE or GetChaStateLv(character, STATE_BAT) >= 1 or GetChaStateLv(character, STATE_JY) >= 1 then
			return true
		else
			return false
		end
end


 

  • Like 1

Share this post


Link to post
Share on other sites
8 hours ago, mkhzaleh said:

😅 so much drama for such old bugs tho?

what do you mean so much drama? hey kid, everyone here is learning and helping each other, if that's your point of view on everything just "drama" then you won't move on in life, no wonder why the community is dead already and everyone that has had a real impact on it left, it's because it was built on toxicity, people like you like to come here and show off that they know something... huh, what do you know? some fixes, adjustments to a game that was created around 2007 and those fixes/adjustments are mostly copied from Wrexor or V3ct0r so there's no credits for your ass here, your brain is full of shit bro, you need to change  your behaviour, if you have something to share, then share it in a gentle way, if you want to show off then fuck off of here, this is men's world and you're behaving like a child, so you'll be treated like a child


Kind regards, AG.

Share this post


Link to post
Share on other sites
24 minutes ago, J0k3r said:

what do you mean so much drama? hey kid, everyone here is learning and helping each other, if that's your point of view on everything just "drama" then you won't move on in life, no wonder why the community is dead already and everyone that has had a real impact on it left, it's because it was built on toxicity, people like you like to come here and show off that they know something... huh, what do you know? some fixes, adjustments to a game that was created around 2007 and those fixes/adjustments are mostly copied from Wrexor or V3ct0r so there's no credits for your ass here, your brain is full of shit bro, you need to change  your behaviour, if you have something to share, then share it in a gentle way, if you want to show off then fuck off of here, this is men's world and you're behaving like a child, so you'll be treated like a child

so mad kid? your way of reply shows how kiddo you are don't you?

and i say what ever i want and yea i see its drama comments and i already shared such  a fix 3 years ago so what ever
and nope not everything there to v3ctor or wrexor credit dude , that's show how kid and useless you are
all credit goes to real top team , if you like this truth or not ..  people does mods, fix exploits that's their credits , no less no more?
what is your impact in this situation ? zero? big mouth? useless ? that's is you ;)

Edited by mkhzaleh

Share this post


Link to post
Share on other sites

Share this post


Link to post
Share on other sites

😅 well i don't even know who is this kid so what ever if he can't handle sarcasm "drama word" and skipped the rest of explaining how the bug works
shows how kiddo he is  🤡
 

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • Create New...