[Python] naar [PHP] inloggen op een XMPP server

Pagina: 1
Acties:

Onderwerpen

Vraag


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Beste Tweakers,

In mijn vorige topic ben ik geholpen om over de eerste drempel te komen van de weg naar communicatie met mijn Ecovacs Deebot robot zuiger. Hier had ik problemen met het nabouwen van de authSign en later bleek er ook nog wat mis met de X509 en RSA. Nu dat allemaal goed loopt ben ik in staat de 3 stappen voor het verkrijgen van de XMPP (of Jabber) sleutel te doorlopen. Maar het lukt me alleen nog niet om echt in te loggen op de XMPP servers van Ecovacs...

Mijn functie voor het sturen van een commando tot nu toe: [link]
PHP:
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
function EcoVacsXMPP_SendCommand($XMPP, $robotNr, $command) {
    $set['server']      = 'msg-'.$XMPP['continent'].'.ecouser.net';     //'msg-'.$glb_continent.'.ecouser.net';
    $set['port']        = 5223;
    $set['username']    = $XMPP['username'];            //sucks      DEBUG    username used to login: 201802265a9437ee73aa7@ecouser.net
    $set['password']    = $XMPP['password'];            //sucks      DEBUG    password used to login: 0/372d00ce/glcSomethingTBbzoppbndSRpTflNTpk1gDCAYLQv
    $set['resource']    = $XMPP['resource'];
    $set['domain']      = $XMPP['domain'];
    $set['vacAddr']     = $XMPP['robot'][$robotNr];     //self.vacuum['did'] + '@' + self.vacuum['class'] + '.ecorobot.net/atom'
    
    print_r($set);
    
    // Send:
    $conn = new XMPPHP_XMPP($set['server'], $set['port'], $set['username'], $set['password'], $set['resource'], $set['domain'], $printlog = true, $loglevel = XMPPHP_Log::LEVEL_VERBOSE);
    $conn->useEncryption(true);
    try {
        echo "connect() start
";
        $conn->connect();
        echo "processUntil() start
";
        $conn->processUntil(array('session_start'));
        echo "presence() start
";
        $conn->presence();
        $conn->message($set['vacAddr'], '<query xmlns="com:ctl"><ctl td="GetChargeState" />');
        $conn->disconnect();
    } catch (XMPPHP_Exception $e) {
        die($e->getMessage());
    }
    
    return; // tijdelijk tot ik kan inloggen
    
    // Receive Answer
    $conn = new XMPPHP_XMPP($set['server'], $set['port'], $set['username'], $set['password'], $set['resource'], $set['domain'], $printlog = true, $loglevel = XMPPHP_Log::LEVEL_VERBOSE);
    //$conn = new XMPPHP_XMPP('talk.google.com', 5222, 'username', 'password', 'xmpphp', 'gmail.com', $printlog=true, $loglevel=XMPPHP_Log::LEVEL_INFO);
    $conn->autoSubscribe();
    $vcard_request = array();
    try {
        $conn->connect();
        while(!$conn->isDisconnected()) {
            $payloads = $conn->processUntil(array('message', 'presence', 'end_stream', 'session_start', 'vcard'));
            foreach($payloads as $event) {
                $pl = $event[1];
                print_r($pl);
                }
            }
    } catch(XMPPHP_Exception $e) {
        die($e->getMessage());
    }
}


Als ik dit met mijn test code er door rammel:
PHP:
35
36
37
38
39
40
41
42
43
44
45
46
47
48
EcoVacsHTTPS_Login($meta);
//print_r($meta);
echo $meta['accessToken'].'
';
EcoVacsHTTPS_getAuthCode($meta);
echo $meta['authCode'].'
';
EcoVacsHTTPS_loginByItToken($meta);
echo $meta['token'].'
';
$XMPP = json_encode(EcoVacsHTTPS_GetDeviceList($meta));
print_r($XMPP);

EcoVacsXMPP_SendCommand2($XMPP, 0, '');
>>> Output:
0ed6edc2a12a716381650c81xxxxxxxx
nl_e096aadd525f3d563afb6f0bxxxxxxxx
BDNvqleD3MMiEtm5hu7pRxkhxxxxxxxx
Array
(
[username] => 201802265a9437ee73aa7@ecouser.net
[password] => 0/a42ad27c/BDNvqleD3MMiEtm5hu7pRxkhxxxxxxxx
[continent] => eu
[resource] => a42axxxx
[domain] => ecouser.net
[robot] => Array
(
[0] => E00010914176xxxxxxxx@107.ecorobot.net/atom
)

)
Array
(
[server] => msg-eu.ecouser.net
[port] => 5223
[username] => 201802265a9437ee73aa7@ecouser.net
[password] => 0/a42ad27c/BDNvqleD3MMiEtm5hu7pRxkhxxxxxxxx
[resource] => a42axxxx
[domain] => ecouser.net
[vacAddr] => E00010914176xxxxxxxxx@107.ecorobot.net/atom
)
connect() start
1534616596 [INFO]: Connecting to tcp://msg-eu.ecouser.net:5223
1534616597 [VERBOSE]: Socket is ready; send it.
1534616597 [VERBOSE]: SENT:
1534616597 [VERBOSE]: Successfully sent 116 bytes.
processUntil() start
1534616597 [VERBOSE]: RECV:
1534616597 [VERBOSE]: RECV: PLAIN
1534616597 [DEBUG]: Calling features_handler
1534616597 [INFO]: Attempting Auth...
1534616597 [INFO]: Trying PLAIN (available : PLAIN)
1534616597 [VERBOSE]: Socket is ready; send it.
1534616597 [VERBOSE]: SENT: ADIwMTgwMjI2NWE5NDM3ZWU3M2FhN0BlY291c2VyLm5ldAAwL2E0MmFkMjdjL0JETnZxbGVEM01NaUV0bTVodTdwUnhraGV1bTlMUm53
1534616597 [VERBOSE]: Successfully sent 176 bytes.
1534616597 [VERBOSE]: RECV: auth error
1534616597 [DEBUG]: Calling sasl_failure_handler
1534616597 [ERROR]: Auth failed!
1534616597 [VERBOSE]: Disconnecting...
1534616597 [VERBOSE]: Socket is ready; send it.
1534616597 [VERBOSE]: SENT:
1534616597 [VERBOSE]: Successfully sent 16 bytes.
1534616597 [VERBOSE]: RECV:
Auth failed!


Ik probeer de code van wpietri (wpietri/sucks te gebruiken voor het bouwen van een IP-Symcon module voor deze stofzuigers. Ik probeer om in het XMPP deel van de code debug outputs in te bouwen om te zien wat er nou precies gebeurt. Maar volgens mij moet ik in dit geval echt de sleekxmpp lib in om dit zichtbaar te maken. Voor de XMPP in mijn php code gebruik ik XMPPHP en ik draai dit alles weg met PHP 7.2

Ik heb een test VM aan gemaakt met de "Sucks" code erop om het eens met wireshark te bekijken maar verder als de eerste twee handshakes kom ik niet omdat de rest encrypted is.

Iemand een idee hoe ik dit verder kan reversed engineren? Of heeft er iemand een idee wat er in mijn code fout gaat? Als ik alleen al in staat ben om de rouwe tekst uit die XMPP te trekken dan kan ik er zelf wel wat omheen bouwen.

Groeten Martijn

Beste antwoord (via Verwijderd op 21-08-2018 16:52)


  • DJMaze
  • Registratie: Juni 2002
  • Niet online
Verwijderd schreef op maandag 20 augustus 2018 @ 23:24:
Ook heb ik de plain functie in fabiang geprobeerd met en zonder de authzid toevoeging. Maar ik blijf "auth error" als response krijgen.
Dan is er iets mis op de XMPP Server en niet op je Client.

De fablang log zou iets moeten vertellen. Hier meer info: https://xmpp.org/rfcs/rfc6120.html#sasl-errors
En voor de oude: https://tools.ietf.org/html/rfc3920#section-6.4

[ Voor 7% gewijzigd door DJMaze op 20-08-2018 23:55 ]

Maak je niet druk, dat doet de compressor maar

Alle reacties


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Ik ben onder tussen wat verder. SleekXMPP welke gebruikt wordt door de code van wpietri om te communiceren handelt de opbouw username/password string anders af dan XMPPHP:
SleekXMPP:
Python:
76
77
78
79
authzid = self.credentials['authzid']
authcid = self.credentials['username']
password = self.credentials['password']
return authzid + b'\x00' + authcid + b'\x00' + password


XMPPHP:
PHP:
359
$this->send("<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='PLAIN'>" . base64_encode("\x00" . $this->user . "\x00" . $this->password) . "</auth>");


En laat deze authzid nou gedefineerd zijn in de code van wpietri [link]:
Python:
428
self.credentials['authzid'] = user

Zonder de @ecouser.net dus.

Ik snap alleen nog niet helemaal wat die base64_encode() daar nou doet in de XMPPHP... deze zie ik zo 123 nog niet terug in de SleekXMPP library.
Iemand hier nog een idee over?

Groet Martijn

Acties:
  • +1 Henk 'm!

  • DJMaze
  • Registratie: Juni 2002
  • Niet online
Ik heb maanden geleden nog een XMPP implementatie gemaakt in PHP.
Misschien heb je er wat aan als voorbeeld: https://bitbucket.org/djm...e/poodle/xmpp/?at=default

Daarin zie je in /extensions/sasl.php het login gedeelte.
Zoals je merkt werkt inloggen in XMPP d.m.v. SASL en doe je dat inderdaad met een base64 encoded string.

Ik denk eerder dat je probleem de oude XMPPHP library is. XMPP is namelijk tegenwoordig een stuk geavanceerder.
Probeer het eens met https://github.com/fabiang/xmpp

@mdiks P.S. ik bedenk nu net dat ik misschien weet waar je de mist in bent gegaan met het vorige topic.
Zie:
- RFC 3923
- XEP-0188
- XEP-0200
- XEP-0380
- XEP-0384

[ Voor 28% gewijzigd door DJMaze op 20-08-2018 15:03 ]

Maak je niet druk, dat doet de compressor maar


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
DJMaze schreef op maandag 20 augustus 2018 @ 12:01:
@mdiks P.S. ik bedenk nu net dat ik misschien weet waar je de mist in bent gegaan met het vorige topic.
Zie:
- RFC 3923
- XEP-0188
- XEP-0200
- XEP-0380
- XEP-0384
Bedankt voor de info... Ik zie zelf nog niet helemaal de link. Het is hobby maar mijn vrouw klaagt nu al ;) Even zonder gein, als ik de grote "puzzel" heb opgelost dan ga ik wel kijken of ik dingen mooier/lochiser kan maken, maar ik wil altijd eerst eerst resultaat.
Ik heb je laatste voorbeeldje nog wel geprobeerd. Helaas wou dit niet.
DJMaze schreef op maandag 20 augustus 2018 @ 12:01:
Ik heb maanden geleden nog een XMPP implementatie gemaakt in PHP.
Misschien heb je er wat aan als voorbeeld: https://bitbucket.org/djm...e/poodle/xmpp/?at=default

Daarin zie je in /extensions/sasl.php het login gedeelte.
Zoals je merkt werkt inloggen in XMPP d.m.v. SASL en doe je dat inderdaad met een base64 encoded string.

Ik denk eerder dat je probleem de oude XMPPHP library is. XMPP is namelijk tegenwoordig een stuk geavanceerder.
Probeer het eens met https://github.com/fabiang/xmpp
Mooi voorbeeld inderdaad! ik zie dat je daar de PLAIN mechanism hel zelfde afhandelt als SCRAM-SHA-1 Ik ga dit zeker nog eens door nemenen.
Mijn functie ziet er nu de door jouw voorgestelde lib van Fabiang als volgt uit:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
function EcoVacsXMPP_SendCommand($XMPP, $robotNr, $command) {

    $set['server']      = 'msg-'.$XMPP['continent'].'.ecouser.net';     //'msg-'.$glb_continent.'.ecouser.net';
    $set['port']        = 5223;
    $set['username']    = $XMPP['username'];            //sucks      DEBUG    username used to login: 201802265a9437ee73aa7@ecouser.net
    $set['password']    = $XMPP['password'];            //sucks      DEBUG    password used to login: 0/372dxxxx/glcTBbzoppbndSRpTflNTpk1xxxxxxxx
    $set['resource']    = $XMPP['resource'];
    $set['domain']      = $XMPP['domain'];
    $set['vacAddr']     = $XMPP['robot'][$robotNr];     //self.vacuum['did'] + '@' + self.vacuum['class'] + '.ecorobot.net/atom'
    
    $logger = new Logger('xmpp');
    $logger->pushHandler(new StreamHandler(__DIR__.'/my_app.log', Logger::DEBUG));
    
    print_r($set);
    
    $options = new Options($set['server'].':'.$set['port']);
    $options->setLogger($logger)
        ->setUsername($set['username'])
        ->setPassword($set['password'])
        ->setTo($set['domain']);
    $client = new Client($options);
    $client->connect();
    $client->send(new Roster);
    $client->send(new Presence);
    $client->send(new Message);
    $client->disconnect();
}

Ook heb ik de plain functie in fabiang geprobeerd met en zonder de authzid toevoeging. Maar ik blijf "auth error" als response krijgen. Ik denk dat ik eens een goeie output van python code moet zien te krijgen om dit eens naast elkaar te leggen en daar op voort te borduren. er gaat volgens mij gewoon iets structureels mis maar ik krijg het niet zichtbaar.

>>Iemand een idee hoe ik sleekxmpp in een "debug" of "verbose" modus kan krijgen?

Acties:
  • Beste antwoord
  • 0 Henk 'm!

  • DJMaze
  • Registratie: Juni 2002
  • Niet online
Verwijderd schreef op maandag 20 augustus 2018 @ 23:24:
Ook heb ik de plain functie in fabiang geprobeerd met en zonder de authzid toevoeging. Maar ik blijf "auth error" als response krijgen.
Dan is er iets mis op de XMPP Server en niet op je Client.

De fablang log zou iets moeten vertellen. Hier meer info: https://xmpp.org/rfcs/rfc6120.html#sasl-errors
En voor de oude: https://tools.ietf.org/html/rfc3920#section-6.4

[ Voor 7% gewijzigd door DJMaze op 20-08-2018 23:55 ]

Maak je niet druk, dat doet de compressor maar


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
aan de server kan ik helaas niks aan veranderen... en support hierin vragen lijkt ook geen optie dus ik zou het echt lokaal moeten oplossen.

De log:
code:
1
2
3
4
5
......
[2018-08-21 08:40:38] xmpp.DEBUG: Received buffer '<stream:features><auth xmlns="http://jabber.org/features/iq-auth"/><mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><mechanism>PLAIN</mechanism></mechanisms></stream:features>' from 'msg-eu.ecouser.net:5223' [] []
[2018-08-21 08:40:38] xmpp.DEBUG: Sending data '<auth xmlns="urn:ietf:params:xml:ns:xmpp-sasl" mechanism="PLAIN">ADIwMTgwMjI2NWE5NDxxxxU3M2FhN0BlY291c2VyLm5ldAAwLzxxxxMyMDEzL3JsclFUQVV5dkJtNmxxxxJ5Y2l3WFdqWWd1V1hzY1hF</auth>' to 'msg-eu.ecouser.net:5223' [] []
[2018-08-21 08:40:38] xmpp.DEBUG: Listener "Fabiang\Xmpp\EventListener\Stream\Authentication" is currently blocking [] []
[2018-08-21 08:40:39] xmpp.DEBUG: Received buffer '<failure xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><not-authorized/><text>auth error</text></failure>' from 'msg-eu.ecouser.net:5223' [] []

RFC3920 >>> The authentication failed because the initiating entity did not provide valid credentials
RFC6120 >>> The authentication failed because the initiating entity did not provide proper credentials
beide het zelfde verhaal dus iets met de credentials... iets structureels dus wat ik zelf al wel dacht.

Ik ben in mijn beste python aan het prutsen gegaan in sleekxmpp en heb een log regel aan de PLAIN() toe gevoegd en de logger lib aan geroepen: link
Python:
22
23
24
import logging

log = logging.getLogger(__name__)

Python:
78
79
80
81
82
83
    def process(self, challenge=b''):
        authzid = self.credentials['authzid']
        authcid = self.credentials['username']
        password = self.credentials['password']
        log.error("Use PLAIN mechanism with: " + str(authzid) + " " + str(authcid) + " " + str(password))
        return authzid + b'\x00' + authcid + b'\x00' + password

>>>> Use PLAIN mechanism with: b'201802265a9437ee73aa7' b'201802265a9437ee73aa7' b'0/c4xxxx2b/tIvrJxjyjxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
oftewel 2 maal zonder @ecouser.net |:(

aangepast in fabiang:
PHP:
61
62
63
64
65
66
67
68
    public function authenticate($username, $password)
    {
    $user = str_replace("@ecouser.net","",$username);
        $authString = XML::quote(base64_encode($user . "\x00" . $user . "\x00" . $password));
        $this->getConnection()->send(
            '<auth xmlns="urn:ietf:params:xml:ns:xmpp-sasl" mechanism="PLAIN">' . $authString . '</auth>'
        );
    }

en tada *O* :
<success xmlns="urn:ietf:params:xml:ns:xmpp-sasl"/>

[ Voor 0% gewijzigd door Verwijderd op 21-08-2018 14:35 . Reden: [/] ]


Acties:
  • 0 Henk 'm!

  • DJMaze
  • Registratie: Juni 2002
  • Niet online
Verwijderd schreef op dinsdag 21 augustus 2018 @ 14:32:
aangepast in fabiang:
PHP:
61
62
63
64
65
66
67
68
    public function authenticate($username, $password)
    {
    $user = str_replace("@ecouser.net","",$username);
        $authString = XML::quote(base64_encode($user . "\x00" . $user . "\x00" . $password));
        $this->getConnection()->send(
            '<auth xmlns="urn:ietf:params:xml:ns:xmpp-sasl" mechanism="PLAIN">' . $authString . '</auth>'
        );
    }

en tada *O* :
<success xmlns="urn:ietf:params:xml:ns:xmpp-sasl"/>
Aha!

Die breinbreker had ik opgelost in mijn XMPP versie.
Zie regel 68 https://bitbucket.org/djm...iew-default#stream.php-68

Mijn probleem was als volgt:
- mijn $config string is in URI format
- 'host' is de server waarmee je verbindt
- 'user' is de gebruiker.

Bijvoorbeeld:
- 'host' = example.com
- 'user' = user@example.org

Een XMPP server kan immers meerdere domeinen beheren.
In mijn code wordt dit opgesplitst in een 'user' en een 'to' (volgens de SNI specs).
Het resultaat is:
code:
1
<stream:stream to="example.org" xmlns:stream="jabber:client" xmlns="jabber:client" version="1.0">

Zonder de 'to' (dus als je de '@domein' weglaat in je 'user') krijg je:
code:
1
<stream:stream to="example.com" xmlns:stream="jabber:client" xmlns="jabber:client" version="1.0">


Zoals je ziet is in XMPP de 'user' ALTIJD zonder de '@domein'.
Echter, als je dus in een ander domein wil dan gebruik je de 'to'.

In dit geval geef jij dus de verkeerde $username op en is dit niet de schuld van fablang (die handelt de 'to' anders af dan ik).
PHP:
1
2
$options->setTo('ecouser.net');
$options->setUsername('mdiks'); // Dus ZONDER @ecouser.net!!!


Doe dan een "feature request" bij fablang:
PHP:
1
2
3
4
5
6
7
8
9
    public function setUsername($username)
    {
        $username = explode('@', $username, 2);
        $this->username = $username[0];
        if (!empty($username[1])) {
            $this->to = $username[1];
        }
        return $this;
    }

[ Voor 11% gewijzigd door DJMaze op 22-08-2018 01:52 ]

Maak je niet druk, dat doet de compressor maar

Pagina: 1