Hacking Movable Type to get ScribeFire to work
Note: this is a little of an unusual post for me!
Martin has always been fairly positive about the ScribeFire plugin for Mozilla Firefox. True, it has its quirks, but the plugin seems to work fairly well. I decided to also take a look at it, but was unable to get it to work at my first attempt. I just could not get my blog added to the interface, yet I am running a supported engine (Movable Type). ScribeFire insisted that I provided an invalid username/password.
Here is what I did to get it to work.
First, on my web server, I started sniffing network traffic:
$ sudo tcpdump -s0 -Anl port 80 and host ip-address-of-my-pc
This
will dump the entire packet content of any traffic flowing to or from
port 80 on my server, going to or from my PC from which I attempt to
log in.
The packet that is sent from my PC to the server's xml-rpc script looks fairly easy:
13:09:29.919805 IP 10.0.1.2.56236 > 10.0.1.3.80: P 857:1238(381) ack 1 win 65535
E.....@.w....d7.H.S%...P.}k.x.t]P...#...<?xml version="1.0" encoding="UTF-8" ?><methodCall>
<methodName>blogger.getUsersBlogs</methodName>
<params>
<param>
<value>
<string/>
</value>
</param>
<param>
<value>
<string>username</string>
</value>
</param>
<param>
<value>
<string>password</string>
</value>
</param>
</params>
</methodCall>
Nothing exciting in there.
However,
the server's response was more interesting and contained an RPC fault
message, which included a string "Invalid login". Since Movable Type is
Open Source, I was able to locate that same string in the code using a
simple grep. After changing that
string by postfixing it with a bunch of 'XXX', I retried my request to
make sure that I was indeed looking at the correct code.
This is where I had my first revelation; the code was:
my $auth = $author->api_password eq $pass;
Movable
Type was not checking my regular user's password, but some kind of
special API password! That's a problem, since I have no idea what that
password is. I looked through the GUI, but was unable to find where it
is set.
So, how do you find a password that you don't know?
Simple: add a line:
die _fault(MT->translate($author->api_password));
right after that password check.
This
will create another RPC fault for any username/password combination
that I try, but instead of the fault description, it will include the
representation of the value of the $author->api_password variable.
If
MovableType stores that password in an unprotected form in that
variable, I would be golden. If they would only store a hash, that
would make my life (significantly) more complicated.
Fortunately
for me, but as illustrated by this post, not very securely, they do
not. Pasting the string that was returned to me in my tcpdump output
into the password field, and removing the line above gave me full
access to my blog's content.
Just to make sure that the API
password is indeed stored in plain text in the database, I logged on to
the mysql server and checked:
mysql>; select author_api_password from mt_author where author_nickname='my-login';
+---------------------+
| author_api_password |
+---------------------+
| zeekrut_pazz |
+---------------------+
1 row in set (0.00 sec)
On the positive note: my "normal" user password is encrypted using some algorithm. I'm
sure the source code will also tell me what that is. Just to make sure, I changed the password in the database.
Posted through ScribeFire.
Martin has always been fairly positive about the ScribeFire plugin for Mozilla Firefox. True, it has its quirks, but the plugin seems to work fairly well. I decided to also take a look at it, but was unable to get it to work at my first attempt. I just could not get my blog added to the interface, yet I am running a supported engine (Movable Type). ScribeFire insisted that I provided an invalid username/password.
Here is what I did to get it to work.
First, on my web server, I started sniffing network traffic:
$ sudo tcpdump -s0 -Anl port 80 and host ip-address-of-my-pc
This
will dump the entire packet content of any traffic flowing to or from
port 80 on my server, going to or from my PC from which I attempt to
log in.
The packet that is sent from my PC to the server's xml-rpc script looks fairly easy:
13:09:29.919805 IP 10.0.1.2.56236 > 10.0.1.3.80: P 857:1238(381) ack 1 win 65535
E.....@.w....d7.H.S%...P.}k.x.t]P...#...<?xml version="1.0" encoding="UTF-8" ?><methodCall>
<methodName>blogger.getUsersBlogs</methodName>
<params>
<param>
<value>
<string/>
</value>
</param>
<param>
<value>
<string>username</string>
</value>
</param>
<param>
<value>
<string>password</string>
</value>
</param>
</params>
</methodCall>
Nothing exciting in there.
However,
the server's response was more interesting and contained an RPC fault
message, which included a string "Invalid login". Since Movable Type is
Open Source, I was able to locate that same string in the code using a
simple grep. After changing that
string by postfixing it with a bunch of 'XXX', I retried my request to
make sure that I was indeed looking at the correct code.
This is where I had my first revelation; the code was:
my $auth = $author->api_password eq $pass;
Movable
Type was not checking my regular user's password, but some kind of
special API password! That's a problem, since I have no idea what that
password is. I looked through the GUI, but was unable to find where it
is set.
So, how do you find a password that you don't know?
Simple: add a line:
die _fault(MT->translate($author->api_password));
right after that password check.
This
will create another RPC fault for any username/password combination
that I try, but instead of the fault description, it will include the
representation of the value of the $author->api_password variable.
If
MovableType stores that password in an unprotected form in that
variable, I would be golden. If they would only store a hash, that
would make my life (significantly) more complicated.
Fortunately
for me, but as illustrated by this post, not very securely, they do
not. Pasting the string that was returned to me in my tcpdump output
into the password field, and removing the line above gave me full
access to my blog's content.
Just to make sure that the API
password is indeed stored in plain text in the database, I logged on to
the mysql server and checked:
mysql>; select author_api_password from mt_author where author_nickname='my-login';
+---------------------+
| author_api_password |
+---------------------+
| zeekrut_pazz |
+---------------------+
1 row in set (0.00 sec)
On the positive note: my "normal" user password is encrypted using some algorithm. I'm
sure the source code will also tell me what that is. Just to make sure, I changed the password in the database.
Posted through ScribeFire.