Nessus RESTful API - Java 实施问题 POST

Nessus RESTful API - Java Problems implementing POST

我目前的任务是为 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.run(HttpURLConnection.java:1890)
    at sun.net.www.protocol.http.HttpURLConnection.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 无效。 尽管我不知道(并且互联网提供的信息少得惊人)关于 "array" 在 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 也没有太大帮助,正如您在上面看到的那样。

问题:

谢谢!

我终于修好了!

问题出在我作为负载发送的数据字符串的格式上。它没有记录,但 API 仅适用于 JSON-Requests。巧合的是,我的第一个 POST-Request ( /session ) 有效 JSON,而第二个 ( /scans/{id}/launch) 无效。

所以做有效的 JSON 作为 POST 数据有效负载就成功了:

    String query = "scans/" + scanId + "/launch";
    String launchJson = "{\"scan_id\":\"" +String.valueOf(scanId) + "\", \"alt_targets\":[\"" + ip +"\"]}";

    /* launch it! */
    Response respLaunch = null;
    try {
        respLaunch = postRequest(query, launchJson);
    } catch (Exception e) {
        e.printStackTrace();
    }

...这会导致有效的 JSON POST 数据有效负载:{"scan_id":"21", "alt_targets":["127.0.0.1"]}

...而不是旧的:scan_id=21&alt_targets=[10.208.65.226]