pwn 0.5.383 → 0.5.385

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -1
  3. data/Gemfile +1 -1
  4. data/README.md +3 -3
  5. data/lib/pwn/plugins/git.rb +1 -1
  6. data/lib/pwn/reports/fuzz.rb +1 -1
  7. data/lib/pwn/reports/phone.rb +1 -1
  8. data/lib/pwn/reports/sast.rb +335 -112
  9. data/lib/pwn/reports/uri_buster.rb +1 -1
  10. data/lib/pwn/sast/amqp_connect_as_guest.rb +0 -1
  11. data/lib/pwn/sast/apache_file_system_util_api.rb +0 -1
  12. data/lib/pwn/sast/aws.rb +0 -1
  13. data/lib/pwn/sast/banned_function_calls_c.rb +0 -1
  14. data/lib/pwn/sast/base64.rb +0 -2
  15. data/lib/pwn/sast/beef_hook.rb +0 -1
  16. data/lib/pwn/sast/cmd_execution_java.rb +0 -1
  17. data/lib/pwn/sast/cmd_execution_python.rb +0 -1
  18. data/lib/pwn/sast/cmd_execution_ruby.rb +0 -1
  19. data/lib/pwn/sast/cmd_execution_scala.rb +0 -1
  20. data/lib/pwn/sast/csrf.rb +0 -1
  21. data/lib/pwn/sast/deserial_java.rb +0 -1
  22. data/lib/pwn/sast/emoticon.rb +0 -1
  23. data/lib/pwn/sast/eval.rb +0 -1
  24. data/lib/pwn/sast/factory.rb +0 -1
  25. data/lib/pwn/sast/http_authorization_header.rb +0 -1
  26. data/lib/pwn/sast/inner_html.rb +0 -1
  27. data/lib/pwn/sast/keystore.rb +0 -1
  28. data/lib/pwn/sast/local_storage.rb +0 -1
  29. data/lib/pwn/sast/location_hash.rb +0 -1
  30. data/lib/pwn/sast/log4j.rb +0 -1
  31. data/lib/pwn/sast/logger.rb +0 -1
  32. data/lib/pwn/sast/md5.rb +0 -1
  33. data/lib/pwn/sast/outer_html.rb +0 -1
  34. data/lib/pwn/sast/padding_oracle.rb +0 -1
  35. data/lib/pwn/sast/password.rb +0 -1
  36. data/lib/pwn/sast/php_input_mechanisms.rb +0 -1
  37. data/lib/pwn/sast/php_type_juggling.rb +0 -1
  38. data/lib/pwn/sast/pom_version.rb +0 -1
  39. data/lib/pwn/sast/port.rb +0 -1
  40. data/lib/pwn/sast/post_message.rb +0 -1
  41. data/lib/pwn/sast/private_key.rb +0 -1
  42. data/lib/pwn/sast/redirect.rb +0 -1
  43. data/lib/pwn/sast/redos.rb +0 -1
  44. data/lib/pwn/sast/shell.rb +0 -1
  45. data/lib/pwn/sast/signature.rb +0 -1
  46. data/lib/pwn/sast/sql.rb +0 -1
  47. data/lib/pwn/sast/ssl.rb +0 -1
  48. data/lib/pwn/sast/sudo.rb +0 -1
  49. data/lib/pwn/sast/task_tag.rb +0 -1
  50. data/lib/pwn/sast/throw_errors.rb +0 -1
  51. data/lib/pwn/sast/token.rb +0 -1
  52. data/lib/pwn/sast/type_script_type_juggling.rb +0 -1
  53. data/lib/pwn/sast/version.rb +0 -1
  54. data/lib/pwn/sast/window_location_hash.rb +0 -1
  55. data/lib/pwn/version.rb +1 -1
  56. data/third_party/pwn_rdoc.jsonl +2 -1
  57. metadata +3 -3
@@ -160,6 +160,14 @@ module PWN
160
160
  text-decoration: underline;
161
161
  }
162
162
 
163
+ div.dt-container {
164
+ width: 1275px !important;
165
+ }
166
+
167
+ div.dt-scroll-body {
168
+ width: 1275px !important;
169
+ }
170
+
163
171
  table {
164
172
  width: 100%;
165
173
  border-spacing:0px;
@@ -172,6 +180,15 @@ module PWN
172
180
  td {
173
181
  vertical-align: top;
174
182
  word-wrap: break-word !important;
183
+ border: none !important;
184
+ }
185
+
186
+ table.multi_line_select tr.odd {
187
+ background-color: #dedede !important; /* Gray for odd rows */
188
+ }
189
+
190
+ table.multi_line_select tr.even {
191
+ background-color: #ffffff !important; /* White for even rows */
175
192
  }
176
193
 
177
194
  tr.highlighted td {
@@ -180,11 +197,25 @@ module PWN
180
197
  </style>
181
198
 
182
199
  <!-- jQuery & DataTables -->
200
+ <script type="text/javascript" src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
201
+
202
+ <link href="https://cdn.datatables.net/v/dt/jszip-3.10.1/dt-2.3.3/b-3.2.4/b-colvis-3.2.4/b-html5-3.2.4/b-print-3.2.4/fc-5.0.4/fh-4.0.3/kt-2.12.1/r-3.0.6/rg-1.5.2/rr-1.5.0/sc-2.4.3/sb-1.8.3/sp-2.3.5/sl-3.1.0/datatables.min.css" rel="stylesheet" integrity="sha384-51NLFpi/9qR2x0LAjQHiFAjV765f0g9+05EmKQ/QWINR/y3qonty8mPy68vEbo0z" crossorigin="anonymous">
203
+
204
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.2.7/pdfmake.min.js" integrity="sha384-VFQrHzqBh5qiJIU0uGU5CIW3+OWpdGGJM9LBnGbuIH2mkICcFZ7lPd/AAtI7SNf7" crossorigin="anonymous"></script>
205
+
206
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.2.7/vfs_fonts.js" integrity="sha384-/RlQG9uf0M2vcTw3CX7fbqgbj/h8wKxw7C3zu9/GxcBPRKOEcESxaxufwRXqzq6n" crossorigin="anonymous"></script>
207
+
208
+ <script src="https://cdn.datatables.net/v/dt/jszip-3.10.1/dt-2.3.3/b-3.2.4/b-colvis-3.2.4/b-html5-3.2.4/b-print-3.2.4/fc-5.0.4/fh-4.0.3/kt-2.12.1/r-3.0.6/rg-1.5.2/rr-1.5.0/sc-2.4.3/sb-1.8.3/sp-2.3.5/sl-3.1.0/datatables.min.js" integrity="sha384-jvnxkXTB++rTO/pbg6w5nj0jm5HiSGtTcBW5vnoLGRfmSxw3eyqNA0bJ+m6Skjw/" crossorigin="anonymous"></script>
209
+
210
+ <script src="https://cdn.sheetjs.com/xlsx-0.20.2/package/dist/xlsx.full.min.js"></script>
211
+
212
+ <!--
183
213
  <script type="text/javascript" src="//code.jquery.com/jquery-3.6.0.min.js"></script>
184
214
 
185
215
  <link rel="stylesheet" type="text/css" href="//cdn.datatables.net/v/dt/dt-1.11.4/b-2.2.2/b-colvis-2.2.2/b-html5-2.2.2/b-print-2.2.2/cr-1.5.5/fc-4.0.1/fh-3.2.1/kt-2.6.4/r-2.2.9/rg-1.1.4/rr-1.2.8/sc-2.0.5/sp-1.4.0/sl-1.3.4/datatables.min.css"/>
186
216
 
187
217
  <script type="text/javascript" src="//cdn.datatables.net/v/dt/dt-1.11.4/b-2.2.2/b-colvis-2.2.2/b-html5-2.2.2/b-print-2.2.2/cr-1.5.5/fc-4.0.1/fh-3.2.1/kt-2.6.4/r-2.2.9/rg-1.1.4/rr-1.2.8/sc-2.0.5/sp-1.4.0/sl-1.3.4/datatables.min.js"></script>
218
+ -->
188
219
  </head>
189
220
 
190
221
  <body id="pwn_body">
@@ -194,19 +225,18 @@ module PWN
194
225
  </h1><br /><br />
195
226
  <h2 id="report_name"></h2><br />
196
227
 
197
- <div>
198
- <!--<button type="button" id="button">Rows Selected</button>-->
199
- <button type="button" id="export_selected">Export Selected to JSON</button>
200
- </div><br />
228
+ <div class="dt-buttons" id="button_group">
229
+ <!--<button type="button" id="debug_rows_selected">Rows Selected</button>-->
230
+ </div>
201
231
 
202
232
  <div>
203
- <b>Toggle Column(s):</b>&nbsp;
233
+ <b>Toggle Column(s) Visibility:</b>&nbsp;
204
234
  <a class="toggle-vis" data-column="1" href="#">Timestamp</a>&nbsp;|&nbsp;
205
235
  <a class="toggle-vis" data-column="2" href="#">Test Case / Security References</a>&nbsp;|&nbsp;
206
236
  <a class="toggle-vis" data-column="3" href="#">Path</a>&nbsp;|&nbsp;
207
237
  <a class="toggle-vis" data-column="4" href="#">Line#, Formatted Content, AI Analysis, &amp; Last Committed By</a>&nbsp;|&nbsp;
208
- <a class="toggle-vis" data-column="6" href="#">Raw Content</a>&nbsp;|&nbsp;
209
- <a class="toggle-vis" data-column="7" href="#">Test Case (Anti-Pattern) Filter</a>
238
+ <a class="toggle-vis" data-column="5" href="#">Raw Content</a>&nbsp;|&nbsp;
239
+ <a class="toggle-vis" data-column="6" href="#">Test Case (Anti-Pattern) Filter</a>
210
240
  </div>
211
241
  <br /><br />
212
242
 
@@ -227,13 +257,6 @@ module PWN
227
257
  <th>Test Case (Anti-Pattern) Filter</th>
228
258
  </tr>
229
259
  </thead>
230
- <col width="30px" />
231
- <col width="60px" />
232
- <col width="300px" />
233
- <col width="90px" />
234
- <col width="90px" />
235
- <col width="300px" />
236
- <col width="90px" />
237
260
  <!-- DataTables <tbody> -->
238
261
  </table>
239
262
  </div>
@@ -244,106 +267,189 @@ module PWN
244
267
  var line_entry_uri = "";
245
268
  $(document).ready(function() {
246
269
  var oldStart = 0;
270
+ var windowHeight = $(window).height();
271
+
272
+ // Calculate scrollY: Subtract an offset for non-table elements
273
+ var offset = 400;
274
+ var min_scroll_height = 100;
275
+ var scrollYHeight = Math.max(min_scroll_height, windowHeight - offset); // Ensure minimum of 600px
247
276
  var table = $('#pwn_scan_git_source_results').DataTable( {
277
+ "order": [[2, 'asc']],
278
+ "scrollY": scrollYHeight + "px",
279
+ "scrollCollapse": true,
248
280
  "paging": true,
249
- "lengthMenu": [10, 25, 50, 100, 250, 500, 1000, 2500, 5000],
250
- "pagingType": "full_numbers",
251
- "fnDrawCallback": function ( oSettings ) {
252
- /* Need to redo the counters if filtered or sorted */
253
- if ( oSettings.bSorted || oSettings.bFiltered ) {
254
- for ( var i=0, iLen=oSettings.aiDisplay.length ; i<iLen ; i++ ) {
255
- $('td:eq(0)', oSettings.aoData[ oSettings.aiDisplay[i] ].nTr ).html( i+1 );
256
- }
257
- }
258
- // Jump to top when utilizing pagination
259
- if ( oSettings._iDisplayStart != oldStart ) {
260
- var targetOffset = $('#pwn_body').offset().top;
261
- $('html,body').animate({scrollTop: targetOffset}, 500);
262
- oldStart = oSettings._iDisplayStart;
281
+ "lengthMenu": [25, 50, 100, 250, 500, 1000, 2500, 5000],
282
+ "drawCallback": function () {
283
+ var api = this.api();
284
+
285
+ // Redo the row counters
286
+ api.column(0, {page: 'current'} ).nodes().each(function(cell, i) {
287
+ cell.innerHTML = i + 1;
288
+ });
289
+
290
+ // Jump to top of scroll body when utilizing pagination
291
+ var info = api.page.info();
292
+ if (info.start !== oldStart) {
293
+ $('.dt-scroll-body').animate({scrollTop: 0}, 500);
294
+ oldStart = info.start;
263
295
  }
264
296
  },
265
297
  "ajax": "#{report_name}.json",
266
- //"deferRender": true,
267
- "dom": "fplitfpliS",
298
+ "deferRender": false,
299
+ "layout": {
300
+ },
268
301
  "autoWidth": false,
269
302
  "columns": [
270
303
  { "data": null },
271
304
  {
272
305
  "data": "timestamp",
273
- "render": $.fn.dataTable.render.text()
306
+ "render": function (data, type, row, meta) {
307
+ if (type === 'display') {
308
+ timestamp = htmlEntityEncode(data);
309
+ return '<table class="squish"><tr><td style="width:70px;" align="left">' + timestamp + '</td></tr></table>';
310
+ } else {
311
+ return data;
312
+ }
313
+ }
274
314
  },
275
315
  {
276
316
  "data": "security_references",
277
317
  "render": function (data, type, row, meta) {
278
- var sast_dirname = data['sast_module'].split('::')[0].toLowerCase() + '/' + data['sast_module'].split('::')[1].toLowerCase();
279
- var sast_module = data['sast_module'].split('::')[2];
280
- var sast_test_case = sast_module.replace(/\\.?([A-Z])/g, function (x,y){ if (sast_module.match(/\\.?([A-Z][a-z])/g) ) { return "_" + y.toLowerCase(); } else { return y.toLowerCase(); } }).replace(/^_/g, "");
281
-
282
- return '<table class="squish"><tr><td style="width:150px;" align="left"><a href="https://github.com/0dayinc/pwn/tree/master/lib/' + htmlEntityEncode(sast_dirname) + '/' + htmlEntityEncode(sast_test_case) + '.rb" target="_blank">' + htmlEntityEncode(data['sast_module'].split("::")[2]) + '</a><br /><br /><a href="' + htmlEntityEncode(data['nist_800_53_uri']) + '" target="_blank">NIST 800-53: ' + htmlEntityEncode(data['section']) + '</a><br /><br /><a href="' + htmlEntityEncode(data['cwe_uri']) + '" target="_blank">CWE:' + htmlEntityEncode(data['cwe_id']) + '</a></td></tr></table>';
318
+ if (type === 'display') {
319
+ var sast_dirname = data['sast_module'].split('::')[0].toLowerCase() + '/' + data['sast_module'].split('::')[1].toLowerCase();
320
+ var sast_module = data['sast_module'].split('::')[2];
321
+ var sast_test_case = sast_module.replace(/\\.?([A-Z])/g, function (x,y){ if (sast_module.match(/\\.?([A-Z][a-z])/g) ) { return "_" + y.toLowerCase(); } else { return y.toLowerCase(); } }).replace(/^_/g, "");
322
+
323
+ return '<table class="squish"><tr><td style="width:125px;" align="left"><a href="https://github.com/0dayinc/pwn/tree/master/lib/' + htmlEntityEncode(sast_dirname) + '/' + htmlEntityEncode(sast_test_case) + '.rb" target="_blank">' + htmlEntityEncode(data['sast_module'].split("::")[2]) + '</a><br /><br /><a href="' + htmlEntityEncode(data['nist_800_53_uri']) + '" target="_blank">NIST 800-53: ' + htmlEntityEncode(data['section']) + '</a><br /><br /><a href="' + htmlEntityEncode(data['cwe_uri']) + '" target="_blank">CWE:' + htmlEntityEncode(data['cwe_id']) + '</a></td></tr></table>';
324
+ } else {
325
+ return data['sast_module'].split("::")[2] + ' | NIST 800-53: ' + data['section'] + ' | CWE:' + data['cwe_id'];
326
+ }
283
327
  }
284
328
  },
285
329
  {
286
330
  "data": "filename",
287
331
  "render": function (data, type, row, meta) {
288
- line_entry_uri = htmlEntityEncode(
289
- data['git_repo_root_uri'] + '/' + data['entry']
290
- );
332
+ if (type === 'display') {
333
+ line_entry_uri = htmlEntityEncode(
334
+ data['git_repo_root_uri'] + '/' + data['entry']
335
+ );
291
336
 
292
- file = htmlEntityEncode(data['entry']);
337
+ file = htmlEntityEncode(data['entry']);
293
338
 
294
- return '<table class="squish"><tr><td style="width:150px;" align="left"><a href="' + line_entry_uri + '" target="_blank">' + file + '</a></td></tr></table>';
339
+ return '<table class="squish"><tr><td style="width:200px;" align="left"><a href="' + line_entry_uri + '" target="_blank">' + file + '</a></td></tr></table>';
340
+ } else {
341
+ return data['entry'];
342
+ }
295
343
  }
296
344
  },
297
345
  {
298
346
  "data": "line_no_and_contents",
299
347
  "render": function (data, type, row, meta) {
300
- var pwn_rows = '<table class="multi_line_select squish" style="width: 665px"><tbody>';
301
- for (var i = 0; i < data.length; i++) {
302
- var tr_class;
303
- if (i % 2 == 0) { tr_class = "odd"; } else { tr_class = "even"; }
304
-
305
- var filename_link = row.filename;
306
-
307
- var author_and_email_arr = data[i]['author'].split(" ");
308
- var email = author_and_email_arr[author_and_email_arr.length - 1];
309
- var email_user_arr = email.split("@");
310
- var assigned_to = email_user_arr[0].replace("&lt;", "");
311
-
312
- var uri = '#uri';
313
-
314
- var canned_email_results = 'Timestamp: ' + row.timestamp + '\\n' +
315
- 'Source Code File Impacted: ' + $("<div/>").html(filename_link).text() + '\\n\\n' +
316
- 'Source Code in Question:\\n\\n' +
317
- data[i]['line_no'] + ': ' +
318
- $("<div/>").html(data[i]['contents'].replace(/\\s{2,}/g, " ")).text() + '\\n\\n';
319
-
320
- var canned_email = email.replace("&lt;", "").replace("&gt;", "") + '?subject=Potential%20Bug%20within%20Source%20File:%20'+ encodeURIComponent(row.filename) +'&body=Greetings,%0A%0AThe%20following%20information%20likely%20represents%20a%20bug%20discovered%20through%20automated%20security%20testing%20initiatives:%0A%0A' + encodeURIComponent(canned_email_results) + 'Is%20this%20something%20that%20can%20be%20addressed%20immediately%20or%20would%20filing%20a%20bug%20be%20more%20appropriate?%20%20Please%20let%20us%20know%20at%20your%20earliest%20convenience%20to%20ensure%20we%20can%20meet%20security%20expectations%20for%20this%20release.%20%20Thanks%20and%20have%20a%20great%20day!';
321
-
322
- domain = line_entry_uri.replace('http://','').replace('https://','').split(/[/?#]/)[0];
323
- if (domain.includes('stash') || domain.includes('bitbucket') || domain.includes('gerrit')) {
324
- to_line_number = line_entry_uri + '#' + data[i]['line_no'];
325
- } else {
326
- // e.g. GitHub, GitLab, etc.
327
- to_line_number = line_entry_uri + '#L' + data[i]['line_no'];
348
+ if (type === 'display') {
349
+ var pwn_rows = '<table class="multi_line_select squish" style="width: 725px"><tbody>';
350
+ for (var i = 0; i < data.length; i++) {
351
+ var tr_class;
352
+ if (i % 2 == 0) { tr_class = "odd"; } else { tr_class = "even"; }
353
+
354
+ var filename_link = row.filename;
355
+
356
+ var author_and_email_arr = data[i]['author'].split(" ");
357
+ var email = author_and_email_arr[author_and_email_arr.length - 1];
358
+ var email_user_arr = email.split("@");
359
+ var assigned_to = email_user_arr[0].replace("&lt;", "");
360
+
361
+ var uri = '#uri';
362
+
363
+ var canned_email_results = 'Timestamp: ' + row.timestamp + '\\n' +
364
+ 'Source Code File Impacted: ' + $("<div/>").html(filename_link).text() + '\\n\\n' +
365
+ 'Source Code in Question:\\n\\n' +
366
+ data[i]['line_no'] + ': ' +
367
+ $("<div/>").html(data[i]['contents'].replace(/\\s{2,}/g, " ")).text() + '\\n\\n';
368
+
369
+ var canned_email = email.replace("&lt;", "").replace("&gt;", "") + '?subject=Potential%20Bug%20within%20Source%20File:%20'+ encodeURIComponent(row.filename) +'&body=Greetings,%0A%0AThe%20following%20information%20likely%20represents%20a%20bug%20discovered%20through%20automated%20security%20testing%20initiatives:%0A%0A' + encodeURIComponent(canned_email_results) + 'Is%20this%20something%20that%20can%20be%20addressed%20immediately%20or%20would%20filing%20a%20bug%20be%20more%20appropriate?%20%20Please%20let%20us%20know%20at%20your%20earliest%20convenience%20to%20ensure%20we%20can%20meet%20security%20expectations%20for%20this%20release.%20%20Thanks%20and%20have%20a%20great%20day!';
370
+
371
+ domain = line_entry_uri.replace('http://','').replace('https://','').split(/[/?#]/)[0];
372
+ if (domain.includes('stash') || domain.includes('bitbucket') || domain.includes('gerrit')) {
373
+ to_line_number = line_entry_uri + '#' + data[i]['line_no'];
374
+ } else {
375
+ // e.g. GitHub, GitLab, etc.
376
+ to_line_number = line_entry_uri + '#L' + data[i]['line_no'];
377
+ }
378
+
379
+ pwn_rows = pwn_rows.concat('<tr class="' + tr_class + '"><td style="width:50px" align="left"><a href="' + htmlEntityEncode(to_line_number) + '" target="_blank">' + htmlEntityEncode(data[i]['line_no']) + '</a>:&nbsp;</td><td style="width:300px" align="left">' + htmlEntityEncode(data[i]['contents']) + '</td><td style="width:200px" align=:left">' + htmlEntityEncode(data[i]['ai_analysis']) + '</td><td style="width:175px" align="right"><a href="mailto:' + canned_email + '">' + htmlEntityEncode(data[i]['author']) + '</a></td></tr>');
328
380
  }
329
-
330
- pwn_rows = pwn_rows.concat('<tr class="' + tr_class + '"><td style="width:90px" align="left"><a href="' + htmlEntityEncode(to_line_number) + '" target="_blank">' + htmlEntityEncode(data[i]['line_no']) + '</a>:&nbsp;</td><td style="width:300px" align="left">' + htmlEntityEncode(data[i]['contents']) + '</td><td style="width:300px" align=:left">' + htmlEntityEncode(data[i]['ai_analysis']) + '</td><td style="width:200px" align="right"><a href="mailto:' + canned_email + '">' + htmlEntityEncode(data[i]['author']) + '</a></td></tr>');
381
+ pwn_rows = pwn_rows.concat('</tbody></table>');
382
+ return pwn_rows;
383
+ } else {
384
+ var lines = [];
385
+ for (var i = 0; i < data.length; i++) {
386
+ lines.push(data[i]['line_no'] + ': ' + data[i]['contents'] + ' | AI: ' + data[i]['ai_analysis'] + ' | By: ' + data[i]['author']);
387
+ }
388
+ return lines.join('\\n');
331
389
  }
332
- pwn_rows = pwn_rows.concat('</tbody></table>');
333
- return pwn_rows;
334
390
  }
335
391
  },
336
392
  {
337
393
  "data": "raw_content",
338
- "render": $.fn.dataTable.render.text()
394
+ "render": function (data, type, row, meta) {
395
+ if (type === 'display') {
396
+ raw_content = htmlEntityEncode(data);
397
+ return '<table class="squish"><tr><td style="width:300px;" align="left">' + raw_content + '</td></tr></table>';
398
+ } else {
399
+ return data;
400
+ }
401
+ }
339
402
  },
340
403
  {
341
404
  "data": "test_case_filter",
342
- "render": $.fn.dataTable.render.text()
405
+ "render": function (data, type, row, meta) {
406
+ if (type === 'display') {
407
+ test_case_filter = htmlEntityEncode(data);
408
+ return '<table class="squish"><tr><td style="width:300px;" align="left">' + test_case_filter + '</td></tr></table>';
409
+ } else {
410
+ return data;
411
+ }
412
+ }
343
413
  }
344
414
  ],
345
415
  "initComplete": function(settings, json) {
346
416
  $('#report_name').text(json.report_name);
417
+ var raw_content_column = 5;
418
+ var test_case_filter_column = 6;
419
+ table.column(raw_content_column).visible(false);
420
+ table.column(test_case_filter_column).visible(false);
421
+
422
+ // Add export buttons after initialization
423
+ new $.fn.dataTable.Buttons(table, {
424
+ buttons: [
425
+ {
426
+ text: 'Select / Deselect All Lines',
427
+ action: function () {
428
+ select_deselect_all();
429
+ }
430
+ },
431
+ {
432
+ text: 'Export to JSON',
433
+ action: function () {
434
+ export_selected();
435
+ }
436
+ },
437
+ {
438
+ text: 'Export to Excel',
439
+ action: function () {
440
+ exportToExcelOrPdf('excel');
441
+ }
442
+ },
443
+ {
444
+ text: 'Export to PDF',
445
+ action: function () {
446
+ exportToExcelOrPdf('pdf');
447
+ }
448
+ }
449
+ ]
450
+ });
451
+
452
+ table.buttons().container().insertAfter('#button_group');
347
453
  }
348
454
  });
349
455
 
@@ -411,66 +517,183 @@ module PWN
411
517
  column.visible( ! column.visible() );
412
518
  });
413
519
 
414
- $('#button').click( function () {
520
+ $('#debug_rows_selected').click( function () {
415
521
  alert($('.multi_line_select tr.highlighted').length +' row(s) highlighted');
416
522
  });
417
523
 
418
- $('#export_selected').click( function () {
419
- if ($('.multi_line_select tr.highlighted').length === 0) {
420
- alert('No rows selected');
421
- return;
524
+ // Select All and Deselect All
525
+ function select_deselect_all() {
526
+ if ($('.multi_line_select tr.highlighted').length === $('.multi_line_select tr').length) {
527
+ $('.multi_line_select tr.highlighted').removeClass('highlighted');
528
+ } else {
529
+ $('.multi_line_select tr:not(.highlighted)').addClass('highlighted');
422
530
  }
531
+ }
532
+
533
+ function getExportData() {
534
+ return new Promise((resolve) => {
535
+ $.getJSON(table.ajax.url(), function(original_json) {
536
+ let new_data;
537
+ if ($('.multi_line_select tr.highlighted').length === 0) {
538
+ new_data = original_json.data;
539
+ } else {
540
+ var selected_results = {};
541
+
542
+ $('.multi_line_select tr.highlighted').each(function() {
543
+ var inner_tr = $(this);
544
+ var main_tr = inner_tr.closest('td').parent();
545
+ var row = table.row(main_tr);
546
+ var row_index = row.index();
547
+ var line_index = inner_tr.index();
548
+
549
+ if (selected_results[row_index] === undefined) {
550
+ selected_results[row_index] = {
551
+ row: row,
552
+ lines: []
553
+ };
554
+ }
423
555
 
424
- $.getJSON(table.ajax.url(), function(original_json) {
425
- var selected_results = {};
426
-
427
- $('.multi_line_select tr.highlighted').each(function() {
428
- var inner_tr = $(this);
429
- var main_tr = inner_tr.closest('td').parent();
430
- var row = table.row(main_tr);
431
- var row_index = row.index();
432
- var line_index = inner_tr.index();
433
-
434
- if (selected_results[row_index] === undefined) {
435
- selected_results[row_index] = {
436
- row: row,
437
- lines: []
438
- };
439
- }
440
-
441
- selected_results[row_index].lines.push(line_index);
442
- });
556
+ selected_results[row_index].lines.push(line_index);
557
+ });
443
558
 
444
- var new_data = [];
559
+ new_data = [];
445
560
 
446
- Object.keys(selected_results).forEach(function(ri) {
447
- var sel = selected_results[ri];
448
- var orig_row_data = sel.row.data();
449
- var new_row_data = JSON.parse(JSON.stringify(orig_row_data));
561
+ Object.keys(selected_results).forEach(function(ri) {
562
+ var sel = selected_results[ri];
563
+ var orig_row_data = sel.row.data();
564
+ var new_row_data = JSON.parse(JSON.stringify(orig_row_data));
450
565
 
451
- sel.lines.sort((a, b) => a - b);
452
- new_row_data.line_no_and_contents = sel.lines.map(function(li) {
453
- return orig_row_data.line_no_and_contents[li];
454
- });
566
+ sel.lines.sort((a, b) => a - b);
567
+ new_row_data.line_no_and_contents = sel.lines.map(function(li) {
568
+ return orig_row_data.line_no_and_contents[li];
569
+ });
455
570
 
456
- new_row_data.raw_content = new_row_data.line_no_and_contents.map(l => l.contents).join('\\n');
571
+ new_row_data.raw_content = new_row_data.line_no_and_contents.map(l => l.contents).join('\\n');
457
572
 
458
- new_data.push(new_row_data);
573
+ new_data.push(new_row_data);
574
+ });
575
+ }
576
+ resolve({data: new_data, report_name: original_json.report_name});
459
577
  });
578
+ });
579
+ }
580
+
581
+ function export_selected() {
582
+ if ($('.multi_line_select tr.highlighted').length === 0 && !confirm('No lines selected. Export all records?')) {
583
+ return;
584
+ }
460
585
 
461
- original_json.data = new_data;
586
+ getExportData().then(({data, report_name}) => {
587
+ var original_json = {report_name: report_name, data: data};
462
588
 
463
589
  var json_str = JSON.stringify(original_json, null, 2);
464
590
  var blob = new Blob([json_str], { type: 'application/json' });
465
591
  var url = URL.createObjectURL(blob);
466
592
  var a = document.createElement('a');
467
593
  a.href = url;
468
- a.download = (original_json.report_name || 'selected') + '.json';
594
+ a.download = report_name + '.json';
469
595
  document.body.appendChild(a);
470
596
  a.click();
471
597
  document.body.removeChild(a);
472
598
  URL.revokeObjectURL(url);
473
599
  });
600
+ }
601
+
602
+ function exportToExcelOrPdf(type) {
603
+ if ($('.multi_line_select tr.highlighted').length === 0 && !confirm('No lines selected. Export all records?')) {
604
+ return;
605
+ }
606
+
607
+ getExportData().then(({data, report_name}) => {
608
+ // Flatten data for export
609
+ var flatData = [];
610
+ data.forEach(function(row) {
611
+ row.line_no_and_contents.forEach(function(line) {
612
+ flatData.push({
613
+ timestamp: row.timestamp,
614
+ test_case: row.security_references.sast_module.split('::')[2],
615
+ nist: row.security_references.section,
616
+ cwe: row.security_references.cwe_id,
617
+ path: row.filename.entry,
618
+ line_no: line.line_no,
619
+ contents: line.contents,
620
+ ai_analysis: line.ai_analysis,
621
+ author: line.author
622
+ });
623
+ });
624
+ });
625
+
626
+ if (type === 'excel') {
627
+ var ws = XLSX.utils.json_to_sheet(flatData);
628
+ var wb = XLSX.utils.book_new();
629
+ XLSX.utils.book_append_sheet(wb, ws, 'PWN SAST Results');
630
+ XLSX.writeFile(wb, report_name + '.xlsx');
631
+ } else if (type === 'pdf') {
632
+ var docDefinition = {
633
+ pageOrientation: 'landscape',
634
+ pageSize: 'LETTER',
635
+ content: [
636
+ { text: '~ pwn sast: ' + report_name, style: 'header' },
637
+ {
638
+ table: {
639
+ headerRows: 1,
640
+ widths: [40, 30, 50, 30, 75, 30, 155, 155, 50],
641
+ body: [
642
+ ['Timestamp', 'Test Case', 'NIST 800-53', 'CWE', 'Path', 'Line#', 'Content', 'AI Analysis', 'Author'],
643
+ ...flatData.map(r => [
644
+ r.timestamp,
645
+ r.test_case,
646
+ r.nist,
647
+ r.cwe,
648
+ r.path,
649
+ r.line_no,
650
+ r.contents,
651
+ r.ai_analysis,
652
+ r.author
653
+ ])
654
+ ]
655
+ },
656
+ layout: 'lightHorizontalLines'
657
+ }
658
+ ],
659
+ styles: {
660
+ title: {
661
+ alignment: 'center',
662
+ fontSize: 15
663
+ },
664
+ tableHeader: {
665
+ bold: true,
666
+ fontSize: 12,
667
+ color: 'white',
668
+ fillColor: '#2d4154',
669
+ alignment: 'center'
670
+ },
671
+ tableBodyEven: {},
672
+ tableBodyOdd: {
673
+ fillColor: '#dedede'
674
+ },
675
+ tableFooter: {
676
+ bold: true,
677
+ fontSize: 8,
678
+ color: 'white',
679
+ fillColor: '#2d4154'
680
+ },
681
+ },
682
+ defaultStyle: {
683
+ fontSize: 6
684
+ }
685
+ };
686
+ pdfMake.createPdf(docDefinition).download(report_name + '.pdf');
687
+ }
688
+ });
689
+ }
690
+
691
+ // Detect window size changes and recalculate/update scrollY
692
+ $(window).resize(function() {
693
+ var newWindowHeight = $(window).height();
694
+ var newScrollYHeight = Math.max(min_scroll_height, newWindowHeight - offset); // Your offset
695
+ $('.dt-scroll-body').css('max-height', newScrollYHeight + 'px')
696
+ table.columns.adjust().draw(false); // Adjust columns first, then redraw without data reload
474
697
  });
475
698
  });
476
699
  </script>
@@ -94,7 +94,7 @@ module PWN
94
94
  </div><br />
95
95
 
96
96
  <div>
97
- <b>Toggle Column(s):</b>&nbsp;
97
+ <b>Toggle Column(s) Visibility:</b>&nbsp;
98
98
  <a class="toggle-vis" data-column="1" href="#">Request Time</a>&nbsp;|&nbsp;
99
99
  <a class="toggle-vis" data-column="2" href="#">Response Time</a>&nbsp;|&nbsp;
100
100
  <a class="toggle-vis" data-column="3" href="#">Duration</a>&nbsp;|&nbsp;
@@ -22,7 +22,6 @@ module PWN
22
22
  result_arr = []
23
23
  logger_results = ''
24
24
 
25
- Dir.chdir(dir_path)
26
25
  PWN::Plugins::FileFu.recurse_in_dir(dir_path: dir_path) do |entry|
27
26
  if File.file?(entry) && File.basename(entry) !~ /^pwn.+(html|json|db)$/ && File.basename(entry) !~ /\.JS-BEAUTIFIED$/ && entry !~ /test/i
28
27
  line_no_and_contents_arr = []
@@ -21,7 +21,6 @@ module PWN
21
21
  result_arr = []
22
22
  logger_results = ''
23
23
 
24
- Dir.chdir(dir_path)
25
24
  PWN::Plugins::FileFu.recurse_in_dir(dir_path: dir_path) do |entry|
26
25
  if File.file?(entry) && File.basename(entry) !~ /^pwn.+(html|json|db)$/ && File.basename(entry) !~ /\.JS-BEAUTIFIED$/ && entry !~ /test/i
27
26
  line_no_and_contents_arr = []
data/lib/pwn/sast/aws.rb CHANGED
@@ -20,7 +20,6 @@ module PWN
20
20
  result_arr = []
21
21
  logger_results = ''
22
22
 
23
- Dir.chdir(dir_path)
24
23
  PWN::Plugins::FileFu.recurse_in_dir(dir_path: dir_path) do |entry|
25
24
  if File.file?(entry) && File.basename(entry) !~ /^pwn.+(html|json|db)$/ && File.basename(entry) !~ /\.JS-BEAUTIFIED$/ && entry !~ /test/i
26
25
  line_no_and_contents_arr = []
@@ -22,7 +22,6 @@ module PWN
22
22
  result_arr = []
23
23
  logger_results = ''
24
24
 
25
- Dir.chdir(dir_path)
26
25
  PWN::Plugins::FileFu.recurse_in_dir(dir_path: dir_path) do |entry|
27
26
  if (File.file?(entry) && File.basename(entry) !~ /^pwn.+(html|json|db)$/ && File.basename(entry) !~ /\.JS-BEAUTIFIED$/) && (File.extname(entry) == '.c' || File.extname(entry) == '.cpp' || File.extname(entry) == '.c++' || File.extname(entry) == '.cxx' || File.extname(entry) == '.h' || File.extname(entry) == '.hpp' || File.extname(entry) == '.h++' || File.extname(entry) == '.hh' || File.extname(entry) == '.hxx' || File.extname(entry) == '.ii' || File.extname(entry) == '.ixx' || File.extname(entry) == '.ipp' || File.extname(entry) == '.inl' || File.extname(entry) == '.txx' || File.extname(entry) == '.tpp' || File.extname(entry) == '.tpl') && entry !~ /test/i
28
27
  line_no_and_contents_arr = []