|
|
@@ -13,14 +13,17 @@
|
|
|
#define PROG_NAME "a.out"
|
|
|
#endif
|
|
|
|
|
|
+// Seconds
|
|
|
+#define KEY_EPS 1
|
|
|
+
|
|
|
+#define SSH_SETUP_PACKET_COUNT 4
|
|
|
+
|
|
|
#define FLAG_SHORT_HELP "-h"
|
|
|
#define FLAG_LONG_HELP "--help"
|
|
|
|
|
|
#define FLAG_SHORT_DIFF "-d"
|
|
|
#define FLAG_LONG_DIFF "--diff"
|
|
|
|
|
|
-#define FILTER_KEY_PKT "tcp[13] & 8 == 8 and dst port 22"
|
|
|
-
|
|
|
/* Format of keylog lines in log file.
|
|
|
* 4 = the fd SSH reads user input from (don't know why it isn't 0 but it isn't)
|
|
|
* 16384 = How many bytes SSH reads as a time
|
|
|
@@ -38,7 +41,7 @@ typedef struct {
|
|
|
FILE* keylog;
|
|
|
char* keylogName;
|
|
|
struct timeval keylogStart;
|
|
|
- List* timecaps;
|
|
|
+ TimeCap* timecap;
|
|
|
struct timeval synEpsiolon;
|
|
|
} Args;
|
|
|
|
|
|
@@ -85,20 +88,13 @@ void check_error(int cond, char* str) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-void check_error_pcap(int cond, pcap_t* pcap, char* str) {
|
|
|
- if (cond) {
|
|
|
- pcap_perror(pcap, str);
|
|
|
- exit(1);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
void print_usage(int exitCode) {
|
|
|
- printf("Usage: %s [options] keylog pcap [pcap ...]\n"
|
|
|
- "Pair a keylog to a SSH TCP stream.\n\n"
|
|
|
+ printf("Usage: %s [options] keylog pcap\n"
|
|
|
+ "Pair each key in a keylog to a packet.\n\n"
|
|
|
"Options:\n"
|
|
|
"%-20s Show this help message and exit\n"
|
|
|
- "%-20s The allowable difference in time (in seconds) between keylog \n"
|
|
|
- "%-20s start and flow start\n",
|
|
|
+ "%-20s The allowable difference in time (in seconds) between client\n"
|
|
|
+ "%-20s and server.\n",
|
|
|
PROG_NAME,
|
|
|
" "FLAG_SHORT_HELP", "FLAG_LONG_HELP,
|
|
|
" "FLAG_SHORT_DIFF", "FLAG_LONG_DIFF, "");
|
|
|
@@ -128,20 +124,6 @@ void parse_flag(char** argv, Args* res, size_t* i) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-/* Assumes each pcap has at least one packet and each pcap doesn't overlap.
|
|
|
- */
|
|
|
-static void add_timecap(List* pcaps, char* filename) {
|
|
|
- char* errBuf = alloca(PCAP_ERRBUF_SIZE + strlen(filename) +
|
|
|
- sizeof(NO_PACKET_ERR));
|
|
|
- TimeCap* cap = new_timecap(filename, errBuf);
|
|
|
- if (cap == NULL) {
|
|
|
- fprintf(stderr, "%s: %s\n", filename, errBuf);
|
|
|
- }
|
|
|
- else {
|
|
|
- list_add_head(pcaps, cap);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
static void read_line(FILE* keylog) {
|
|
|
int c;
|
|
|
while ((c = fgetc(keylog)) != '\n' && c != EOF) {
|
|
|
@@ -160,14 +142,20 @@ static struct timeval get_keylog_start(FILE* keylog) {
|
|
|
}
|
|
|
|
|
|
static Args get_args(int argc, char** argv) {
|
|
|
- Args res = {NULL, NULL, {0, 0}, new_list(NULL), DEFAULT_SYN_E};
|
|
|
+ Args res = {NULL, NULL, {0, 0}, NULL, DEFAULT_SYN_E};
|
|
|
size_t i = 1;
|
|
|
+ char* errBuff;
|
|
|
while (argv[i]) {
|
|
|
if (argv[i][0] == '-') {
|
|
|
parse_flag(argv, &res, &i);
|
|
|
}
|
|
|
else if (res.keylog) {
|
|
|
- add_timecap(res.timecaps, argv[i]);
|
|
|
+ errBuff = alloca(PCAP_ERRBUF_SIZE + strlen(argv[i]) +
|
|
|
+ sizeof(NO_PACKET_ERR));
|
|
|
+ res.timecap = new_timecap(argv[i], errBuff);
|
|
|
+ if (res.timecap == NULL) {
|
|
|
+ fprintf(stderr, "%s: %s\n", argv[i], errBuff);
|
|
|
+ }
|
|
|
}
|
|
|
else {
|
|
|
res.keylog = fopen(argv[i], "r");
|
|
|
@@ -177,14 +165,15 @@ static Args get_args(int argc, char** argv) {
|
|
|
}
|
|
|
++i;
|
|
|
}
|
|
|
- if (res.keylog == NULL || res.timecaps == NULL) {
|
|
|
+ if (res.keylog == NULL || res.timecap == NULL) {
|
|
|
print_usage(1);
|
|
|
}
|
|
|
return res;
|
|
|
}
|
|
|
|
|
|
-void timeval_subtract(struct timeval *result, struct timeval *x, struct timeval *y)
|
|
|
-{
|
|
|
+void timeval_subtract(struct timeval *result,
|
|
|
+ struct timeval *x,
|
|
|
+ struct timeval *y) {
|
|
|
*result = *x;
|
|
|
if (result->tv_usec < y->tv_usec) {
|
|
|
result->tv_sec -= 1;
|
|
|
@@ -196,12 +185,10 @@ void timeval_subtract(struct timeval *result, struct timeval *x, struct timeval
|
|
|
result->tv_usec = abs(result->tv_usec);
|
|
|
}
|
|
|
|
|
|
-int is_match(void* tc, void* a) {
|
|
|
+int timercmp_eps(struct timeval* a, struct timeval* b, struct timeval eps) {
|
|
|
struct timeval diff;
|
|
|
- TimeCap* cap = (TimeCap*) tc;
|
|
|
- Args* args = (Args*) a;
|
|
|
- timeval_subtract(&diff, &args->keylogStart, &cap->time);
|
|
|
- return timercmp(&diff, &args->synEpsiolon, <);
|
|
|
+ timeval_subtract(&diff, a, b);
|
|
|
+ return timercmp(&diff, &eps, <);
|
|
|
}
|
|
|
|
|
|
void print_time(struct timeval ts) {
|
|
|
@@ -230,17 +217,21 @@ void print_keystroke(Keystroke key) {
|
|
|
printf(" %hu\n", key.packetId);
|
|
|
}
|
|
|
|
|
|
+void skip_n_packets(pcap_t* pcap, size_t n) {
|
|
|
+ struct pcap_pkthdr header;
|
|
|
+ while (n-- > 0) {
|
|
|
+ pcap_next(pcap, &header);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
void match_packets_to_keys(TimeCap* cap, FILE* keylog) {
|
|
|
- struct bpf_program filter;
|
|
|
struct pcap_pkthdr header;
|
|
|
Keystroke key = get_next_key(keylog);
|
|
|
Packet* data;
|
|
|
- int err = pcap_compile(cap->pcap, &filter, FILTER_KEY_PKT, true,
|
|
|
- PCAP_NETMASK_UNKNOWN);
|
|
|
- check_error_pcap(err == -1, cap->pcap, NULL);
|
|
|
- pcap_setfilter(cap->pcap, &filter);
|
|
|
+ skip_n_packets(cap->pcap, SSH_SETUP_PACKET_COUNT);
|
|
|
while ((data = (Packet*) pcap_next(cap->pcap, &header)) != NULL) {
|
|
|
- if (timercmp(&header.ts, &key.time, >)) {
|
|
|
+ if (timercmp(&header.ts, &key.time, >) ||
|
|
|
+ timercmp_eps(&header.ts, &key.time, double_to_timeval(KEY_EPS))) {
|
|
|
key.packetTime = header.ts;
|
|
|
key.packetId = data->id;
|
|
|
print_keystroke(key);
|
|
|
@@ -248,26 +239,17 @@ void match_packets_to_keys(TimeCap* cap, FILE* keylog) {
|
|
|
key = get_next_key(keylog);
|
|
|
}
|
|
|
}
|
|
|
- pcap_freecode(&filter);
|
|
|
}
|
|
|
|
|
|
void cleanup(Args args) {
|
|
|
- delete_list(args.timecaps, delete_timecap);
|
|
|
+ delete_timecap(args.timecap);
|
|
|
fclose(args.keylog);
|
|
|
}
|
|
|
|
|
|
int main(int argc, char** argv) {
|
|
|
Args args = get_args(argc, argv);
|
|
|
- TimeCap* cap = (TimeCap*) list_find(args.timecaps, &args, is_match);
|
|
|
int exitStatus = 0;
|
|
|
- if (cap != NULL) {
|
|
|
- match_packets_to_keys(cap, args.keylog);
|
|
|
- }
|
|
|
- else {
|
|
|
- fprintf(stderr, "Failed to find matching flow file for %s.\n",
|
|
|
- args.keylogName);
|
|
|
- exitStatus = 1;
|
|
|
- }
|
|
|
+ match_packets_to_keys(args.timecap, args.keylog);
|
|
|
cleanup(args);
|
|
|
return exitStatus;
|
|
|
}
|