Hotline Login Sequence

In examining hotline X and output from OT Session Watcher I was able to create a unix program which opened a SOCK_STREAM (stream socket) and connected to a hotline server.  Initially I thought it might be possible to open 100 or so streams to a server, but only 5 are permitted from the same client.  Anyway here is the connection sequence:  (from the clients perspective)

Send 12 bytes: 54 52 54 50 48 4F 54 4C 00 01 00 02

Recieve 8 bytes: 54 52 54 50 00 00 00 00

Send 41 bytes: 00 00 00 6B 00 00 00 01 00 00 00 00 00 00 00 15 00 00 00 15 00 02 00 66 00 09 48 4C 5F 53 6F 63 6B 65 74 00 68 00 02 00 9D

Send 22 bytes: 00 00 01 2C 00 00 00 02 00 00 00 00 00 00 00 02 00 00 00 02 00 00

Send 22 bytes: 00 00 00 65 00 00 00 03 00 00 00 00 00 00 00 02 00 00 00 02 00 00

Recieve 22 bytes: 00 01 00 00 00 00 00 01 00 00 00 00 00 00 00 02 00 00 00 02 00 00

Recieve X bytes: List of users on server (in hex).

Recieve news/agreement. (Can be ignored)

That is the full login sequence, of course with that sequence you will get logged into the server as "HL_Socket", the second send tells the server what nick to login with.

The following program "hotline_socket.cpp" is included in this file:

------Cut here------
/*
 * This program logs into a hotline server and posts a news message.
 * It is not meant to bomb servers, though it could easily be modified to
 * do so. It simply demonstrates the login sequence for the hotline
 * server.
 *
 * Special thanx to Ballbach and Matt. 
 *
 *				[email protected]
 *
 * Tested under Linux. The default port number for hotline servers is 5500
 * To compile: g++ hotline_socket.cpp
 * To use: a.out <host> <port-number>
 *
 */

#include <iostream.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/time.h>

main(int argc, char *argv[])
{
int sock_fd;
struct sockaddr_in dest_addr;
struct hostent *he;
char buf[8];
char users[100000];
char tmp[22];
int i;

char *login_seq = 
"\x00\x00\x00\x6B\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x15\x00\x00\x00"
"\x15\x00\x02\x00\x66\x00\x09\x48\x4C\x5F\x53\x6F\x63\x6B\x65\x74\x00\x68\x00"
"\x02\x00\x9D/";

char *login_seq2 =
"\x00\x00\x01\x2C\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00"
"\x02\x00\x00/";

char *login_seq3 =
"\x00\x00\x00\x65\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00"
"\x02\x00\x00/";

char *news_post =
"\x00\x00\x00\x67\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x2C\x00\x00\x00"
"\x2C\x00\x01\x00\x65\x00\x26\x59\x6F\x75\x20\x68\x61\x76\x65\x20\x62\x65\x65"
"\x6E\x20\x68\x61\x78\x4F\x72\x65\x64\x20\x62\x79\x20\x61\x20\x53\x4F\x43\x4B"
"\x5F\x53\x54\x52\x45\x41\x4D/";

/* To send a chat message, the first \x67 should be \x69 */

if (argc != 3) {
	cout << "Usage: " << argv[0] << " <hostname> <port-number>\n";
exit(1);
}

if ((he=gethostbyname(argv[1])) == NULL) {  /* get the host info */
	cout << "Unknown host.\n";
            exit(1);
}

dest_addr.sin_family = AF_INET;
i = atoi(argv[2]);
dest_addr.sin_port = htons(i);
dest_addr.sin_addr = *((struct in_addr *)he->h_addr);
bzero(&(dest_addr.sin_zero), 8);

if((sock_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
	cout << "Cannot open socket.\n";
exit(1);
}

if(connect(sock_fd, (struct sockaddr *)&dest_addr, sizeof(struct sockaddr)) == -1) {
	cout << "Could not connect to socket.\n";
exit(1);
}

/* Send the initial TRTPHOTL\0\1\0\2 and recieve TRTP\0\0\0 */
send(sock_fd, "TRTPHOTL\0\1\0\2", 12, 0);
recv(sock_fd, buf, 8, 0);

send(sock_fd, login_seq, 41, 0);  /*Send nick, login...*/
send(sock_fd, login_seq2, 22, 0);
send(sock_fd, login_seq3, 22, 0);

recv(sock_fd, tmp, 22, 0);
recv(sock_fd, users, 100000, 0); 
/* If the # of users on the server > one hundred thousand bytes then this
 * will not work */

/* Ok now we are logged in */

cout << "Posting to news...\n";
send(sock_fd, news_post, 64, 0);
recv(sock_fd, tmp, 22, 0);

/*Fuck all the recvs we should be doing here and quit :) */
close(sock_fd);

exit(0);
}