Issue27254
This issue tracker has been migrated to GitHub,
and is currently read-only.
For more information,
see the GitHub FAQs in the Python's Developer Guide.
Created on 2016-06-07 18:29 by Emin Ghuliev, last changed 2022-04-11 14:58 by admin. This issue is now closed.
Messages (6) | |||
---|---|---|---|
msg267714 - (view) | Author: Emin Ghuliev (Emin Ghuliev) | Date: 2016-06-07 18:28 | |
/* This is used to get the application class for Tk 4.1 and up */ argv0 = (char*)attemptckalloc(strlen(className) + 1); //<=== classname allocated if (!argv0) { PyErr_NoMemory(); Py_DECREF(v); return NULL; } strcpy(argv0, className); <==== //classname copy to argv0 if (Py_ISUPPER(Py_CHARMASK(argv0[0]))) argv0[0] = Py_TOLOWER(Py_CHARMASK(argv0[0])); Tcl_SetVar(v->interp, "argv0", argv0, TCL_GLOBAL_ONLY); // argv0 passed to v->interp and freed; ckfree(argv0); then v->interp passed to the Tcl_AppInit function if (Tcl_AppInit(v->interp) != TCL_OK) in Tcl_AppInit call to (and passed the v->interp) the Tcl_DStringAppend. allocates the specified byte Tcl_DStringAppend function then heap memory passed to memcpy. Realloc arguments presentation in the native tcl allocator; char * Tcl_Realloc(ptr, size) disassemble: gdb> print /x $rdi $4 = 0x7ffff03c8810 0x7ffff03c8814: 0x41414141 ....... gdb> print /x $rsi $2 = 0x3ffffe 0x00007ffff3a07dfe <+46>: call 0x7ffff3935040 <Tcl_Realloc> after return to the caller function. Performed memory copy operation. 0x00007ffff3a07e0a <+58>: lea rdi,[rax+rdx*1] < === destination buffer $rax = 0x7fffeffc5810 - $rdx = 0x100000 $rax+$rdx = 0x7ffff00c5810 0x00007ffff3a07e0e <+62>: mov rsi,r12 < === source buffer 0x00007ffff3a07e11 <+65>: movsxd rdx,ebp <=== 0xfffff 0x00007ffff3a07e14 <+68>: call 0x7ffff39155c0 <memcpy@plt> copy to $rdi bytes to $rsi buffer with 0xfffff byte; ASAN report. ================================================================= ==27988==ERROR: AddressSanitizer: heap-use-after-free on address 0x7f4e6ba64810 at pc 0x4665ea bp 0x7fff89a4ab80 sp 0x7fff89a4a340 READ of size 1048575 at 0x7f4e6ba64810 thread T0 ==27988==WARNING: Trying to symbolize code, but external symbolizer is not initialized! #0 0x4665e9 (/home/eminus/Downloads/Python-2.7.11/python+0x4665e9) #1 0x7f4e6f0a3e18 (/usr/lib/x86_64-linux-gnu/libtcl8.6.so+0x116e18) #2 0x7f4e6f38744e (/usr/lib/x86_64-linux-gnu/libtk8.6.so+0x6244e) #3 0x7f4e6f6b6e4c (/home/eminus/Downloads/Python-2.7.11/build/lib.linux-x86_64-2.7/_tkinter.so+0x19e4c) #4 0x7f4e6f6a7fc5 (/home/eminus/Downloads/Python-2.7.11/build/lib.linux-x86_64-2.7/_tkinter.so+0xafc5) #5 0x5e1813 (/home/eminus/Downloads/Python-2.7.11/python+0x5e1813) #6 0x5d319c (/home/eminus/Downloads/Python-2.7.11/python+0x5d319c) #7 0x721353 (/home/eminus/Downloads/Python-2.7.11/python+0x721353) #8 0x4acb2a (/home/eminus/Downloads/Python-2.7.11/python+0x4acb2a) #9 0x4b6c62 (/home/eminus/Downloads/Python-2.7.11/python+0x4b6c62) #10 0x4acb2a (/home/eminus/Downloads/Python-2.7.11/python+0x4acb2a) #11 0x5f0823 (/home/eminus/Downloads/Python-2.7.11/python+0x5f0823) #12 0x4b0a08 (/home/eminus/Downloads/Python-2.7.11/python+0x4b0a08) #13 0x4acb2a (/home/eminus/Downloads/Python-2.7.11/python+0x4acb2a) #14 0x5e2d19 (/home/eminus/Downloads/Python-2.7.11/python+0x5e2d19) #15 0x5d319c (/home/eminus/Downloads/Python-2.7.11/python+0x5d319c) #16 0x5d2041 (/home/eminus/Downloads/Python-2.7.11/python+0x5d2041) #17 0x660980 (/home/eminus/Downloads/Python-2.7.11/python+0x660980) #18 0x65fc8a (/home/eminus/Downloads/Python-2.7.11/python+0x65fc8a) #19 0x48e46c (/home/eminus/Downloads/Python-2.7.11/python+0x48e46c) #20 0x7f4e72389ec4 (/lib/x86_64-linux-gnu/libc.so.6+0x21ec4) #21 0x48c5bc (/home/eminus/Downloads/Python-2.7.11/python+0x48c5bc) 0x7f4e6ba64810 is located 16 bytes inside of 2097166-byte region [0x7f4e6ba64800,0x7f4e6bc6480e) freed by thread T0 here: #0 0x4766d3 (/home/eminus/Downloads/Python-2.7.11/python+0x4766d3) #1 0x7f4e6f09b52d (/usr/lib/x86_64-linux-gnu/libtcl8.6.so+0x10e52d) previously allocated by thread T0 here: #0 0x4764d9 (/home/eminus/Downloads/Python-2.7.11/python+0x4764d9) #1 0x7f4e6f09b0cc (/usr/lib/x86_64-linux-gnu/libtcl8.6.so+0x10e0cc) SUMMARY: AddressSanitizer: heap-use-after-free ??:0 ?? Shadow bytes around the buggy address: 0x0fea4d7448b0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0fea4d7448c0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0fea4d7448d0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0fea4d7448e0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0fea4d7448f0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa =>0x0fea4d744900: fd fd[fd]fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0fea4d744910: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0fea4d744920: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0fea4d744930: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0fea4d744940: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0fea4d744950: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd Shadow byte legend (one shadow byte represents 8 application bytes): Addressable: 00 Partially addressable: 01 02 03 04 05 06 07 Heap left redzone: fa Heap right redzone: fb Freed heap region: fd Stack left redzone: f1 Stack mid redzone: f2 Stack right redzone: f3 Stack partial redzone: f4 Stack after return: f5 Stack use after scope: f8 Global redzone: f9 Global init order: f6 Poisoned by user: f7 ASan internal: fe ==27988==ABORTING PoC from Tkinter import * class Application(Frame): def say_hi(self): print ("hi there, everyone!") def createWidgets(self): self.QUIT = Button(self) self.QUIT["text"] = "QUIT" self.QUIT["fg"] = "red" self.QUIT["command"] = self.quit self.QUIT.pack({"side": "left"}) self.hi_there = Button(self) self.hi_there["text"] = "Hello", self.hi_there["command"] = self.say_hi self.hi_there.pack({"side": "left"}) def __init__(self, master=None): Frame.__init__(self, master) self.pack() self.createWidgets() root = Tk(screenName=None, baseName=None, className='A'*0xfffff, useTk=1) app = Application(master=root) app.mainloop() root.destroy() |
|||
msg267727 - (view) | Author: Serhiy Storchaka (serhiy.storchaka) * | Date: 2016-06-07 19:02 | |
Minimal reproducer: from tkinter import Tk Tk(className='A'*0xfffff) This looks as Tcl/Tk problem. |
|||
msg267795 - (view) | Author: Emin Ghuliev (Emin Ghuliev) | Date: 2016-06-08 06:19 | |
Yeah you're right but Python doesn't check the classname length. Therefore then heap overflow occurred in the Tcl. |
|||
msg267798 - (view) | Author: Serhiy Storchaka (serhiy.storchaka) * | Date: 2016-06-08 06:52 | |
What size is safe for className? |
|||
msg267800 - (view) | Author: Emin Ghuliev (Emin Ghuliev) | Date: 2016-06-08 07:02 | |
the appropriate size should be chosen I) |
|||
msg267860 - (view) | Author: Emin Ghuliev (Emin Ghuliev) | Date: 2016-06-08 14:45 | |
psuedocode <+16>: movsxd rdx,DWORD PTR [rbx+0x8] <+20>: lea eax,[rdx+rbp*1] newSize = length ($rdx) + dsPtr->length ($rbp) gdb > print /x $rbp $5 = 0xfffff gdb > print /x $rdx $6 = 0x100000 newsize = 0xfffff+0x100000 = 0x1fffff <Tcl_DStringAppend+23> cmp eax,DWORD PTR [rbx+0xc] ← $pc <Tcl_DStringAppend+26> jl 0x7ffff6194e38 <Tcl_DStringAppend+104> newSize ($eax) >= dsPtr->spaceAvl gdb > print /x $eax $7 = 0x1fffff gdb > x/x $rbx+0xc 0x7fffffffd0cc: 0x001ffffe condition: 0x1fffff >= 0x001ffffe = True if (newSize >= dsPtr->spaceAvl) { <Tcl_DStringAppend+31> lea esi,[rax+rax*1] ; magic compiler optimization :) (newSize(0x1fffff)*2) /* */ dsPtr->spaceAvl = newSize * 2; gdb > print /x $rax $4 = 0x1fffff $esi = 0x1fffff+0x1fffff (newSize(0x1fffff)*2) = 0x3ffffe /* */ => <+34>: lea rax,[rbx+0x10] <+38>: mov DWORD PTR [rbx+0xc],esi <+41>: cmp rdi,rax ; $rax = dsPtr->staticSpace and $rdi = dsPtr->string <+44>: je 0x7ffff6194e50 <Tcl_DStringAppend+128> condition : dsPtr->string == dsPtr->staticSpace = False then jump to '<Tcl_DStringAppend+46> call 0x7ffff60c2040 <Tcl_Realloc>' if (dsPtr->string == dsPtr->staticSpace) { char *newString = ckalloc(dsPtr->spaceAvl); memcpy(newString, dsPtr->string, (size_t) dsPtr->length); dsPtr->string = newString; } else { <Tcl_DStringAppend+46> call 0x7ffff60c2040 <Tcl_Realloc> $rsi = 0x3ffffe $rdi = 0x7ffff333e020 dsPtr->string = ckrealloc(dsPtr->string = 0x7ffff333e020, dsPtr->spaceAvl = 0x3ffffe); } } disassemble: <Tcl_DStringAppend+58> lea rdi,[rax+rdx*1] ; dsPtr->string + dsPtr->length <Tcl_DStringAppend+62> mov rsi,r12 ; bytes <Tcl_DStringAppend+65> movsxd rdx,ebp ; length <Tcl_DStringAppend+68> call 0x7ffff60a25c0 <memcpy@plt> memcpy(dsPtr->string + dsPtr->length, bytes, length); |
History | |||
---|---|---|---|
Date | User | Action | Args |
2022-04-11 14:58:32 | admin | set | github: 71441 |
2016-07-05 06:09:47 | Emin Ghuliev | set | resolution: third party |
2016-07-05 06:09:30 | Emin Ghuliev | set | status: open -> closed |
2016-06-12 13:54:16 | Emin Ghuliev | set | title: heap overflow in Tkinter module -> UAF in Tkinter module |
2016-06-08 14:45:49 | Emin Ghuliev | set | messages: + msg267860 |
2016-06-08 07:02:41 | Emin Ghuliev | set | messages: + msg267800 |
2016-06-08 06:52:03 | serhiy.storchaka | set | messages: + msg267798 |
2016-06-08 06:19:08 | Emin Ghuliev | set | messages: + msg267795 |
2016-06-07 19:02:10 | serhiy.storchaka | set | versions:
+ Python 3.5, Python 3.6, - Python 3.3, Python 3.4 nosy: + serhiy.storchaka messages: + msg267727 type: security -> crash |
2016-06-07 18:29:00 | Emin Ghuliev | create |