-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathRCat.rkt
More file actions
170 lines (153 loc) · 7.35 KB
/
RCat.rkt
File metadata and controls
170 lines (153 loc) · 7.35 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
#lang racket
(require racket/system)
(require racket/tcp)
(require racket/udp)
(define machine-list '())
;; preparing port matching file by splitting the file into a list of string
(define tcp_port_match(file->lines "common_tcp_ports.txt"))
(for-each (lambda (x) (regexp-split #rx"\t" x)) tcp_port_match)
(define udp_port_match(file->lines "common_udp_ports.txt"))
(for-each (lambda (x) (regexp-split #rx"\t" x)) udp_port_match)
;; break up each string by delimiting tab
(define tport-to-service (map (lambda (x) (regexp-split #rx"\t" x)) tcp_port_match))
(define uport-to-service (map (lambda (x) (regexp-split #rx"\t" x)) udp_port_match))
;; example outoutput
;> (ips->machines "192.168.1.1-10" "1-443" "t")
;> (all-tports)
;IP: 192.168.1.1
;Open ports:
; 23 (Telnet)
; 80 (HTTP)
; 53 (Domain Name System (DNS))
; 443 (HTTPS)
;
;IP: 192.168.1.8
;Open ports:
(displayln "How to use RCat")
(displayln "Usage for multiple machines :")
(displayln "\t> (ips->machines \"192.168.74.100-254\" \"1-443\" \"t\")")
(displayln "\t> (all-tports)")
(displayln "Usage for single machine : ")
(displayln "\t> (define router (machine \"192.168.74.185\" \"1-4096\" \"t\"))")
(displayln "\t> (router '(tports))")
(displayln "\t> (router '(tport \"80\"))")
; Checks to see if the user gives a single IP address or a range of IP addresses
; If given a range, each IP is subjected to a ICMP Ping to determine if the machine is alive or not to avoid unnecessary connection attempt with probes
; before adding to the machine-list in the global environment
(define (RCat targets ports protocols)
(if (regexp-match? #rx".*-.*" targets)
(ips->machines targets ports protocols)
(machine targets ports protocols)))
; Takes a range of IP addresses ( denoted by '-' ) and pings each system. We count the machine as dead if we do not receive a response
; within three seconds, otherwise we are creating an individual machine object and adding it to the list of machines in the global environment
(define (ips->machines targets ports protocols)
(define (probe-ping addr)
(thread (lambda ()
(let ((ping-input '()))
(if (regexp-match? #rx".*64.*" (read-string 4096 (car (process (string-append "ping -c 3 " addr)))))
(set! machine-list (cons (machine addr ports protocols) machine-list));add-machine-alive addr)
"No connection detected")))))
(for-each (lambda (target-ip) (probe-ping target-ip) ) (range->list targets)))
;; print out ip and tcp port of every machine in machine-list
(define (all-tports)
(for-each
(lambda (machine-dispatch) (begin
(printf "IP: ~a\nOpen TCP ports:\n" (machine-dispatch '(ip)))
(machine-dispatch '(tports))
(printf "\n")))
machine-list))
; Print out ip and udp port of every machine in machine-list
(define (all-uports)
(for-each (lambda (machine-dispatch)
(begin (printf "IP: ~a\nOpen UDP ports:\n" (machine-dispatch '(ip))) (machine-dispatch '(uports)) (printf "\n")) )
machine-list))
; convert from range of ips to a list of ips
; (range->list "192.168.1-15") -> '("192.168.1.1" ... "192.168.1.15")
(define (range->list targets)
(let*((range(regexp-split #rx"-" targets))
(octets (regexp-split #rx"\\." (car range)))
(three-octets (string-append (car octets) "." (cadr octets) "." (caddr octets) "."))
(start (cadddr octets))
(end (cadr range))
(individual-machines-int (enum-range-i (string->number start) (string->number end)) )
(individual-machines-string (map number->string individual-machines-int))
(subnet (map (lambda (x) (string-append three-octets x)) individual-machines-string) ))
subnet))
; from ps3c
; iterative function to create and return a list of number sequentially within a given range
(define (enum-range-i a b)
(define (enum-range-halper a b total)
(if (> a b)
total
(enum-range-halper (add1 a) b (append total (list a) ))))
(enum-range-halper a b '()))
;; Machine object
; takes an IP address[string], port(s)[string], and protocol[string]
; returns dispatch procedure
(define (machine ip ports protocols)
(define open-tcp '())
(define open-udp '())
(define udp-socket (udp-open-socket) )
(define (add-udp port)
(set! open-udp (cons port open-udp)))
(define (add-tcp port)
(set! open-tcp (cons port open-tcp)))
(define (check-uport port)
(if (memq port open-udp) #t #f))
(define (check-tport port)
(if (memq (string->number port) open-tcp) #t #f))
; map across our list of open ports. For each port we print it out and then map across the list of strings loaded from the common ports text file
; we check every pair to see if it is the correct number then display the matching service if we find it.
(define (display-tports list-of-ports)
(match-tports (foldr (lambda (p q) (sort-iter p q ) ) '() list-of-ports)))
(define (match-udp-ports uport-list) (for-each (lambda (openport)
(begin (printf "\t~a\t" openport)
(for-each (lambda (x) (cond ((string=? (car x) (number->string openport)) (display (cdr x))))) uport-to-service)) (display "\n"))
uport-list))
(define (probe-udp port)
(thread (lambda ()
(if
(udp-connect! udp-socket ip port)
(add-udp port)
"No connection detected"))))
(define (probe-tcp port)
(thread
(lambda () (with-handlers ([exn:fail? (lambda (exn) exn )])
(if
(let-values (((input output) (tcp-connect ip port))) (list input output))
(add-tcp port)
"No connection detected")))))
(define (dispatch message)
(cond((eq? (car message) 'tports) (display-tports open-tcp))
((eq? (car message) 'uports) (match-udp-ports open-udp))
((eq? (car message) 'ip) ip)
((eq? (car message) 'tport) (check-tport (cadr message)) )
((eq? (car message) 'uport) (check-uport (cadr message)) )
(else error "Bad moves, dude")))
(begin (cond ((string=? protocols "t")
(map (lambda (x) (probe-tcp x)) (enum-ports ports)))
((string=? protocols "u")
(map (lambda (x) (probe-udp x)) (enum-ports ports))))
dispatch))
;; break a range up ports in form "1-443"
;; return a list of numbers
(define (enum-ports ports)
(if (regexp-match? #rx".*-.*" ports)
(let*((range(regexp-split #rx"-" ports))
(start (car range))
(end (cadr range))
(port-range-numbers(enum-range-i (string->number start) (string->number end)))
(port-range-strings (map number->string port-range-numbers)))
port-range-numbers)
(list (string->number ports))))
(define (sort-iter element port-list)
(cond((null? port-list) (cons element port-list))
((< (car port-list) element) (cons (car port-list) (sort-iter element (cdr port-list))))
(else (cons element port-list))))
; (foldr (lambda (p q) (sort-iter p q ) ) '() '(1 4 7 2 9))
(define (match-tports tport-list)
(for-each (lambda (openport)
(begin
(printf "\t~a\t" openport)
(for-each (lambda (x) (cond ((string=? (car x) (number->string openport)) (display (cdr x))))) tport-to-service)) (display "\n"))
tport-list))