-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathreport.html
More file actions
1300 lines (1203 loc) · 54.6 KB
/
report.html
File metadata and controls
1300 lines (1203 loc) · 54.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Penetration Test Report - VulnLawyers</title>
<link rel="stylesheet" href="assets/report.css" />
</head>
<body>
<div class="logo">FakeCompany</div>
<div class="classification">CONFIDENTIAL</div>
<label class="switch">
<input type="checkbox" id="themeToggle" />
<span class="slider round"></span>
</label>
<!-- Main Tile Layer -->
<div class="tile-wrapper">
<!-- Report content START -->
<h1 style="text-align: center; font-size: 60px; color: rebeccapurple">
FakeCompany
</h1>
<div class="company-logo">
<img src="assets/company-logo.png" />
</div>
<h1 style="text-align: center">VulnLawyers</h1>
<h1 style="text-align: center">Penetration Test Report</h1>
<p>
<strong>Test Date:</strong> July 2025<br />
<strong>Principal Tester:</strong> Noah Tyson
</p>
<div class="toc">
<h2>Table of Contents</h2>
<ol class="toc-list">
<li><a href="#confidentiality-notice">Confidentiality Notice</a></li>
<li><a href="#executive-summary">Executive Summary</a></li>
<li><a href="#engagement-overview">Engagement Overview</a></li>
<li><a href="#limitations-disclaimer">Limitations</a></li>
<li><a href="#testing-methodology">Testing Methodology</a></li>
<li><a href="#findings">Findings</a></li>
<li>
<a href="#remediation-roadmap">Remediation Roadmap & Compliance Mapping</a>
</li>
<li>
<a href="#technical-attack-path">Technical Attack Path Breakdown</a>
</li>
<li><a href="#technical-remediation">Technical Remediation</a>
<ol>
<li><a href="#C-01">C-01 | Passwords Stored in Plaintext</a></li>
<li><a href="#C-02">C-02 | Insecure Direct Object Reference (IDOR)</a></li>
<li><a href="#H-01">H-01 | Weak Authentication and Brute-Force Vulnerability</a></li>
<li><a href="#M-01">M-01 | Information disclosure via Fuzzing</a></li>
<li><a href="#M-02">M-02 | Information Disclosure via Redirect Body</a></li>
<li><a href="#L-01">L-01 & L-02 & L-03 | Outdated Components</a></li>
<li><a href="#I-01">I-01 | UI Misrepresentation - Purported Deletion of Case Files</a></li>
<li><a href="#I-02">I-02 | Informational: Inconsistent Nginx Versioning in Header Leak</a></li>
</ol>
</li>
<li>
<a href="#appendix-a">Appendices</a>
<ol>
<li><a href="#appendix-a">A. Overall Evaluation Matrix</a></li>
<li><a href="#appendix-b">B. Risk Rating Matrix</a></li>
<li><a href="#appendix-c">C. Tools Used</a></li>
<li><a href="#appendix-d">D. Engagement Points of Contact</a></li>
</ol>
</li>
</ol>
</div>
<br>
<br>
<br>
<h1 id="confidentiality-notice" style="text-align: center; font-size: xx-large;">Confidentiality Notice</h1>
<p style="font-size: xx-large;">This report contains sensitive information pertaining to the security posture,
vulnerabilities, and
infrastructure of the assessed environment. It is intended solely for the use of the client and designated
stakeholders.</p>
<p style="font-size: xx-large;">Unauthorized access, reproduction, distribution, or disclosure of this document or
any of its contents is
strictly prohibited without explicit written consent from the commissioning organization and the testing entity.
</p>
<p style="font-size: xx-large;">All findings, data, and recommendations contained herein must be handled in
accordance with applicable
information security and data protection policies. Misuse or negligent handling of this report could expose the
organization to significant legal, reputational, or operational risk.</p>
<br>
<br>
<br>
<h2 id="executive-summary">Executive Summary</h2>
<p>
Between 10 July 2025 and 24 July 2025, FakeCompany performed an external, black-box web-application penetration
test for VulnLawyers. The recommendations provided in this report are structured to facilitate remediation of the
identified security risks. This document serves as a formal letter of attestation for the recent VulnLawyers
company black-box penetration test.
</p>
<p>
Evaluation ratings are based on a comparison between findings from the
engagement and recognized security industry standards. This document
reflects our considered assessment of VulnLawyers' current security
posture, specifically as it pertains to the network perimeter. The full
evaluation rubric used for this determination can be found in
<a style="color: inherit; text-decoration: none" href="#appendix-a"><strong> Appendix A</strong></a>.
</p>
<p>
It is recommended to review the <a style="color: inherit; text-decoration: none" href="#findings"><strong>
Findings</strong></a> section for a better understanding of risks and security issues discovered.
</p>
<table cellpadding="10" cellspacing="0">
<thead>
<tr>
<th>Scope</th>
<th>Evaluation</th>
<th>Grade</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Web Application Perimeter</strong></td>
<td><strong>Unsatisfactory</strong></td>
<td><strong style="color: #ff5555">F</strong></td>
</tr>
</tbody>
</table>
<p>
Testing identified ten vulnerabilities, of these there were <strong>three key vulnerabilities</strong> ranging
from <em>Critical</em> to <em>High</em> severity:
</p>
<ul>
<li>
<strong>Critical (Plaintext Password Storage):</strong> Passwords found stored in plaintext enabled account
takeover of every user account on the web application.
</li>
<li>
<strong>Critical (Insecure Direct Object Reference):</strong> Direct access to profile details for accounts
other than the one authenticated
was permitted.
</li>
<li>
<strong>High (Brute-force):</strong> Lack of rate limiting enabled
automated password guessing and unauthorized access.
</li>
</ul>
<p>
Successful exploitation demonstrated the possibility of: unauthorized
access to privileged legal data, deletion or tampering of case files,
and exposure of client PII—creating
<em>significant business, reputational, and potential regulatory risk</em>.
</p>
<p>
Immediate remediation of the <em>Critical</em> and
<em>High</em> findings is strongly advised. A detailed, prioritised
roadmap is provided within the report. Re-testing is recommended within
30 days of patching to confirm that controls are effective.
</p>
<br>
<br>
<br>
<h2 id="engagement-overview">Engagement Overview</h2>
<p>
This assessment was conducted as a black-box web application test targeting VulnLawyers' externally-accessible
systems. The primary objective was to identify security weaknesses that could be exploited by an unauthenticated
attacker, with emphasis on evaluating authentication, access controls, session management, and vulnerabilities
outlined in the OWASP Top 10. Testing was performed using a combination of manual techniques and automated
tooling, in line with industry best practices. Where applicable, business logic issues were also analyzed to
assess the application's resilience to misuse. All findings are accompanied by actionable remediation guidance to
assist in mitigating the identified risks.</p>
<br>
<br>
<br>
<h1 id="limitations-disclaimer">Limitations</h1>
<p>This assessment was conducted under a defined scope and with explicit constraints provided prior to testing.
Infrastructure-level testing, including backend server enumeration, network-layer probing, and denial-of-service
attempts, was explicitly out of scope. As a result, findings related to system configuration or patch management
are based solely on passively observed indicators and have not been validated through direct testing.</p>
<p>Additionally, the evaluation was performed from the perspective of an unauthenticated external actor unless
otherwise noted. No persistent access, source code review, or social engineering techniques were employed. The
findings presented herein reflect the application's state only during the assessment window and may not account
for subsequent changes or time-based exposure.</p>
<table>
<thead>
<tr>
<th>Domains Tested</th>
<th>Subomains Permmited?</th>
</tr>
</thead>
<tbody>
<tr>
<td>quartz.ctfio.com</td>
<td>Yes</td>
</tr>
</tbody>
</table>
<br>
<br>
<br>
<h2 id="testing-methodology">Testing Methodology</h2>
<p>The assessment was performed using the following approach:</p>
<ol>
<img src="assets/methodologyflow.png" class="screenshot">
<li>
<strong>Reconnaissance:</strong> Open-source intelligence gathering,
DNS/brute enumeration.
</li>
<li>
<strong>Mapping:</strong> Manual and automated discovery of
application pages and endpoints.
</li>
<li>
<strong>Vulnerability Analysis:</strong> Testing for OWASP Top 10
vulnerabilities and misconfigurations.
</li>
<li>
<strong>Exploitation:</strong> Safe proof-of-concept validation of
identified vulnerabilities.
</li>
<li>
<strong>Reporting:</strong> Documentation of all findings and
recommendations with supporting evidence.
</li>
</ol>
<br>
<br>
<br>
<h2 id="findings">Findings</h2>
<p>
This section will give a high level overview of the findings, specific technical remediations will be found in
that section. The findings in this section are evaluated based on the risk rating
matrix found in <a style="color: inherit; text-decoration: none" href="#appendix-b"><strong> Appendix
B</strong></a>.
</p>
<details>
<summary>
⚠️ C-01 | Critical: Passwords Stored in Plaintext
</summary>
<div class="finding">
<p>
<strong>Finding ID:</strong> C-01
</p>
<p>
<strong>Impact:</strong> Full compromise of all user accounts if attacker gains access to API responses or
internal storage; enables credential reuse attacks across platforms.
</p>
<p>
<strong>Evidence:</strong> Passwords are returned in cleartext within API responses during profile detail
queries (e.g., IDOR vulnerability), exposing them to any user able to access that endpoint.
</p>
<img src="assets/marshaprofdetails.png" class="screenshot">
<p>
<strong>Recommendation:</strong> Immediately implement secure password hashing (e.g., bcrypt or Argon2).
Ensure no plaintext credentials are stored or returned by the application, and enforce a global password reset
post-remediation.
</p>
</div>
</details>
<details>
<summary>
⚠️ C-02 | Critical: IDOR - Direct Access to Another User's Profile Details
</summary>
<div class="finding">
<p>
<strong>Finding ID:</strong> C-02
</p>
<p>
<strong>Impact:</strong> Complete web application compromise by accessing all
user credentials.
</p>
<p>
<strong>Evidence:</strong> Authenticated request to
<code>/lawyers-only-profile-details/2</code> returned Shayne
Cairns's password (<code>q2V944…</code>).
</p>
<img src="assets/IDORShayne.png" class="screenshot" />
<p>
<strong>Recommendation:</strong> Enforce server-side authorization:
ensure users can only access their own data, and never expose
passwords or sensitive data.
</p>
</div>
</details>
<details>
<summary> H-01 | High: Credential Brute-Force on Login Function</summary>
<div class="finding">
<p>
<strong>Finding ID:</strong> H-01
</p>
<p>
<strong>Impact:</strong> Full account takeover of lawyer accounts.
</p>
<p>
<strong>Evidence:</strong> Valid credentials discovered:
<code>jaskaran.lowe@vulnlawyers.ctf:summer</code> via brute force
</p>
<img src="assets/PasswordSpraySuccess.png" class="screenshot" />
<p>
<strong>Recommendation:</strong> Implement rate-limiting, MFA, and
enforce stronger password policies.
</p>
</div>
</details>
<details>
<summary>
M-01 | Medium: Information Disclosure via Fuzzing
</summary>
<div class="finding">
<p>
<strong>Finding ID:</strong> M-01
</p>
<p>
<strong>Impact:</strong> Attackers can map app structure and harvest
preliminary data.
</p>
<p>
<strong>Evidence:</strong> Subdomain discovered via ffuf, <code>data.quartz.ctfio.com</code>
</p>
<img src="assets/vhostfuzz.png" class="screenshot" />
<p>
<strong>Recommendation:</strong> Serve authentication barriers early
(HTTP 401/403), and sanitize public app footprint.
</p>
</div>
</details>
<details>
<summary>
M-02 | Medium: Information Disclosure via Redirect Body
</summary>
<div class="finding">
<p>
<strong>Finding ID:</strong> M-02
</p>
<p>
<strong>Impact:</strong> Attackers can map app structure and harvest
preliminary data.
</p>
<p>
<strong>Evidence:</strong> 302 response from <code class="inline"> /login</code> leaks the
<code> /lawyers-only</code> page.
</p>
<img src="assets/GETtoLogin.png" class="screenshot" />
<p>
<strong>Recommendation:</strong> Remove the body and retire the old route.
</p>
</div>
</details>
<details>
<summary> L-01 | Low: Use of Outdated Software Component - Nginx</summary>
<div class="finding">
<p>
<strong>Finding ID:</strong> L-01
</p>
<p><strong>Impact:</strong> The use of outdated software introduces latent vulnerabilities that may become
exploitable if site functionality expands or if attackers chain weaknesses together. Nginx 1.22.0 is
vulnerable to CVE-2022-41741, CVE-2022-41742, among others.</p>
<p><strong>Evidence:</strong> Wappalyzer identified Nginx v1.22.0, this information is also available in HTTP
response headers.</p>
<ul>
<img src="assets/wappalyzer.png" class="screenshot">
</ul>
<p><strong>Recommendation:</strong> Upgrade major components to their latest secure versions. Establish a
regular dependency review and patch lifecycle process for both frontend and backend components.</p>
</div>
</details>
<details>
<summary> L-02 | Low: Use of Outdated Software Component - jQuery</summary>
<div class="finding">
<p>
<strong>Finding ID:</strong> L-02
</p>
<p><strong>Impact:</strong> The use of outdated software introduces latent vulnerabilities that may become
exploitable if site functionality expands or if attackers chain weaknesses together. jQuery v1.12.4 contains
known cross site scripting (XSS) vulnerabilities.</p>
<p><strong>Evidence:</strong> Wappalyzer identified jQuery v1.12.4, this information is also available by using
the browser JavaScript console and running the command <code>jQuery.fn.jquery</code>.</p>
<ul>
<img src="assets/wappalyzer.png" class="screenshot">
</ul>
<p><strong>Recommendation:</strong> Upgrade major components to their latest secure versions. Establish a
regular dependency review and patch lifecycle process for both frontend and backend components.</p>
</div>
</details>
<details>
<summary> L-03 | Low: Use of Outdated Software Component - Bootstrap</summary>
<div class="finding">
<p>
<strong>Finding ID:</strong> L-03
</p>
<p><strong>Impact:</strong> The use of outdated software introduces latent vulnerabilities that may become
exploitable if site functionality expands or if attackers chain weaknesses together. Bootstrap v3.3.7 is
deprecated with several historic UI-based flaws.</p>
<p><strong>Evidence:</strong> Wappalyzer identified Bootstrap v 3.3.7, this information is also available by
using
the browser JavaScript console and running the command <code>$.fn.tooltip.Constructor.VERSION</code>.</p>
<ul>
<img src="assets/wappalyzer.png" class="screenshot">
</ul>
<p><strong>Recommendation:</strong> Upgrade major components to their latest secure versions. Establish a
regular dependency review and patch lifecycle process for both frontend and backend components.</p>
</div>
</details>
<details>
<summary>
I-01 | Informational: UI Misrepresentation - Purported Deletion of Case Files
</summary>
<div class="finding">
<p>
<strong>Finding ID:</strong> I-01
</p>
<p>
<strong>Impact:</strong> Misleading user interface behavior creates the impression that sensitive data is
deleted when it is not. This undermines user trust and could lead to inappropriate case handling decisions.
</p>
<p>
<strong>Evidence:</strong> When logged in as Shayne Cairns, pressing the “Delete Case” button causes the case
to disappear from Shayne's view, upon leaving the page and coming back the case returns.
</p>
<img src="assets/before.png" class="screenshot" />
<img src="assets/after.png" class="screenshot" />
<p>
<strong>Recommendation:</strong> Ensure that all destructive actions, including case deletions, are handled at
the backend level with verifiable state changes. All user-facing features must reflect the true state
of the underlying data.
</p>
</div>
</details>
<details>
<summary> I-02 | Informational: Inconsistent Nginx Versioning in Header Leak</summary>
<div class="finding">
<p>
<strong>Finding ID:</strong> I-02
</p>
<p><strong>Impact:</strong> Version disclosure may enable targeted exploits against known vulnerabilities in
Nginx
1.18.0 (e.g., CVE-2021-23017 - 1-byte memory overwrite).</p>
<p><strong>Evidence:</strong> GET request to the <code>/images</code> directory results in a 301 and 403
response leaking Nginx version in the footer.</p>
<ul>
<img src="assets/nginxfooter.png" class="screenshot">
</ul>
<p><strong>Recommendation:</strong> Our tentative recommendation is to set server_tokens off; in all Nginx
blocks to suppress version disclosure in headers and bodies. Please review the technical remediation section
for a better understanding.</p>
</div>
</details>
<br>
<br>
<br>
<h2 id="remediation-roadmap">Remediation Roadmap & Compliance Mapping</h2>
<table border="1" cellpadding="6" cellspacing="0">
<thead>
<tr>
<th>Finding</th>
<th>Priority</th>
<th>Estimated Effort</th>
<th>Target Fix Window</th>
<th>Key Compliance Drivers*</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>C-01: Passwords Stored in Plaintext</strong></td>
<td style="color: #ff5555"><strong>Critical</strong></td>
<td>Medium</td>
<td>≤ 14 days</td>
<td>
<a style="color: inherit; text-decoration: none"
href="https://owasp.org/Top10/A07_2021-Identification_and_Authentication_Failures/" target="_blank">OWASP
A07-2021</a>,
<a style="color: inherit; text-decoration: none" href="https://gdpr-info.eu/art-32-gdpr/"
target="_blank">GDPR (Art. 32)</a>,
<a style="color: inherit; text-decoration: none"
href="https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-53r5.pdf#%5B%7B%22num%22%3A488%2C%22gen%22%3A0%7D%2C%7B%22name%22%3A%22XYZ%22%7D%2C88%2C617%2C0%5D"
target="_blank">NIST 800-53 IA-5(1)</a>,
<a style="color: inherit; text-decoration: none"
href="https://iso-docs.com/blogs/iso-27001-standard/iso-27001-annex-a-10-cryptography?_pos=1&_psq=iso-27001-a.10&_ss=e&_v=1.0"
target="_blank">ISO 27001 A.10.1</a>
</td>
</tr>
<tr>
<td><strong>C-02: IDOR - Profile Credential Disclosure</strong></td>
<td style="color: #ff5555"><strong>Critical</strong></td>
<td>Medium</td>
<td>≤ 14 days</td>
<td>
<a style="color: inherit; text-decoration: none"
href="https://owasp.org/Top10/A01_2021-Broken_Access_Control/" target="_blank">OWASP A01 -2021</a>,
<a style="color: inherit; text-decoration: none" href="https://gdpr-info.eu/art-32-gdpr/"
target="_blank">GDPR (Art. 32)</a>,
<a style="color: inherit; text-decoration: none"
href="https://iso-docs.com/blogs/iso-27001-standard/iso-27001-annex-a-9-access-control"
target="_blank">ISO 27001 A.9.4.1</a>,
<a style="color: inherit; text-decoration: none"
href="https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-53r5.pdf#%5B%7B%22num%22%3A181%2C%22gen%22%3A0%7D%2C%7B%22name%22%3A%22XYZ%22%7D%2C88%2C336%2C0%5D"
target="_blank">NIST 800-53 AC-6</a>
</td>
</tr>
<tr>
<td><strong>H-01: Weak Login / Brute-Force Vulnerability</strong></td>
<td style="color: #ff8800"><strong>High</strong></td>
<td>Low - Medium</td>
<td>≤ 30 days</td>
<td>
<a style="color: inherit; text-decoration: none"
href="https://owasp.org/Top10/A07_2021-Identification_and_Authentication_Failures/" target="_blank">OWASP
A07 -2021</a>,
<a style="color: inherit; text-decoration: none"
href="https://iso-docs.com/blogs/iso-27001-standard/iso-27001-annex-a-9-access-control"
target="_blank">ISO 27001 A.9.4.2</a>,
<a style="color: inherit; text-decoration: none"
href="https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-53r5.pdf#%5B%7B%22num%22%3A190%2C%22gen%22%3A0%7D%2C%7B%22name%22%3A%22XYZ%22%7D%2C88%2C650%2C0%5D"
target="_blank">NIST 800-53 AC-7</a>,
<a style="color: inherit; text-decoration: none"
href="https://docs-prv.pcisecuritystandards.org/PCI%20DSS/Standard/PCI-DSS-v4_0_1.pdf" target="_blank">PCI
DSS v4.0 8.3.6</a>,
<a style="color: inherit; text-decoration: none" href="https://www.ncsc.gov.uk/cyberessentials/overview"
target="_blank">Cyber Essentials</a>
</td>
</tr>
<tr>
<td><strong>M-01, M-02: Information Disclosure</strong></td>
<td style="color: #ffaa00"><strong>Medium</strong></td>
<td>Low</td>
<td>≤ 60 days</td>
<td>
<a style="color: inherit; text-decoration: none"
href="https://owasp.org/Top10/A06_2021-Vulnerable_and_Outdated_Components/" target="_blank">OWASP
A06-2021</a>,
<a style="color: inherit; text-decoration: none"
href="https://iso-docs.com/blogs/iso-27001-standard/iso-27001-annex-a-13-communications-security?_pos=1&_psq=iso-27001-a.13&_ss=e&_v=1.0"
target="_blank">ISO 27001 A.13.1.1</a>,
<a style="color: inherit; text-decoration: none"
href="https://cas.docs.cisecurity.org/en/latest/source/Controls3/#34-enforce-data-retention"
target="_blank">CIS Controls 3.4</a>
</td>
</tr>
<tr>
<td><strong>L-01, L-02, L-03: Use of Outdated Software Components</strong><br />
</td>
<td style="color: #ffaa00"><strong>Low</strong></td>
<td>Low</td>
<td>≤ 90 days</td>
<td>
<a style="color: inherit; text-decoration: none"
href="https://owasp.org/Top10/A06_2021-Vulnerable_and_Outdated_Components/" target="_blank">OWASP
A06-2021</a>,
<a style="color: inherit; text-decoration: none"
href="https://iso-docs.com/blogs/iso-27001-standard/iso-27001-annex-a-12-operations-security?_pos=1&_psq=iso-27001-a.12&_ss=e&_v=1.0"
target="_blank">ISO 27001 A.12.6.1</a>,
<a style="color: inherit; text-decoration: none" href="https://gdpr-info.eu/art-32-gdpr/" target="_blank">UK
GDPR (Art. 32)</a>,
<a style="color: inherit; text-decoration: none" href="https://www.ncsc.gov.uk/cyberessentials/overview"
target="_blank">NCSC Cyber Essentials</a>
</td>
</tr>
</tbody>
</table>
<p style="font-size: 0.85em">
*Compliance references are provided for context; VulnLawyers should map
recommendations against their own regulatory obligations. No mappings were made for findings rated Informational.
All references are links.
</p>
<br>
<br>
<br>
<h2 id="technical-attack-path">Technical Attack Path Breakdown</h2>
<p>
The following section tracks the path taken by the tester to uncover the identified vulnerabilities. A complete
list of tools and wordlists used during this assessment is provided in
<a style="color: inherit; text-decoration: none" href="#appendix-c"><strong>Appendix C</strong></a>.
</p>
<p>
The tester began with directory and subdomain enumeration using <code>ffuf</code>. While <code>ffuf</code>
automatically performs recursive directory fuzzing, discovering a new subdomain requires initiating a new scan
scoped to that domain. Note: Although the screenshots show use of the <code>-e</code> flag (for file extensions),
it was not required for this particular case.
</p>
<details>
<summary>
<code
style="font-size: medium;"></> ffuf -H 'Host: FUZZ.quartz.ctfio.com' -u https://quartz.ctfio.com -w <Path to Wordlist> -fs 178</code>
</summary>
<div class="finding">
<img src="assets/vhostfuzz.png" class="screenshot">
</div>
</details>
<details>
<summary><code></> ffuf -u https://quartz.ctfio.com/FUZZ -w <Path to Wordlist> -fs 178</code>
</summary>
<div class="finding">
<img src="assets/DirFuzz.png" class="screenshot">
</div>
</details>
<details>
<summary><code></> ffuf -u https://data.quartz.ctfio.com/FUZZ -w <Path to Wordlist> -fs 178</code>
</summary>
<div class="finding">
<img src="assets/vhostdirfuzz.png" class="screenshot">
</div>
</details>
<p>
After completing the scans, we navigated to the interesting endpoint <code>data.quartz.ctfio.com/users</code> and
discovered a JSON list of valid usernames.
</p>
<img src="assets/subdomain.png" class="screenshot">
<img src="assets/userlistendpoint1.png" class="screenshot">
<p>
Armed with a list of usernames, we attempted to access the login page discovered earlier. However, we encountered
a redirect and an “Access Denied” message. Inspecting the raw HTTP response revealed a new endpoint at
<code>/lawyers-only/</code>.
</p>
<img src="assets/denied.png" class="screenshot">
<img src="assets/GETtoLogin.png" class="screenshot">
<img src="assets/lawyers-onlyLogin.png" class="screenshot">
<p>
At the new login screen, we captured a request containing a username and password and used Caido's Automate
feature to perform a password spraying attack.
</p>
<img src="assets/PasswordsprayRequest.png" class="screenshot">
<p>
We successfully authenticated using the credentials:
<code>jaskaran.lowe@vulnlawyers.ctf:summer</code>
</p>
<img src="assets/PasswordSpraySuccess.png" class="screenshot">
<img src="assets/jaskaranlogin.png" class="screenshot">
<p>
Next, we navigated to the profile update page and intercepted the request when modifying account data. We observed
that profile details are retrieved via an endpoint containing the user ID.
</p>
<img src="assets/profiledetailsscript.png" class="screenshot">
<p>
We visited this endpoint directly to confirm it was accessible externally.
</p>
<img src="assets/profileDetailsSelfAccess.png" class="screenshot">
<p>
Since the endpoint did not enforce access controls, we modified the ID value to test access to other
users' profiles.
</p>
<img src="assets/YusefProfDetails.png" class="screenshot">
<p>
With full visibility into other user profiles, we obtained credentials for all accounts. Notably, Shayne's account
was identified as the manager of a sensitive case file.
</p>
<img src="assets/IDORShayne.png" class="screenshot">
<img src="assets/ShaynesPortal.png" class="screenshot">
<p>
Finally, we used Shayne's account to delete the referenced case file, discovering an implementation flaw. The file
returns after deletion.
</p><img src="assets/before.png" class="screenshot"><img src="assets/after.png" class="screenshot">
<p>After confirming we can compromise the web application, we doubled back to poke at the web application from
different angles noticing inconsistent Nginx versioning when met with a 403 error when accessing the /images and
/js directories.</p>
<img src="assets/nginxfooter.png" class="screenshot">
<br>
<br>
<br>
<h2 id="technical-remediation">Technical Remediation</h2>
<p>The following technical remediations are recommended to address the vulnerabilities identified during the
assessment. Each recommendation is designed to not only resolve the immediate issue but also to promote long-term
security hygiene through defensive development practices, access control enforcement, and architectural
improvements.</p>
<h3 style="text-align: center;" id="C-01">C-01 | Passwords Stored in Plaintext</h3>
<p>To ensure the confidentiality and integrity of user credentials, passwords must never be stored or transmitted in
plaintext. The current practice represents a severe violation of industry best practices and creates significant
risk in the event of database compromise, insider access, or accidental data exposure.</p>
<p>
Passwords must be hashed using a strong, adaptive one-way hashing function such as bcrypt, scrypt, or Argon2id.
These algorithms are specifically designed to resist brute-force and dictionary attacks by increasing
computational effort through configurable cost parameters.</p>
<details>
<summary><code></> Example: Secure Hashing</code></summary>
<pre><code>
from flask import Flask, request, jsonify
import bcrypt
@app.route('/register', methods=['POST'])
def register():
data = request.json
username = data.get("username")
password = data.get("password")
if not username or not password:
return jsonify({"error": "Missing username or password"}), 400
salt = bcrypt.gensalt(rounds=12) ### <-- This is the configurable cost parameter.
hashed = bcrypt.hashpw(password.encode('utf-8'), salt)
users[username] = hashed
return jsonify({"message": f"User {username} registered successfully."}), 201
@app.route('/lawyers-only-login', methods=['POST'])
def login():
data = request.json
username = data.get("username")
password = data.get("password")
stored_hash = users.get(username)
if not stored_hash:
return jsonify({"error": "Invalid credentials"}), 401
if bcrypt.checkpw(password.encode('utf-8'), stored_hash):
return jsonify({"message": "Login successful"}), 200
else:
return jsonify({"error": "Invalid credentials"}), 401
</code></pre>
</details>
<p>Plaintext credentials currently in the database must be invalidated. Users should be prompted to reset their
passwords through a secure password reset flow. Do not attempt to retroactively hash existing plaintext passwords,
as this assumes compromise has not already occurred.</p>
<details>
<summary><code></> Example: Password Reset Flow</code></summary>
<pre><code>
from itsdangerous import URLSafeTimedSerializer
from flask_mail import Message
def send_password_reset_email(user_email):
user = User.query.filter_by(email=user_email).first()
if not user:
return
serializer = URLSafeTimedSerializer(app.config['SECRET_KEY'])
token = serializer.dumps(user.email, salt='password-reset')
reset_url = url_for('reset_password', token=token, _external=True)
msg = Message("Password Reset", recipients=[user.email])
msg.body = f"Click to reset your password: {reset_url}"
mail.send(msg)
@app.route('/reset/<token>', methods=['GET', 'POST'])
def reset_password(token):
serializer = URLSafeTimedSerializer(app.config['SECRET_KEY'])
try:
email = serializer.loads(token, salt='password-reset', max_age=3600)
except SignatureExpired:
return "Token expired", 403
except BadSignature:
return "Invalid token", 403
if request.method == 'POST':
new_password = request.form['password']
user = User.query.filter_by(email=email).first()
user.set_password(new_password)
db.session.commit()
return redirect(url_for('login'))
return render_template('reset_password_form.html', token=token)
</code></pre>
</details>
<p>Sensitive data such as passwords must also be excluded from all application responses and log files. APIs
returning user account details must be audited to ensure no sensitive fields are included, even for authenticated
users.</p>
<p>Access to password hashes (even if secure) should be restricted to the authentication subsystem only. Ensure
logs, backups, and support tooling do not inadvertently leak these values.</p>
<p>Security mechanisms should be in place to ensure that any future code handling credentials enforces secure
practices, such as:</p>
<ol>
<li>Linting or static analysis rules that prevent logging or returning password fields</li>
<li>Developer code reviews with explicit attention to credential handling</li>
<li>Test coverage for registration and login flows validating that no raw passwords are stored or echoed</li>
</ol>
<p>These changes are foundational to any secure authentication system and are necessary for compliance with GDPR
(Art. 32), ISO 27001 Annex A.9, and OWASP recommendations.</p>
<details>
<summary>
<code></> Example: Validation Check</code>
</summary>
<pre><code>
curl -s https://quartz.ctfio.com/profile-details/6 | jq '.password'
</code></pre>
</details>
<h3 style="text-align: center;" id="C-02">C-02 | Insecure Direct Object Reference (IDOR)</h3>
<p>To prevent unauthorized access to user credentials or other sensitive data through predictable URL parameters,
the application should enforce object-level access control on all endpoints. User identifiers exposed in URLs
(e.g., <code>/profile-details/2</code>) should be replaced with opaque references or UUIDs to prevent enumeration.
Additionally, sensitive information such as passwords must never be included in API responses, even when the
requesting user is authenticated.</p>
<p>Access control logic should be implemented server-side using authenticated session context, ensuring that users
may only retrieve, modify, or delete resources they explicitly own. This validation must occur for every request
and should not rely on UI constraints alone.</p>
<details>
<summary><code></> Example: Flask route with object-level access control using session context</code>
</summary>
<pre><code>
from flask import session, abort
@app.route('/lawyers-only-profile-details/<int:user_id>')
def get_profile(user_id):
current_user_id = session.get('user_id')
if user_id != current_user_id:
abort(403)
user = db.get_user_by_id(user_id)
return jsonify(user.to_safe_dict())
</code></pre>
</details>
<h3 style="text-align: center;" id="H-01">H-01 | Weak Authentication and Brute-Force Vulnerability</h3>
<p>To mitigate brute-force and password spraying risks, the login functionality must incorporate robust
anti-automation controls. Rate-limiting should be applied on a per-IP and per-username basis to throttle repeated
login attempts. This can be achieved at the web server level (e.g., Nginx limit_req) or within the application
itself.</p>
<p>Additionally, the application should enforce stronger password policies (e.g., minimum 12 characters,
alphanumeric
and special characters), support multi-factor authentication (MFA), and implement account lockout or delay
mechanisms
after repeated failed logins. All failed authentication attempts should be logged and reviewed regularly.</p>
<details>
<summary><code></> Example: Rate-limiting in Nginx config</code>
</summary>
<pre><code>
limit_req_zone $binary_remote_addr zone=auth_limit:10m rate=5r/m;
server {
location /login {
limit_req zone=auth_limit burst=10 nodelay;
proxy_pass http://backend;
}
}
</code></pre>
</details>
<details>
<summary><code></> Example: Validation Check</code>
</summary>
<pre><code>
for i in {1..10}; do curl -s -X POST https://quartz.ctfio.com/lawyers-only-login -d "user=test&pass=wrong" > /dev/null; done
curl -s -X POST https://quartz.ctfio.com/lawyers-only-login -d "user=test&pass=wrong" | grep -i 'too many attempts'
</code></pre>
</details>
<h3 style="text-align: center;" id="M-01">M-01 | Information disclosure via Fuzzing</h3>
<p>To prevent attackers from discovering hidden subdomains or application instances through fuzzing,
the server configuration should be hardened to reject unknown Host headers. All virtual hosts should be explicitly
declared in the web server configuration, and a default catch-all server block should return an error (e.g., HTTP
444) or redirect to a generic error page.</p>
<details>
<summary><code></> Example: Nginx config</code>
</summary>
<pre><code>
server {
listen 80 default_server;
server_name _;
return 444;
}
server {
listen 80;
server_name quartz.ctfio.com;
root /var/www/quartz;
index index.html;
if ($host !~ ^(quartz\.ctfio\.com)$) {
return 444;
}
}
</code></pre>
</details>
<p>In addition, internal or staging environments should be protected via network-level access control, such as IP
allowlisting or VPN-only access, and should not be accessible from the public internet. DNS records should be
reviewed to ensure that only legitimate and necessary subdomains are publicly resolvable.</p>
<h3 style="text-align: center;" id="M-02">M-02 | Information Disclosure via Redirect Body</h3>
<p>Some web servers may include the original response body in HTTP 30x redirects, which can inadvertently leak
internal information such as error messages, stack traces, or unauthenticated views. This behavior is especially
problematic when the body content contains sensitive information and is delivered to unauthenticated or unintended
clients before redirection completes.</p>
<p>To prevent such disclosures, the application and underlying web server should be configured to avoid rendering
bodies on redirection responses, particularly those involving 302 (Found) and 307 (Temporary Redirect) status
codes. In Nginx, this can be achieved by issuing return directives instead of using rewrite ... redirect, or by
stripping response bodies manually using the empty_gif module or custom headers where applicable.</p>
<details>
<summary><code></> Example: Nginx config</code>
</summary>
<pre><code>
location /login {
if ($unauthorized) {
return 302 https://quartz.ctfio.com/denied;
}
proxy_pass http://quartz.ctfio.com/lawyers-only;
}
</code></pre>
</details>
<details>
<summary><code></> Example: Application level</code>
</summary>
<pre><code>
@app.route('/login', methods=['POST'])
def login():
if not authorized():
return redirect("/denied", code=302)
return render_template("dashboard.html")
</code></pre>
</details>
<p>Additionally, review all authentication-related routes to ensure that redirects are performed early in the
request pipeline, before any content is generated. If application logic must generate content conditionally, guard
those blocks behind strict authentication checks.</p>
<p>This mitigation ensures attackers cannot extract sensitive clues during redirect behavior and aligns with
secure-by-default design principles.</p>
<details>
<summary><code></> Example: Validation Check</code>
</summary>
<pre><code>
curl -i -k -X GET https://quartz.ctfio.com/login --max-redirs 0
</code></pre>
</details>
<h3 style="text-align: center;" id="OutdatedComponents">L-01 & L-02 & L-03 | Outdated Components</h3>
<p>The use of outdated and vulnerable software components introduces unnecessary risk. While the current deployment
may be minimal in functionality, it remains susceptible to exploitation via known vulnerabilities in its core
dependencies.</p>
<p>Nginx 1.22.0: This version is vulnerable to several known issues (e.g., CVE-2025-23419, CVE-2022-41741,
CVE-2022-41742). Upgrade to Nginx 1.26.3 or higher to address these issues. Testing should be conducted to ensure
compatibility with custom modules and configurations.</p>
<p>jQuery 1.12.4: This version contains multiple XSS and DOM-related vulnerabilities. Upgrade to jQuery 3.7.1 or
higher, and refactor deprecated API usage to ensure compatibility.</p>
<p>Bootstrap 3.3.7: This version relies on jQuery and is no longer maintained. Migrate to Bootstrap 5.x, which
provides native JavaScript implementations and improved XSS protections. If full migration is not feasible,
implement strict CSP headers and sanitize all user-provided content with a trusted library such as DOMPurify.</p>
<p>Maintaining an up-to-date dependency chain is essential for defense-in-depth and long-term maintainability of the
application.</p>
<h3 style="text-align: center;" id="I-01">I-01 | UI Misrepresentation - Purported Deletion of Case Files</h3>
<p>The application should accurately represent the outcome of user actions. In the current implementation, the
“Delete Case” button appears to remove a legal case, but the data is not actually deleted from the backend or
hidden from other users. This misrepresentation can mislead users into believing data has been irreversibly
removed.</p>
<p>
If deletion functionality is intended, implement the deletion logic on the server side. This should include a
request handler that validates the user's permissions and securely updates the shared datastore to reflect the
change (e.g., soft-delete the case).</p>
<p>If true deletion is not desired, the frontend should be updated to reflect that the action is only a local or
session-level hiding mechanism, not a persistent removal. Ensure the UI communicates this clearly to avoid
confusion.</p>
<p>Regardless of the approach, actions related to case management should be logged with:</p>
<ol>
<li>User ID</li>
<li>Timestamp</li>
<li>IP Address</li>
<li>Record affected</li>
<li>Reason (if provided)</li>
</ol>
<details>
<summary><code></> Example: Python Implementation</code>
</summary>
<pre><code>
from flask import request, session, abort
from datetime import datetime
@app.route('/case/<int:case_id>/delete', methods=['POST'])
def soft_delete_case(case_id):
case = db.get_case(case_id)
current_user_id = session.get('user_id')
if not case or case.owner_id != current_user_id: