Csapp Buffer Overflow attack Experiment (top)

Source: Internet
Author: User

Csapp Buffer Overflow attack Experiment (top)

Download the Lab tool. Here's the latest handout.

The experimental materials can be found on the Internet some old, some places with the latest handout. It just doesn't matter, it's basically just the difference between the program name (sendstring) or the name of the participant (BUFBOMB-T), and it doesn't affect our experiment.

1. Experimental Tools 1.1 Makecookie

In the following experiment, five "attacks" were made in four times to make your cookie out of place where it originally did not exist, so we first have to create a cookie for ourselves.

The Makecookie in the lab tool is used to generate cookies. The number of references is your name:

32803861 (SYSV), dynamically linked (uses shared libs), \for2.6.9, not stripped[[email protected] bufbomb]$ chmod +x makecookie[[email protected] bufbomb]$ ./makecookie cdai0x5e5ee04e
1.2 Bufbomb

Bufbomb is the program that we want to "attack", the version number of the experimental tool that I downloaded must have the-t number at run time, indicating my name:

[[email protected] bufbomb]$ ./bufbomb You must include a team name with -tUsage: ./bufbomb -t team [-n] [-s] [-h]        -t team:   Specify team name        -n :       Nitro mode        -s :       Submit solution via email        -h :       help015-21300x5e5ee04eType string:It is easier to love this class when you are a TAOuch!: You caused a segmentation fault!Better luck next time
1.3 sendstring

The Sendstring gadget (new version called Hex2raw) can read into our crafted string (hex). Send it to the standard input stream of the Bufbomb. Avoid having to manually enter them on the terminal every time. Either cat pipe or direct redirection is done in two ways:

[[email protected] bufbomb]$ cat exploit.raw | ./sendstring | ./bufbomb -t cdai[[email protected] bufbomb]$ ./sendstring < cat exploit.raw | ./bufbomb -t cdai
2. Warm-up preparation 2.1 "vulnerability" code

The following section of the seemingly "innocent" small function is the source of security vulnerabilities, and the root of root cause is the gets () function does not consider the size of the BUF buffer. All characters entered by the user are saved directly in. Assuming that the user enters too many characters, it causes some data on the stack to be overwritten. This results in a buffer overflow crisis:

int getbuf(){    char buf[12];    Gets(buf);    return1;}
2.2 Buffer Stack Analysis

Before you start a real "attack". Let's start by analyzing what the stack looks like when Bufbomb calls Getbuf ().

Only a comprehensive understanding of the stack structure. We were able to "attack" it at our own pace at the back of the experiment.

First, through the Objdump disassembly Getbuf () function:

[Email protected] bufbomb]$ objdump-s- D-Z Bufbomb | Grep-a15"<GETBUF>:"08048Ad0 <getbuf>:8048AD0: -Push%EBP8048AD1: theE5 mov%esp,%ebp8048AD3: theEc -Sub$0x28,%esp8048AD6:8D $E8 Lea-0X18 (%EBP),%eax8048AD9: the Geneva  -mov%eax, (%ESP)8048Adc:e8 DF FE FF FF call80489C0 <Gets>8048Ae1:c9 leave8048Ae2:b8 on xx xx xxmov$0x1,%eax8048AE7:C3 ret8048Ae8: -Nop8048AE9:8D B4 - xx xx xx xxLea0X0 (%esi,%eiz,1),%esi

Based on the assembly Code of GETBUF (), now analyze what the stack structure looks like at runtime. Basic knowledge can be seen in six-Star Classic csapp-notes (3) in the machine-level representation of the program "7. Runtime code and stack" to review at a high speed. This is not to be discussed here.

First of all. Before Getbuf () is called. %EBP and%esp point to the stack base address of the caller test () and the top address of the stack, where the stack world is still "calm":

..................................................... 0x??

<-%EBP

..................................................... 0x00 <-%esp

When test () runs to call. Based on previous studies. The first two "idiomatic" instructions for the call command and GETBUF () are three things to complete:

    • The call command saves the return address : The so-called Save return address is in fact the calls command to press the PC at that moment (the%EIP value, the address of the next instruction on the message) into the stack . Do you remember? Since the PC has been added first, the instruction runs behind. So after running all the code for GETBUF (), the RET instruction restores the value of the PC. The program will be able to continue running the remaining code of test ().
    • Getbuf () saves the%ebp of Test (): pushes the base address of the test () stack frame onto the stack.
    • Getbuf () saves the%esp of Test (): Saves the stack top address of the test () stack frame to the%ebp of Getbuf (), as the base address of the GETBUF ().

      The leave and RET directives are responsible for restoring%EBP and%ESP.

According to these three "conventions", each function of the stack initially is the same: first return address, then the%EBP of the saved caller, the current%EBP point to this. Instead,%esp points to "lower" depending on the size of the allocated space.

The next step is to analyze the unique parts of Getbuf ().

Before starting further analysis, determine the two rules:1) The address pointed to by the%EBP as 0x00 (relative address); 2) above the horizontal line where the register is pointing is the data on that address .

    1. lea-0x18 (%EBP),%eax: Using the LEA to run complex operations,%eax =%ebp-0x18 = 0x18
    2. mov%eax, (%ESP): Changes the value of the%esp point to the position as the entry of the gets (). % (ESP) = -0x28 position data = -0x18
    3. Call 80489C0: Calls the gets () function.

Regardless of how the get () changes the BUF array using the -0x18, the default is that it will complete the work. So the stack of Getbuf () is the same as the call to gets ():

..................................................... 0x??

.....................................................
Return Address
..................................................... 0x04
Saved%EBP
..................................................... 0x00 <-%ebp

.....................................................
-0x18 (%EAX)
..................................................... -0x28 <-%esp (&arg0)

It's enough to know. You can experiment with the following.

refresher: Call, leave, ret
Call A: Save%eip, Invoke function

  • Push%EIP
  • JMP A

    Leave: Restore caller's%EBP and%ESP, prepare for Exit function

  • mov%ebp,%ESP

  • Pop%EBP

    RET: Change%EIP, return caller to continue running

  • Pop%eip

further recall:
Push A: Press A into the stack and change the stack top pointer%esp

  • mov A, (%ESP)
  • %esp + = 4

    JMP A: Change%eip. "Jump elsewhere" to continue running

  • mov A,%EIP

2.3 GdB Observation

GDB is a powerful debugging tool under Linux. Simple instructions for use such as the following:

    1. GDB : Prepare the Debug program, equivalent to GDB first. Again file.

    2. b : Set a breakpoint for the function.

      b is the abbreviation for break. Except for the function name. It can also be the address, the +/-offset of the current operating place, and so on.

    3. Run: Start running the program. You can add the required number of parameters after run, just as you would when the command line is running normally.
    4. S/n/si/c/kill: S is step in, which goes to the next line of code, and N is step next. Runs the next line of code but does not enter. Si is step instruction. Run the next assembly/CPU instruction, C is continue, and continue until the next breakpoint. Kill terminates debugging.

    5. BT: BT is the abbreviation of BackTrace. Prints the stack path of the currently located function.
    6. Info Frame : Describes the selected stack frame.
    7. info args: Prints the selected stack frame's number of references.
    8. Print: Prints the value of the specified variable.

    9. list: List the corresponding source code.
    10. quit: Exit gdb.
3. "Attack" experiment 3.1 level 0: Candle

Experiment 1 is to change the return address of Getbuf (). Instead of returning to the original caller test () after running Getbuf (), jump to a function called smoke ().

And don't worry, we're going to break the rest of the stack, because the smoke () is going to terminate the program anyway, which also reduces the difficulty.

void smoke(){    printf("Smoke!: You called smoke()\n");    validate(0);    exit(0);}

So the idea is very easy. Based on the previous stack structure analysis, we simply construct a string to copy all of the gets () to the BUF array, resulting in a buffer overflow. The most important point at the same time is that the initial address of the smoke () function is also placed inside the constructed string. Make it happen to cover the return address position of the getbuf () .

So the first step. We first need to know the initial address of smoke ().

This is very easy. Use Objdump to view the symbol table or. Text to find:

[[email protected] bufbomb]$ objdump -t bufbomb bufbomb:     file format elf32-i386SYMBOL TABLE:08048134 l    d  .interp        00000000              .interp    ...08048f40 g     F .text  0000002a              bushandler08048eb0 g     F .text  0000002a              smoke00000000       F *UND*  00000017              [email protected]@GLIBC_2.00804a1d0 g     O .bss   00000004              team    ...

Be able to clearly see smoke's initial address is 0x08048eb0, everything is ready. Now it's possible to construct an "attack" string! Since the title has been said, it's okay to destroy the rest of the data in the stack, except for the smoke address. The rest of us are able to "write blindly".

BUF The address of the first element is -0x18, and the address of the first byte of return addresses is 0x04, the difference between two positions is converted to decimal, which is 0x04-( -0x18) = 4 + =. That is to say we have to construct 28 characters, and then add smoke () to the address can be accurately covered to return to address. For ease of counting, I fill in order from 00 to 99:

[[email protected] bufbomb]$ cat exploit.raw0011223344556677889900112233445566778899001122334455667708048eb0

Unexpectedly is the first run but failed, Bufbomb hint segment fault, thought before analysis are wrong. The result is that I forget the small end of the matter, directly to the smoke () of the first address 0x08048eb0 put to the end of Exploit.new, the PC will point to an illegal memory address, of course, the report section error. Adjust the address to B0 8e 04 08, and Sure enough!

I saw the CMU say "nice job!" to me. Oh, my tears!

[[email protected] bufbomb]$ cat exploit.raw001122334455667788990011223344556677889900112233445566770x5e5ee04eType string:Smoke!: You called smoke()NICE JOB!Sent validation information to grading server
3.2 Level 1: Fireworks

Experiment 2, similar to experiment 1, is to let the caller of Getbuf () test () (not Getbuf ()) run a function that is not called in the code. The fizz () function is in Experiment 2. But experiment 2 slightly increased the difficulty. Not only do we want to let test () run fizz (), but also pass in our cookie as a parameter. Let Fizz () print out to calculate success.

void fizz(int val){    if (val == cookie)    {        printf("Fizz!: You called fizz(0x%x)\n", val);        validate(1);    else        printf("Misfire: You called fizz(0x%x)\n", val);    exit(0);}

The first step is to view the initial address of the fizz () function in the symbol table by OBJDUMP-T. Get the address 0x08048e60, just use it to replace the address of the previous Exploit.raw smoke () can let the Getbuf () run to return to Fizz () (note Do not forget the small end byte order). The "Illusion" of fizz () is called by the buffer overflow, which is the result of the test ().

The second step is very easy, using Makecookie to generate my username "Cdai" cookie is 0x5e5ee04e, then the question is how to correctly set fizz () to participate in it? Before we focused on the three things that the call runtime was called to do, we now brush up on what the user needs to do.

Revisit the disassembly code of the Getbuf (), take the GETBUF () call gets () as an example, and look at the caller's code and the corresponding stack:

[Email protected] bufbomb]$ objdump-s- D-Z Bufbomb | Grep-a15"<GETBUF>:"08048Ad0 <getbuf>:8048AD0: -Push%EBP8048AD1: theE5 mov%esp,%ebp8048AD3: theEc -Sub$0x28,%esp8048AD6:8D $E8 Lea-0X18 (%EBP),%eax8048AD9: the Geneva  -mov%eax, (%ESP)8048Adc:e8 DF FE FF FF call80489C0 <Gets>8048Ae1:c9 leave8048Ae2:b8 on xx xx xxmov$0x1,%eax8048AE7:C3 ret8048Ae8: -Nop8048AE9:8D B4 - xx xx xx xxLea0X0 (%esi,%eiz,1),%esi[[email protected] bufbomb]$ objdump- DBufbomb | Grep-a30"<FIZZ>:"08048E60 <fizz>:8048E60: -Push%EBP8048E61: theE5 mov%esp,%ebp8048E63: theEc ,Sub$0x8,%esp8048E66:8B $  ,mov0x8 (%EBP),%eax ...

Before call gets (). Getbuf () is responsible for pushing the number of participants onto the stack, where the number of participants is (%ESP), which is the position indicated at the top of the stack. With this knowledge. We will be able to prepare for fizz () to participate in. But pay attention to three points:

    1. multiple parameter order problems : If get () has two parameters, the address order on the stack is: the low address (near the top of the stack) is the first parameter. A high address is the second parameter.
    2. stack pointers%ebp and%esp: When we overflow the buffer to the return address position on the getbuf () stack, it actually destroys the rest of the data on the stack. Contains saved%EBP.

      This way Getbuf () is actually unable to recover to test () when running return recovery%EBP. Note: the damage is only%ebp. Because the%ESP is restored with%EBP instead of stored on the stack (Leave=mov%ebp,%esp; Pop%ebp) but it doesn't matter. Just to start running Fizz (),Fizz () will save the de facto "corrupted"%EBP to the stack and continue running from the perfect%esp, according to the Convention .

    3. don't forget to return address: Before the call command will be pressed into%EIP as return address before jumping.

      That is, fizz ()%EBP (pointing to saved%EBP) and the caller's prepared entry are separated by the return address.

The stack looks very awkward at this point. This is very normal. Because normally, getbuf () should go back to its call point after it runs, but since we are good at destroying its stack, the Return of Getbuf () is immediately entered into a function fizz (), and it does not seem surprising.

......................................................................................... 0x?

?


Data on caller ' s stack = Fizz () ' s argument:4ee05e5e
......................................................................................... 0x0c
Data on caller ' s stack = Fizz () ' s return address:padding 00112233
......................................................................................... 0x08
Return Address of getbuf () = Fizz () ' s entry point:608e0408
......................................................................................... 0x04
Saved%ebp = padding 44556677
......................................................................................... 0x00 <-%ebp
Buf on Getbuf () ' s stack = padding 00~99 00~99 00~33
.........................................................................................
-0x18 (%EAX)
......................................................................................... -0x28 <-%esp (&arg0)

Here's what it looks like after entering Fizz (): The entry and return addresses (%EIP) are pressed into the stack according to the caller's "convention" and the call instruction. In accordance with the callee "Convention", Fizz moves the%EBP into the%ESP and moves the%ESP allocation stack space. Everything "normal" seems to be the fizz () Call of Test ()!

The disassembly result from Fizz () also validates this. Sub $0x8,%ESP after allocating stack space. mov 0x8 (%EBP),%eax will be saved into register%eax. Comparing the stacks below,%EBP the caller's%EBP and return address of 8 bytes into the stack, so 0x8 (%EBP) happens to be the values we put in when we "attack".

......................................................................................... 0x??


Fizz () ' s argument:4ee05e5e
......................................................................................... 0x0c
Fizz () ' s return address:00112233
......................................................................................... 0x08
Saved%ebp:44556677
......................................................................................... 0x04 <-%ebp

......................................................................................... 0x00

......................................................................................... -0x08 <-%esp

001122334455667788990011223344556677889900112233445566776080x5e5ee04eType string:Fizz!: You called fizz(0x5e5ee04e)NICE JOB!Sent validation information to grading server

Csapp Buffer Overflow attack Experiment (top)

Related Article

Contact Us

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

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

A Free Trial That Lets You Build Big!

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

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

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

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