Issue information

Issue ID
#4863
Status
Fixed
Severity
None
Started
Hercules Elf Bot
Apr 13, 2011 18:11
Last Post
Hercules Elf Bot
Apr 18, 2012 9:36
Confirmation
Yes (2)
No (0)

Hercules Elf Bot - Apr 13, 2011 18:11

Originally posted by [b]Daegaladh[/b]
[url="http://www.eathena.ws/board/index.php?autocom=bugtracker&showbug=4863"]http://www.eathena.w...er&showbug=4863[/url]

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:

[size=3][b]Exploit 1:[/b][/size]
-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."

[b]How to fix:[/b]

party.c
[codebox]int party_invite(struct map_session_data *sd,struct map_session_data *tsd)
{
struct party_data *p;
int i,flag=0;

nullpo_ret(sd);
if( ( p = party_search(sd->status.party_id) ) == NULL )
return 0;
+ //Only leader can invite.
+ ARR_FIND(0, MAX_PARTY, i, p->data[i].sd == sd);
+ if (i == MAX_PARTY || !p->party.member[i].leader)
+ { //TODO: Find the correct reply packet.
+ clif_displaymessage(sd->fd, msg_txt(282));
+ return 0;
+ }
if( tsd == NULL) { //TODO: Find the correct reply packet.
clif_displaymessage(sd->fd, msg_txt(3));
return 0;
}

...

//Likewise, as long as gm_can_party is off, players can't invite GMs.
clif_displaymessage(sd->fd, msg_txt(81));
return 0;
}

- //Only leader can invite.
- ARR_FIND(0, MAX_PARTY, i, p->data[i].sd == sd);
- if (i == MAX_PARTY || !p->party.member[i].leader)
- { //TODO: Find the correct reply packet.
- clif_displaymessage(sd->fd, msg_txt(282));
- return 0;
- }

if(!battle_config.invite_request_check) {
if (tsd->guild_invite>0 || tsd->trade_partner || tsd->adopt_invite) {
clif_party_inviteack(sd,tsd->statu[/codebox]


[size=3][b]Exploit 2:[/b][/size]
-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."

[b]How to fix:[/b]

party.c
[codebox]int party_invite(struct map_session_data *sd,struct map_session_data *tsd)
{
struct party_data *p;
int i,flag=0;

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

...

if( tsd->status.party_id > 0 || tsd->party_invite > 0 )
{// already associated with a party
clif_party_inviteack(sd,tsd->status.name,0);
return 0;
}
- for(i=0;i<MAX_PARTY;i++){
- if(p->party.member[i].account_id == 0) //Room for a new member.
- flag = 1;
- /* By default Aegis BLOCKS more than one char from the same account on a party.
- * But eA does support it... so this check is left commented.
- if(p->party.member[i].account_id==tsd->status.account_id)
- {
- clif_party_inviteack(sd,tsd->status.name,4);
- return 0;
- }
- */
- }
- if (!flag) { //Full party.
- clif_party_inviteack(sd,tsd->status.name,3);
- return 0;
- }

tsd->party_invite=sd->status.party_id;
tsd->party_invite_account=sd->status.account_id;[/codebox]


[size=3][b]Exploit 3:[/b][/size]
-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"

[b]How to fix:[/b]

clif.c
[codebox]void clif_parse_FriendsListAdd(int fd, struct map_session_data *sd)
{
struct map_session_data *f_sd;
int i, f_fd;

f_sd = map_nick2sd((char*)RFIFOP(fd,2));

+ // Friend already exists
+ for (i = 0; i < MAX_FRIENDS && sd->status.friends[i].char_id != 0; i++) {
+ if (sd->status.friends[i].char_id == f_sd->status.char_id) {
+ clif_displaymessage(fd, "Ese amigo ya está registrado.");
+ return;
+ }
+ }
+
+ if (i == MAX_FRIENDS) {
+ //No space, list full.
+ clif_friendslist_reqack(sd, f_sd, 2);
+ return;
+ }

// Friend doesn't exist (no player with this name)
if (f_sd == NULL) {

...

// @noask [LuzZza]
if(f_sd->state.noask) {
clif_noask_sub(sd, f_sd, 5);
return;
}

- // Friend already exists
- for (i = 0; i < MAX_FRIENDS && sd->status.friends[i].char_id != 0; i++) {
- if (sd->status.friends[i].char_id == f_sd->status.char_id) {
- clif_displaymessage(fd, "Friend already exists.");
- return;
- }
- }
-
- if (i == MAX_FRIENDS) {
- //No space, list full.
- clif_friendslist_reqack(sd, f_sd, 2);
- return;
- }

f_fd = f_sd->fd;
WFIFOHEAD(f_fd,packet_len(0x207));[/codebox]

This post has been edited by Brian on Feb 13, 2012 1:29

Hercules Elf Bot - Dec 6, 2011 14:54

Originally posted by [b]Ind[/b]
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?

Hercules Elf Bot - Feb 12, 2012 4:10

Originally posted by [b]Lighta[/b]
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..

Hercules Elf Bot - Feb 12, 2012 10:40

Originally posted by [b]Angezerus[/b]
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.

Hercules Elf Bot - Mar 14, 2012 17:22

Originally posted by [b]MarkZD[/b]
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.

Hercules Elf Bot - Mar 14, 2012 23:22

Originally posted by [b]Daegaladh[/b]
[quote name='Ind' timestamp='1323183258' post='5153']
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?
[/quote]

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:


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

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

Exploit 3:


[CODEBOX]
f_sd = map_nick2sd((char*)RFIFOP(fd,2));

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

- // Friend already exists
- for (i = 0; i < MAX_FRIENDS && sd->status.friends[i].char_id != 0; i++) {
- if (sd->status.friends[i].char_id == f_sd->status.char_id) {
- clif_displaymessage(fd, "Friend already exists.");
- return;
- }
- }
-
- if (i == MAX_FRIENDS) {
- //No space, list full.
- clif_friendslist_reqack(sd, f_sd, 2);
- return;
- }
-
f_fd = f_sd->fd;
WFIFOHEAD(f_fd,packet_len(0x207));
WFIFOW(f_fd,0) = 0x207;[/CODEBOX]

This post has been edited by Daegaladh on Mar 14, 2012 23:25

Hercules Elf Bot - Mar 22, 2012 12:18

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

This post has been edited by Epoque on Mar 22, 2012 12:32

Hercules Elf Bot - Mar 25, 2012 14:38

Originally posted by [b]Daegaladh[/b]
You introduced the same bug as here [url="http://rathena.org/board/tracker/issue-5506-map-crash-party/"]http://rathena.org/board/tracker/issue-5506-map-crash-party/[/url] in friend list, because you forgot to add the check for f_sd

This post has been edited by Daegaladh on Mar 25, 2012 14:40