walk down the dictionary to fetch nested urls (thanks seanthegeek)

This commit is contained in:
Jurriaan Bremer
2017-05-09 18:14:16 +02:00
parent cbd5b27d2e
commit 5c3f7e32d2
3 changed files with 61 additions and 22 deletions
+46 -22
View File
@@ -537,6 +537,49 @@ class PdfDocument(object):
def _sanitize(self, d, key):
return self._parse_string(d.get(key, "").decode("latin-1"))
def walk_object(self, obj, entry):
if isinstance(obj, peepdf.PDFCore.PDFStream):
stream = obj.decodedStream
# Is this actually Javascript code?
if not peepdf.JSAnalysis.isJavascript(stream):
return
javascript = stream.decode("latin-1")
entry["javascript"].append({
"orig_code": javascript,
"beautified": jsbeautify(javascript),
"urls": [],
})
return
if isinstance(obj, peepdf.PDFCore.PDFDictionary):
for url in obj.urlsFound:
entry["urls"].append(self._parse_string(url))
for url in obj.uriList:
entry["urls"].append(self._parse_string(url))
# TODO We should probably add some more criteria here.
uri_obj = obj.elements.get("/URI")
if uri_obj:
if isinstance(uri_obj, peepdf.PDFCore.PDFString):
entry["urls"].append(uri_obj.value)
else:
log.warning(
"Identified a potential URL, but its associated "
"type is not a string?"
)
for element in obj.elements.values():
self.walk_object(element, entry)
return
if isinstance(obj, peepdf.PDFCore.PDFArray):
for element in obj.elements:
self.walk_object(element, entry)
return
def run(self):
p = peepdf.PDFCore.PDFParser()
r, f = p.parse(
@@ -564,29 +607,10 @@ class PdfDocument(object):
"urls": [],
}
for obj in f.body[version].objects.values():
if obj.object.type == "stream":
stream = obj.object.decodedStream
# Is this actually Javascript code?
if not peepdf.JSAnalysis.isJavascript(stream):
continue
javascript = stream.decode("latin-1")
row["javascript"].append({
"orig_code": javascript,
"beautified": jsbeautify(javascript),
"urls": [],
})
continue
if obj.object.type == "dictionary":
for url in obj.object.urlsFound:
row["urls"].append(self._parse_string(url))
for url in obj.object.uriList:
row["urls"].append(self._parse_string(url))
for idx, obj in enumerate(f.body[version].objects.values()):
self.walk_object(obj.object, row)
row["urls"] = sorted(set(row["urls"]))
ret.append(row)
return ret
Binary file not shown.
+15
View File
@@ -138,6 +138,21 @@ class TestProcessing(object):
r = s.run()["pdf"][0]
assert "var x = unescape" in r["javascript"][0]["orig_code"]
def test_phishing0_pdf(self):
set_cwd(tempfile.mkdtemp())
s = Static()
s.set_task({
"category": "file",
"package": "pdf",
"target": "phishing0.pdf",
})
s.set_options({
"pdf_timeout": 30,
})
s.file_path = "tests/files/phishing0.pdf"
assert "googleattachmentsigned" in s.run()["pdf"][0]["urls"][0]
@mock.patch("cuckoo.processing.static.dispatch")
def test_pdf_mock(self, p):
set_cwd(tempfile.mkdtemp())