Jump to content

Recommended Posts

Posted

A typical Sunday morning. (EDIT: Its Monday sorry , lost track of time.)

 

EDIT: Doesnt work exactly as i first speculated. Thanks nik.

 

 

Typical day today. I woke up in the morning, took my breakfast, then i thought, hmm lets go in msn see whats up with our server. Admin pms me, server crashed. Hmm , i try to login , loginserver works fine, but gameserver is displayed down. Ok probably some exception in gameserver, lets look at the log. Nothing ... Interesting situation ;) Going to loginserver, checking the log. NullPointerException. Hmm how did the loginserver npe ? Oops whats that , a strange packet. Ok lets look at the source. 5 mins later, source turns out to be exploitable.

 

Ok. Im fine with l2jserver having many unsanitized input with out checks for exceptions. But wait a minute. I run lameguard, that means no noob can run phx on my server. So apparently, the one that did this, was some guy who has already bypassed gameguard. Not some average person. And that exploit, its not around. Hmm, plot thickens ! Could it be some l2jserver developer ? Some arch enemy ? Dont know. What i know is that today you have an exploit that allows you to crash any login server of hi5 l2jserver. Maybe l2dc too since they copy l2jserver a lot. Since im pretty sure that the guy who uses the exploit, is an l2jserver developer and since im also sure that he is a big jackass, i thought hey ! Lets be a jackass too and release this to the public so everyone goes and wrecks havoc to servers. Now lets see how fast l2jserver devs will fix this :)

 

The exploit:

 

Lets look first at a packet that a user can craft and send to the server. Its called ReplyCharacters.java

 

public ReplyCharacters(byte[] decrypt, GameServerThread server)

{

super(decrypt);

String account = readS();

int chars = readC();

int charsToDel = readC();

long[] charsList = new long[charsToDel];

for (int i = 0; i < charsToDel; i++)

{

charsList = readQ();

}

LoginController.getInstance().setCharactersOnServer(account,

chars, charsList, server.getServerId());

}

 

Aside from all the other reads, we got a string read here from the client with the account name. Now that can be crafted to point to an account name that doesnt exist. Lets say we craft a packet and we send it to the server crafted with phx with altered account so as the account does not exist. Then look at the last call in the constructor. Lets see what this function does.

 

public void setCharactersOnServer(String account, int charsNum, long[] timeToDel, int serverId)

{

L2LoginClient client = _loginServerClients.get(account);

 

if (charsNum > 0)

client.setCharsOnServ(serverId, charsNum);

 

if (timeToDel.length > 0)

client.serCharsWaitingDelOnServ(serverId, timeToDel);

}

 

Wait a minute. There is no check if loginServerClients data structure contains an account with that name. So client may be null. But there is no null check afterwards. So a call to the client may crash the gameserver thread that handles the packet parsing and execution. Thread crashes, no more play!

 

 

The solution:

 

You can check for npe, but the best is not to handle many business logic in the gameserverthread. One reason why each packet gets scheduled in a different runnable is so as when an exception happens, the main thread serving the packets, not to crash. Thats why we dont do business logic in the constructor. We let the abstract RunImpl to be executed in a new runnable cause the constructor is called by the gameserverthread not the new task that executes the packet.

 

The greetings:

 

The one that did that to my server, well played. Oh and while you were taking your time to execute faulty packets, last night , i was focking your mother :)

 

Lets see how fast the l2jserver dev-spies will get to this :)

 

Edit: Hide hide hide!

Edit2 , reply to Edit1: Ya as if they dont have VIP spy accounts ;)

Posted

The greetings:

 

The one that did that to my server, well played. Oh and while you were taking your time to execute faulty packets, last night , i was focking your mother Smiley

Rofl

Posted

If thats how you fix things, you sure have lots to learn yet. :)

 

 

Would be nice If you give the full script too

+1 anyway

 

I dont code hack scripts to execute exploits cause i find it totally stupid and unethical. Only l2jserver developers hide exploits and crash other servers ( cough Zekex cough ).

Posted

Its easy, simple and fast fix. I dont know what do you expect more than this... a LS-GS/GS-LS communication rework?

 

Oh also there is a comment left in the no leechers zone of the l2jforums regarding you (i wont involve names here, i want to keep the poster anonymous, also i dont intend to offend you by this, its just an interesting comment that i want you to see):

Guy who wrote it is noob, its bug causing npe in part which shows player count on accs and thats not client communication, lol. login client was simply removed before packet with count arrived... and talking about lameguard in this situation  ::) n/c
Posted

Read again the packet trace. The account name is sent by the client to the loginserver. The loginserver processes it and then it sends a ReplyCharacters to the gameserver. Tell that guy from your private zone to recheck what he says. I checked it 3 times to be sure cause i had my doubts too when i first saw the ls-gs communication. The requested account name is passed from client to loginserver and THEN to gameserverthread unfiltered. If thats not the case, then its probably some race that corrupts the data somehow. Ill recheck to be sure.

 

Even if its roots are not traced back to client, still an npe in the gameserverthread is not a small issue. And tell that guy from your private forum ( and i know who he is ! ), if im a noob, then what is he, that allows in his project, developers that call business logic inside the constructor ? Especially at his age. You see the tragic irony dont you ? ;)

 

login client was simply removed before packet with count arrived...

 

Thats even worse than exploiting a non-filtered input, dont you think ?

Posted

When you successfully login at the server

java/com/l2jserver/loginserver/clientpackets/RequestAuthLogin.java

                                case AUTH_SUCCESS:

                                        client.setAccount(_user);

                                        lc.getCharactersOnAccount(_user);

                                        client.setState(LoginClientState.AUTHED_LOGIN);

                                        client.setSessionKey(lc.assignSessionKeyToClient(_user, client));

 

It requests char list on the successfully logged in account (it cant be nonexistant since it successfully logged in).

        public void getCharactersOnAccount(String account)

        {

                Collection<GameServerInfo> serverList = GameServerTable.getInstance().getRegisteredGameServers().values();

                for (GameServerInfo gsi : serverList)

                {

                        if (gsi.isAuthed())

                              gsi.getGameServerThread().requestCharacters(account);

                }

        }

        public void requestCharacters(String account)

        {

                RequestCharacters rc = new RequestCharacters(account);

                try

                {

                        sendPacket(rc);

                }

                catch (IOException e)

                {

                        e.printStackTrace();

                }

        }

The packet is sent to the GS

                                                case 0x05:

                                                        RequestCharacters rc = new RequestCharacters(decrypt);

                                                      getCharsOnServer(rc.getAccount());

                                                        break;

and LoginServerThread processes it

private void getCharsOnServer(String account)

{

Connection con = null;

int chars = 0;

List<Long> charToDel = new ArrayList<Long>();

try

{

con = L2DatabaseFactory.getInstance().getConnection();

PreparedStatement statement = con.prepareStatement("SELECT deletetime FROM characters WHERE account_name=?");

statement.setString(1, account);

ResultSet rset = statement.executeQuery();

while (rset.next())

{

chars++;

long delTime = rset.getLong("deletetime");

if (delTime != 0)

charToDel.add(delTime);

}

rset.close();

statement.close();

}

catch (SQLException e)

{

_log.log(Level.WARNING, "Exception: getCharsOnServer: " + e.getMessage(), e);

}

finally

{

L2DatabaseFactory.close(con);

}

 

ReplyCharacters rec = new ReplyCharacters(account, chars, charToDel);

try

{

sendPacket(rec);

}

catch (IOException e)

{

if (Config.DEBUG)

_log.log(Level.WARNING, "", e);

}

 

}

And eventually we reach ReplyCharacters...

 

 

Now... after tracing all this, tell me how can you call this algorithm using invalid account?

Posted

Indeed i was wrong. I apologize for not being 6 years in l2j and cause i dont know all the 1700 files of code (that makes me a noob i guess ...) :) . Still doesnt explain why it causes an npe though. Cause might i have overlooked the previous one being careless, but my eyes dont fail me, the gameserverthread crashes. And i doubt im dellusional in that:

 

 

Exception in thread "GameServerThread-30@127.0.0.1" java.lang.NullPointerException

       at com.l2jserver.loginserver.LoginController.setCharactersOnServer(LoginController.java:509)

       at com.l2jserver.loginserver.network.gameserverpackets.ReplyCharacters.<init>(ReplyCharacters.java:41)

       at com.l2jserver.loginserver.network.L2JGameServerPacketHandler.handlePacket(L2JGameServerPacketHandler.java:87)

       at com.l2jserver.loginserver.GameServerThread.run(GameServerThread.java:133)

 

The gameserverthread doesnt wake up one morning and says "hey what a wonderful day, lets crash". Im waiting for some explanation from the "wise" l2jserver developers, who in their boundless wisdom call all us non l2jserver devs, noobs.

Posted

Not knowing the l2j code doesnt make you a noob, nor knowing the whole code makes you pro. Its all about experience.

Also, l2j devs treat most ppl like that because they are just pissed off. Many idiots, leechers, noobs that think that they know a lot are behind all this.

Because 90% of the l2j community is like that, l2j devs are used to treat ppl like that, even ppl that do not deserve it.

 

Anyway, the reason that you got NPE is probably because somehow the account wasnt inside _loginServerClients

 

Posted

Somebody can explain in video or normal how to do this exploit, its a lot of text.........

Useless share actually, it is just a war here.

Keep your head down.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  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...