Issue Information
-
#004863
-
0 - None Assigned
-
Fixed
Issue Confirmations
-
Yes (2)No (0)
Exploits that let you know if a player or GM is on
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));
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?
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..
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.
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.
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.
Exploit 1 and 2 fixed in [rev='15763'].
Exploit 3 fixed in [rev='15764'].
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.