Skip to content

Commit 891dffb

Browse files
feat(js): adds RSYNC module (#6410)
* adding min auth support * adding unauth list modules + auth list files in module * example * adding rsync test * bump go.mod --------- Co-authored-by: Dwi Siswanto <[email protected]>
1 parent 63aed75 commit 891dffb

File tree

7 files changed

+283
-8
lines changed

7 files changed

+283
-8
lines changed

cmd/integration-test/javascript.go

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ var jsTestcases = []TestCaseInfo{
1515
{Path: "protocols/javascript/ssh-server-fingerprint.yaml", TestCase: &javascriptSSHServerFingerprint{}, DisableOn: func() bool { return osutils.IsWindows() || osutils.IsOSX() }},
1616
{Path: "protocols/javascript/net-multi-step.yaml", TestCase: &networkMultiStep{}},
1717
{Path: "protocols/javascript/net-https.yaml", TestCase: &javascriptNetHttps{}},
18+
{Path: "protocols/javascript/rsync-test.yaml", TestCase: &javascriptRsyncTest{}, DisableOn: func() bool { return osutils.IsWindows() || osutils.IsOSX() }},
1819
{Path: "protocols/javascript/oracle-auth-test.yaml", TestCase: &javascriptOracleAuthTest{}, DisableOn: func() bool { return osutils.IsWindows() || osutils.IsOSX() }},
1920
{Path: "protocols/javascript/vnc-pass-brute.yaml", TestCase: &javascriptVncPassBrute{}},
2021
{Path: "protocols/javascript/postgres-pass-brute.yaml", TestCase: &javascriptPostgresPassBrute{}, DisableOn: func() bool { return osutils.IsWindows() || osutils.IsOSX() }},
@@ -30,6 +31,7 @@ var (
3031
vncResource *dockertest.Resource
3132
postgresResource *dockertest.Resource
3233
mysqlResource *dockertest.Resource
34+
rsyncResource *dockertest.Resource
3335
pool *dockertest.Pool
3436
defaultRetry = 3
3537
)
@@ -124,7 +126,7 @@ func (j *javascriptOracleAuthTest) Execute(filePath string) error {
124126
results := []string{}
125127
var err error
126128
_ = pool.Retry(func() error {
127-
//let ssh server start
129+
// let oracle server start
128130
time.Sleep(3 * time.Second)
129131
results, err = testutils.RunNucleiTemplateAndGetResults(filePath, finalURL, debug)
130132
return nil
@@ -258,6 +260,38 @@ func (j *javascriptNoPortArgs) Execute(filePath string) error {
258260
return expectResultsCount(results, 1)
259261
}
260262

263+
type javascriptRsyncTest struct{}
264+
265+
func (j *javascriptRsyncTest) Execute(filePath string) error {
266+
if rsyncResource == nil || pool == nil {
267+
// skip test as rsync is not running
268+
return nil
269+
}
270+
tempPort := rsyncResource.GetPort("873/tcp")
271+
finalURL := "localhost:" + tempPort
272+
defer purge(rsyncResource)
273+
errs := []error{}
274+
for i := 0; i < defaultRetry; i++ {
275+
results := []string{}
276+
var err error
277+
_ = pool.Retry(func() error {
278+
//let rsync server start
279+
time.Sleep(3 * time.Second)
280+
results, err = testutils.RunNucleiTemplateAndGetResults(filePath, finalURL, debug)
281+
return nil
282+
})
283+
if err != nil {
284+
return err
285+
}
286+
if err := expectResultsCount(results, 1); err == nil {
287+
return nil
288+
} else {
289+
errs = append(errs, err)
290+
}
291+
}
292+
return multierr.Combine(errs...)
293+
}
294+
261295
// purge any given resource if it is not nil
262296
func purge(resource *dockertest.Resource) {
263297
if resource != nil && pool != nil {
@@ -397,4 +431,20 @@ func init() {
397431
if err := mysqlResource.Expire(30); err != nil {
398432
log.Printf("Could not expire mysql resource: %s", err)
399433
}
434+
435+
// setup a temporary rsync server
436+
rsyncResource, err = pool.RunWithOptions(&dockertest.RunOptions{
437+
Repository: "alpine",
438+
Tag: "latest",
439+
Cmd: []string{"sh", "-c", "apk add --no-cache rsync shadow && useradd -m rsyncuser && echo 'rsyncuser:mysecret' | chpasswd && echo 'rsyncuser:MySecret123' > /etc/rsyncd.secrets && chmod 600 /etc/rsyncd.secrets && echo -e '[data]\\n path = /data\\n comment = Local Rsync Share\\n read only = false\\n auth users = rsyncuser\\n secrets file = /etc/rsyncd.secrets' > /etc/rsyncd.conf && mkdir -p /data && exec rsync --daemon --no-detach --config=/etc/rsyncd.conf"},
440+
Platform: "linux/amd64",
441+
})
442+
if err != nil {
443+
log.Printf("Could not start Rsync resource: %s", err)
444+
return
445+
}
446+
// by default expire after 30 sec
447+
if err := rsyncResource.Expire(30); err != nil {
448+
log.Printf("Could not expire Rsync resource: %s", err)
449+
}
400450
}

go.mod

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ require (
5353
github.com/DataDog/gostackparse v0.7.0
5454
github.com/Masterminds/semver/v3 v3.2.1
5555
github.com/Mzack9999/gcache v0.0.0-20230410081825-519e28eab057
56+
github.com/Mzack9999/go-rsync v0.0.0-20250821180103-81ffa574ef4d
5657
github.com/Mzack9999/goja v0.0.0-20250507184235-e46100e9c697
5758
github.com/Mzack9999/goja_nodejs v0.0.0-20250507184139-66bcbf65c883
5859
github.com/alexsnet/go-vnc v0.1.0
@@ -269,6 +270,7 @@ require (
269270
github.com/jinzhu/inflection v1.0.0 // indirect
270271
github.com/josharian/intern v1.0.0 // indirect
271272
github.com/k14s/starlark-go v0.0.0-20200720175618-3a5c849cc368 // indirect
273+
github.com/kaiakz/ubuffer v0.0.0-20200803053910-dd1083087166 // indirect
272274
github.com/kataras/jwt v0.1.10 // indirect
273275
github.com/kevinburke/ssh_config v1.2.0 // indirect
274276
github.com/klauspost/compress v1.18.2 // indirect

go.sum

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,8 @@ github.com/Mzack9999/gcache v0.0.0-20230410081825-519e28eab057 h1:KFac3SiGbId8ub
8787
github.com/Mzack9999/gcache v0.0.0-20230410081825-519e28eab057/go.mod h1:iLB2pivrPICvLOuROKmlqURtFIEsoJZaMidQfCG1+D4=
8888
github.com/Mzack9999/go-http-digest-auth-client v0.6.1-0.20220414142836-eb8883508809 h1:ZbFL+BDfBqegi+/Ssh7im5+aQfBRx6it+kHnC7jaDU8=
8989
github.com/Mzack9999/go-http-digest-auth-client v0.6.1-0.20220414142836-eb8883508809/go.mod h1:upgc3Zs45jBDnBT4tVRgRcgm26ABpaP7MoTSdgysca4=
90+
github.com/Mzack9999/go-rsync v0.0.0-20250821180103-81ffa574ef4d h1:DofPB5AcjTnOU538A/YD86/dfqSNTvQsAXgwagxmpu4=
91+
github.com/Mzack9999/go-rsync v0.0.0-20250821180103-81ffa574ef4d/go.mod h1:uzdh/m6XQJI7qRvufeBPDa+lj5SVCJO8B9eLxTbtI5U=
9092
github.com/Mzack9999/goja v0.0.0-20250507184235-e46100e9c697 h1:54I+OF5vS4a/rxnUrN5J3hi0VEYKcrTlpc8JosDyP+c=
9193
github.com/Mzack9999/goja v0.0.0-20250507184235-e46100e9c697/go.mod h1:yNqYRqxYkSROY1J+LX+A0tOSA/6soXQs5m8hZSqYBac=
9294
github.com/Mzack9999/goja_nodejs v0.0.0-20250507184139-66bcbf65c883 h1:+Is1AS20q3naP+qJophNpxuvx1daFOx9C0kLIuI0GVk=
@@ -634,6 +636,8 @@ github.com/k14s/difflib v0.0.0-20201117154628-0c031775bf57 h1:CwBRArr+BWBopnUJhD
634636
github.com/k14s/difflib v0.0.0-20201117154628-0c031775bf57/go.mod h1:B0xN2MiNBGWOWi9CcfAo9LBI8IU4J1utlbOIJCsmKr4=
635637
github.com/k14s/starlark-go v0.0.0-20200720175618-3a5c849cc368 h1:4bcRTTSx+LKSxMWibIwzHnDNmaN1x52oEpvnjCy+8vk=
636638
github.com/k14s/starlark-go v0.0.0-20200720175618-3a5c849cc368/go.mod h1:lKGj1op99m4GtQISxoD2t+K+WO/q2NzEPKvfXFQfbCA=
639+
github.com/kaiakz/ubuffer v0.0.0-20200803053910-dd1083087166 h1:IAukUBAVLUWBcexOYgkTD/EjMkfnNos7g7LFpyIdHJI=
640+
github.com/kaiakz/ubuffer v0.0.0-20200803053910-dd1083087166/go.mod h1:T4xUEny5PVedYIbkMAKYEBjMyDsOvvP0qK4s324AKA8=
637641
github.com/kataras/jwt v0.1.10 h1:GBXOF9RVInDPhCFBiDumRG9Tt27l7ugLeLo8HL5SeKQ=
638642
github.com/kataras/jwt v0.1.10/go.mod h1:xkimAtDhU/aGlQqjwvgtg+VyuPwMiyZHaY8LJRh0mYo=
639643
github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
id: rsync-test
2+
3+
info:
4+
name: Rsync Test
5+
author: pdteam
6+
severity: info
7+
8+
javascript:
9+
- code: |
10+
const rsync = require('nuclei/rsync');
11+
rsync.IsRsync(Host, Port);
12+
13+
args:
14+
Host: "{{Host}}"
15+
Port: "873"
16+
17+
matchers:
18+
- type: dsl
19+
dsl:
20+
- "success == true"
21+

pkg/js/generated/go/librsync/rsync.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ func init() {
2121

2222
// Objects / Classes
2323
"IsRsyncResponse": gojs.GetClassConstructor[lib_rsync.IsRsyncResponse](&lib_rsync.IsRsyncResponse{}),
24+
"RsyncClient": gojs.GetClassConstructor[lib_rsync.RsyncClient](&lib_rsync.RsyncClient{}),
2425
},
2526
).Register()
2627
}

pkg/js/generated/ts/rsync.ts

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,61 @@ export function IsRsync(host: string, port: number): IsRsyncResponse | null {
1313
return null;
1414
}
1515

16-
16+
/**
17+
* RsyncClient is a client for RSYNC servers.
18+
* Internally client uses https://github.com/gokrazy/rsync driver.
19+
* @example
20+
* ```javascript
21+
* const rsync = require('nuclei/rsync');
22+
* const client = new rsync.RsyncClient();
23+
* ```
24+
*/
25+
export class RsyncClient {
26+
27+
// Constructor of RsyncClient
28+
constructor() {}
29+
30+
/**
31+
* Connect establishes a connection to the rsync server with authentication.
32+
* @example
33+
* ```javascript
34+
* const rsync = require('nuclei/rsync');
35+
* const client = new rsync.RsyncClient();
36+
* const connected = client.Connect('acme.com', 873, 'username', 'password', 'backup');
37+
* ```
38+
*/
39+
public Connect(host: string, port: number, username: string, password: string, module: string): boolean | null {
40+
return null;
41+
}
42+
43+
/**
44+
* ListModules lists available modules on the rsync server.
45+
* @example
46+
* ```javascript
47+
* const rsync = require('nuclei/rsync');
48+
* const client = new rsync.RsyncClient();
49+
* const modules = client.ListModules('acme.com', 873, 'username', 'password');
50+
* log(toJSON(modules));
51+
* ```
52+
*/
53+
public ListModules(host: string, port: number, username: string, password: string): string[] | null {
54+
return null;
55+
}
56+
57+
/**
58+
* ListFilesInModule lists files in a specific module on the rsync server.
59+
* @example
60+
* ```javascript
61+
* const rsync = require('nuclei/rsync');
62+
* const client = new rsync.RsyncClient();
63+
* const files = client.ListFilesInModule('acme.com', 873, 'username', 'password', 'backup');
64+
* log(toJSON(files));
65+
* ```
66+
*/
67+
public ListFilesInModule(host: string, port: number, username: string, password: string, module: string): string[] | null {
68+
return null;
69+
}
70+
}
1771

1872
/**
1973
* IsRsyncResponse is the response from the IsRsync function.

0 commit comments

Comments
 (0)