-
-
Save sport4minus/32f2b31acaa34f1a7687de57b1cc73d7 to your computer and use it in GitHub Desktop.
| # Brennenstuhl Premium-Web-Line V3 is a socket strip with an embedded web server. | |
| # It can be switched via a web interface or using http get requests. The latter is a bit under-documented, | |
| # so here's what i found out: | |
| # The built-in server accepts only authenticated http get requests (using digest auth). | |
| # each command has its own url, like so: http://{IP-OF-THE-SOCKETSTRIP}/cgi/{commandname}?params | |
| # full list can be found in a PDF called "Premium-Web-Line V3 CGI specification.pdf" which is included in the download package of the official software: | |
| # download link -> https://www.brennenstuhl.com/index.php?module=explorer&index[explorer][action]=download&index[explorer][file]=firmware/premium-web-line-v3-software-3_3_6.zip | |
| # here's an example on how to toggle one of the two relais (nr. 0) | |
| # modified a general digest auth example from stackoverflow: https://stackoverflow.com/questions/23254013/http-digest-basic-auth-with-python-requests-module | |
| import logging | |
| import requests | |
| from requests.auth import HTTPDigestAuth | |
| try: | |
| import httplib | |
| except ImportError: | |
| import http.client as httplib | |
| httplib.HTTPConnection.debuglevel = 1 | |
| # you need to initialize logging, | |
| # otherwise you will not see anything from requests | |
| logging.basicConfig(level=logging.DEBUG) | |
| # make request | |
| url = 'http://10.0.1.118/cgi/toggleRelay?Rel=0' #Rel=1 would toggle the other relay | |
| # user / password is factory set to admin/admin - you better change this quick. | |
| r = requests.get(url, auth=HTTPDigestAuth('admin', 'admin'), | |
| timeout=10) | |
| print(r.status_code) | |
| print(r.headers) |
Thank you, very useful 👍
i also tried curl but never got the parameters right..
then python.
I would really like to how it's done though...
Yeah, curl can also do a getand a digest authentication.. But I always get a permission denied" error. Maybe I should do a Wireshark debug session to understand the difference between the python and the curl command. Would be a nice learning.
same here – if you find the time to do that, i'd be curious to hear why it fails.
I've compared the auth calls of requests and curl. I'm guessing that the http server in the BS bar has a bad implementation of the auth workflow. When using requests, it will cover for the first 401 reply and just continue. Curl on the other hand is very strict and stops properly after the 401 reply.
send: b'GET /cgi/getIpSet HTTP/1.1\r\nHost: 192.168.1.12\r\nUser-Agent: python-requests/2.31.0\r\nAccept-Encoding: gzip, deflate\r\nAccept: */*\r\nConnection: keep-alive\r\n\r\n'
reply: 'HTTP/1.1 401 Unauthorized\r\n'
header: Server: nbsoftware/1.1
header: Access-Control-Allow-Origin: *
header: WWW-Authenticate: Digest realm="Enter User/Password",qop="auth",nonce="1ad2cb12ba47519b888b2e20aeffd76c",opaque="Opaque_Test_ddd123987fe20_finish",algorithm=MD5,stale=false
header: Connection: keep-alive
header: Content-type: text/html
header: Content-Length: 755
send: b'GET /cgi/getIpSet HTTP/1.1\r\nHost: 192.168.1.12\r\nUser-Agent: python-requests/2.31.0\r\nAccept-Encoding: gzip, deflate\r\nAccept: */*\r\nConnection: keep-alive\r\nAuthorization: Digest username="admin", realm="Enter User/Password", nonce="1ad2cb12ba47519b888b2e20aeffd76c", uri="/cgi/getIpSet", response="fc157353a8d56506adb2ae8bc999e15c", opaque="Opaque_Test_ddd123987fe20_finish", algorithm="MD5", qop="auth", nc=00000001, cnonce="18778a09be6f16d4"\r\n\r\n'
reply: 'HTTP/1.1 200 OK\r\n'
header: Server: nbsoftware/1.1
header: Access-Control-Allow-Origin: *
header: Connection: keep-alive
header: Content-type: text/plain
header: Content-Length: 47
Request successful! Status: 200
Most of the time was wasted on trial and error with curl and assuming that something was broken with curl...
@martinlauer
thank you very much for the investigation - good to know the bad implementation is at the other end in this case :)
Using curl with --digest works for me:
$ curl -v --insecure --digest --user admin:$PASS "https://10.4.2.24/cgi/toggleRelay?Rel=1"
* Trying 10.4.2.24...
* TCP_NODELAY set
* Connected to 10.4.2.24 (10.4.2.24) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH
* successfully set certificate verify locations:
* CAfile: /etc/ssl/certs/ca-certificates.crt
CApath: /etc/ssl/certs
* TLSv1.2 (OUT), TLS header, Certificate Status (22):
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Request CERT (13):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Certificate (11):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Client hello (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS change cipher, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384
* ALPN, server did not agree to a protocol
* Server certificate:
* subject: CN=ws_brs; O=brennenstuhl; C=DE
* start date: Feb 1 00:00:00 2021 GMT
* expire date: Dec 31 00:00:00 2024 GMT
* issuer: CN=ws_brs; O=brennenstuhl; C=DE
* SSL certificate verify result: self signed certificate (18), continuing anyway.
* Server auth using Digest with user 'admin'
> GET /cgi/toggleRelay?Rel=1 HTTP/1.1
> Host: 10.4.2.24
> User-Agent: curl/7.52.1
> Accept: */*
>
< HTTP/1.1 401 Unauthorized
< Server: nbsoftware/1.1
< Access-Control-Allow-Origin: *
< WWW-Authenticate: Digest realm="Enter User/Password",qop="auth",nonce="65a1c5a32484549eff860456e58bd940",opaque="Opaque_Test_ddd123987fe20_finish",algorithm=MD5,stale=false
< Content-type: text/html
< Content-Length: 730
<
* Ignoring the response-body
* Curl_http_done: called premature == 0
* Connection #0 to host 10.4.2.24 left intact
* Issue another request to this URL: 'https://10.4.2.24/cgi/toggleRelay?Rel=1'
* Found bundle for host 10.4.2.24: 0x55fc973a8820 [can pipeline]
* Re-using existing connection! (#0) with host 10.4.2.24
* Connected to 10.4.2.24 (10.4.2.24) port 443 (#0)
* Server auth using Digest with user 'admin'
> GET /cgi/toggleRelay?Rel=1 HTTP/1.1
> Host: 10.4.2.24
> Authorization: Digest username="admin", realm="Enter User/Password", nonce="65a1c5a32484549eff860456e58bd940", uri="/cgi/toggleRelay?Rel=1", cnonce="OGM3OGExMjVkNTZlMzg0ZGMwMjUxNjliMGMxM2ExN2E=", nc=00000001, qop=auth, response="429989a05c5f10b96ae400da19be4118", opaque="Opaque_Test_ddd123987fe20_finish", algorithm="MD5"
> User-Agent: curl/7.52.1
> Accept: */*
>
* SSL read: error:00000000:lib(0):func(0):reason(0), errno 104
* Connection died, retrying a fresh connect
* Curl_http_done: called premature == 0
* Closing connection 0
* Issue another request to this URL: 'https://10.4.2.24/cgi/toggleRelay?Rel=1'
* Hostname 10.4.2.24 was found in DNS cache
* Trying 10.4.2.24...
* TCP_NODELAY set
* Connected to 10.4.2.24 (10.4.2.24) port 443 (#1)
* ALPN, offering h2
* ALPN, offering http/1.1
* Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH
* successfully set certificate verify locations:
* CAfile: /etc/ssl/certs/ca-certificates.crt
CApath: /etc/ssl/certs
* SSL re-using session ID
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS change cipher, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* TLSv1.2 (OUT), TLS change cipher, Client hello (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384
* ALPN, server did not agree to a protocol
* Server certificate:
* subject: CN=ws_brs; O=brennenstuhl; C=DE
* start date: Feb 1 00:00:00 2021 GMT
* expire date: Dec 31 00:00:00 2024 GMT
* issuer: CN=ws_brs; O=brennenstuhl; C=DE
* SSL certificate verify result: self signed certificate (18), continuing anyway.
* Server auth using Digest with user 'admin'
> GET /cgi/toggleRelay?Rel=1 HTTP/1.1
> Host: 10.4.2.24
> Authorization: Digest username="admin", realm="Enter User/Password", nonce="65a1c5a32484549eff860456e58bd940", uri="/cgi/toggleRelay?Rel=1", cnonce="OGM3OGExMjVkNTZlMzg0ZGMwMjUxNjliMGMxM2ExN2E=", nc=00000002, qop=auth, response="86ad0087d5c0411ea80c9f24b67d08ce", opaque="Opaque_Test_ddd123987fe20_finish", algorithm="MD5"
> User-Agent: curl/7.52.1
> Accept: */*
>
< HTTP/1.1 200 OK
< Server: nbsoftware/1.1
< Access-Control-Allow-Origin: *
< Content-type: text/plain
< Content-Length: 0
<
* Curl_http_done: called premature == 0
* Connection #1 to host 10.4.2.24 left intact
@chwdt ooooh interesting.
might the --insecure flag be the key to success?
i'll try next time i am near the device.
@sport4minus No, I need --insecure because I use https, and the device uses a self-signed certificate.
i see, missed the 's' :)
Great! Thankyou! I always tried the same via
curlbut that does not work. Foreverboy searching a one-liner:python3 -c "import requests; r = requests.get('http://192.168.0.12/cgi/toggleRelay?Rel=0', auth=requests.auth.HTTPDigestAuth('admin', 'admin'), timeout=10); print(r.status_code)"