Czat onet'u jest jednym z najpopularniejszych polskich czatów via WWW. Do korzystania z niego konieczna jest graficzna przeglądarka i maszyna wirtualna Javy. Autor artykułu z czystej ciekawości kilkukrotnie podchodził do problemu reverse engineeringu protokołów używanych przez popularne czaty. Od samego początku onet.czat wykorzystywał protokół dość zbliżony do IRCa, uzupełniony o proste metody autoryzacji. Na początku polegały one na przekazaniu komendy ZUOAUTH oraz nick'a w postaci heksadecymalnego łańcucha wraz z pewną stałą. Metoda ta została dość szybko wycofana po mojej pierwszej publikacji na ten temat. Kolejne wersje zawierają nieco bardziej skomplikowany schemat autoryzacji typu challenge-and-response. Informacje opublikowane w artykule pochodzą wyłącznie z reverse engineeringu klienta.
ProtokółPo ustanowieniu połączenia, autoryzacja przebiega w następujący sposób:
klient: AUTHKEY serwer: [hostname] 006 * :[key] klient: AUTHKEY [key2] klient: ONETAUTH LOCAL [nick] * [wersja] |
Gdzie [key] jest 16 znakowym łańcuchem tekstowym podanym przez serwer, a [key2] podobnym łancuchem, poddanym pewnym przekształceniom przez klienta.
PatchPoniżej publikuję patcha na klienta IRC BitchX 1.0c19, pozwalającego na korzystanie z czat.onet. Użycie wygląda następująco:
$ BitchX -p 5013 nick czat-s.onet.pl |
--- BitchX/source/numbers.c.orig 2002-02-28 05:22:50.000000000 +0100
+++ BitchX/source/numbers.c 2002-12-09 02:35:26.000000000 +0100
@@ -70,6 +70,92 @@
char *thing_ansi = NULL;
+
+ static char s1[17];
+
+ static int f1[] = {
+ 14, 1, 48, 40, 34, 30, 52, 59, 2, 59,
+ 6, 60, 22, 13, 9, 33, 19, 14, 58, 27,
+ 22, 15, 36, 46, 8, 11, 44, 59, 30, 0,
+ 23, 45, 2, 10, 23, 37, 41, 13, 34, 43,
+ 11, 40, 42, 34, 53, 52, 6, 11, 4, 2,
+ 38, 26, 18, 12, 10, 27, 24, 55, 25, 54,
+ 55, 49, 38, 58, 59, 0, 33, 39, 14, 5,
+ 21, 25, 45, 1, 60, 37, 53, 4
+ };
+ static int f2[] = {
+ 25, 43, 43, 47, 41, 36, 32, 9, 44, 20,
+ 49, 7, 55, 22, 10, 20, 15, 53, 5, 59,
+ 30, 37, 20, 27, 11, 14, 41, 3, 17, 1,
+ 23, 42, 45, 4, 28, 24, 41, 60, 34, 23,
+ 19, 21, 31, 12, 43, 41, 32, 59, 32, 37,
+ 56, 0, 13, 15, 28, 25, 29, 8, 28, 47,
+ 9, 51, 27, 55, 55, 55, 18, 34, 54, 52,
+ 58, 11, 12, 28, 24, 56, 7, 57
+ };
+ static int f3[] = {
+ 27, 48, 27, 16, 3, 29, 56, 44, 5, 37,
+ 45, 60, 59, 47, 58, 38, 29, 27, 46, 5,
+ 51, 54, 7, 6, 49, 11, 54, 45, 13, 38,
+ 60, 40, 24, 26, 57, 28, 55, 52, 11, 60,
+ 28, 57, 58, 25, 42, 55, 2, 10, 21, 48,
+ 16, 10, 40, 23, 16, 28, 35, 9, 11, 48,
+ 47, 9, 27, 10, 35, 22, 38, 29, 13, 49,
+ 28, 41, 45, 25, 4, 25, 19, 6
+ };
+ static int p1[] = {
+ 1, 9, 12, 7, 2, 6, 0, 5, 3, 11,
+ 4, 14, 10, 8, 13, 15
+ };
+ static int p2[] = {
+ 12, 5, 1, 4, 15, 0, 2, 11, 10, 14,
+ 7, 6, 8, 3, 9, 13
+ };
+
+char *transformKey(char *s) {
+ char ai[16], ai1[16], c;
+ int i, j, k, l, i1, j1, k1, l1, i2;
+
+ if (strlen(s) < 16)
+ return "(key to short)";
+
+ for(i = 0; i < 16; i++)
+ {
+ c = s[i];
+ ai[i] = (c> '9' ? c> 'Z' ? (c - 97) + 36 : (c - 65) + 10 : c - 48);
+ }
+
+ for(j = 0; j < 16; j++)
+ ai[j] = f1[ai[j] + j];
+
+ memcpy(ai1, ai, sizeof(ai1));
+
+ for(k = 0; k < 16; k++)
+ ai[k] = (ai[k] + ai1[p1[k]]) % 62;
+
+ for(l = 0; l < 16; l++)
+ ai[l] = f2[ai[l] + l];
+
+ memcpy(ai1, ai, sizeof(ai1));
+
+ for(i1 = 0; i1 < 16; i1++)
+ ai[i1] = (ai[i1] + ai1[p2[i1]]) % 62;
+
+ for(j1 = 0; j1 < 16; j1++)
+ ai[j1] = f3[ai[j1] + j1];
+
+ for(k1 = 0; k1 < 16; k1++)
+ {
+ l1 = ai[k1];
+ ai[k1] = l1>= 10 ? l1>= 36 ? (97 + l1) - 36 : (65 + l1) - 10 : 48 + l1;
+ s1[k1] = ai[k1];
+ }
+
+ s1[16]='\0';
+
+ return s1;
+ }
+
/*
* numeric_banner: This returns in a static string of either "xxx" where
* xxx is the current numeric, or "***" if SHOW_NUMBERS is OFF
@@ -549,6 +635,13 @@
send_to_server("COOKIE %s", s);
break;
}
+ case 6:
+ {
+ send_to_server("AUTHKEY %s", transformKey(*ArgList));
+ send_to_server("ONETAUTH LOCAL %s * 2.1.1", get_server_nickname(from_server));
+ break;
+ }
+
case 4: /* #define RPL_MYINFO 004 */
{
got_initial_version_28(ArgList);
--- BitchX/source/server.c.orig 2002-03-25 06:21:24.000000000 +0100
+++ BitchX/source/server.c 2002-12-09 02:41:32.000000000 +0100
@@ -2236,6 +2236,7 @@
void register_server (int ssn_index, char *nick)
{
int old_from_server = from_server;
+/*
if (server_list[ssn_index].password)
my_send_to_server(ssn_index, "PASS %s", server_list[ssn_index].password);
@@ -2243,8 +2244,10 @@
(send_umode && *send_umode) ? send_umode :
(LocalHostName?LocalHostName:hostname),
username, *realname ? realname : space);
+*/
- change_server_nickname(ssn_index, nick);
+ accept_server_nickname(ssn_index, nick);
+ my_send_to_server(ssn_index, "AUTHKEY");
server_list[ssn_index].login_flags &= ~LOGGED_IN;
server_list[ssn_index].login_flags &= ~CLOSE_PENDING;
@@ -2755,8 +2758,6 @@
reset_nickname(ssn_index);
}
- if (server_list[ssn_index].s_nickname)
- my_send_to_server(ssn_index, "NICK %s", server_list[ssn_index].s_nickname);
}
void accept_server_nickname (int ssn_index, char *nick)
|

Wszystkie materiały na mojej stronie dostępne są na licencji Creative Commons Uznanie autorstwa-Użycie niekomercyjne-Na tych samych warunkach 2.5 Polska.