New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
UAF in Tkinter module #71441
Comments
/* 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;
}
then v->interp passed to the Tcl_AppInit function 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 disassemble: 0x00007ffff3a07e0a <+58>: lea rdi,[rax+rdx*1] < === destination buffer $rax = 0x7fffeffc5810 - $rdx = 0x100000 0x00007ffff3a07e0e <+62>: mov rsi,r12 < === source buffer
ASAN report. ================================================================= 0x7f4e6ba64810 is located 16 bytes inside of 2097166-byte region [0x7f4e6ba64800,0x7f4e6bc6480e) previously allocated by thread T0 here: SUMMARY: AddressSanitizer: heap-use-after-free ??:0 ?? 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() |
Minimal reproducer: from tkinter import Tk
Tk(className='A'*0xfffff) This looks as Tcl/Tk problem. |
Yeah you're right but Python doesn't check the classname length. Therefore then heap overflow occurred in the Tcl. |
What size is safe for className? |
the appropriate size should be chosen I) |
psuedocode <+16>: movsxd rdx,DWORD PTR [rbx+0x8] 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 newSize ($eax) >= dsPtr->spaceAvl gdb > print /x $eax gdb > x/x $rbx+0xc 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: |
For reference, a Tcl ticket was opened for this issue: https://core.tcl-lang.org/tcl/info/d59715d0cffb |
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: