Jump to content

  •  

Bug Tracker Migration

June 3rd
Good news everyone! The staff has decided that it is time to slowly kill off this Bug Tracker. We will begin the process of slowly migrating from this Bug Tracker over to our Github Issues which can be found here: https://github.com/HerculesWS/Hercules/issues

Over the next couple of days, I will be closing off any opportunity to create new reports. However, I still will keep the opportunity to reply to existing Bug Reports. Doing this will allow us to slowly fix any bug reports we have listed here so that we can easily migrate over to our Issue Tracker.

Update - June 7th 2015: Creating new bug posts has been disabled. Please use our https://github.com/HerculesWS/Hercules/issues tracker to post bugs. Users are still able to reply to existing bug posts.

- Administration

Issue Information

  • #004863

  • 0 - None Assigned

  • Fixed

Issue Confirmations

  • Yes (2)No (0)
Photo

Exploits that let you know if a player or GM is on

Posted by Hercules Bot on 13 April 2011 - 06:11 PM

Originally posted by Daegaladh
http://www.eathena.w...er&showbug=4863

There exploits allows a normal player to know if another player is on without that player realized.
Some of my users was using one of theres exploits to know when the GMs are on or not and bother them.

There are 3 of them:

Exploit 1:
-You're in a party and you're not the leader
-Use /invite to the character you want to know if is on or not
-If is OFF you'll receive "player is offline or do not exist", if is ON you'll receive "You need to be a party leader to use this command."

How to fix:

party.c
int party_invite(struct map_session_data *sd,struct map_session_data *tsd)<br />{<br />	struct party_data *p;<br />	int i,flag=0;<br />	<br />	nullpo_ret(sd);<br />	if( ( p = party_search(sd->status.party_id) ) == NULL )<br />		return 0;<br />+	//Only leader can invite.<br />+	ARR_FIND(0, MAX_PARTY, i, p->data[i].sd == sd);<br />+	if (i == MAX_PARTY || !p->party.member[i].leader)<br />+	{	//TODO: Find the correct reply packet.<br />+		clif_displaymessage(sd->fd, msg_txt(282));<br />+		return 0;<br />+	}<br />	if( tsd == NULL) {	//TODO: Find the correct reply packet.<br />		clif_displaymessage(sd->fd, msg_txt(3));<br />		return 0;<br />	}<br /><br />...<br /><br />		//Likewise, as long as gm_can_party is off, players can't invite GMs.<br />		clif_displaymessage(sd->fd, msg_txt(81));<br />		return 0;<br />	}<br />	<br />-	//Only leader can invite.<br />-	ARR_FIND(0, MAX_PARTY, i, p->data[i].sd == sd);<br />-	if (i == MAX_PARTY || !p->party.member[i].leader)<br />-	{	//TODO: Find the correct reply packet.<br />-		clif_displaymessage(sd->fd, msg_txt(282));<br />-		return 0;<br />-	}<br /><br />	if(!battle_config.invite_request_check) {<br />		if (tsd->guild_invite>0 || tsd->trade_partner || tsd->adopt_invite) {<br />			clif_party_inviteack(sd,tsd->statu



Exploit 2:
-You're the leader of a party and your party is full
-Use /invite to the character you want to know if is on or not
-If is OFF you'll receive "player is offline or do not exist", if is ON you'll receive "Your party is full."

How to fix:

party.c
int party_invite(struct map_session_data *sd,struct map_session_data *tsd)<br />{<br />	struct party_data *p;<br />	int i,flag=0;<br />	<br />	nullpo_ret(sd);<br />	if( ( p = party_search(sd->status.party_id) ) == NULL )<br />		return 0;<br />+	for(i=0;i<MAX_PARTY;i++){<br />+		if(p->party.member[i].account_id == 0) //Room for a new member.<br />+			flag = 1;<br />+	/* By default Aegis BLOCKS more than one char from the same account on a party.<br />+	 * But eA does support it... so this check is left commented.<br />+		if(p->party.member[i].account_id==tsd->status.account_id)<br />+		{<br />+			clif_party_inviteack(sd,tsd->status.name,4);<br />+			return 0;<br />+		}<br />+	*/<br />+	}<br />+	if (!flag) { //Full party.<br />+		clif_party_inviteack(sd,tsd->status.name,3);<br />+		return 0;<br />+	}<br />	if( tsd == NULL) {	//TODO: Find the correct reply packet.<br />		clif_displaymessage(sd->fd, msg_txt(3));<br />		return 0;<br />	}<br /><br />...<br /><br />	if( tsd->status.party_id > 0 || tsd->party_invite > 0 )<br />	{// already associated with a party<br />		clif_party_inviteack(sd,tsd->status.name,0);<br />		return 0;<br />	}<br />-	for(i=0;i<MAX_PARTY;i++){<br />-		if(p->party.member[i].account_id == 0) //Room for a new member.<br />-			flag = 1;<br />-	/* By default Aegis BLOCKS more than one char from the same account on a party.<br />-	 * But eA does support it... so this check is left commented.<br />-		if(p->party.member[i].account_id==tsd->status.account_id)<br />-		{<br />-			clif_party_inviteack(sd,tsd->status.name,4);<br />-			return 0;<br />-		}<br />-	*/<br />-	}<br />-	if (!flag) { //Full party.<br />-		clif_party_inviteack(sd,tsd->status.name,3);<br />-		return 0;<br />-	}<br />		<br />	tsd->party_invite=sd->status.party_id;<br />	tsd->party_invite_account=sd->status.account_id;



Exploit 3:
-You need to have your friend list full
-Turn on the chat 1:1 to non-friends
-Whisper the player you want to know is on or off when you're sure he's off
-Let the window 1:1 of that player opened
-Right click on the window and add to friend list
-If player is ON you'll receive "you're friend list is full", if is OFF you'll receive "player is offline or do not exist"

How to fix:

clif.c
void clif_parse_FriendsListAdd(int fd, struct map_session_data *sd)<br />{<br />	struct map_session_data *f_sd;<br />	int i, f_fd;<br /><br />	f_sd = map_nick2sd((char*)RFIFOP(fd,2));<br /><br />+	// Friend already exists<br />+	for (i = 0; i < MAX_FRIENDS && sd->status.friends[i].char_id != 0; i++) {<br />+		if (sd->status.friends[i].char_id == f_sd->status.char_id) {<br />+			clif_displaymessage(fd, "Ese amigo ya está registrado.");<br />+			return;<br />+		}<br />+	}<br />+<br />+	if (i == MAX_FRIENDS) {<br />+		//No space, list full.<br />+		clif_friendslist_reqack(sd, f_sd, 2);<br />+		return;<br />+	}<br /><br />	// Friend doesn't exist (no player with this name)<br />	if (f_sd == NULL) {<br /><br />...<br /><br />	// @noask [LuzZza]<br />	if(f_sd->state.noask) {<br />		clif_noask_sub(sd, f_sd, 5);<br />		return;<br />	}<br /><br />-	// Friend already exists<br />-	for (i = 0; i < MAX_FRIENDS && sd->status.friends[i].char_id != 0; i++) {<br />-		if (sd->status.friends[i].char_id == f_sd->status.char_id) {<br />-			clif_displaymessage(fd, "Friend already exists.");<br />-			return;<br />-		}<br />-	}<br />-<br />-	if (i == MAX_FRIENDS) {<br />-		//No space, list full.<br />-		clif_friendslist_reqack(sd, f_sd, 2);<br />-		return;<br />-	}<br />		<br />	f_fd = f_sd->fd;<br />	WFIFOHEAD(f_fd,packet_len(0x207));

Originally posted by Ind
exploit 2: the fix you provided will crash if the tsd is not known; I'm not sure what'd be the best alternative (as checking for the tsd would just keep the exploit), always reply with no tsd name?
exploit 3: the fix you provided will crash if the friend (f_sd) is not found, again i'm not sure what'd be the best workaround for this -- in both cases you can actually send a pm to the nick and find out, so i'm not sure this is actually an issue -- how does it work in officials btw?

Originally posted by Lighta
Well I think an easy fix for this would be a status that gm could turn on and off like (INVISIBLE).
Once gm will be on this state pm /invite would return msg like his not here.
We could add little bitflag too so other gm could still pm him etc..

Originally posted by Angezerus
There is another exploit option:
on a server with @who enabled you can checg how many gms on by using first @who, then usig /w.
@who will show a list without gms, /w will show the number of online players incl gms. The difference between the two lists/numbers is the number of online gms.

I don't think its a bug, but the easyest way is simply sending a pm to the gms... So if a gm wants perfect stealth mode, it would be adviseable something similar stat like /hide, like Lighta said.

Originally posted by MarkZD
Just check if player has perfecthide on and send an offline message.

About /who problem, it should check the hidden gms too and deduct it from the total.

I didn't see the /who function, if it checks directly from database there could be a fild to flag it, so select will discard flags 1 on count.

Originally posted by Daegaladh

exploit 2: the fix you provided will crash if the tsd is not known; I'm not sure what'd be the best alternative (as checking for the tsd would just keep the exploit), always reply with no tsd name?exploit 3: the fix you provided will crash if the friend (f_sd) is not found, again i'm not sure what'd be the best workaround for this -- in both cases you can actually send a pm to the nick and find out, so i'm not sure this is actually an issue -- how does it work in officials btw?


Sorry, I've just realized of this report XD (I'm the author of the original one)
And yep, I know about the crash, and this is what I did:

Exploit 2:


<br />  nullpo_ret(sd);<br />  if( ( p = party_search(sd->status.party_id) ) == NULL )<br />  return 0;<br />+<br />+ //Only leader can invite.<br />+ ARR_FIND(0, MAX_PARTY, i, p->data[i].sd == sd);<br />+ if (i == MAX_PARTY || !p->party.member[i].leader)<br />+ { //TODO: Find the correct reply packet.<br />+ clif_displaymessage(sd->fd, msg_txt(282));<br />+ return 0;<br />+ }<br />+<br />+ if( tsd != NULL) { //TODO: Find the correct reply packet.<br />+ for(i=0;i<MAX_PARTY;i++){<br />+ if(p->party.member[i].account_id == 0) //Room for a new member.<br />+ flag = 1;<br />+ /* By default Aegis BLOCKS more than one char from the same account on a party.<br />+  * But eA does support it... so this check is left commented.<br />+ if(p->party.member[i].account_id==tsd->status.account_id)<br />+ {<br />+ clif_party_inviteack(sd,tsd->status.name,4);<br />+ return 0;<br />+ }<br />+ */<br />+ }<br />+ if (tsd != NULL && !flag) { //Full party.<br />+ clif_party_inviteack(sd,tsd->status.name,3);<br />+ return 0;<br />+ }<br />+ }<br />  if( tsd == NULL) {<br />  clif_party_inviteack(sd, "", 7);<br />  return 0;<br />@@ -352,14 +380,6 @@<br />  return 0;<br />  }<br />  <br />- //Only leader can invite.<br />- ARR_FIND(0, MAX_PARTY, i, p->data[i].sd == sd);<br />- if (i == MAX_PARTY || !p->party.member[i].leader)<br />- { //TODO: Find the correct reply packet.<br />- clif_displaymessage(sd->fd, msg_txt(282));<br />- return 0;<br />- }<br />-<br />  if(!battle_config.invite_request_check) {<br />  if (tsd->guild_invite>0 || tsd->trade_partner || tsd->adopt_invite) {<br />  clif_party_inviteack(sd,tsd->status.name,0);<br />@@ -377,23 +397,7 @@<br />  clif_party_inviteack(sd,tsd->status.name,0);<br />  return 0;<br />  }<br />- for(i=0;i<MAX_PARTY;i++){<br />- if(p->party.member[i].account_id == 0) //Room for a new member.<br />- flag = 1;<br />- /* By default Aegis BLOCKS more than one char from the same account on a party.<br />-  * But eA does support it... so this check is left commented.<br />- if(p->party.member[i].account_id==tsd->status.account_id)<br />- {<br />- clif_party_inviteack(sd,tsd->status.name,4);<br />- return 0;<br />- }<br />- */<br />- }<br />- if (!flag) { //Full party.<br />- clif_party_inviteack(sd,tsd->status.name,3);<br />- return 0;<br />- }<br />-<br />+<br />  tsd->party_invite=sd->status.party_id;<br />  tsd->party_invite_account=sd->status.account_id;<br />


Exploit 3:


<br />  f_sd = map_nick2sd((char*)RFIFOP(fd,2));<br /><br />  // Friend doesn't exist (no player with this name)<br />+ if (f_sd != NULL) {<br />+ // Friend already exists<br />+ for (i = 0; i < MAX_FRIENDS && sd->status.friends[i].char_id != 0; i++) {<br />+ if (sd->status.friends[i].char_id == f_sd->status.char_id) {<br />+ clif_displaymessage(fd, "Friend already exists.");<br />+ return;<br />+ }<br />+ }<br />+<br />+ if (f_sd != NULL && i == MAX_FRIENDS) {<br />+ //No space, list full.<br />+ clif_friendslist_reqack(sd, f_sd, 2);<br />+ return;<br />+ }<br />+ }<br />  if (f_sd == NULL) {<br />  clif_displaymessage(fd, msg_txt(3));<br />  return;<br />@@ -12171,20 +12245,6 @@<br />  return;<br />  }<br /><br />- // Friend already exists<br />- for (i = 0; i < MAX_FRIENDS && sd->status.friends[i].char_id != 0; i++) {<br />- if (sd->status.friends[i].char_id == f_sd->status.char_id) {<br />- clif_displaymessage(fd, "Friend already exists.");<br />- return;<br />- }<br />- }<br />-<br />- if (i == MAX_FRIENDS) {<br />- //No space, list full.<br />- clif_friendslist_reqack(sd, f_sd, 2);<br />- return;<br />- }<br />-<br />  f_fd = f_sd->fd;<br />  WFIFOHEAD(f_fd,packet_len(0x207));<br />  WFIFOW(f_fd,0) = 0x207;

Edited by Daegaladh, 14 March 2012 - 11:25 PM.


Originally posted by Epoque
Exploit 1 and 2 fixed in [rev='15763'].
Exploit 3 fixed in [rev='15764'].

Originally posted by Daegaladh
You introduced the same bug as here http://rathena.org/b...ap-crash-party/ in friend list, because you forgot to add the check for f_sd

Edited by Daegaladh, 25 March 2012 - 02:40 PM.