It is my great pleasure to be an author of M3 Ideas. Thanks very much for Thibaud’s invitation.
I put my foot into M3 water five years ago and M3 Ideas has been giving me great help in developing my technical skills since then. It is my great honor to share my work and make contributions to it.
The issue of access control on grid management pages has been a trouble to me for nearly two years. The installation web page of ISO, in our case, http://BE Server:19005/LSO/index.html is very close to the grid information page, http://BE Server:19005/grid/info.html and the grid management pages, http://BE Server:19005/grid/ui/#. It is fairly easy for a user with web skills to figure out the latter two web pages and he/she can explore and check basically all the grid information.
Although the grid management pages requires credentials to log on to be able to start or stop a process, a user actually can try the default account, and the famous password, which are mentioned by the Companion, to get full control. This is not a joke, but a real case. It makes M3 system really vulnerable. Even if users do not make any actions to it, there is no sense and it is ridiculous to disclose all the system information to the public.
We did raise InforXtreme case for Infor to fix it. However, they could not give a robust solution after a long time discussion. The reason is the grid management pages and LSO is sharing the same Java process in the BE server. If you check the TCP connections and processes using netstat in the BE server, you would find there is no way to tell which connection is from the grid management pages visit or from LSO request, which is the biggest technical challenge.
After many tests it seems the most feasible solution is to analyze each incoming and outgoing TCP packet in the BE sever to see whether there are any patterns. If we can be 100% sure that a remote IP address is visiting the grid management pages according to the patterns, then we can apply IPSec to block it automatically. Although it means that IP address cannot use LSO as well, it can be sorted out by manually removing it from the black list given a promise is made not to visit again. If the promise is broken, there is no second chance for them. It is something like Damocles’ Sword.
So I made a Console Application using C# as follows.
using System; using System.Collections.Generic; using SharpPcap; using SharpPcap.LibPcap; using System.Text; using System.Net.Mail; using System.Diagnostics; namespace CA_Grid { class CA_Grid { static List<string> jsIPList; static void Main(string[] args) { jsIPList = new List<string>(); var varDevices = CaptureDeviceList.Instance; if(varDevices.Count<1) { Console.WriteLine("No devices were found on this machine"); return; } Console.WriteLine("The following devices are available on this machine:"); Console.WriteLine("----------------------------------------------------"); Console.WriteLine(); int i = 0; foreach(var varDec in varDevices) { Console.WriteLine("{0}) {1}", i, varDec.Description); i++; } Console.WriteLine(); Console.Write("-- Please choose a device to capture: "); int varChoice = 0; if (!int.TryParse(Console.ReadLine(), out varChoice) || varChoice>=i) { Console.WriteLine("The device is not valid!"); return; } ICaptureDevice varDevice =varDevices[varChoice]; varDevice.OnPacketArrival += Device_OnPacketArrival; varDevice.Open(); varDevice.Filter = "ip and tcp"; Console.WriteLine(); Console.WriteLine("-- Listening on {0}, hit 'Ctrl-C' to exit...",varDevice.Description); varDevice.Capture(); varDevice.OnPacketArrival -=Device_OnPacketArrival; varDevice.Close(); } private static void Device_OnPacketArrival(object sender, CaptureEventArgs e) { try { string varMIP = "BE Server IP Address"; if (e == null || e.Packet == null) return; if (e.Packet.Data == null) return; var varPacket = PacketDotNet.Packet.ParsePacket(e.Packet.LinkLayerType, e.Packet.Data); if (varPacket == null) return; if (varPacket.GetType()!=typeof(PacketDotNet.EthernetPacket)) return; var varIP = (PacketDotNet.IpPacket)varPacket.Extract(typeof(PacketDotNet.IpPacket)); if (varIP == null) return; string varDIP = varIP.DestinationAddress.ToString(); string varSIP = varIP.SourceAddress.ToString(); if (varSIP != varMIP) return; var varTCP = (PacketDotNet.TcpPacket)varPacket.Extract(typeof(PacketDotNet.TcpPacket)); if (varTCP == null) return; if (varTCP.PayloadData == null) return; var varData = Encoding.UTF8.GetString(varTCP.PayloadData); if (varData == null) return; string varDPort = varTCP.DestinationPort.ToString(); string varSPort = varTCP.SourcePort.ToString(); bool varHTTPS = varSPort == "443"; bool varHTTP = varSPort.Contains("19005") && varData.Contains("text/html") && varData.Contains("gzip"); if ((varHTTPS || varHTTP) && !jsIPList.Contains(varDIP)) { jsIPList.Add(varDIP); string varWay = varHTTP ? "HTTP" : "HTTPS"; string varM1 = "----------------------------------------------------"; string varM2 = string.Format("{0}, {1}, {2}", DateTime.Now, varDIP, varWay); string varM3 = "Original IP packet: " + varIP.ToString(); string varM4 = "Original TCP packet: " + varTCP.ToString(); string varM5 = "Original TCP Header: " + varData; if (varDIP != "IP to Exclude") { using (var varProcess = new Process()) { varProcess.StartInfo.FileName = "cmd.exe"; varProcess.StartInfo.UseShellExecute = false; varProcess.StartInfo.RedirectStandardInput = true; varProcess.StartInfo.RedirectStandardOutput = true; varProcess.StartInfo.RedirectStandardError = true; varProcess.StartInfo.CreateNoWindow = true; varProcess.Start(); string varCommand = "netsh ipsec static add filter filterlist=\"IP_Filter_Grid\" srcaddr=" + varDIP + " dstaddr=me protocol=TCP mirrored=No"; varProcess.StandardInput.WriteLine(varCommand); varProcess.StandardInput.WriteLine("exit"); varProcess.StandardInput.AutoFlush = true; varProcess.WaitForExit(); } } Console.WriteLine(varM1); Console.WriteLine(varM2); Console.WriteLine(); Console.WriteLine(varM3); Console.WriteLine(); Console.WriteLine(varM4); Console.WriteLine(); Console.WriteLine(varM5); Console.WriteLine(); using (var varSMTP = new SmtpClient("Mail Forwarder IP Address")) { using (var varMail = new MailMessage()) { varMail.From = new MailAddress("from address"); varMail.To.Add("my e-mail address"); varMail.Subject = "Unauthorised Access to Infor Grid Management Pages"; varMail.Body = varM1 + "\r\n" + varM2 + "\r\n" + "\r\n" + varM3 + "\r\n" + "\r\n" + varM4 + "\r\n" + "\r\n" + varM5; varSMTP.Send(varMail); } } } } catch (Exception ex) { Console.WriteLine(ex.Message); } } } }
SharpPcap can be downloaded from GitHub. It has two Dlls, SharpPcap for capturing packets and Packet.Net for packet analysis. WinPcap needs to be downloaded and installed into the BE server. There is no need to restart the server after installation.
The console application is running in an asynchronous mode, so there is trivial impact on the M3 performance.
The script starts with detecting all the devices first. Then it asks for a device number to listen to. Each device could be a network adapter. A filter is applied to the device for IP and TCP packets. An event to capture the packets is attached to the device. Finally the listening starts.
The event handler has the key logic.
1. Two patterns to find the visit to the grid management pages.
(1) HTTPS: The source port would be 443.
(2) HTTP: The packet contains text/html and gzip.
HTTPS communication is encrypted, so we cannot analyze the packet content. Fortunately LSO never uses the port of 443.
2. If the destination IP address is not on the white list, then it would be added to the IPSec filter list. We need to manually create a IPSec policy and a IPSec filter & Action beforehand.
3. Console would output the captured information.
4. An e-mail alert would be sent with the captured information.
5. A global variable of jsIPList is used to keep the IP addresses already captured to avoid repeated alerts.
Then it works. There were three IT users from local division, who still tried to access to the grid management pages on Monday as usual. Then they found they could not visit it any more, as well as LSO. So far there are no normal users to be blocked, no matter whether they run M3 programs, or download LSO from the installation web page. All of sudden the two-year headache is gone.
If you have the similar concerns to me, I hope the above solution would give you a ride. If you have got any issues using the solution, please reply to this post or send me an e-mail at warren.dahai.hou@gmail.com.
Finally my heartfelt appreciations to all the authors on this website, as well as the author of SharpPcap and Packet.Net.
Hi Warren,
Infor asked me to reply to your article to refute any false claims and to clarify any ambiguities.
Is your article refering to an environment with a Grid version 1.x on premise (not Grid 2.x on cloud)? I will assume it is.
I have not worked with the Grid in half a year, so I do not remember it all. Here is some general understanding I remember. For exact answers, I would have to inquire.
NETWORK AREA
When Infor installs a Grid on premise, the Grid is restricted to the private network, it is not available to the public Internet.
COMPANION
The Infor Companion does not reveal actual passwords. If it does show any passwords, they are sample passwords for illustration purposes. If by coincidence there was a production Grid that used such passwords, change the passwords immediately.
GRID 1.x
The Grid version 1.x provides some of its pages anonymously by design, not by vulnerability. It was built in a time when environments were on-premise, and the threat model trusted the private network and its internal users. The anonymous pages provide some information to the Grid clients, e.g. for service discovery and monitoring; you are seeing the HTML equivalent of the REST GET services. If an attacker were to gain access to the private network – but then it would be a bigger problem – the anonymous Grid would not provide actionable operations (POST, PUT, DELETE), and the attacker would be limited to information gathering only; it is arguably informative, yet it is not critical from a security point of view. And if an attacker were able to obtain a user password – but then it would be another bigger problem – it would have limited access to the Grid; there are various levels of access to the Grid, from anonymous, to granular user, to granular administration, to full Grid administration which is granted to certain admins only. As for the Grid routers, they had both HTTP and HTTPS enabled by default. Now, the solution you propose of analyzing and filtering at the network level is unnecessary and insufficient; it may actually break applications. The correct solution is to setup the Grid topology securely, to setup the Grid routers such that they restrict access to the anonymous pages, to disable HTTP and to leave HTTPS only, to setup the Grid users and roles accordingly, and to use strong passwords. For more information, refer to the Grid Administration and Grid Security Guides available at https://docs.infor.com/help_m3_coreit_13.4/index.jsp?topic=%2Fcom.lawson.help.administration%2Findex2.html&cp=6
GRID 2.x
On the other hand, the Grid version 2.x was re-architected for cloud environments. On a multi tenant cloud, most if not all Grid pages are unavailable except to internal Infor Cloud administrators, tightly secured off the Internet. HTTP is disabled by default, and only HTTPS is available. Authentication and authorization are handled by federated services, OpenID, SAML, OAuth. Grid passwords are cryptographically strong.
Those are the basics. Let me know should you need more details.
Regards,
Thibaud
LikeLike
Dear Thibaud,
Thanks very much for the detailed comments. Our application is hosted by AMS.
In fact our request is very simple compared to Infor’s fairly long explanations, “Do not have unauthorized users access to the grid management pages”. However, such a simple requirement cannot be satisfied after months of investigations via InforXtreme, as any users can access to the server view, if they know the url, which is very easy to figure out.
The key is INFORMATION SECURITY. A well secured system can allow administrators control the access to any piece of information of the system. Can Infor allow sales guys access to their server room?
The application I made is working very well. It captured all unauthorized accesses cross the world. Basically every local admin can figure out the url. After several rounds of internal communications, the issue is sorted out now.
It is not sure from which technical perspective Infor can conclude that the solution might break applications. It is just a simple version of firewall. If it can break applications, then all the anti-virus software needs to be removed, as well as Windows Firewall.
So far we cannot see any application with issues related to this solution. Actually our system has been running fairly smoothly for this year.
Besides this solution, I have made several applications to monitor server down, service down, job down, which strongly ensure our system can minimize the interruptions caused by a variety of outrages. It is not to show off my skills, but simply encourage Infor to listen to the voices of their customers, and take actions to get M3 perform better in a continuous improvement way. The more they try to explain, the less chances they would make improvements.
Regards,
Warren
LikeLike