Skip to content

Commit 5d79201

Browse files
authored
fix(js): incorrect postgres exec call signature (#6731)
Make sure postgres Exec/ExecContext are invoked with the correct argument order, preventing context from being passed as the query. * fixing pg syntax * adding test
1 parent 3fdc06b commit 5d79201

File tree

3 files changed

+110
-10
lines changed

3 files changed

+110
-10
lines changed

cmd/integration-test/javascript.go

Lines changed: 59 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,19 @@ var jsTestcases = []TestCaseInfo{
1717
{Path: "protocols/javascript/net-https.yaml", TestCase: &javascriptNetHttps{}},
1818
{Path: "protocols/javascript/oracle-auth-test.yaml", TestCase: &javascriptOracleAuthTest{}, DisableOn: func() bool { return osutils.IsWindows() || osutils.IsOSX() }},
1919
{Path: "protocols/javascript/vnc-pass-brute.yaml", TestCase: &javascriptVncPassBrute{}},
20+
{Path: "protocols/javascript/postgres-pass-brute.yaml", TestCase: &javascriptPostgresPassBrute{}, DisableOn: func() bool { return osutils.IsWindows() || osutils.IsOSX() }},
2021
{Path: "protocols/javascript/multi-ports.yaml", TestCase: &javascriptMultiPortsSSH{}},
2122
{Path: "protocols/javascript/no-port-args.yaml", TestCase: &javascriptNoPortArgs{}},
2223
}
2324

2425
var (
25-
redisResource *dockertest.Resource
26-
sshResource *dockertest.Resource
27-
oracleResource *dockertest.Resource
28-
vncResource *dockertest.Resource
29-
pool *dockertest.Pool
30-
defaultRetry = 3
26+
redisResource *dockertest.Resource
27+
sshResource *dockertest.Resource
28+
oracleResource *dockertest.Resource
29+
vncResource *dockertest.Resource
30+
postgresResource *dockertest.Resource
31+
pool *dockertest.Pool
32+
defaultRetry = 3
3133
)
3234

3335
type javascriptNetHttps struct{}
@@ -169,6 +171,38 @@ func (j *javascriptVncPassBrute) Execute(filePath string) error {
169171
return multierr.Combine(errs...)
170172
}
171173

174+
type javascriptPostgresPassBrute struct{}
175+
176+
func (j *javascriptPostgresPassBrute) Execute(filePath string) error {
177+
if postgresResource == nil || pool == nil {
178+
// skip test as postgres is not running
179+
return nil
180+
}
181+
tempPort := postgresResource.GetPort("5432/tcp")
182+
finalURL := "localhost:" + tempPort
183+
defer purge(postgresResource)
184+
errs := []error{}
185+
for i := 0; i < defaultRetry; i++ {
186+
results := []string{}
187+
var err error
188+
_ = pool.Retry(func() error {
189+
//let postgres server start
190+
time.Sleep(3 * time.Second)
191+
results, err = testutils.RunNucleiTemplateAndGetResults(filePath, finalURL, debug)
192+
return nil
193+
})
194+
if err != nil {
195+
return err
196+
}
197+
if err := expectResultsCount(results, 1); err == nil {
198+
return nil
199+
} else {
200+
errs = append(errs, err)
201+
}
202+
}
203+
return multierr.Combine(errs...)
204+
}
205+
172206
type javascriptMultiPortsSSH struct{}
173207

174208
func (j *javascriptMultiPortsSSH) Execute(filePath string) error {
@@ -292,4 +326,23 @@ func init() {
292326
if err := vncResource.Expire(30); err != nil {
293327
log.Printf("Could not expire resource: %s", err)
294328
}
329+
330+
// setup a temporary postgres instance
331+
postgresResource, err = pool.RunWithOptions(&dockertest.RunOptions{
332+
Repository: "postgres",
333+
Tag: "latest",
334+
Env: []string{
335+
"POSTGRES_PASSWORD=postgres",
336+
"POSTGRES_USER=postgres",
337+
},
338+
Platform: "linux/amd64",
339+
})
340+
if err != nil {
341+
log.Printf("Could not start postgres resource: %s", err)
342+
return
343+
}
344+
// by default expire after 30 sec
345+
if err := postgresResource.Expire(30); err != nil {
346+
log.Printf("Could not expire postgres resource: %s", err)
347+
}
295348
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
id: postgres-pass-brute
2+
3+
info:
4+
name: PostgreSQL Password Bruteforce
5+
author: pdteam
6+
severity: high
7+
description: |
8+
This template bruteforces passwords for protected PostgreSQL instances.
9+
If PostgreSQL is not protected with password, it is also matched.
10+
metadata:
11+
shodan-query: product:"PostgreSQL"
12+
tags: js,network,postgresql,authentication
13+
14+
javascript:
15+
- pre-condition: |
16+
isPortOpen(Host,Port)
17+
18+
code: |
19+
const postgres = require('nuclei/postgres');
20+
const client = new postgres.PGClient;
21+
success = client.Connect(Host, Port, User, Pass);
22+
23+
args:
24+
Host: "{{Host}}"
25+
Port: "5432"
26+
User: "{{usernames}}"
27+
Pass: "{{passwords}}"
28+
29+
attack: clusterbomb
30+
payloads:
31+
usernames:
32+
- postgres
33+
- admin
34+
- root
35+
passwords:
36+
- ""
37+
- postgres
38+
- password
39+
- admin
40+
- root
41+
stop-at-first-match: true
42+
43+
matchers:
44+
- type: dsl
45+
dsl:
46+
- "success == true"
47+

pkg/js/libs/postgres/postgres.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ func isPostgres(executionId string, host string, port int) (bool, error) {
8282
// const client = new postgres.PGClient;
8383
// const connected = client.Connect('acme.com', 5432, 'username', 'password');
8484
// ```
85-
func (c *PGClient) Connect(ctx context.Context, host string, port int, username, password string) (bool, error) {
85+
func (c *PGClient) Connect(ctx context.Context, host string, port int, username string, password string) (bool, error) {
8686
ok, err := c.IsPostgres(ctx, host, port)
8787
if err != nil {
8888
return false, err
@@ -104,7 +104,7 @@ func (c *PGClient) Connect(ctx context.Context, host string, port int, username,
104104
// const result = client.ExecuteQuery('acme.com', 5432, 'username', 'password', 'dbname', 'select * from users');
105105
// log(to_json(result));
106106
// ```
107-
func (c *PGClient) ExecuteQuery(ctx context.Context, host string, port int, username, password, dbName, query string) (*utils.SQLResult, error) {
107+
func (c *PGClient) ExecuteQuery(ctx context.Context, host string, port int, username string, password string, dbName string, query string) (*utils.SQLResult, error) {
108108
ok, err := c.IsPostgres(ctx, host, port)
109109
if err != nil {
110110
return nil, err
@@ -157,7 +157,7 @@ func executeQuery(executionId string, host string, port int, username string, pa
157157
// const client = new postgres.PGClient;
158158
// const connected = client.ConnectWithDB('acme.com', 5432, 'username', 'password', 'dbname');
159159
// ```
160-
func (c *PGClient) ConnectWithDB(ctx context.Context, host string, port int, username, password, dbName string) (bool, error) {
160+
func (c *PGClient) ConnectWithDB(ctx context.Context, host string, port int, username string, password string, dbName string) (bool, error) {
161161
ok, err := c.IsPostgres(ctx, host, port)
162162
if err != nil {
163163
return false, err
@@ -207,7 +207,7 @@ func connect(executionId string, host string, port int, username string, passwor
207207
_ = db.Close()
208208
}()
209209

210-
_, err := db.Exec(ctx, "select 1")
210+
_, err := db.ExecContext(ctx, "select 1")
211211
if err != nil {
212212
switch true {
213213
case strings.Contains(err.Error(), "connect: connection refused"):

0 commit comments

Comments
 (0)