使用 Python Selenium 抓取 NetGear 交换机 GS752TPP 信息

问题描述 投票:0回答:2

我在一个项目中使用型号为 GS752TPP 的 NetGear 交换机。该模型能够提供以太网供电,我想通过网络界面自动抓取该信息,因为没有可用的 API。我需要连接设备随着时间的推移的功耗。请参阅以下图片以获得更好的理解:NetGear Switch Power Monitoring Table

pynetgear Python 脚本不适用于我的模型。

我正在使用 Python Selenium 打开无头 Firefox 来访问网络界面。我可以将密码发送到相应的字段,登录并单击右侧选项卡(见下面的代码)。我可以看到表中的数据,但在 HTML 中不可见。我无法通过 CSS 或 xpath 访问这些字段。为了找到正确的 CSS 或 xpath,我使用了 Firefox 的 Selenium IDE 插件。

检查网站网络后,我找到了正确的请求,它返回了我需要的数据:

网址

https://<ip_address>/cgi/get.cgi?cmd=poe_port&dummy=1612446184975&bj4=07e0349a9b364bf17177eafe167deaa6

卷曲

curl 'https://<ip_address>/cgi/get.cgi?cmd=poe_port&dummy=1612446184975&bj4=07e0349a9b364bf17177eafe167deaa6' -H 'User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:85.0) Gecko/20100101 Firefox/85.0' -H 'Accept: application/json, text/javascript, */*; q=0.01' -H 'Accept-Language: en-US,en;q=0.5' --compressed -H 'X-CSRF-XSID: xZTyso9GzNQ5sMRarzmkCSJQAssA1WLUlk0Q5cwdPStiUJb0KlE+92EkFgVgroCVlMuOjcR8Rk6EIYCixMl53z+dCunTYwWs0Z76er0EvZPiSGIjCUtYi3BV0VS0OLq6sA32EIPfSDBE/xE5xa/3Uzovxo6Sc8OodurgbgxWGoE=' -H 'X-Requested-With: XMLHttpRequest' -H 'Connection: keep-alive' -H 'Referer: https://<ip_address>/html/sys_poe_port.html?aj4=2a08be6&bj4=9fa58c963a822462157cbfc45f82c702' -H 'Cookie: testcookie; cookie_language=defLang'

NetGear 使用 X-CSRF 令牌来更安全地抵御攻击。 This 大致描述了那是什么。所以我假设我需要以下内容来重新创建 URL:

  1. cmd=poe_port&dummy=
    之后的价值(每个新会话都有机会)
  2. X-CRSF-XSID 令牌(不幸的是,cookie 中没有此令牌)

我是否必须自己在 Selenium 中运行任何 Javascript 或者如何自动下载功耗?
非常感谢任何帮助,我将为您提供任何缺失的信息。

谢谢和问候,
René

访问 NetGear Web 界面直至数据导出的代码。

from selenium import webdriver
from selenium.webdriver.common.by import By
profile = webdriver.FirefoxProfile()
profile.accept_untrusted_certs = True
options = webdriver.FirefoxOptions()
options.headless = True
driver = webdriver.Firefox(executable_path="/home/ubuntu/geckodriver", firefox_options=options, firefox_profile=profile)
driver.get("https://<ip_address>")
driver.find_element(By.ID, "password").send_keys(<password>)
driver.find_element(By.ID, "local_login").click()
driver.find_element(By.ID, "menu_fld2SysPoE").click()
driver.find_element(By.ID, "menu_fldAdv").click()
driver.find_element(By.ID, "menu_doc4SysPoEPort").click()

更新我

在 Raspberry Pi 上安装 npm 后,我安装了来自 Taisuke Yamada 的

gs310tp
包。您可以在这里找到该包。然后用
.node_modules/gs310tp/bin/gs310tp.js -u https://<ip_address< -p <password> poe status
运行它。然而,这会产生错误
(node:444693) UnhandledPromiseRejectionWarning: Error: self signed certificate
。要禁用此消息,可以先运行
export NODE_TLS_REJECT_UNAUTHORIZED='0'
。但请注意,这会降低安全性。

一个包含 Javascript 的简单 Python 脚本如下所示

import subprocess
import re

p = subprocess.Popen(["./gs310tp.js", "-u https://ip", "-p SecurePassword", "poe", "status"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
p.wait()

out, err = p.communicate()
out = bytes.decode(out)  # Convert from byte to string
# Conversion from string to dict is quite tricky and I dont need that so I used regex instead

out = out.replace('"', '')
out = out.replace("'", "")
voltage = re.findall("voltage: \d+", out)
ampere = re.findall("amphere: \d+", out)
power = re.findall("power: \d+", out)
python selenium networking router
2个回答
1
投票

我最近对 NetGear GS310TP PoE 交换机进行了相同的自动化。 它使用“get.cgi”和“set.cgi”对进行管理,就像您的模型一样,因此两个模型可能共享相同的保护方法。

获取 X-CSRF-XSID 的密钥:是一个有点复杂的过程。

您首先必须在提交正确密码(到 cmd=home_loginAuth API)后几秒钟,使用 API(cmd=home_loginStatus API)获取一次性临时密钥。该密钥只能获取一次,如果多次获取将使身份验证状态无效。

这个临时密钥包含 2(或 3)个东西:

  1. 前 32 个字节:生成 X-CSRF-XSID 所需的未加密令牌:
  2. 接下来的5个字节:RSA公钥数据(“e”参数)
  3. 剩余字节:RSA公钥数据(“n”参数)

使用一些兼容的 RSA 库,使用给定的 RSA 密钥加密以上 32 字节令牌。对结果进行 Base64 编码并将其设置为 X-CSRF-XSID: header,我就可以开始了。

进行“兼容”加密需要一些时间,并且 openssl 不适合我。我最终从 GS310TP 中获取实际的 JavaScript 文件(rsa.js 及其依赖项)并使用 nodejs 在本地运行它。

GS310TP 还使用“aj4=”、“dummy=”和“bj4=”进行棘手的查询参数验证,但解决方法非常容易,因为您只需重放捕获的字符串或设置 URL 参数的 MD5 哈希值并将其附加即可作为“bj4=”参数。

我确实有工作代码,但无法共享,因为它目前具有我无法透露的硬编码参数。我希望这个描述足以让您继续前进!


0
投票

我正在向上面 Taisuke Yamada 提供的答案添加代码。

我花了一些时间使用 .Net

RSACryptoServiceProvider
进行加密才能完成这项工作。主要问题是 Netgear 单元返回的临时密钥
sess
的值需要进一步从 Base64 字符串以及十六进制字符串解密为字节数组。关键是“e”参数应该是十六进制的 {1, 0, 1} 或 10001 的字节数组。在对 UI 进行逆向工程时,他们使用 JavaScript RSAKey() 函数,该函数具有 .setPublic(n, e) 方法,该方法接受十六进制字符串形式的值。 .Net 方法需要字节数组。

var responseString = "...";
var jsonData = (JObject)JsonConvert.DeserializeObject(responseString);
var sess = jsonData.SelectToken("data.sess").Value<string>();
var data = Convert.FromBase64String(sess);
var decodedSess = Encoding.ASCII.GetString(data);

var tabid = decodedSess.Substring(0, 32);
var rsa_exponent = decodedSess.Substring(32, 5);
var rsa_modulus = decodedSess.Substring(37, decodedSesss.Length - 37);

string csrfHeader = "";
using (var rsa = new RSACryptoServiceProvider())
{
    var param = new RSAParameters()
    {
        Modulus = rsa_modulus.StringToByteArray(),
        Exponent = rsa_exponent.StringToByteArray(),
    }
    rsa.ImportParameters(param);

    var encryptedData = rsa.Encrypt(Encoding.ASCII.GetBytes(tabid), false);
    csrfHeader = Convert.ToBase64String(encryptedData);
}

client.DefaultRequestHeaders.Add("X-Csrf-Xsid", csrfHeader);
© www.soinside.com 2019 - 2024. All rights reserved.