Fix path traversal in Topaz extraction (arbitrary file write)
The Topaz header record "tag" is read verbatim from the untrusted book file by bookReadString() and then used unsanitized to build the output filename in extractFiles(). A crafted tag such as "../../foo" let a malicious .azw/Topaz file write attacker-controlled bytes outside the extraction directory. The payload content requires no book key, since an unencrypted record with compressedLength == 0 is returned raw. Strip the record name to its basename before joining it to destdir so traversal sequences (../, /, \) can no longer escape, and add an abspath-based containment check as defense in depth. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -358,7 +358,16 @@ class TopazBook:
|
||||
destdir = os.path.join(outdir,"page")
|
||||
if name == b'glyphs':
|
||||
destdir = os.path.join(outdir,"glyphs")
|
||||
# The record name is read verbatim from the (untrusted) book
|
||||
# file, so strip any directory components to stop a crafted
|
||||
# name (e.g. "../../foo") from writing outside of destdir.
|
||||
fname = os.path.basename(fname)
|
||||
outputFile = os.path.join(destdir,fname)
|
||||
# Defense in depth: never let the resolved path escape destdir.
|
||||
real_out = os.path.abspath(outputFile)
|
||||
real_dir = os.path.abspath(destdir)
|
||||
if not (real_out == real_dir or real_out.startswith(real_dir + os.sep)):
|
||||
raise DrmException("Invalid book record name: {0}".format(repr(name)))
|
||||
print(".", end=' ')
|
||||
record = self.getBookPayloadRecord(name,index)
|
||||
if isinstance(record, str):
|
||||
|
||||
Reference in New Issue
Block a user