dragon-realms/dr-lich

Simutronics onsite team connection questions.

Closed this issue · 2 comments

Lyneya (Nora) has asked me to post this here and if anyone has any questions to forward to the onsite team, they can be sent to her through discord. Her discord handle is Lyneya#1483.

The service that we want to discontinue listens on port 7900 at eaccess.play.net.  We probably have multiple domain names that point to that IP address.  Information exchanged to that service is not protected to any modern standard of encryption.

The replacement service listens on the same IP address but port 7910.  It uses the TLS protocol standard.  The data sent over the encrypted channel is the same format as before except there are no newlines at the end of messages (we rely on TLS to deliver complete messages).

It is important that clients verify that the certificate received by the handshake is what we've configured on the server (to prevent man in the middle attacks).  We use a self-signed certificate, so you can't follow the certificate chain to a trusted root certificate.  In our Windows client, we include the certificate in a file that is read and compared with the received certificate.

That is the high level technical description of what needs to be done.  Beyond that, we can try to answer questions and provide sample C++ code from what we do in the SGE.

I have sample code that should work/be enough to update our version of core lich, but I'm not in a position to be able to commit on my fork / submit the PR right now.

This is the POC code I used that spits out the response from the login server:

#!/usr/bin/env ruby
# encoding: US-ASCII

require 'socket'
require 'openssl'

acct = ''
pass = ''
gamecode = 'DR'

      hostname = 'eaccess.play.net'
      port     = 7910
      cert = OpenSSL::X509::Certificate.new("-----BEGIN CERTIFICATE-----\nMIIFUDCCAzigAwIBAgIJAP1LKTzYRs74MA0GCSqGSIb3DQEBCwUAMDwxCzAJBgNV\nBAYTAlVTMREwDwYDVQQIDAhNaXNzb3VyaTEaMBgGA1UECgwRU2ltdXRyb25pY3Mg\nQ29ycC4wIBcNMTgwNzE2MjIzNjMyWhgPMzAxNzExMTYyMjM2MzJaMDwxCzAJBgNV\nBAYTAlVTMREwDwYDVQQIDAhNaXNzb3VyaTEaMBgGA1UECgwRU2ltdXRyb25pY3Mg\nQ29ycC4wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQD3IDOqTKtc+RmW\nZkv3isBPtqKD8rcTyjWFLzIazYnN7ZGmRMGtBTFATx4ugy1WiLih9pUOo84W5M7i\nMwZlbzxQAUPiRfX3U7xowe5LuzDHSxqWzylkkgmkdCX9K8JoN4FnuIWUMuMji7f/\ncY7eL/Flob6pFMD9U7NZDvVpYH05Fnn0LAsaK0DKtPcms5+EWNh+uYgTjZbaVMyY\nAPTEN8Rh0NpR8CWNqErM6kbt+4NBqzKMIrJEfSSgQHhkXK+r37O+d3rpmgyFFJPl\nfFHlwxEKutdhd5z0MWV/Fj+hc2p0pExy6yDJNYDgI+iMas5aYowtOgHx2sX+pGkc\nCYgBkAyhAmhCja0Nl/TEbOgksnSvwGLWufc+TF89CZMGI7UmRdez/YKc0DR/zhjF\nAPsMur8wJOtps9ZueYqTqJ9SvwRoRT8Nlz0q/891t7P97rZ/+9C1AVJFtuIp3zM4\nGusqdxRqAsgVrgZmsY7FPti8dNTDcv1ZUiFt/FfHGEyJXbt7oYDr1CDAX17KRcc3\nFK9XaChz4VNlLGCYbCjMdPIqTP4M4xdma2bBMza4Nmr1qioDO27wa9zBiSe3Mskg\ntUm1cBmZ7eDfGprmMzg4FKY3WEBHQQINyuh9UNfqIijgAiPw4GN7jCpV3YH3mPRP\nHKlRSkfq8DxD5SXVV0+DyRslzLuDEQIDAQABo1MwUTAdBgNVHQ4EFgQUFNOI3jnn\nfZpGE12nVsE9QTgX2IQwHwYDVR0jBBgwFoAUFNOI3jnnfZpGE12nVsE9QTgX2IQw\nDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAPh0dOcZ4F2hQzwwr\nigLaY1p3fnjuGxnESwCPxJ3X+HVNclBh4Z3ndoonKunA+7CSxR9R4+ls/8RMmmr2\nQymzWYHTNbpe1dX+NgZGRTKiZEjqr8O0P02YEiLEUwG3YoWBSuka83LEDb+cB9AT\nUz90i1FMhGy9h+nBtP0r+mToQOnoKREmSoN03ucPVauionxAb7EqGlKciIyu4UE5\nuFY0kr5FqCIINtVIozyN2Xn/ATu6W5BlqET/PWapRa0230Pa6e3EKXVvjLxcMa2x\nyv+Pi/UQmMtpZXBu5qeYOPdppJs5WM33Q9PsCH7zGHziTbX85bhXIy1Y5TaGGjGK\nZZ/Je3zBn1JbyP+lC/DhRBpVwAbHqFCudxdSG4qcLR4r2hmTO8+LShXONmoH6XbR\nYwlb9aBrEYSr1cTrBnsFm07Bw3Ou9qXLfcF2nyT37U+DU8B9dcTll+Q1OPgYVbqG\nVfW7ZYQvvxb7EbXPcYedjGn1ZTGwJ5HRhJB0wNcH6wJIqw3y85hsqGFyw4zPOnDV\nZx2fEiycV6+6T8OIk2cwhZDcI0BI1iqKkRUdMLnVV/e3M9jERis1ValbeDVV+/8b\nLk71vz0A0lktJcULiMHWrym3IL7NTjuoZBJD8jgHETi4UEa0IB+Z7/Qr8F+UIygn\nAfksN019Wv0yPmHgubaJB2AT4ic=\n-----END CERTIFICATE-----")
      cert_store              = OpenSSL::X509::Store.new
      ssl_context             = OpenSSL::SSL::SSLContext.new
      ssl_context.cert_store  = cert_store
      ssl_context.options     = (OpenSSL::SSL::OP_NO_SSLv2 + OpenSSL::SSL::OP_NO_SSLv3)
      cert_store.add_cert(cert)
      login_socket = TCPSocket.open(hostname, port)
      login_server = OpenSSL::SSL::SSLSocket.new(login_socket)
      login_server.sync_close = true
      login_server.connect


if login_server
   puts login_server.state
   login_server.puts "K\n"
   hashkey = login_server.sysread(32)
   puts hashkey
   if 'test'[0].class == String
      password = pass.split('').collect { |c| c.getbyte(0) }
      hashkey = hashkey.split('').collect { |c| c.getbyte(0) }
   else
      password = pass.split('').collect { |c| c[0] }
      hashkey = hashkey.split('').collect { |c| c[0] }
   end
   password.each_index { |i| password[i] = ((password[i]-32)^hashkey[i])+32 }
   password = password.collect { |c| c.chr }.join
   login_server.puts "A\t#{acct}\t#{password}\n"
   password = nil
   response = login_server.sysread(1500)
   puts response
   login_key = /KEY\t([^\t]+)\t/.match(response).captures.first
   if login_key
      login_server.puts "M\n"
      response = login_server.sysread(1500)
      puts response
      if response =~ /^M\t/
        login_server.puts "G\t#{gamecode}\n"
        response = login_server.sysread(1500)
        puts response

        login_server.puts "P\t#{gamecode}\n"
        response = login_server.sysread(1500)
        puts response

        login_server.puts "C\n"
        response = login_server.sysread(1500)
        puts response
		#this response needs to be parsed to find the character you want to use.  Format is tab separated: 
		#C	<Used Slots>	<Available Slots>	?	?	W_<ACCT>_000	<CHARACTER0>	W_<ACCT>_001	<CHARACTER1>	W_<ACCT>_002	<CHARACTER2>	etc
		#I'm lazy and don't want to write the parsing code here so I've just hard coded it to get the first character
		
		login_server.puts "L\tW_#{acct}_000\tSTORM\n"
        response = login_server.sysread(1500)
        puts response
      else
         login_server.close unless login_server.closed?
         $stdout.puts "error: unrecognized response from server. (#{response})"
      end
   else
      login_server.close unless login_server.closed?
      $stdout.puts "Something went wrong... probably invalid user id and/or password.\nserver response: #{response}"
      exit
   end
else
   $stdout.puts "error: failed to connect to server"
   exit
end

This is the POC code I used that spits out the response from the login server

Thanks!