В настоящее время мне поручено автоматизировать Nessus.
В то время как почти все работает нормально, я кусаю камень, работая с этим вызовом (из API-DOCU):
Request
HTTP Request
POST /scans/{scan_id}/launch
Parameters
scan_id integer The id of the scan to launch.
alt_targets array If specified, these targets will be scanned instead of the default. Value can be an array where each index is a target, or an array with a single index of comma separated targets.
Response
Status Code Description
200 Returned if the scan was successfully launched.
403 Returned if the scan is disabled.
404 Returned if the scan does not exist.
я проверил вызов(ы) с помощью CURL, который отлично работает:
curl -X POST -H 'X-Cookie: token=db565871198eec7fd9569dd1e3ffb8b2a60f757329749bc5' -H 'Content-Type:application/json' --data '{"scan_id":"21", "alt_targets":[127.0.0.1]}' -k "https://nessusServer:8834/scans/21/launch"
... который возвращает предполагаемый результат:
{"scan_uuid":"06c4aed8-ee64-c44e-9800-f6aeed1ba94fab8b2ed9c1033626"}
Теперь к сути проблемы: делаем то же самое на Java!
Я получаю следующее:
java.io.IOException: Server returned HTTP response code: 400 for URL: https://nessusServer:8834/scans/21/launch
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at sun.net.www.protocol.http.HttpURLConnection$10.run(HttpURLConnection.java:1890)
at sun.net.www.protocol.http.HttpURLConnection$10.run(HttpURLConnection.java:1885)
at java.security.AccessController.doPrivileged(Native Method)
at sun.net.www.protocol.http.HttpURLConnection.getChainedException(HttpURLConnection.java:1884)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1457)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1441)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:254)
at at.bachmann.se.security.NessusAPI.postRequest(NessusAPI.java:466)
мой метод postRequest выглядит так (и работает с другими вызовами!):
/**
* Sends a post Request
*
* @param urlPathAdditional
* .. the added part of the path (e.g. /scans/{scanID} )
* @param headers
* .. Map<String, String> the Request Properties
*
* @return Response ... Response-Clazz containing String and Code
* @throws UnsupportedEncodingException
*/
public Response postRequest(String urlPathAdditional, Map<String, String> headers) throws Exception {
System.out.println("postRequest()......");
StringJoiner sj = new StringJoiner("&");
for (Map.Entry<String, String> entry : headers.entrySet())
sj.add(URLEncoder.encode(entry.getKey(), "UTF-8") + "=" + URLEncoder.encode(entry.getValue(), "UTF-8"));
String postData = sj.toString();
System.out.println("postData: " + sj.toString());
URL obj;
HttpsURLConnection con = null;
try {
obj = new URL(apiUrl + urlPathAdditional);
con = (HttpsURLConnection) obj.openConnection();
TrustModifier.relaxHostChecking(con); // here's where the magic happens: SSL is overrated! :)
con.setRequestMethod("POST");
} catch (KeyManagementException | NoSuchAlgorithmException | KeyStoreException |IOException e1) {
e1.printStackTrace();
}
//con.setRequestProperty("Content-Type", "application/json");
con.setRequestProperty("User-Agent", USER_AGENT);
con.setRequestProperty("Accept-Language", "en-US,en;q=0.5");
//con.setRequestProperty("Charset", "UTF-8");
//con.setRequestProperty("Content-Length", Integer.toString(postData.length()));
con.setRequestProperty("X-Cookie", "token=" + token);
con.setDoOutput(true);
int respCode = 0;
/* Send post request */
try {
DataOutputStream wr = new DataOutputStream(con.getOutputStream());
wr.writeBytes(postData);
wr.flush();
wr.close();
} catch (IOException e) {
e.printStackTrace();
}
respCode = con.getResponseCode();
/* read response */
BufferedReader in = new BufferedReader(
new InputStreamReader(con.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
return new Response(response.toString(), respCode);
}
... теперь я подозреваю, что вывод postData: alt_targets=%27127.0.0.1%27&scan_id=21
недействителен. Хотя я понятия не имею (и Интернет дает удивительно мало информации) о том, что такое «массив» в контексте запроса POST и как он кодируется в POST. В CURL это работает отлично, а в Java - нет, несмотря на то, что этот метод подходит для других вызовов API (создание сеансов и получение токена работает с тем же методом).
Вот вызывающая часть кода:
/* at this point the server is ready */
/* so we need to get the ID of the scan-name we want to launch */
int scanId = getScanIdForName(terminalOrM1 + scanType);
/* Scanner is Ready for a new Scan! */
// 200 Returned if the scan was successfully launched.
// 403 Returned if the scan is disabled.
// 404 Returned if the scan does not exist.
String query = "scans/" + scanId + "/launch";
String targets = "\'" + ip + "\'"; // <= DOESN'T WORK
//String target = ip; // DOESN'T WORK EITHER -- so what does?
//String target = "[" + ip + "]"; // NO WORK
Map<String, String> headers = new HashMap<>();
headers.put("alt_targets", targets);
headers.put("scan_id", String.valueOf(scanId));
/* launch it! */
Response respLaunch = null;
try {
respLaunch = postRequest(query, headers);
} catch (Exception e) {
e.printStackTrace();
}
API-Docu тоже мало помогает, как вы можете видеть выше.
Вопросы:
- как правильно отправить значения «массива» в запросе POST?
- как я могу увидеть/отладить/проверить, что на самом деле отправлено/как выглядит POST?
- как исправить мой скрипт?
Благодарю вас!