Message392392
The library winreg[1] can be used to access registry on windows.
>reg.SetValueEx(key, 'X', 0, reg.REG_DWORD, -1337)
`SetValueEx` could store data in the value field of an open registry key,
In the source file of "PC/winreg.c", `Py2Reg`is called first
```
static PyObject *
winreg_SetValueEx_impl(PyObject *module, HKEY key,
const Py_UNICODE *value_name, PyObject *reserved,
DWORD type, PyObject *value)
/*[clinic end generated code: output=811b769a66ae11b7 input=900a9e3990bfb196]*/
{
BYTE *data;
DWORD len;
LONG rc;
if (!Py2Reg(value, type, &data, &len))
...
```
`Py2Reg` is implemented in the same file:
```
Py2Reg(PyObject *value, DWORD typ, BYTE **retDataBuf, DWORD *retDataSize)
{
Py_ssize_t i,j;
switch (typ) {
case REG_DWORD:
if (value != Py_None && !PyLong_Check(value))
return FALSE;
*retDataBuf = (BYTE *)PyMem_NEW(DWORD, 1);
if (*retDataBuf == NULL){
PyErr_NoMemory();
return FALSE;
}
*retDataSize = sizeof(DWORD);
if (value == Py_None) {
DWORD zero = 0;
memcpy(*retDataBuf, &zero, sizeof(DWORD));
}
else {
DWORD d = PyLong_AsUnsignedLong(value);
memcpy(*retDataBuf, &d, sizeof(DWORD));
}
break;
```
When the type is set with reg.REG_DWORD, `PyLong_AsUnsignedLong(value)` will change the value's type, and then memcpy the returned value directly, without any check.
In the Objects/longobject.c, as the comment said:
/* Get a C unsigned long int from an int object.
Returns -1 and sets an error condition if overflow occurs. */
If PyLong_AsUnsignedLong return -1, the -1 will be stored in the registry though the error occured
PoC:
import winreg as reg
key = reg.CreateKey(reg.HKEY_CURRENT_USER, 'SOFTWARE\\Classes\\r3pwn')
try:
print("Set Subkey X: -1337")
reg.SetValueEx(key, 'X', 0, reg.REG_DWORD, -1337)
except Exception as e:
print("Get Subkey: ", reg.QueryValueEx(key, "X")[0])
try:
print("Set Subkey Y: 2**33")
reg.SetValueEx(key, 'Y', 0, reg.REG_DWORD, 2**33)
except Exception as e:
print("Get Subkey: ", reg.QueryValueEx(key, "Y")[0])
The Test Environment
OS: Windows
Python Version: 3.9.0
python winreg_bug.py
Set Subkey X: -1337
Get Subkey: 4294967295
Set Subkey Y: 2**33
Get Subkey: 4294967295
the return value should be checked:
DWORD d = PyLong_AsUnsignedLong(value);
+ if (d == (unsigned long)-1 && PyErr_Occurred())
+ return False;
memcpy(*retDataBuf, &d, sizeof(DWORD));
[1] https://docs.python.org/3.9/library/winreg.html#winreg.SetValueEx |
|
Date |
User |
Action |
Args |
2021-04-30 08:42:01 | r3pwnx | set | recipients:
+ r3pwnx |
2021-04-30 08:42:01 | r3pwnx | set | messageid: <1619772121.59.0.631498595724.issue43984@roundup.psfhosted.org> |
2021-04-30 08:42:01 | r3pwnx | link | issue43984 messages |
2021-04-30 08:42:01 | r3pwnx | create | |
|