-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathQualysManageAuth.py
185 lines (154 loc) · 6.53 KB
/
QualysManageAuth.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
'''
Qualys API Authenitcation Management
Author Siggi Bjarnason Copyright 2018
Website http://www.ipcalc.us/ and http://www.icecomputing.com
Description:
This is script where I start to explore Qualys API calls, parsing the XML responses, etc.
Following packages need to be installed as administrator
pip install requests
pip install xmltodict
'''
# Import libraries
import sys
import requests
import os
import string
import time
import xmltodict
import urllib.parse as urlparse
import subprocess as proc
# End imports
dictParams = {}
#
# Begin User Input: Make changes to this section as needed. To disable an line not needed put # in front of it.
#
strSystemType = "windows" # Requires unix, windows or other qualys authentication system types. Cisco and Checkpoint not supported at this time.
dictParams["action"] = "update" #required to be create, update or delete
dictParams["ips"] = "10.93.120.248" # IP address list. Required for create, optional for update, not valid for delete. Has to be unique when provided
dictParams["username"] = "MyTest" # Username. Required for create, optional for update, not valid for delete.
dictParams["password"] = "qawerewrqwert" # Password. Required for create, optional for update, not valid for delete.
dictParams["title"] = "Siggi's API Auth Windows Test #3" # Authentication title. Required for create, optional for update, not valid for delete. Has to be unique when provided
dictParams["ids"] = "130657" # Authentication profile ID, required for update and delete, not valid for create
#
#End User Input: Any changes below this line will either break the script or change how it operates. Proceed with caution.
#
print ("This is a Qualys API Sample script. This is running under Python Version {0}.{1}.{2}".format(sys.version_info[0],sys.version_info[1],sys.version_info[2]))
now = time.asctime()
print ("The time now is {}".format(now))
strConf_File = "QualysAPI.ini"
strMethod = "post"
strAPIFunction = "api/2.0/fo/auth/" + strSystemType
if os.path.isfile(strConf_File):
print ("Configuration File exists")
else:
print ("Can't find configuration file {}, make sure it is the same directory as this script".format(strConf_File))
sys.exit(4)
strLine = " "
print ("Reading in configuration")
objINIFile = open(strConf_File,"r")
strLines = objINIFile.readlines()
objINIFile.close()
for strLine in strLines:
strLine = strLine.strip()
if "=" in strLine:
strConfParts = strLine.split("=")
if strConfParts[0] == "APIBaseURL":
strBaseURL = strConfParts[1]
if strConfParts[0] == "APIRequestHeader":
strHeadReq = strConfParts[1]
if strConfParts[0] == "QUserID":
strUserName = strConfParts[1]
if strConfParts[0] == "QUserPWD":
strPWD = strConfParts[1]
if strConfParts[0] == "SaveLocation":
strSavePath = strConfParts[1]
print ("calculating stuff ...")
strHeader={'X-Requested-With': strHeadReq}
if strBaseURL[-1:] != "/":
strBaseURL += "/"
if strAPIFunction[-1:] != "/":
strAPIFunction += "/"
if strSavePath[-1:] != "\\":
strSavePath += "\\"
def MakeAPICall (strURL, strHeader, strUserName,strPWD, strMethod):
iErrCode = ""
strErrText = ""
print ("Doing a {} to URL: \n{}\n".format(strMethod,strURL))
try:
if strMethod.lower() == "get":
WebRequest = requests.get(strURL, headers=strHeader, auth=(strUserName, strPWD))
print ("get executed")
if strMethod.lower() == "post":
WebRequest = requests.post(strURL, headers=strHeader, auth=(strUserName, strPWD))
print ("post executed")
except Exception as err:
print ("Issue with API call. {}".format(err))
raise
sys.exit(7)
if isinstance(WebRequest,requests.models.Response)==False:
print ("response is unknown type")
sys.exit(5)
# end if
print ("call resulted in status code {}".format(WebRequest.status_code))
dictResponse = xmltodict.parse(WebRequest.text)
if isinstance(dictResponse,dict):
if "SIMPLE_RETURN" in dictResponse:
try:
if "CODE" in dictResponse["SIMPLE_RETURN"]["RESPONSE"]:
iErrCode = dictResponse["SIMPLE_RETURN"]["RESPONSE"]["CODE"]
strErrText = dictResponse["SIMPLE_RETURN"]["RESPONSE"]["TEXT"][:-1]
except KeyError as e:
print ("KeyError: {}".format(e))
print (WebRequest.text)
iErrCode = "Unknown"
strErrText = "Unexpected error"
if "BATCH_RETURN" in dictResponse:
if "CODE" in dictResponse["BATCH_RETURN"]["RESPONSE"]["BATCH_LIST"]["BATCH"] :
iErrCode = dictResponse["BATCH_RETURN"]["RESPONSE"]["BATCH_LIST"]["BATCH"]["CODE"]
strErrText = dictResponse["BATCH_RETURN"]["RESPONSE"]["BATCH_LIST"]["BATCH"]["TEXT"][:-1]
else:
print ("Response not a dictionary")
sys.exit(8)
if iErrCode == "1920" :
tmpErrStr = ""
dictTemp = {}
strErrParts = strErrText.splitlines()
# errResponse = {"Failure":{"errCode":iErrCode,"errText":strErrParts[0]+"\n"+strErrParts[1]}}
# print (strErrParts[0]+"\n"+strErrParts[1])
for strErrPart in strErrParts:
iLoc = strErrPart.find(" is used by ")
if iLoc > 8:
strIPAddr = strErrPart[5:iLoc]
strAuthName = strErrPart[iLoc+12:]
dictTemp[strIPAddr]=strAuthName
# print ("{} : {}".format(strIPAddr,strAuthName))
else:
# print (strErrPart)
tmpErrStr += strErrPart + "\n"
if len(dictTemp) > 0:
return {"Failure":{"errCode":iErrCode,"errText":tmpErrStr,"IP_List":dictTemp}}
else:
return {"Failure":{"errCode":iErrCode,"errText":tmpErrStr}}
if iErrCode != "" or WebRequest.status_code !=200:
return "There was a problem with your request. HTTP error {} code {} {}".format(WebRequest.status_code,iErrCode,strErrText)
else:
return dictResponse
strListScans = urlparse.urlencode(dictParams)
strURL = strBaseURL + strAPIFunction +"?" + strListScans
APIResponse = MakeAPICall(strURL,strHeader,strUserName,strPWD,strMethod)
if isinstance(APIResponse,str):
print(APIResponse)
if isinstance(APIResponse,dict):
if "Failure" in APIResponse:
print ("Unexpected issue occured.\nCode: {}\n{}".format(APIResponse["Failure"]["errCode"],APIResponse["Failure"]["errText"]))
if "IP_List" in APIResponse["Failure"]:
for strIPKey in APIResponse["Failure"]["IP_List"]:
print ("{} uses {}".format(APIResponse["Failure"]["IP_List"][strIPKey],strIPKey))
if "BATCH_RETURN" in APIResponse:
if "BATCH_LIST" in APIResponse["BATCH_RETURN"]["RESPONSE"]:
if "TEXT" in APIResponse["BATCH_RETURN"]["RESPONSE"]["BATCH_LIST"]["BATCH"] :
print ("{}".format(APIResponse["BATCH_RETURN"]["RESPONSE"]["BATCH_LIST"]["BATCH"]["TEXT"]))
if "ID" in APIResponse["BATCH_RETURN"]["RESPONSE"]["BATCH_LIST"]["BATCH"]["ID_SET"] :
print ("ID: {}".format(APIResponse["BATCH_RETURN"]["RESPONSE"]["BATCH_LIST"]["BATCH"]["ID_SET"]["ID"]))
else:
print ("No records")