def api(request, logtype, udomain, hashstr):
apistatus = False
host = "%s.%s." % (hashstr, udomain)
if logtype == 'dns':
res = DNSLog.objects.filter(host__contains=host)
if len(res) > 0:
apistatus = True
elif logtype == 'web':
res = WebLog.objects.filter(path__contains=host)
if len(res) > 0:
apistatus = True
else:
return HttpResponseRedirect('/')
return render(request, 'api.html', {'apistatus': apistatus})
host = "%s.%s." % (hashstr, udomain) 这尼玛~ 只能查询xxxx.fuck.dns5.org的类型了.对于fuck.dns5.org/?cmd=fuck的形式好像不能查询。这尼玛~本想重新改写的.发现工程量太大了,就拿dnslog来修改api函数就好了 #重新改写api #1.默认访问全部的日志信息 #2.可以访问/api/xxxx/dns|web/ #3.可以精确定位到/api/xxxx/(dns|web)/xxxx/ 步骤 #先获取userid #xxx = (select userid from logview_user where udomain = udomain) 再根据dns|web的方式分别执行sql语句 if logtype == 'dns': #需要执行的是select log_time,host from logview_dnslog where userid = xxx and path like '%hashstr%' elif logtype == 'web': #需要执行的是SELECT "remote_addr","http_user_agent","log_time","path" FROM "logview_weblog" WHERE "user_id"=xxx and path like '%hashstr%' 这里的hashstr其实是可以为空的.就拿默认的数据库来测试
SELECT "log_time","remote_addr","http_user_agent","path" FROM "logview_weblog" WHERE user_id=(select id from logview_user where udomain = 'test') and path like '3%'
log_time remote_addr http_user_agent path
113.135.96.202 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.87 Safari/537.36 123.test.dnslog.link/
113.135.96.202 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.87 Safari/537.36 123.test.dnslog.link/favicon.ico
保持hashstr为空
SELECT "log_time","remote_addr","http_user_agent","path" FROM "logview_weblog" WHERE user_id=(select id from logview_user where udomain = 'test') and path like '%%'
结果依然是
log_time remote_addr http_user_agent path
113.135.96.202 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.87 Safari/537.36 123.test.dnslog.link/
113.135.96.202 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.87 Safari/537.36 123.test.dnslog.link/favicon.ico
这样就保证了xxx的完整性 大概改写后的api函数为
def api(request, logtype, udomain, hashstr):
result = ''
#首先保证udomain不能为空
if len(udomain)>0:
if logtype == 'dns':
sql = "select log_time,host from logview_dnslog where userid = (select userid from logview_user \"
"where udomain = {udomain}) and path like '%{hash}%'".format(udomain=udomain,hash=hashstr)
elif logtype == 'web':
sql = "SELECT log_time,remote_addr,http_user_agent,path FROM logview_weblog WHERE user_id=(select \"
"id from logview_user where udomain = {udomain}) and path like '%{hash}%'".format(udomain=udomain,hash=hashstr)
logging.info(sql)
#excute.sql
return result
$ ./w3af_api
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
另外一个是docker
$ cd extras/docker/scripts/
$ ./w3af_api_docker
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
2.认证。可以自行更换密码的。密码默认的加密方式是sha512sum。
生成密码
$ echo -n "secret" | sha512sum
bd2b1aaf7ef4f09be9f52ce2d8d599674d81aa9d6a4421696dc4d93dd0619d682ce56b4d64a9ef097761ced99e0f67265b5f76085e5b0ee7ca4696b2ad6fe2b2 -
$ ./w3af_api -p "bd2b1aaf7ef4f09be9f52ce2d8d599674d81aa9d6a4421696dc4d93dd0619d682ce56b4d64a9ef097761ced99e0f67265b5f76085e5b0ee7ca4696b2ad6fe2b2"
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
也可以把账户密码等信息写入yml配置文件来加载启动。
3.api使用方式
开始一个新的扫描 [POST] /scans/
查看扫描状态 GET /scans/0/status
获取相关的漏洞信息使用 GET /scan/kb/
删除相关的信息 DELETE /scans/0/
获取扫描信息 GET /scans/
暂停扫描 GET /scans/0/pause
停止扫描 GET /scans/0/stop
查看扫描日志 GET /scans/0/log
{
"attributes": {
"db": "MySQL database",
"error": "mysql_"
},
"cwe_ids": [
"89"
],
"cwe_urls": [
"https://cwe.mitre.org/data/definitions/89.html"
],
"desc": "SQL injection in a MySQL database was found at: \"http://testphp.acunetix.com/userinfo.php\", using HTTP method POST. The sent post-data was: \"uname=a%27b%22c%27d%22&pass=FrAmE30.\" which modifies the \"uname\" parameter.",
"fix_effort": 50,
"fix_guidance": "The only proven method to prevent against SQL injection attacks while still maintaining full application functionality is to use parameterized queries (also known as prepared statements). When utilising this method of querying the database, any value supplied by the client will be handled as a string value rather than part of the SQL query.\n\nAdditionally, when utilising parameterized queries, the database engine will automatically check to make sure the string being used matches that of the column. For example, the database engine will check that the user supplied input is an integer if the database column is configured to contain integers.",
"highlight": [
"mysql_"
],
"href": "/scans/0/kb/29",
"id": 29,
"long_description": "Due to the requirement for dynamic content of today's web applications, many rely on a database backend to store data that will be called upon and processed by the web application (or other programs). Web applications retrieve data from the database by using Structured Query Language (SQL) queries.\n\nTo meet demands of many developers, database servers (such as MSSQL, MySQL, Oracle etc.) have additional built-in functionality that can allow extensive control of the database and interaction with the host operating system itself. An SQL injection occurs when a value originating from the client's request is used within a SQL query without prior sanitisation. This could allow cyber-criminals to execute arbitrary SQL code and steal data or use the additional functionality of the database server to take control of more server components.\n\nThe successful exploitation of a SQL injection can be devastating to an organisation and is one of the most commonly exploited web application vulnerabilities.\n\nThis injection was detected as the tool was able to cause the server to respond to the request with a database related error.",
"name": "SQL injection",
"owasp_top_10_references": [
{
"link": "https://www.owasp.org/index.php/Top_10_2013-A1",
"owasp_version": "2013",
"risk_id": 1
}
],
"plugin_name": "sqli",
"references": [
{
"title": "SecuriTeam",
"url": "http://www.securiteam.com/securityreviews/5DP0N1P76E.html"
},
{
"title": "Wikipedia",
"url": "http://en.wikipedia.org/wiki/SQL_injection"
},
{
"title": "OWASP",
"url": "https://www.owasp.org/index.php/SQL_Injection"
},
{
"title": "WASC",
"url": "http://projects.webappsec.org/w/page/13246963/SQL%20Injection"
},
{
"title": "W3 Schools",
"url": "http://www.w3schools.com/sql/sql_injection.asp"
},
{
"title": "UnixWiz",
"url": "http://unixwiz.net/techtips/sql-injection.html"
}
],
"response_ids": [
1494
],
"severity": "High",
"tags": [
"web",
"sql",
"injection",
"database",
"error"
],
"traffic_hrefs": [
"/scans/0/traffic/1494"
],
"uniq_id": "82f91e8c-759b-43b9-82cb-59ff9a38a836",
"url": "http://testphp.acunetix.com/userinfo.php",
"var": "uname",
"vulndb_id": 45,
"wasc_ids": [],
"wasc_urls": []
}
def import_poc(pyfile,url):
poc_path = os.getcwd()+"/bugscannew/"
path = poc_path + pyfile + ".py"
filename = path.split("/")[-1].split(".py")[0]
sys.path.append(poc_path)
poc0 = imp.load_source('audit', path)
audit_function = poc0.audit
from dummy import *
audit_function.func_globals.update(locals())
ret = audit_function(url)
if ret is not None and 'None' not in ret:
#print ret
return ret
暂时没完美调用的方式.简单的贴个demo
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import re,os
import imp,sys
import time,json
import logging,glob
import requests
from mysql_class import MySQL
"""
logging.basicConfig(
level=logging.DEBUG,
format="[%(asctime)s] %(levelname)s: %(message)s")
"""
"""
1.识别具体的cms
2.从数据库获取cms--如果没有获取到考虑全部便利
3.输出结果
"""
def timestamp():
return str(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))
"""
DROP TABLE IF EXISTS `bugscan`;
CREATE TABLE `bugscan` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`service` varchar(256) COLLATE utf8_bin DEFAULT NULL,
`filename` varchar(256) COLLATE utf8_bin DEFAULT NULL,
`time` varchar(256) COLLATE utf8_bin DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
SET FOREIGN_KEY_CHECKS = 1;
"""
dbconfig = {'host':'127.0.0.1','port': 3306,'user':'root','passwd':'root123','db':'proscan','charset':'utf8'}
db = MySQL(dbconfig)
def insert(filename):
file_data = open(filename,'rb').read()
service = re.findall(r"if service.*==(.*?):",file_data)
if len(service)>0:
servi = service[0].replace("'", "").replace("\"", "").replace(" ", "")
sqlInsert = "insert into `bugscan`(id,service,filename,time) values ('','%s','%s','%s');" % (str(servi),str(filename.replace('./bugscannew/','')),str(timestamp()))
print sqlInsert
#db.query(sql=sqlInsert)
#print servi,filename
def check(service,url):
if service == 'www':
sqlsearch = "select filename from `bugscan` where service = '%s'" %(service)
elif service != 'www':
sqlsearch = "select filename from `bugscan` where service = 'www' or service = '%s'" %(service)
print sqlsearch
if int(db.query(sql=sqlsearch))>0:
result = db.fetchAllRows()
for row in result:
#return result
for colum in row:
colum = colum.replace(".py","")
import_poc(colum,url)
def import_poc(pyfile,url):
poc_path = os.getcwd()+"/bugscannew/"
path = poc_path + pyfile + ".py"
filename = path.split("/")[-1].split(".py")[0]
sys.path.append(poc_path)
poc0 = imp.load_source('audit', path)
audit_function = poc0.audit
from dummy import *
audit_function.func_globals.update(locals())
ret = audit_function(url)
if ret is not None and 'None' not in ret:
#print ret
return ret
def whatcms(url):
headers = {"Content-Type":"application/x-www-form-urlencoded; charset=UTF-8",
"Referer":"http://whatweb.bugscaner.com/look/",
}
"""
try:
res = requests.get('http://whatweb.bugscaner.com/look/',timeout=60, verify=False)
if res.status_code==200:
hashes = re.findall(r'value="(.*?)" name="hash" id="hash"',res.content)[0]
except Exception as e:
print str(e)
return False
"""
data = "url=%s&hash=0eca8914342fc63f5a2ef5246b7a3b14_7289fd8cf7f420f594ac165e475f1479"%(url)
try:
respone = requests.post("http://whatweb.bugscaner.com/what/",data=data,headers=headers,timeout=60, verify=False)
if int(respone.status_code)==200:
result = json.loads(respone.content)
if len(result["cms"])>0:
return result["cms"]
else:
return "www"
except Exception as e:
print str(e)
return "www"
if __name__ == '__main__':
#for filename in glob.glob(r'./bugscannew/*.py'):
# insert(filename)
url = "http://0day5.com/"
print check(whatcms(url),url)
The primary purpose of the Optiv attack and penetration testing (A&P) team is to simulate adversarial threat activity in an effort to test the efficacy of defensive security controls. Testing is meant to assess many facets of organizational security programs by using real-world attack scenarios. This type of assessment helps identify areas of strength, or areas of improvement regarding organizations' IT security processes, personnel and systems.
There exists a cat-and-mouse game in IT security, a never-ending arms race. Malicious actors implement new attacks; defensive controls are deployed to detect and deter those same attacks. It behooves organizations to attempt to be proactive in their defensive posture, and identify new methods of attack and preemptively put controls in place to stop them. Optiv A&P strives to maintain technical expertise in both the offensive and attack arena, along with the defensive methods used to detect and prevent attacks. To stay relevant and effective in this ever-changing threat landscape, it is paramount that organizations that specialize in assessing organizational security posture stay relevant to the tactics, techniques and procedures (TTPs) that are used by genuine threat actors. Optiv engages in proactive threat research to identify TTPs that could be used by threat actors to compromise systems or data.
Attacks that Stay Below the Radar
A goal of many attackers is to implement campaigns that go undetected. The longer an organization is unware of a breach condition, the more time an attacker has to identify and exfiltrate sensitive information, and use the compromised environment as a pivot point for more nefarious activity.
Optiv A&P implements advanced attacks in an effort to identify gaps in detective capabilities, and assist organizations in detecting the attacks.
A recent example of this activity is abusing native functionality with Microsoft SQL Server (MSSQL) to gain command and control of database servers using MSSQL Server Agent Jobs.
Microsoft SQL Server Agent
The MSSQL Server Agent is a windows service that can be used to perform automated tasks. The agent jobs can be scheduled, and run under the context of the MSSQL Server Agent service. However, using agent proxy capabilities, the jobs can be run with different credentials as well.
The Attack
During a recent engagement, a SQL injection condition was identified in a web application that was using MSSQL Server 2012. At the request of the client, Optiv performed the assessment in a surreptitious manner, making every effort to avoid detection. Optiv devised a way to take advantage of native MSSQL Server functionality to execute commands on the underlying Windows operating system. Also, the xp_cmdshell stored procedure had been disabled, and the ability to create custom stored procedures had also been limited.
Many monitoring or detection systems generate alerts when a commonly abused MSSQL stored procedure (xp_cmdshell) is used during an attack. The usage of xp_cmdshell by attackers, and penetration testers has caused many organizations to disable it, limit its ability to be used and tune alerting systems to watch for it.
Optiv identified a scenario wherein the MSSQL Server Agent could be leveraged to gain command execution on target database server. However, the server had to meet several conditions:
The MSSQL Server Agent service needs to be running.
The account that is being used must have permissions to create and execute agent jobs (in this case the database account that was running the service that had a SQL injection condition).
Optiv identified two MSSQL Agent Job subsystems that could be advantageous to attackers: the CmdExec and PowerShell subsystems. These two features can execute operating systems commands, and PowerShell respectively.
Optiv used the SQL injection entry point to create and execute the agent job. The job's command was PowerShell code that created a connection to an Optiv controlled IP address and downloaded additional PowerShell instructions that established an interactive command and control session between the database server, and the Optiv controlled server.
Here is the SQL syntax breakdown. Note, in the below download-string command, the URI is between two single quotes, not double quotes. This is to escape single quotes within SQL.
The above string is for easier copying and pasting, if you want to recreate this attack scenario.
The below quickly shows a demo on how to weaponize this attack.
The SQL syntax is URL encoded. In this specific instance the attack is being sent via an HTTP GET request, hence the necessity to URL encode the payload.
The request, with the SQL injection payload, to an HTTP GET parameter that is vulnerable to SQL injection is shown. Note the %20 (space character) added to the beginning of the payload.
Once the payload is run we can see a command and control session is established, running with the SQLSERVERAGENT account's privileges.
On the victim SQL server we can see the SQL Agent job has been created.
The below video demonstrates the full attack.
Attack Post Mortem
This attack can be leveraged to run MSSQL Server Agent jobs on other MSSQL servers, if the Agent service on the victim is configured to use an account with permissions to other MSSQL servers. Also, Agent jobs can be scheduled, and may be used as an evasive means to maintain a persistent connection to victim MSSQL servers.
In some instances, if the MSSQL Server Agent service is configured with an account that has more privileges than that of the database user, for example an Active Directory domain service account, this attack can be used by an attacker to escalate their privileges.
Mitigation
General web application hygiene should be used to prevent attack vectors like SQL injection. Use prepared statements in SQL queries within web applications, and abstracting application logic from backend databases. Employ web application firewalls to detect and block attacks on applications.
Internal systems that do not need to communicate directly with Internet hosts should be disallowed from doing so. This can prevent command and control channels from being established between internal assets, and attacker controlled endpoints. Employ strict network egress filtering.
MSSQL Server Agent jobs can be abused by any attacker that has the ability to execute SQL queries on a database server. To specifically limit the attack surface of MSSQL Server Agent jobs ensure that databases are running under the context of user accounts with the concept of least privilege. If the account that a database is running under does not have permissions to create and start MSSQL Server Agent jobs this attack is negated. Also, if the MSSQL Server Agent service is not in use it should be disabled.
for dport in dhost.findall('ports/port'):
# protocol
proto = dport.get('protocol')
# port number converted as integer
port = int(dport.get('portid'))
# state of the port
state = dport.find('state').get('state')
# reason
reason = dport.find('state').get('reason')
# name, product, version, extra info and conf if any
name = product = version = extrainfo = conf = cpe = ''
for dname in dport.findall('service'):
name = dname.get('name')
if dname.get('product'):
product = dname.get('product')
if dname.get('version'):
version = dname.get('version')
if dname.get('extrainfo'):
extrainfo = dname.get('extrainfo')
if dname.get('conf'):
conf = dname.get('conf')
for dcpe in dname.findall('cpe'):
cpe = dcpe.text
# store everything
if not proto in list(scan_result['scan'][host].keys()):
scan_result['scan'][host][proto] = {}
scan_result['scan'][host][proto][port] = {'state': state,
'reason': reason,
'name': name,
'product': product,
'version': version,
'extrainfo': extrainfo,
'conf': conf,
'cpe': cpe}
试想下如果把name以及tunnel取出来同时匹配不就好了。于是对此进行修改。410-440行
name = product = version = extrainfo = conf = cpe = tunnel =''
for dname in dport.findall('service'):
name = dname.get('name')
if dname.get('product'):
product = dname.get('product')
if dname.get('version'):
version = dname.get('version')
if dname.get('extrainfo'):
extrainfo = dname.get('extrainfo')
if dname.get('conf'):
conf = dname.get('conf')
if dname.get('tunnel'):
tunnel = dname.get('tunnel')
for dcpe in dname.findall('cpe'):
cpe = dcpe.text
# store everything
if not proto in list(scan_result['scan'][host].keys()):
scan_result['scan'][host][proto] = {}
scan_result['scan'][host][proto][port] = {'state': state,
'reason': reason,
'name': name,
'product': product,
'version': version,
'extrainfo': extrainfo,
'conf': conf,
'tunnel':tunnel,
'cpe': cpe}
for targetHost in scanner.all_hosts():
if scanner[targetHost].state() == 'up' and scanner[targetHost]['tcp']:
for targetport in scanner[targetHost]['tcp']:
#print(scanner[targetHost]['tcp'][int(targetport)])
if scanner[targetHost]['tcp'][int(targetport)]['state'] == 'open' and scanner[targetHost]['tcp'][int(targetport)]['product']!='tcpwrapped':
if scanner[targetHost]['tcp'][int(targetport)]['name']=='http' and scanner[targetHost]['tcp'][int(targetport)]['tunnel'] == 'ssl':
scanner[targetHost]['tcp'][int(targetport)]['name'] = 'https'
else:
scanner[targetHost]['tcp'][int(targetport)]['name'] = scanner[targetHost]['tcp'][int(targetport)]['name']
print(domain+'\t'+targetHosts+'\t'+str(targetport) + '\t' + scanner[targetHost]['tcp'][int(targetport)]['name'] + '\t' + scanner[targetHost]['tcp'][int(targetport)]['product']+scanner[targetHost]['tcp'][int(targetport)]['version'])
#if scanner[targetHost]['tcp'][int(targetport)]['name'] in ["https","http"]: