Alert & Fix for: System.ArgumentException: The surrogate pai


Site Admin
Posts: 455
Joined: Tue Jun 17, 2008 2:33 pm
PostPosted: Mon May 11, 2009 3:07 pm
The following crashes occurred beginning yesterday:
Code: Select all
System.ArgumentException: The surrogate pair (0xD9FF, 0x8EB4) is invalid. A high surrogate character (0xD800 - 0xDBFF) must always be paired with a low surrogate character (0xDC00 - 0xDFFF).
   at System.Xml.XmlTextEncoder.WriteSurrogateChar(Char lowChar, Char highChar)
   at System.Xml.XmlTextEncoder.Write(String text)
   at System.Xml.XmlTextWriter.WriteString(String text)
   at System.Xml.XmlWriter.WriteAttributeString(String localName, String value)
   at Server.Engines.Reports.XmlPersistanceWriter.SetString(String key, String value)
   at Server.Engines.Reports.PageInfo.SerializeAttributes(PersistanceWriter op)
   at Server.Engines.Reports.PersistableObject.Serialize(PersistanceWriter op)
   at Server.Engines.Reports.StaffHistory.SerializeChildren(PersistanceWriter op)
   at Server.Engines.Reports.PersistableObject.Serialize(PersistanceWriter op)
   at Server.Engines.Reports.XmlPersistanceWriter.WriteDocument(PersistableObject root)
   at Server.Engines.Reports.StaffHistory.Save()
   at Server.Engines.Reports.Reports.UpdateOutput(Object state)
   at System.Threading._ThreadPoolWaitCallback.WaitCallback_Context(Object state)
   at System.Threading.ExecutionContext.runTryCode(Object userData)
   at System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData)
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading._ThreadPoolWaitCallback.PerformWaitCallbackInternal(_ThreadPoolWaitCallback tpWaitCallBack)
   at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback(Object state)

Code: Select all
System.InvalidOperationException: Token StartElement in state Error would result in an invalid XML document.
   at System.Xml.XmlTextWriter.AutoComplete(Token token)
   at System.Xml.XmlTextWriter.WriteStartElement(String prefix, String localName, String ns)
   at System.Xml.XmlWriter.WriteStartElement(String localName)
   at Server.Engines.Reports.XmlPersistanceWriter.BeginObject(PersistableType typeID)
   at Server.Engines.Reports.PersistableObject.Serialize(PersistanceWriter op)
   at Server.Engines.Reports.PageInfo.SerializeChildren(PersistanceWriter op)
   at Server.Engines.Reports.PersistableObject.Serialize(PersistanceWriter op)
   at Server.Engines.Reports.StaffHistory.SerializeChildren(PersistanceWriter op)
   at Server.Engines.Reports.PersistableObject.Serialize(PersistanceWriter op)
   at Server.Engines.Reports.XmlPersistanceWriter.WriteDocument(PersistableObject root)
   at Server.Engines.Reports.StaffHistory.Save()
   at Server.Engines.Reports.Reports.UpdateOutput(Object state)
   at System.Threading._ThreadPoolWaitCallback.WaitCallback_Context(Object state)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading._ThreadPoolWaitCallback.PerformWaitCallbackInternal(_ThreadPoolWaitCallback tpWaitCallBack)
   at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback(Object state)

This was caused by a unicode page entry crafted in such a way as to cause an error when converting to xml during staff report serialization.

The following code fixes this potential exploit:
Add this fuction to PagePromtGump.cs
Code: Select all
        public string UnicodeToASCII(string unicodeString)
        {
            try
            {
                Encoding ascii = Encoding.ASCII;
                Encoding unicode = Encoding.Unicode;

                // Convert the string into a byte[].
                byte[] unicodeBytes = unicode.GetBytes(unicodeString);

                // Perform the conversion from one encoding to the other.
                byte[] asciiBytes = Encoding.Convert(unicode, ascii, unicodeBytes);

                // Convert the new byte[] into a char[] and then into a string.
                // This is a slightly different approach to converting to illustrate
                // the use of GetCharCount/GetChars.
                char[] asciiChars = new char[ascii.GetCharCount(asciiBytes, 0, asciiBytes.Length)];
                ascii.GetChars(asciiBytes, 0, asciiBytes.Length, asciiChars, 0);
                return new string(asciiChars);
            }
            catch
            {
                return "[Unparsable Unicode String]";
            }
        }

In the same file, in the OnResponse method, change this line: (near line 55)
Code: Select all
                    PageQueue.Enqueue(new PageEntry(m_From, text, m_Type));

to this:
Code: Select all
                    PageQueue.Enqueue(new PageEntry(m_From, UnicodeToASCII(text), m_Type));

This will prevent unicode from being sent in pages. The resulting page will contain '?' where unicode characters were. If this is not desireable the conversion could be done in the serialization, but I put the code here becuase I needed to fix this fast.

the original ip addresses of the exploiter were:
213.243.164.9
88.115.39.161
66.179.208.36

He has continued to proxy in to sent these crafted unicode pages. Shoot me a pm if you want a list of all the banned ip's associated with this event.

Posts: 97
Joined: Sun Apr 19, 2009 8:49 am
Location: Gorizia - Italy
PostPosted: Sun Oct 03, 2010 8:14 am
Thanks.

Implemented on Midgard Shard (www.midgardshard.it).

^_^

Return to RunUO 1.0 & 2.0

Who is online

Users browsing this forum: No registered users and 2 guests

cron