Đọc tiếp →
Nov 21, 2009
Nov 19, 2009
YMSG16
This will be used to document the YMSG16 protocol
The Yahoo Packet
Header
Header size is 20 bytes and include the following:
- Service name “YMSG” (4 bytes)
- The protocol version (2 bytes])
- VendorId flag (2 bytes)
- Length of the content of the message (2 bytes)
- Yahoo service code (2 bytes)
- Status Code (4 bytes)
- Session Id (4 bytes)
Y M S G 16 100 16 138 0 65159168
59 4d 53 47 | 00 10 | 00 64 | 00 10 | 00 8a | 00 00 00 00 |00 40 e2 03
In our example the service name is of-course YMSG, the protocol version is 16, the VendorId flag is always set to 0 for windows client(and libpurple) and 100 for mac client, and the length of our packet is 138 bytes.
The service code in this example is 0x8a or 138 which is the YAHOO_SERVICE_KEEPALIVE of a simple ping.
The status code is basic status of the message.
Status_Codes
Status | Code | Hex |
Client Request | 0 | 0x00000000 |
Server Response | 1 | 0x00000001 |
Available | 0 | 0x00000000 |
Be Right Back | 1 | 0x00000001 |
Unknown | 1515563605 | 0x5a55aa55 |
Offline | 1515563606 | 0x5a55aa56 |
Data
For the remainder of this document, packets will be written in the following format:
YMSG_SERVICE_AUTH, YMSG_STATUS_AVAILABLE
1: YahooID
Where YMSG_SERVICE_AUTH is the service code and YMSG_STATUS_AVAILABLE is the status sent in the header. The numbers following this are the key/value pairs sent in the body of the message. Refer to the table in ServiceCodes below for the meaning and values of the YMSG constants.
In all places where a Yahoo ID is mentioned, this ID should be all lowercase.
ServiceCodes
Service | Service Code |
---|---|
YMSG_STATUS_AVAILABLE | 0x00 |
YMSG_SERVICE_AUTH | 0x57 |
YMSG_SERVICE_AUTHRESP | 0x54 |
YMSG_SERVICE_NOTIFY | 0x4B |
YMSG_SERVICE_MESSAGE | 0x09 |
YMSG_SERVICE_LOGON | 0x01 |
Authentication
YMSG_SERVICE_AUTH, YMSG_STATUS_AVAILABLE
1: YahooID
YMSG_SERVICE_AUTH, YMSG_STATUS_AVAILABLE
1: YahooID
13: 2
94: challenge string
POST https://login.yahoo.com/config/pwtoken_get
src=ymsgr
ts=
login=YahooID
passwd=password
chal=challenge
If successful, the reply from this page will look like this:
0
ymsgr=AEejLkUy6t02kuZ_UXdifPhDOaZ1pXGWBIiGuw55QUksy0U-
partnerid=pXGWBIiGuw55QUksy0U-
If the first line is the number 0, it was successful. Other numbers mean different things.
POST https://login.yahoo.com/config/pwtoken_get
src=ymsgr
ts=
token=AEejLkUy6t02kuZ_UXdifPhDOaZ1pXGWBIiGuw55QUksy0U-
Pass the token as a param here. If successful, you'll get a reply back like this:
0
crumb=XLs.4fhxC8O
Y=v=1&n=1juip...; path=/; domain=.yahoo.com
T=z=mI8tKBmOR...; path=/; domain=.yahoo.com
cookievalidfor=86400
$Yv = ($ycookie =~ /^Y=(.+?)$/);
$Tz = ($tcookie =~ /^T=(.+?)$/);
Here is some Perl code for the MD5 hashing and Y64 encoding:
sub auth16 {
my ($crumb,$challenge) = @_;
# Concat the crumb in front of the challenge
my $crypt = $crumb . $challenge;
# Make an MD5 hash of it
my $md5_ctx = Digest::MD5->new();
$md5_ctx->add ($crypt);
my $md5_digest = $md5_ctx->digest();
# Encode in Y64
my $base64_str = _to_y64($md5_digest);
return $base64_str;
}
# Y64 encoding function, adapted from PHP
sub _to_y64 {
my $source_str = shift;
my @source = split(//, $source_str);
my @yahoo64 = split(//, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._");
my $limit = length($source_str) - (length($source_str) % 3);
my $dest = "";
my $i;
for ($i = 0; $i < $limit; $i += 3) {
$dest .= $yahoo64[ ord($source[$i]) >> 2];
$dest .= $yahoo64[ ((ord($source[$i]) << 4) & 0x30) | (ord($source[$i + 1]) >> 4) ];
$dest .= $yahoo64[ ((ord($source[$i + 1]) << 2) & 0x3C) | (ord($source[$i + 2]) >> 6)];
$dest .= $yahoo64[ ord($source[$i + 2]) & 0x3F ];
}
my $switch = length($source_str) - $limit;
if ($switch == 1) {
$dest .= $yahoo64[ ord($source[$i]) >> 2];
$dest .= $yahoo64[ (ord($source[$i]) << 4) & 0x30 ];
$dest .= '--';
}
elsif ($switch == 2) {
$dest .= $yahoo64[ ord($source[$i]) >> 2];
$dest .= $yahoo64[ ((ord($source[$i]) << 4) & 0x30) | (ord($source[$i + 1]) >> 4)];
$dest .= $yahoo64[ ((ord($source[$i + 1]) << 2) & 0x3C) ];
$dest .= '-';
}
return $dest;
}
YMSG_SERVICE_AUTHRESP, YMSG_STATUS_AVAILABLE
1: YahooID
0: YahooID
277: Yv Cookie
278: Tz Cookie
307: Auth16 hash
244: 4194239
2: YahooID
2: 1
98: us
135: 9.0.0.2162
If successful, the server sends you your buddy list and some other packets.
Examples
Sending and receiving messages
YMSG_SERVICE_MESSAGE, YMSG_STATUS_AVAILABLE
0: YahooID
1: ActiveID
5: TargetID
14: Message
YMSG_SERVICE_MESSAGE, YMSG_STATUS_AVAILABLE
5: our YahooID
4: their YahooID
14: their message
5 is our ID, 4 is the ID of the sender, and 14 is the message.
Buzzing a User
To "buzz" a user, simply send a message where the Message is
Sending/Receiving Typing Notifications
YMSG_SERVICE_NOTIFY, YMSG_STATUS_AVAILABLE
4: our YahooID
5: target's YahooID
13: typing status (0 or 1)
14: space character ' '
49: literal text "TYPING"
YMSG_SERVICE_NOTIFY, YMSG_STATUS_AVAILABLE
4: their YahooID
5: our YahooID
49: literal text "TYPING"
13: typing status (0 or 1)
14: space character ' '
YMSG_STATUS_AVAILABLE
YMSG_SERVICE_STATUS?, YMSG_STATUS_AVAILABLEĐọc tiếp →
59 4d 53 47 00 10 00 64 00 18 00 c7 00 00 00 00 YMSG...d........
00 56 ba 91 33 c0 80 6d 61 74 74 2e 61 75 73 74 .V..3..matt.aust
69 6e c0 80 32 31 33 c0 80 32 c0 80 in..213..2..
Yahoo! Authentication Schemes
Written by SlicK, RSTZone.org
Author: SlicK
Email: slick@rstzone.org
Website: http://rstzone.org or http://en.rstzone.org
This article is a result of about 2 weeks of research, tests and lots of hard work and will cover a few aspects related to Yahoo! that some of you may already know but nonetheless, i find them interesting. The purpose is to shed some light on a few "myths" about yahoo! and to answer some of the questions related to them.
Part I. "yahoo64" Encoding Algorithm
Part II. Analysis of the Yahoo Token
Part III. Yahoo! Messenger - "Remember my ID and Password"
Part IV. YMSGR v15 Authentication
Part V. The analysis and explanation of Yahoo! cookies
Part I. "yahoo64" Encoding Algorithm
This Algorithm is used by Yahoo! anywhere there is a need to transform a string of non-printable characters into a printable one.
Its called coding not crypting because it does not offer any protection for the string of characters to be coded. Without going into to many cryptographic details, we need to mention that yahoo64 is very similar to base64 but its charset is longer(two more chars).
For yahoo64 the charset is: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._"
yahoo64 has a few characteristics that need to be mentioned:
- all the characters from the coded string are part of the above mentioned charset
- the length of the string is a multiple of 4
- based on the length of the initial string, the end of the crypted string may be "-" or "--"
Part II. Analysis of the Yahoo Token
From what i've noticed so far, the Yahoo! token is a sum of the user and password, unique for each username and is changed in part, every time the password is changed. Basically, owning this token means that you are either the owner of the account (username) or an entity who has the permission from its owner to act in his/her name on yahoo servers.
The user ca obtain his token by accessing this link:
where USERNAME and PASSWORD are a valid username/password combination.
An example of response to a request to "https://login.yahoo.com/config/pwtoken_get" can be this:
ymsgr=AGG6e0diD9m.3D4YlFPVcdBT1wFXKSBWP0Hl.gyQKd.qec8-
partnerid=KSBWP0Hl.gyQKd.qec8-
Code:
The following 4 characters represent the "timestamp" (the number of seconds elapsed since 1-1-1970) when the user was created or when the password was changed, only that the "timestamp" is reversed. For an instance, in the above given example, the "timestamp" will be 0x477BBA61(decimal 1199290977) which means "Wed, 2 Jan 2008 16:22:57 GMT"
Decoding "partnerid" we get the following string:
which, as we can see are the last 14 characters at the end of the token.
Starting with version 7.x.x.x Yahoo! Messenger doesn't memorize the password when the "Remember my ID and Password"is checked. Instead, it retains the token I spoke of earlier since the token is enough for a successful authentication.
The token is crypted and saved at this key in the windows registry:
The user is also saved(as it is needed for decoding) at this key:
This is an example of an ETS string
This is the result after decoding:
The only thing i noticed about this string is that the first 4 characters are the timestamp when this string was created (upon login)
Part IV. YMSGR v15 Authentication
COOKIE authentication (based on token).
username and password to make a request at: "https://login.yahoo.com/config/pwtoken_get" to get the token
- Once connected to one of the yahoo servers, it sends a VERIFY package (0x4C)
- If it receives a valid VERIFY reply from the server, it begins the authentication procedure
- Sends an AUTH package (0x57) with the following parameters:
"1" - USERNAME
- Receives a "AUTHRESP" package (0x54) from which it extracts the value of parameter "94" (CHALLANGE)
- Having a valid token of the user, it will make a request to "https://login.yahoo.com/config/pwtoken_login" o obtain the "Y" and "T"
values of the cookie as well as the "crumb" value (CRUMB)
- It creates a string (STRING307) like this: yahoo64(md5(CRUMB+CHALLENGE))
- Then it send an AUTHRESP package (0x54) with parameters:
"277" - parameter Y
"278" - parameter T
"307" - STRING307
"0" - USERNAME
"2" - USRNAME
"2" - "1"
"1" - USERNAME
"244" - a random number (ex. "2097087")
"98" - "us"
"135" - client version (ex. "8.1.0.421")
"148" - "-120"
request and so on.
Once the user is authenticated by a Yahoo service, he will receive the "Y" and "T" so my analysis was focused on these 2 cookies.
The Y cookie can be configured to expire anytime between 15 mins to 24 hours. The T cookie usually expires when you close your browser or when you logout form the account. For services with low security such as the "My Yahoo" page, the Y cookie is enough but for the more important ones, mail, calendar, etc. the T cookie is a must. As you probably noticed a Yahoo cookie is made in pairs "parameters=value". Further on, i will analyze the parameters that form each cookie and i will try to come with an explanation for their presence and purpose.
Code:
ENCODED=abcdefghijklmnopqrstuvxyzw0123456789._
Thus, for this cookie the username is "qvkqvk"
The T cookie
~A&d=c2wBTkRVM0FUSTRNek0wTXpZNU56Zy0BYQFRQUUBenoBQ3I3ZUhCZ1dBAXRpcAFzNkpUZEM-
Code:
This is a yahoo64 coded string. After decoding the "d" value from the given example we will have the following string:
Code:
You can notice that this string is also a paired "parameter=value" one.
The value of the "sl" parameter is also a yahoo64 coded string:
This is number is unique for each user and does not modify even if you change the password.
The "zz" parameter represents the timestamp(in Yahoo format) when the cookie was created(same as the first timestamp from the "z" parameter) and 3 extra characters.
The "tip" parameter is the same for all Yahoo! users but is changing periodically(i don't know the exact interval).
Thats about it. Congratulations to those who been patient enough to read it through the end.
The yahoo64 algorithm
Code:
{
$yahoo64="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._";
$limit=strlen($source)-(strlen($source)%3);
$dest="";
for($i=0;$i<$limit;$i+=3)
{
$dest.=$yahoo64[ord($source[$i])>>2];
$dest.=$yahoo64[((ord($source[$i])<<4)&0x30)>>4)];
$dest.=$yahoo64[((ord($source[$i+1])<<2)&0x3c)>>6)];
$dest.=$yahoo64[ord($source[$i+2])&0x3F];
}
{
case 1:
{
$dest.=$yahoo64[ord($source[$i])>>2];
$dest.=$yahoo64[(ord($source[$i])<<4)&0x30];
$dest.='--';
} break;
{
$dest.=$yahoo64[ord($source[$i])>>2];
$dest.=$yahoo64[((ord($source[$i])<<4)&0x30)>>4)];
$dest.=$yahoo64[((ord($source[$i+1])<<2)&0x3c)];
$dest.='-';
} break;
}
return($dest);
}
{
for($i=0;$i<64;$i++) { if($string[$i]==$chr) { return($i); } } return(-1);
}
{
$yahoo64="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._";
$len=strlen($source);
if($source[$len-1]=='-') { $plus=2; }
if($source[$len-2]=='-') { $plus=1; }
if($plus>0) { $len-=4; };
for($i=0;$i<$len;$i+=4)
{
$chr1=Index($yahoo64,$source[$i]);
$chr2=Index($yahoo64,$source[$i+1]);
$chr3=Index($yahoo64,$source[$i+2]);
$chr4=Index($yahoo64,$source[$i+3]);
$dest.=chr(($chr1<<2)|($chr2>>4));
$dest.=chr((($chr2&0xF)<<4)|($chr3>>2));
$dest.=chr((($chr3&0x3)<<6)|($chr4&0x3F));
}
switch($plus)
{
case 1:
{
$chr1=Index($yahoo64,$source[$i]);
$chr2=Index($yahoo64,$source[$i+1]);
$dest.=chr(($chr1<<2)|($chr2>>4));
} break;
case 2:
{
$chr1=Index($yahoo64,$source[$i]);
$chr2=Index($yahoo64,$source[$i+1]);
$chr3=Index($yahoo64,$source[$i+2]);
$dest.=chr(($chr1<<2)|($chr2>>4));
$dest.=chr((($chr2&0xF)<<4)|($chr3>>2));
} break;
}
return($dest);
}
print("Original string=$string
\n");
print("Encoded string=$encoded
\n");
print("Decoded string=$decoded
\n");
?> Đọc tiếp →
Nov 17, 2009
Nov 12, 2009
Yahoo's YMSG Protocol v16
Yahoo's YMSG Protocol v16
This is my findings on version 16 of Yahoo's YMSG protocol.
Servers
cs101.msg.sp1.yahoo.com - cs130.msg.sp1.yahoo.com
cs101.msg.ac4.yahoo.com - cs130.msg.ac4.yahoo.com
Login
First we send the usual empty packet type 4C just to tell the server we are about to login
Next we send packet type 57 which only contains field type 1 containing our username
Yahoo's reply to this is packet type 57 which contains the following fields
1 - Our usernameWe then take the challenge string and use it to retrieve this url
13 - Something to do with our status. Should be set to 2 in this reply
94 - The challenge string
https://login.yahoo.com/config/pwtoken_get?src=ymsgr&ts=&login=USERNAME&passwd=PASSWORD&chal=CHALLENGESTRINGThe reply to this will depend on if we have the correct information or not. The first line of the response will always be an integer indicating various things.
If the integer is 0 then the information we have supplied is correct.
100 - if username or password is missing.
1013 - username contains @yahoo.com or similar which needs removing.
1212 - is the username or password is incorrect.
1213 - is a security lock from to many failed login attempts
1214 - is a security lock
1218 - if the account has been deactivated by Yahoo
1235 - if the username does not exist.
1236 - locked due to to many login attempts
Seems to work just as well without the challenge string though.
Anyway if the username and password is correct the second line of the reply will be our token as such
ymsgr=OURTOKENIt has a third line as well but this serves no purpose to us.
Once we have our token we use it to retrieve this url
https://login.yahoo.com/config/pwtoken_login?src=ymsgr&ts=&token=OURTOKENAgain the first line of the reply is an intger to indicate the status with 0 being good and 100 meaning something is wrong.
Line 2 is our crumb as
crumb=OURCRUMBThe next two lines contain our Y= cookie and T= cookie respectively. The last line is the life of the cookie.
Now we return back to normal YMSG
First we need to get a hash using the crumb and the challenge string. It just uses the standard Yahoo Base64 variation.
Function for hashing the crumbHere is the function as used in Pidgin
Public Function ProcessAuth16(ByVal Crumb As String, ByVal Challenge As String)
Dim Crypt As String = String.Join(String.Empty, New String() {Crumb, Challenge})
Dim Hash As Byte() = HashAlgorithm.Create("MD5").ComputeHash(Encoding.[Default].GetBytes(Crypt))
Dim Auth As String = Convert.ToBase64String(Hash).Replace("+", ".").Replace("/", "_").Replace("=", "-")
Return Auth.ToString
End Function
/* This is the y64 alphabet... it's like base64, but has a . and a _ */We now send packet type 54 to our server with the following fields:
static const char base64digits[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._";
/* This is taken from Sylpheed by Hiroyuki Yamamoto. We have our own tobase64 function
* in util.c, but it has a bug I don't feel like finding right now ;) */
static void to_y64(char *out, const unsigned char *in, gsize inlen)
/* raw bytes in quasi-big-endian order to base 64 string (NUL-terminated) */
{
for (; inlen >= 3; inlen -= 3)
{
*out++ = base64digits[in[0] >> 2];
*out++ = base64digits[((in[0] <<>> 4)];
*out++ = base64digits[((in[1] <<>> 6)];
*out++ = base64digits[in[2] & 0x3f];
in += 3;
}
if (inlen > 0)
{
unsigned char fragment;
*out++ = base64digits[in[0] >> 2];
fragment = (in[0] << 4) & 0x30;
if (inlen > 1)
fragment |= in[1] >> 4;
*out++ = base64digits[fragment];
*out++ = (inlen < 2) ? '-' : base64digits[(in[1] << 2) & 0x3c];
*out++ = '-';
}
*out = '\0';
}
1 - usernameAnd that's it. We have successfully logged in using YMSG version 16. Đọc tiếp →
0 - username
277 - The Y cookie not including the Y= part
278 - The T cookie not including the T= part
307 - Our hash created using the Y64 function
244 - Rekkanoryo says this is internal build number. I just use 2097087
2 - username
2 - Not sure why we use 2 again but this one just contains the character 1
98 - Country but best just use us
135 - Messenger version number. Currently I use 9.0.0.1389