-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 - ------------------------------------ The Cult of a Cardinal Number (Equal to the Sum of 1+1) by Phantasmal Phantasmagoria phantasmal@hush.ai - ---- Table of Contents ------------- 1 - Introduction 2 - Technical Details 3 - Final Thoughts - ---- Introduction ------------------ On September 23 the ISS X-Force team released details of a flaw regarding the handling of ASCII file translations in the ProFTPD server. The code in question was rapidly patched by the ProFTPD team. However, a small and more subtle overflow was left unnoticed, an off-by-one condition. On closer analysis it was found that the patch created to fix the original ISS flaw introduced yet another off-by-one overflow, effectively allowing two bytes to overflow past the end of an internal buffer. Exploitation of this vulnerabilty could lead to remote privilege escalation to the root user. Both holes were fixed in a clean up of the problematic code in version 1.2.9rc3. Affected versions: 1.2.7/1.2.7p 1.2.8/1.2.8p 1.2.9rc1/1.2.9rc1p 1.2.9rc2/1.2.9rc2p Unaffected versions: 1.2.9rc3 1.2.9 - ------------------------------------ - ---- Technical Details ------------- As in the case of the ISS bug this issue resides in the _xlate_ascii_write() function, used to insert a preceeding CR for every LF. It can be triggered by the RETR ftp command. static void _xlate_ascii_write(char **buf, unsigned int *buflen, unsigned int bufsize) { char *tmpbuf = *buf; unsigned int tmplen = *buflen; unsigned int lfcount = 0; unsigned int added = 0; int res = 0; register unsigned int i = 0; if (tmpbuf[0] == '\n') lfcount++; .. if ((res = (bufsize - tmplen - lfcount)) <= 0) { /* [A] */ pool *copy_pool = make_sub_pool(session.xfer.p); char *copy_buf - pcalloc(copy_pool, tmplen); memmove(copy_buf, tmpbuf, tmplen); session.xfer.bufsize = tmplen + lfcount; /* [B] */ session.xfer.buf = pcalloc(session.xfer.p,session.xfer.bufsize); session.xfer.buf++; /* [C] */ session.xfer.bufstart = session.xfer.buf; memmove(session.xfer.buf, copy_buf, tmplen); /* [D] */ destroy_pool(copy_pool); tmpbuf = session.xfer.buf; bufsize = session.xfer.bufsize; } if (tmpbuf[0] == '\n') { memmove(&(tmpbuf[1]), &tmpbuf[0], bufsize); /* [E] */ tmpbuf[0] = '\r'; added++; lfcount--; } .. tmpbuf[tmplen+added] = '\0'; /* [F] */ *buf = tmpbuf; *buflen = tmplen + added; } These flaws are made possible at a number of stages. Firstly, we need to get into the if statement at [A]. This is easy enough to do. The variable bufsize is the actual size of the buffer we are attacking, which when using the RETR command is 1024. For the sake of the overflows, we want to get 'res' to exactly 0. There are a number of possible combinations to do this, the simplest of which is passing a 1023 byte long buffer containing a single LF in the first character to the _xlate_ascii_write() function. Knowing that we can trigger the if statement we can shift our attention to session.xfer.buf, the buffer we will be overflowing. The first important mistake occurs when session.xfer.bufsize is set to 1024 at [B], where it should actually be 1025 (1023 + CR + NULL). This is followed by the crux of the overflows at [C]. It is entirely unnessecary to increase session.xfer.buf here. It essentialy reduces the amount of valid space in the buffer to 1023. The final significant event leading to the overflows is at [D], where 1023 bytes of our buffer (including the starting LF) is moved to session.xfer.buf. Due to the slip-up at [C], we lose our NULL terminating byte; our buffer is exactly contiguous to the end of valid space. The first off-by-one overflow occurs at [E]. The last character of our 1023 byte long argument to _xlate_ascii_write() is moved past the boundary of allocated space for session.xfer.buf to make room for the preceeding CR to our LF. We can control this value. We can't, however, control the next off-by-one at [F]. Due to [C], the line at [F] should be setting tmpbuf[1022] to NULL. The value at tmpbuf[1023] is what we just oveflowed. Instead, tmpbuf[1023 + 1] gets set to NULL. Perhaps it would be more accurate to call this an off-by-two, but as the overflow at [F] existed even before the ISS bug was patched that would only introduce confusion. - ------------------------------------ - ---- Final thoughts ---------------- It is difficult, if not impossible, to please every group of the security community when releasing information pertaining to a vulnerability. Some will say that I should of contacted the vendor, some will say I should of kept the bug to myself, some will say I should of released exploit code. I can only offer one account; The Cult of a Cardinal Number has finished. It was found, exploited, and patched. And it has finished. Some might label me - black hat, white hat. But quite honestly, there is no such thing as 'hats'. There are those who can hack and there are those who can't, regardless of what type of disclosure they choose, or where they like to discuss security, or even what they use for a name. To those in favour of full-disclosure, everything you need to know in order to form a successful exploit is out there. I refuse to aid and abet technically inept members on any side of the digital security divide who are not willing and eager to learn. Programming does not make you a hacker, breaking in to a computer does not make you a hacker. Learning and thinking creatively, that's what it's really about. That's what makes you a hacker. - ------------------------------------ -----BEGIN PGP SIGNATURE----- Note: This signature can be verified at https://www.hushtools.com/verify Version: Hush 2.3 wkYEARECAAYFAkBDdjIACgkQImcz/hfgxg201wCfTBWOL+XcuC+UeDMqW41HWsJHEwEA n0ml1AZLGfwwurjb1xsyvOdna2fW =OIQH -----END PGP SIGNATURE----- Concerned about your privacy? Follow this link to get FREE encrypted email: https://www.hushmail.com/?l=2 Free, ultra-private instant messaging with Hush Messenger https://www.hushmail.com/services.php?subloc=messenger&l=434 Promote security and make money with the Hushmail Affiliate Program: https://www.hushmail.com/about.php?subloc=affiliate&l=427