Skip to content

Commit 9658776

Browse files
committed
Land rapid7#9079, adding @h00die's gopher scanner
2 parents f250e15 + c517ded commit 9658776

File tree

2 files changed

+251
-0
lines changed

2 files changed

+251
-0
lines changed
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
## Vulnerable Application
2+
3+
Any gopher server will work. There seems to only be [a few left](https://en.wikipedia.org/wiki/Gopher_(protocol)#Server_software)
4+
in 2017.
5+
6+
A few options for local installation and testing are below.
7+
8+
### Docker Install
9+
10+
A [dockerized gopher server written in Go](https://hub.docker.com/r/prodhe/gopher/) is available. To install and run this, with content being
11+
served out of a temporary directory in which you'll be left:
12+
13+
```
14+
$ docker pull prodhe/gopher
15+
Using default tag: latest
16+
latest: Pulling from prodhe/gopher
17+
627beaf3eaaf: Already exists
18+
8800e3417eb1: Pull complete
19+
d9f3bcdad0eb: Pull complete
20+
c018073abd26: Pull complete
21+
b2855f535c50: Pull complete
22+
23480a2f73d8: Pull complete
23+
1555a5435ec5: Pull complete
24+
0728d289e0fc: Pull complete
25+
6f6f265b58ee: Pull complete
26+
Digest: sha256:69931d56946d192d9bd155a88b6f365cb276e9edf453129d374e64d244d1edaa
27+
Status: Downloaded newer image for prodhe/gopher:latest
28+
$ cd `mktemp -d`;
29+
$ sudo docker run --rm -d -it --name gopher_test -v `pwd -P`:/public -p 70:70 prodhe/gopher
30+
2017/10/20 16:45:01 Serving /public/ at localhost:70
31+
$ date > test.txt
32+
$ echo HELLO > README.md
33+
```
34+
35+
*NOTE*: Don't forget to `docker stop` the container ID returned from the `docker run` command just run above:
36+
```
37+
$ docker stop X
38+
X
39+
```
40+
41+
42+
### Ubuntu 16.04 Install
43+
44+
First we need to install the server:
45+
46+
```
47+
sudo apt-get install gopher-server
48+
```
49+
Next, we need to build content for the scanner to find. Gopher works off of a `gophermap`, somewhat similar
50+
to a content index page, where files are listed in a menu type system.
51+
52+
```
53+
echo "<html><h1>hello world</h1></html>" | sudo tee /var/gopher/example.html
54+
echo "foobarbaz" | sudo tee /var/gopher/foobar.txt
55+
sudo mkdir /var/gopher/msf
56+
echo "meterpreter rules" | sudo tee /var/gopher/msf/meterp.txt
57+
sudo wget "https://pbs.twimg.com/profile_images/580131056629735424/2ENTk2K2.png" -O /var/gopher/msf/logo.png
58+
59+
echo -ne "gopher custom gophermap\n\nhHello World\t/example.html\t1.1.1.1\t70\n0Foo File\t/foobar.txt\t1.1.1.1\t70\n1msf\t/msf\t1.1.1.1\t70\nhmetasploit homepage\tURL:http://metasploit.com/\n" | sudo tee /var/gopher/gophermap
60+
sudo chmod +r -R /var/gopher
61+
```
62+
63+
In this case we create an html file, text file, a directory with a text file and png file in it. Enough content so its nice to look at.
64+
Next we write our `gophermap` file. The first line is just an intro. After that, we list our files that the client can access.
65+
66+
The format of these lines is: `XSome text here[TAB]/path/to/content[TAB]example.org[TAB]port`. The first character, `X` is the file type
67+
which can be referenced in the table below. The final address (example.org) and PORT are optional.
68+
69+
The following table contains the file types associated with the characters:
70+
71+
| Itemtype | Content |
72+
|----------|---------------------------------|
73+
| 0 | Text file |
74+
| 1 | Directory |
75+
| 2 | CSO name server |
76+
| 3 | Error |
77+
| 4 | Mac HQX filer |
78+
| 5 | PC binary |
79+
| 6 | UNIX uuencoded file |
80+
| 7 | Search server |
81+
| 8 | Telnet Session |
82+
| 9 | Binary File |
83+
| c | Calendar (not in 2.06) |
84+
| e | Event (not in 2.06) |
85+
| g | GIF image |
86+
| h | HTML, Hypertext Markup Language |
87+
| i | inline text type |
88+
| s | Sound |
89+
| I | Image (other than GIF) |
90+
| M | MIME multipart/mixed message |
91+
| T | TN3270 Session |
92+
93+
## Verification Steps
94+
95+
1. Install the application
96+
2. Start msfconsole
97+
3. Do: ```use auxiliary/scanner/gopher/gopher_gophermap```
98+
4. Do: ```set rhosts [IPs]```
99+
5. Do: ```run```
100+
6. You should see the gophermap file printed in a parsed format
101+
102+
## Options
103+
104+
**PATH**
105+
106+
It is possible to view content within a directory of the gophermap. If the intial run shows directory `Directory: foobar`,
107+
setting **path** to `/foobar` will enumerate the contents of that folder. Default: [empty string].
108+
109+
## Scenarios
110+
111+
### Docker Gopher Server
112+
```
113+
msf > use auxiliary/scanner/gopher/gopher_gophermap
114+
msf auxiliary(gopher_gophermap) > set RHOSTS localhost
115+
RHOSTS => localhost
116+
msf auxiliary(gopher_gophermap) > run
117+
118+
[+] 127.0.0.1:70 - Text file: README.md
119+
[+] 127.0.0.1:70 - Path: localhost:70/README.md
120+
[+] 127.0.0.1:70 - Text file: test.txt
121+
[+] 127.0.0.1:70 - Path: localhost:70/test.txt
122+
[*] Scanned 1 of 1 hosts (100% complete)
123+
[*] Auxiliary module execution completed
124+
```
125+
### Gopher-server on Ubuntu 16.04
126+
127+
```
128+
msf > use auxiliary/scanner/gopher/gopher_gophermap
129+
msf auxiliary(gopher_gophermap) > set rhosts 1.1.1.1
130+
rhosts => 1.1.1.1
131+
msf auxiliary(gopher_gophermap) > set verbose true
132+
verbose => true
133+
msf auxiliary(gopher_gophermap) > run
134+
135+
[+] 1.1.1.1:70 - gopher custom gophermap
136+
[+] 1.1.1.1:70 -
137+
[+] 1.1.1.1:70 - HTML: Hello World
138+
[+] 1.1.1.1:70 - Path: 1.1.1.1:70/example.html
139+
[+] 1.1.1.1:70 - Text file: Foo File
140+
[+] 1.1.1.1:70 - Path: 1.1.1.1:70/foobar.txt
141+
[+] 1.1.1.1:70 - Directory: msf
142+
[+] 1.1.1.1:70 - Path: 1.1.1.1:70/msf
143+
[+] 1.1.1.1:70 - HTML: metasploit homepage
144+
[+] 1.1.1.1:70 - Path: 1.1.1.1:70/URL:http://metasploit.com/
145+
[*] Scanned 1 of 1 hosts (100% complete)
146+
[*] Auxiliary module execution completed
147+
148+
```
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
##
2+
# This module requires Metasploit: https://metasploit.com/download
3+
# Current source: https://github.com/rapid7/metasploit-framework
4+
##
5+
6+
class MetasploitModule < Msf::Auxiliary
7+
include Msf::Exploit::Remote::Tcp
8+
include Msf::Auxiliary::Report
9+
include Msf::Auxiliary::Scanner
10+
11+
def initialize
12+
super(
13+
'Name' => 'Gopher gophermap Scanner',
14+
'Description' => %q(
15+
This module identifies Gopher servers, and processes the gophermap
16+
file which lists all the files on the server.
17+
),
18+
'References' =>
19+
[
20+
['URL', 'https://sdfeu.org/w/tutorials:gopher']
21+
],
22+
'Author' => 'h00die',
23+
'License' => MSF_LICENSE
24+
)
25+
26+
register_options(
27+
[
28+
Opt::RPORT(70),
29+
OptString.new('PATH', [false, 'Path to enumerate', ''])
30+
]
31+
)
32+
end
33+
34+
TYPE_MAP = {
35+
'0' => 'Text file',
36+
'1' => 'Directory',
37+
'2' => 'CSO name server',
38+
'3' => 'Error',
39+
'4' => 'Mac HQX filer',
40+
'5' => 'PC binary',
41+
'6' => 'UNIX uuencoded file',
42+
'7' => 'Search server',
43+
'8' => 'Telnet Session',
44+
'9' => 'Binary File',
45+
'c' => 'Calendar',
46+
'e' => 'Event',
47+
'g' => 'GIF image',
48+
'h' => 'HTML',
49+
'i' => 'inline text',
50+
's' => 'Sound',
51+
'I' => 'Image',
52+
'M' => 'MIME multipart/mixed message',
53+
'T' => 'TN3270 Session'
54+
}.freeze
55+
56+
def get_type(char)
57+
TYPE_MAP.fetch(char.chomp)
58+
end
59+
60+
def run_host(ip)
61+
begin
62+
connect
63+
sock.put("#{datastore['path']}\r\n")
64+
gophermap = sock.get_once
65+
if gophermap
66+
gophermap.split("\r\n").each do |line|
67+
line_parts = line.split("\t")
68+
next unless line_parts.length >= 2
69+
# syntax: [type_character]description[tab]path[tab, after this is optional]server[tab]port
70+
line_parts = line.split("\t")
71+
desc = line_parts[0]
72+
type_char = desc.slice!(0) # remove first character which is the file type
73+
file_type = get_type(type_char)
74+
if file_type && file_type == 'inline text'
75+
print_good(desc)
76+
next
77+
end
78+
if file_type
79+
print_good(" #{file_type}: #{desc}")
80+
else
81+
print_good(" Invalid File Type (#{type_char}): #{desc}")
82+
end
83+
if line_parts.length >= 3
84+
print_good(" Path: #{line_parts[2]}:#{line_parts[3]}#{line_parts[1]}")
85+
elsif line.length >= 2
86+
print_good(" Path: #{line_parts[2]}#{line_parts[1]}")
87+
else
88+
print_good(" Path: #{line_parts[1]}")
89+
90+
end
91+
end
92+
report_service(host: ip, port: rport, service: 'gopher', info: gophermap)
93+
else
94+
print_error('No gophermap')
95+
end
96+
rescue ::Rex::ConnectionError, ::IOError, ::Errno::ECONNRESET
97+
rescue ::Exception => e
98+
print_error("#{ip}: #{e} #{e.backtrace}")
99+
ensure
100+
disconnect
101+
end
102+
end
103+
end

0 commit comments

Comments
 (0)