Lufer

  • 首页
  • 编程
  • 学习笔记
  • 日常折腾
Lufer
Code the World
  1. 首页
  2. 学习笔记
  3. WriteUP
  4. 正文

网络安全技能实训 WP

2025年7月1日 17点热度 0人点赞 0条评论

MISC

Shadow

题目

这里是影子的领域,这里藏着光与影的秘密。 那是转瞬即逝的光,还是永恒的影?

题解

用nc连环境,得到一些提示

用python连一下,结果复制出来,替换掉特殊字符,可以看见flag

神秘数据

题目

小明收到一份神秘的文件,观察了文章的段落很久之后终于露出了笑容,你能找到里面隐藏的数据吗? flag格式,flag{xxx},其中xxx为解码得到的值

题解

题目是一段文章,观察可以发现有的后面空一行,有的后面空两行,记录为二进制01,然后二进制转字符获得flag。

Cypto

猜猜我是谁

LQGSK6GUJWNAK4GOJMIIG=J2NWURVU5MJWEMJUZ25TA=WC2SYDMLKCVLYSGLWKMS6=X2GEUHX2GOT2ENUXVNTYQ=

题目

四段同样类型的文本,先栅栏,得到一串base64,解码获得flag。

Web

Nodejs Bypass

题目

没有人比我更懂 nodejs

题解

附件中有两个js文件

const fs = require("fs");
const SECRET_COOKIE = process.env.SECRET_COOKIE || "this_is_testing_cookie"

const flag1 = fs.readFileSync("/flag1")
const flag2 = fs.readFileSync("/flag2")

function merge(target, source) {
    for (let key in source) {
        if (key == "__proto__") {
            continue; // no proto, please bypass
        }
        if (key in target && key in source) {
            merge(target[key], source[key])
        } else {
            target[key] = source[key]
        }
    }
}

function LoginController(req, res) {
    try {
        let user = {}
        merge(user, req.body)

        if (user.username !== "admin" || user.password !== Math.random().toString()) {
            res.status(401).type("text/html").send("Login Failed")
        } else {
            res.cookie("user", SECRET_COOKIE)
            req.user = "admin"
            res.redirect("/flag1")
        }
    } catch (e) {
        console.log(e)
        res.status(401).type("text/html").send("What the heck")
    }
}

function Flag1Controller(req, res) {
    try {
        if (req.cookies.user === SECRET_COOKIE || req.user == "admin") {
            res.setHeader("This_Is_The_Flag1", flag1.toString().trim())
            res.status(200).type("text/html").send("Login success. Welcome,admin!")
        } else {
            res.status(401).type("text/html").send("Unauthorized")
        }
    } catch (__) { }
}

function Flag2Controller(req, res) {
    let checkcode = req.body.checkcode ? req.body.checkcode : 1234;
    console.log(req.body)
    if (checkcode.length === 16) {
        try {
            checkcode = checkcode.toLowerCase()
            if (checkcode !== "aGr5AtSp55dRacer") {
                res.status(403).json({ "msg": "Invalid Checkcode1:" + checkcode })
            }
        } catch (__) { }
        res.status(200).type("text/html").json({ "msg": "You Got Another Part Of Flag: " + flag2.toString().trim() })
    } else {
        res.status(403).type("text/html").json({ "msg": "Invalid Checkcode2:" + checkcode })
    }
}

module.exports = {
    LoginController,
    Flag1Controller,
    Flag2Controller
}
const express = require("express")
const fs = require("fs")
const cookieParser = require("cookie-parser");
const controller = require("./controller")

const app = express();
const PORT = Number(process.env.PORT) || 80
const HOST = '0.0.0.0'


app.use(express.urlencoded({ extended: false }))
app.use(cookieParser())
app.use(express.json())

app.use(express.static('static'))

app.get("/", (res) => {
    res.sendFile(__dirname, "static/index.html")
})

app.post("/", (req, res) => {
    controller.LoginController(req, res)
})

app.get("/flag1", (req, res) => {
    controller.Flag1Controller(req, res)
})

app.post("/flag2", (req, res) => {
    controller.Flag2Controller(req, res)
})

app.listen(PORT, HOST, () => {
    console.log(`Server is listening on Host ${HOST} Port ${PORT}.`)
})

审计代码,发现存在flag1和flag2两个入口

先看flag1,需要检测req.user==admin。

通过constructor进行原型链污染,把用户设置为admin。

然后访问flag1,发现已经成功登录。

重放这个请求,可以得到前半截flag。

然后审计flag2,发现需要传入checkcode,长度为16,并且要与指定字符串相等,因为先执行了toLowerCase函数,因此不能直接传入,需要产生异常跳出try代码块才能执行后续部分。

传入数组,进行比较时会抛出异常,因为长度要求是16,因此构造长度为16的数组。

用GET会提示错误,那就用POST。

One Number SQL

题目

GZTime 把 flag 藏到数据库里,只给大家看 flag 的一小截,但是这不影响你拿到 flag 吧 ~

题解

访问页面,得到一句提示

小 GZ 露出 flag 的一角,但是这离成功远远不够,你能将 flag 整条拖出来吗 

审计代码,发现存在隐藏提示。

<p class="secret">something secrets in /hint <span class="emoji key"></span></p>

访问hint,得到代码。

def waf(str):
    length = 0
    for c in str:
        if(c.isdigit()):
            length += length * 10 + int(c)
    return length > 0 and length < 10

@app.route('/getFlag')
def getFlag():
    flag_len = request.args.get("len")

    try:
        if(waf(flag_len)):
            result = cursor.execute(f"select substr(flag,1,{flag_len}) from flag")
            result = result.fetchone()
            print(len(result[0]))
            if(len(result[0])):
                return render_template('getflag.html',message=result[0]) # Only the first query information of sql can be obtained
            else:
                return render_template('getflag.html',message="nothing here")
        else:
            return render_template('getflag.html',message="len should be 0 < len < 10")
    except:
        return render_template('getflag.html',message="Error! Please Try Again Meow~ ")

审计代码发现,需要访问getFlag,传入参数len,用于执行select语句,但是len最大不能超过10,因此构造语句,断开并重新构造查询语句。

传入一个小于10的数字绕过WAF,然后同步构造from flag where 'a'='b',通过假条件让返回的结果为空,再通过union select执行我们的真实操作,select flag from flag,添加两个减号,注释掉后续内容。

len=1) from flag where 'a'='b' union select flag from flag--

The Moment of Token

题目

转瞬即逝的时机,转瞬即逝的宝藏。

题解

审计代码,发现有一句提示。

 <!-- maybe... int(time.time()) - int(password) < 5 -->

那么输入的密码要和时间戳的差要小于5,抓包改时间戳,header里面发现一个jwt的token。

在线JWT解密,发现有个gift字段,是base32加密后的flag。

标签: 暂无
最后更新:2025年7月4日

Lufer

新的一天开始啦

点赞
< 上一篇
下一篇 >

文章评论

razz evil exclaim smile redface biggrin eek confused idea lol mad twisted rolleyes wink cool arrow neutral cry mrgreen drooling persevering
取消回复

文章目录
  • MISC
    • Shadow
      • 题目
      • 题解
    • 神秘数据
      • 题目
      • 题解
  • Cypto
    • 猜猜我是谁
      • 题目
  • Web
    • Nodejs Bypass
      • 题目
      • 题解
    • One Number SQL
      • 题目
      • 题解
    • The Moment of Token
      • 题目
      • 题解

COPYRIGHT © 2025 lufer.cc.

Theme Kratos Made By Seaton Jiang

鲁ICP备2021045819号