Jump to content
Sign in to follow this  
Totoka

KOP2 SQL-Injections/Holes

Recommended Posts

Hello!
Someone know how many holes has the server side?
I know about the mac address at the login packet.

But, are there more 'holes'?

  • Like 1

Discord: andresc

Share this post


Link to post
Share on other sites

Hello @Totoka!

 

AccountServer.exe

  1. MAC address in login packet.

GroupServer.exe

  1. Pin set packet;
  2. Pin change packet.

GameServer.exe (not SQL inj)

  1. Party searching on the sea;
  2. Players can make monster skills (skill upgrade packet);
  3. Players can make 20lv skill (skill upgrade packet).

 

  • Like 2

Share this post


Link to post
Share on other sites

@V3ct0r

 

GroupServer.exe

  • Q 1. - Is the once which can be set/change at the character selection screen?
-- This query is being executed from the GroupServer, once I change it at the client.
update account set password='96E79218965EB72C92A549DD5A330112' where act_id=?

-- The only way comes to my mind an sql-injection, is in case the  MD5 comes from the client.
  •  Q 2. Do you know if this is the case?

 

GameServer.exe

  • Q 1. "Party searching on the sea". How this affect the game ?
  • A 2-3. "Skill Upgrade packet". Mother of god, I'm going to inject myself some caffeine, I'll need it for x64dbg :x. X)

Discord: andresc

Share this post


Link to post
Share on other sites

Are there any GameServers that have patched all these holes? @V3ct0r @7n6


logo-big.png   logo.png

                                   Sunny Go! Online                                                                    pko.host                                                 

Share this post


Link to post
Share on other sites
On 13/08/2016 at 11:03 AM, Totoka said:

@V3ct0r

 

GroupServer.exe

  • Q 1. - Is the once which can be set/change at the character selection screen?

-- This query is being executed from the GroupServer, once I change it at the client.
update account set password='96E79218965EB72C92A549DD5A330112' where act_id=?

-- The only way comes to my mind an sql-injection, is in case the  MD5 comes from the client.
  •  Q 2. Do you know if this is the case?

 

GameServer.exe

  • Q 1. "Party searching on the sea". How this affect the game ?
  • A 2-3. "Skill Upgrade packet". Mother of god, I'm going to inject myself some caffeine, I'll need it for x64dbg :x. X)

 

GroupServer.exe ~
>.< fuck yeah! moliyo loves the client side validation stuff, has much cpu usage at the server side (?
except the string length! ... it should be less or equal to 32 at the server side. Ahahahaha

 

GameServer.exe
- just for now, i'm gonna ignore the packet 0x0041 from client to gate, and remove that 'feature' about the party searching to avoid crashes.  I didnt try it, but anyway dont care x)

- skill upgrade, I'll try by using a lua function, kind of proxy/middleware between each skill execution to know if the 'role'/'character' has the skill, dunno if thats going to work  properly.

 


Discord: andresc

Share this post


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

 

- skill upgrade, I'll try by using a lua function, kind of proxy/middleware between each skill execution to know if the 'role'/'character' has the skill, dunno if thats going to work  properly.

 

http://pastebin.com/awx5fydQ

 

I made that a while ago (just tried to make it less messy now), it might be useful. (havent tested it in a while, so might be buggy, but is a good base)

 

Whenever a player uses a skill, it check if the level is >10 or if the level is > their stored level, and if it is then the player is jailed. (you need to manually edit poss skillbook/ rb skillbook/ rb npc etc to record the skill once it is given)

  • Like 1

Share this post


Link to post
Share on other sites
On 16/08/2016 at 1:57 PM, 7n6 said:

http://pastebin.com/awx5fydQ

 

I made that a while ago (just tried to make it less messy now), it might be useful. (havent tested it in a while, so might be buggy, but is a good base)

 

Whenever a player uses a skill, it check if the level is >10 or if the level is > their stored level, and if it is then the player is jailed. (you need to manually edit poss skillbook/ rb skillbook/ rb npc etc to record the skill once it is given)

 

Very useful!
thank you

------------------------------------------------------------------------------------------------------------------------------------------------------------

@7n6 @KONG @V3ct0r

 

I would like to use memory instead of files, someone knows if something like this would work?

-- an example skill begin function
function skill_begin(atk,def,slv)
    print('skill function',atk,def,slv)
end

-- proxy validator with its validation closure
function skill_proxy(skillid, funcName)
    print('skill proxy for', skillid, funcName)
    local pFunc = _G[funcName] -- does a copy before get overrided, to be used into the closure
    return function(atk,def,slv)
        print('skill closure', skillid, funcName, pFunc)
        -- validate if atk really has this skill
        -- validate level
        -- ...
        -- if all good, then execute the being function
        -- the one we stored a pointer copy into @pFunc
        pFunc(atk,def,slv)
    end
end

-- rewrite every skill begin function
-- a loop for every skill at skillinfo.txt {
    local currentSkillId = 1
    local currentFuncName = 'skill_begin' -- index 30 i guess
    _G[currentFuncName] = skill_proxy(currentSkillId,currentFuncName)
-- }

-- simulating an skill being called:
local pSource = 'char1'
local pTarget = 'char2'
local skillLv = 20

skill_begin(pSource ,pTarget , skillLv)

-----------------------------------------------------------
-- posible output:
skill proxy for   1          skill_begin
skill closure     1          skill_begin     function: 0x1788ed0
skill function    char1      char2           20

I do not know if there are the necessary functions to validate these, I shall do a research.

 

----------------------------------------------------------------------------------------------------------

Forget it, bad idea, there is no way to check an skill upgrade from Lua, i had to end up with ASM into GameServer.

Edited by Totoka
update answ, magic #

Discord: andresc

Share this post


Link to post
Share on other sites

GameServer.exe

to avoid skills which are not for these class or players, check your skillinfo.txt, and be sure that all the skills used by the players are not set to class any(-1)

 

this function is the ones who check if the requested skill to be upgraded is allowed. by class/ level etc...

problem is that the wildcard (-1) allows anyone to learn anything.

 

here an non-tested solution =P, suppose to work.

 

skill-upgrade.patch006.png

 

patched:

skill-upgrade.patch006.done.png

 

Dunno what kind of problems comes after this.

 

On 18/08/2016 at 10:36 AM, mrsesshoumaru said:

I wanted to understand how can a player can add monster skills like that? How does it work? is it like force pvp?

By using third party software, or filtering the send function at game.exe to edit the packet, you are able to change the skill ID, and level. ( the gameserver.exe check that, but there is a wildcard problem which could be patched out).


Discord: andresc

Share this post


Link to post
Share on other sites

Why someone still bothers with HEX ? if you guys already have SRC.

And even if you want "classic" still can use "detours" functionality to only patch selected functions. A bit troublesome, but need to start somewhere. no?

 

As for the Skill Bug.

Same function, is used to Learn HIDDEN skills that are used by Items. (Granade for example).

So the fix, is not so obvious. And simple HEX can introduce more problems that it fix.

IF I where fixing it, I would duplicate function. One for the Item Skill use, and one for Upgrade Skill packet.

  • Like 1

Share this post


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

Why someone still bothers with HEX ? if you guys already have SRC.

And even if you want "classic" still can use "detours" functionality to only patch selected functions. A bit troublesome, but need to start somewhere. no?

 

As for the Skill Bug.

Same function, is used to Learn HIDDEN skills that are used by Items. (Granade for example).

So the fix, is not so obvious. And simple HEX can introduce more problems that it fix.

IF I where fixing it, I would duplicate function. One for the Item Skill use, and one for Upgrade Skill packet.

I prefer to use the old binary + and extender, instead of these sources, and also i love ASM.

 

That patch was done for skill upgrade, not for it usage.

For those you should use @7n6 script which is very useful.

 

An item has nothing to do at that patch, items can't learn/upgrade skill's. fairies can be an exception, but i don't think they go the same way to learn skills.

Do you already test it?

 

Tested, you are right :$, items also use this function, thank you!

 

Quote

IF I where fixing it, I would duplicate function. One for the Item Skill use, and one for Upgrade Skill packet.

An extender library with some function can also do the same, plus gives freedom to also do extra validations it needs

Edited by Totoka

Discord: andresc

Share this post


Link to post
Share on other sites

I have a solution. I check skill ID and level using my lua function before GameServer.exe call LearnSkill() function:

 

 

skillfix1.png

 

skillfix2.png

 

functions.lua:

-- The function checks if skill can be learned or upgraded
function CheckCanUpgradeSkill(role, skill_id) 

       -- Check if player has skill
       local skill = GetSkillLv(role, skill_id) 
       if (skill > 0) then 
           
          -- Looking for the skill in 'special' skill list which can't be upgraded using 'plus' button in skill form (Fairy possession for example) 
          local Data 
          for Data in SkillList do 
              
             if SkillList [Data] == skill_id then   
                SystemNotice(role, "It is impossible to upgrade the skill!") 
                return 0 
             end 
              
          end 
              
          -- Player has skill and it is not 'special' skill. It is OK!
          return 1 
           
       end 
           
       -- Player hasn't the skill
       SystemNotice(role, "You haven't learned this skill. It is impossible to increase the level!") 
       return 0 

end

 

variable.lua

SkillList        = {} 
SkillList[1]     = 0280 
SkillList[2]     = 0311 
SkillList[3]     = 0312 
SkillList[4]     = 0313 
SkillList[5]     = 0314 
SkillList[6]     = 0315 
SkillList[7]     = 0316 
SkillList[8]     = 0317 
SkillList[9]     = 0318 
SkillList[10]    = 0319 
SkillList[11]    = 0321 
SkillList[12]    = 0322 
SkillList[13]    = 0323 
SkillList[14]    = 0324 
SkillList[15]    = 0338 
SkillList[16]    = 0339 
SkillList[17]    = 0340 
SkillList[18]    = 0341 
SkillList[19]    = 0453 
SkillList[20]    = 0454 
SkillList[21]    = 0455 
SkillList[22]    = 0456 
SkillList[23]    = 0457 
SkillList[24]    = 0458 
SkillList[25]    = 0459 
SkillList[26]    = 0467

 

  • Like 1

Share this post


Link to post
Share on other sites

To repair party search system we have to fix two ponters:

prtsearch1.png

 

prtsearch2.png

 

prtsearch3.png

  • Like 1

Share this post


Link to post
Share on other sites
7 часов назад, kLabMouse сказал:

IF I where fixing it, I would duplicate function. One for the Item Skill use, and one for Upgrade Skill packet.

But if function too big? (Ты будешь переписывать целую функцию даже если она огромная?)


Share this post


Link to post
Share on other sites

The LUA solution is BAD. because Lua is single threaded, and everything else just locks before LUA does it's job.

On the other hand, just duplicating same function with patch, and redirecting Skill Upgrade to use patched functions should solve the problem

 

5 hours ago, V3ct0r said:

But if function too big? (Ты будешь переписывать целую функцию даже если она огромная?)

Why not? There is no limitation for Injected DLL.

Share this post


Link to post
Share on other sites

GameServer.exe extension

CCharacter.h

looks like a mess, I shall clean it, once i finish the extension. @PCanLearnSkill pointer to function CanLearnSkill.

 

CCharacter pseudo class

// CCharacter.h
#define CALL_MEMBER(pObject,pMember) (pObject->*(pMember))

#define PCanLearnSkill 0x0053FE10

#define TEXTMAX  0x20
#define SKILLMAX 0x259

class CCharacter {
private:
	void*			pUnknow01;
	char			sID[TEXTMAX];
	char			bUnknow01[0x38];
	unsigned int	pointX1;
	unsigned int	pointY1;
	unsigned int	pointX2;
	unsigned int	pointY2;
	char			bUnknow02[0x10];
	// absolute offset 0x7C
	unsigned int	direction;
	char			bUnknow03[0x18];
	char			mapName[TEXTMAX];
	// absolute offset 0xB8
	char			cityName[TEXTMAX];
	char			bUnknow04[0x10C];
	char			name[TEXTMAX];
	char			bUnknow05[0x3140];
	// absolute offset 0x3350
	struct Skills {
		char  learned;    // flag 0/1, is set when a character has this skill ?
		char  level;      // skill level
		short id;         // skill id
		void *pUnknown1;  // dunno
		void *pUnknown2;  // ...
	} skills[SKILLMAX];
  
	// here is also more bytes, but dont care for now

private:
	// used to find a character skill by id
	Skills* skillByID(unsigned short id);

public:
	bool CanLearnSkill(struct CSkillRecord *pSkill, char nextLv);
};

 

// CCharacter.cpp
#include <stdio.h>    // printf
#include "TableData.h"
#include "Character.h"

CCharacter::Skills*
CCharacter::skillByID(unsigned short id)
{
	unsigned short it=0;
	for(;it<SKILLMAX;++it) {
		if( skills[it].id == id )
			return &skills[it];
	} return NULL;
}

bool
CCharacter::CanLearnSkill(CSkillRecord *pSkill, char nextLv)
{
	bool res = false;
	{
		Skills* skill = skillByID( pSkill->sID );
		typedef bool(CCharacter::*call_t)(CSkillRecord*,char);
		void *pCall = reinterpret_cast<void*>(PCanLearnSkill);
		call_t call=reinterpret_cast<call_t&>(pCall);
		// calls the original function member
		res = CALL_MEMBER(this,call)(pSkill,nextLv);
		// do extra checks for those very special skills
		if( res ) { // PCanLearnSkill returns true
			// ...
			printf("%d valid!\n", pSkill->sID);
		} else { // PCanLearnSkill returns false
			// ...
			printf("%d invalid!\n", pSkill->sID);
		}
	} return res;
}

 

//TableData.h
// taked from kop2 source

#pragma once
#define	defSKILL_NAME_LEN			17
#define defSKILL_ICON_NAME_LEN		17
#define defSKILL_JOB_SELECT_NUM		9
#define defSKILL_ITEM_NEED_NUM		8
#define defSKILL_PRE_SKILL_NUM		3
#define defEFFECT_SELF_ATTR_NUM		2
#define defEFFECT_TAR_ATTR_NUM		2
#define defEXPEND_ITEM_NUM			2
#define defSKILL_OPERATE_NUM		3
#define defSKILL_POSE_NUM			10
#define defSKILL_RANGE_SET_SCRIPT	33
#define defSKILL_EFFECT_SCRIPT_LEN	33
#define defSKILL_ACTION_EFFECT		3
#define defSKILL_ITEM_EFFECT		2
#define defSELF_EFFECT_NUM			2

typedef struct CRawDataInfo {
    int				bExist;
	int				nIndex;
	char			szDataName[72];
	unsigned long	dwLastUseTick;
	int				bEnable;
	void*			pData;
	unsigned long	dwPackOffset;
	unsigned long	dwDataSize;
	int				nID;
    unsigned long	dwLoadCnt;

} CRawDataInfo;

typedef struct CSkillRecord: public CRawDataInfo {

	short	sID;
	char	szName[defSKILL_NAME_LEN];
	char    chFightType;
	char	chJobSelect[defSKILL_JOB_SELECT_NUM][2];

	short	sItemNeed[3][defSKILL_ITEM_NEED_NUM][2];
	short	sConchNeed[defSKILL_ITEM_NEED_NUM][3];
	char	chPhase;
	char	chType;
	short	sLevelDemand;
	short	sPremissSkill[defSKILL_PRE_SKILL_NUM][2];
	char	chPointExpend;
	char	chSrcType;
	char	chTarType;
	short	sApplyDistance;
	char	chApplyTarget;
	char	chApplyType;
	char	chHelpful;
	short	sAngle;
	short	sRadii;
	char	chRange;
	char	szPrepare[defSKILL_RANGE_SET_SCRIPT];
	char	szUseSP[defSKILL_EFFECT_SCRIPT_LEN];
	char	szUseEndure[defSKILL_EFFECT_SCRIPT_LEN];
	char	szUseEnergy[defSKILL_EFFECT_SCRIPT_LEN];
	char	szSetRange[defSKILL_EFFECT_SCRIPT_LEN];
	char	szRangeState[defSKILL_EFFECT_SCRIPT_LEN];
	char	szUse[defSKILL_EFFECT_SCRIPT_LEN];
	char	szEffect[defSKILL_EFFECT_SCRIPT_LEN];
	char	szActive[defSKILL_EFFECT_SCRIPT_LEN];
	char	szInactive[defSKILL_EFFECT_SCRIPT_LEN];
	int		nStateID;
	short	sSelfAttr[defEFFECT_SELF_ATTR_NUM];
	short	sSelfEffect[defSELF_EFFECT_NUM];
	short	sItemExpend[defEXPEND_ITEM_NUM][2];
	short	sBeingTime;
	short	sTargetAttr[defEFFECT_TAR_ATTR_NUM];
	short	sSplashPara;
	short	sTargetEffect;
	short	sSplashEffect;
	short	sVariation;
	short	sSummon;
	short	sPreTime;
	char	szFireSpeed[defSKILL_EFFECT_SCRIPT_LEN];
	char	chOperate[defSKILL_OPERATE_NUM];

public:
	short	sActionHarm;
	char	chActionPlayType;
	short	sActionPose[defSKILL_POSE_NUM];
	short	sActionKeyFrme;
	short	sWhop;
	short	sActionDummyLink[defSKILL_ACTION_EFFECT];
	short	sActionEffect[defSKILL_ACTION_EFFECT];
	short	sActionEffectType[defSKILL_ACTION_EFFECT];
	short	sItemDummyLink;
	short	sItemEffect1[defSKILL_ITEM_EFFECT];
	short	sItemEffect2[defSKILL_ITEM_EFFECT];
	short	sSkyEffectActionKeyFrame;
	short   sSkyEffectActionDummyLink;
	short   sSkyEffectItemDummyLink;
	short   sSkyEffect;
	short	sSkySpd;
	short	sWhoped;
	short   sTargetDummyLink;
	short	sTargetEffectID;
	char	chTargetEffectTime;
    short   sAgroundEffectID;
	short	sWaterEffectID;
	char	szICON[defSKILL_ICON_NAME_LEN];
	char	chPlayTime;
	char	szDescribeHint[128];
	char	szEffectHint[128];
	char	szExpendHint[128];
} CSkillRecord;

 

finally hooks/replace CCharacter::CanLearnSkill at gameserver.exe with this one =P


Discord: andresc

Share this post


Link to post
Share on other sites
19 часов назад, kLabMouse сказал:

The LUA solution is BAD. because Lua is single threaded, and everything else just locks before LUA does it's job.

I do not deny. But it works. 

When character uses an item he also locks LUA? What is the difference between item usage and CheckCanUpgradeSkill() calling?

 

19 часов назад, kLabMouse сказал:

Why not? There is no limitation for Injected DLL.

We have to know addresses of all functions/methods which are used in our code and memory structures (CCharacter for example). It is waste of time if function too big and we need patch several bytes. It is much easier to jump into the code cave.

 

 

@Totoka

Does your extension check if player want to learn fairy possession or he send wrong skill level?


Share this post


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

I do not deny. But it works. 

When character uses an item he also locks LUA? What is the difference between item usage and CheckCanUpgradeSkill() calling?

 

Yes. LUA locks all the other threads that will call LUA or work with Characters. That's why Server has FPS rate.

And with each additional LUA code, or more complex lua functions, situation is getting more and more worth.

 

1 hour ago, V3ct0r said:

We have to know addresses of all functions/methods which are used in our code and memory structures (CCharacter for example). It is waste of time if function too big and we need patch several bytes. It is much easier to jump into the code cave.

 

This is just a small price to pay for modifying existing code. And Structures, that is even more easy. Just dump .pdb

Share this post


Link to post
Share on other sites
19 hours ago, V3ct0r said:

I do not deny. But it works. 

When character uses an item he also locks LUA? What is the difference between item usage and CheckCanUpgradeSkill() calling?

 

We have to know addresses of all functions/methods which are used in our code and memory structures (CCharacter for example). It is waste of time if function too big and we need patch several bytes. It is much easier to jump into the code cave.

 

 

@Totoka

Does your extension check if player want to learn fairy possession or he send wrong skill level?

 

no, it's working, but still a dummy without validations, kind of proxy method for future usages, which also uses the CCharacter context/class.

that can be done here:

 

		// calls the original function member
		res = CALL_MEMBER(this,call)(pSkill,nextLv);
		// after calling the original function, to aproach some other validation it has already
		// skills ID's, character class and etc. may also be checked here

		// do extra checks for those very special skills
		if( res ) { // PCanLearnSkill returns true
			// ... your validation here, if the original function was succeeded
			printf("%d valid!\n", pSkill->sID);
		} else { // PCanLearnSkill returns false
			// ...
			printf("%d invalid!\n", pSkill->sID);
		}

I do not do it becose currently im focused at other points.
One thing more, this extension does not apply for the previous hex patch(the jmp one), that one should be avoided

 

apply by injecting the compiled dll, and replacing the original method call for this one.

my case, I rewrote that calling to use a pointer call, ( call dword ptr ds:[myAddressWhereIStoreMyPointerHere] ), and to make it posible some extra bytes has to be removed

 

gameserver-ccharacter-extension.png

 

gameserver-ccharacter-extension2.png

 

// 0x006E5560 is the address i choose to store the original pointer (volaite, coz dunno where is used currently, but i'm testing so =P), which i rewrote as fallow.
// (that memory addres is RW). In a not writable case, this can not be done like this.
// instead, memory permissions should be changed in order to write it, and back to it's original permissions.

	__asm {
		mov eax, CCharacter::CanLearnSkill // move my method to eax
		mov dword ptr ds:[0x006E5560], eax // move eax to the addres i choose, which currently has te original method, just in case.
	}

 

Edited by Totoka

Discord: andresc

Share this post


Link to post
Share on other sites
2 hours ago, Totoka said:

this can by apply by injecting the compiled dll, and replacing the original method call for this one.

my case, I rewrote that calling to use a pointer call, ( call dword ptr ds:[myAddressWhereIStoreMyPointerHere] ), and to make it posible some extra bytes has to be removed

This is called "Splicing" or some call "detour".

There is a Lib called detours that does exactly what you need. Normally it can wrap around only functions as whole piece.

But you can also detour pieces of functions if you can force to use absolute address and __naked functions.

 

I solved this problem long time ago, using an a DLL written in NASM. All it did, is detoured predefined address to my own defined function.

But sometimes, to call original functions, all you need is a simple function with jump to absolute address.

  • Like 1

Share this post


Link to post
Share on other sites

 

Quote

There is a Lib called detours that does exactly what you need. Normally it can wrap around only functions as whole piece.

 

Sounds nice, do you have links/docs?


Discord: andresc

Share this post


Link to post
Share on other sites
34 minutes ago, Totoka said:

 

 

Sounds nice, do you have links/docs?

https://www.microsoft.com/en-us/research/project/detours/

http://stackoverflow.com/questions/11048176/detouring-a-member-function-via-an-injected-dll

http://www.ownedcore.com/forums/world-of-warcraft/world-of-warcraft-bots-and-programs/wow-memory-editing/389635-src-c-yet-another-detour.html

 

And How I did to load luajit:

https://mega.nz/#!cxsQhSzQ!Ya9YTqygbPoofFHfeSwSua_ysYMc9eZr7EGRK_OTwdE

and to all function inside GameServer. use something like API.asm with code:

 

__imp__??3@YAXPAX@Z: dd 005FFCE6h
proc ??3@YAXPAX@Z
     jmp dword [__imp__??3@YAXPAX@Z]
endp
align 10h

 

To make Binary load your DLL. use "CFF Explorer" and add the "dummy" import function to import list.

 

P.S. Please note, that Above examples where made for NASM and our own (unpublished) binary. So the offsets and code may not work for you.

  • Like 1

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.

Sign in to follow this  

×
×
  • Create New...