Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -665,6 +665,7 @@
- [3632 - Pentesting distcc](network-services-pentesting/3632-pentesting-distcc.md)
- [3690 - Pentesting Subversion (svn server)](network-services-pentesting/3690-pentesting-subversion-svn-server.md)
- [3702/UDP - Pentesting WS-Discovery](network-services-pentesting/3702-udp-pentesting-ws-discovery.md)
- [4000,10080 - Pentesting TiDB](network-services-pentesting/4000-10080-pentesting-tidb.md)
- [4369 - Pentesting Erlang Port Mapper Daemon (epmd)](network-services-pentesting/4369-pentesting-erlang-port-mapper-daemon-epmd.md)
- [4786 - Cisco Smart Install](network-services-pentesting/4786-cisco-smart-install.md)
- [4840 - OPC Unified Architecture](network-services-pentesting/4840-pentesting-opc-ua.md)
Expand Down
157 changes: 157 additions & 0 deletions src/network-services-pentesting/4000-10080-pentesting-tidb.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
# 4000,10080 - Pentesting TiDB

{{#include ../banners/hacktricks-training.md}}

## Basic Information

TiDB is a distributed SQL database with a MySQL-compatible client listener, but an assessment must also cover the HTTP status and control planes of TiDB, Placement Driver (PD), TiKV, and the monitoring stack. These interfaces are normally useful only from trusted cluster networks; if they are reachable after an SSRF, VPN foothold, container escape, or internal-host compromise, they can expose topology and runtime data or accept administrative operations without database credentials.<sup>[[1]](#references)[[3]](#references)</sup>

Common listeners are shown below. Ports are configurable, and **9090** is the Prometheus listener observed in the assessed deployment rather than a TiDB protocol port.<sup>[[1]](#references)[[3]](#references)</sup>

| Port | Component | Purpose |
| --- | --- | --- |
| `4000/tcp` | TiDB | MySQL protocol for applications and DBA tools |
| `10080/tcp` | TiDB | HTTP status, metrics, configuration, and profiling |
| `2379/tcp` | PD | TiDB-to-PD traffic and PD HTTP API |
| `2380/tcp` | PD | Communication between PD nodes |
| `20160/tcp` | TiKV | TiKV service traffic |
| `20180/tcp` | TiKV | HTTP status and metrics |
| `9090/tcp` | Prometheus | Monitoring UI and HTTP API when deployed |

## Listener and transport enumeration

From a cluster host, map each socket to its process; remotely, scan the complete component set instead of stopping at the MySQL-compatible listener. Then test HTTP and HTTPS separately because an open status port might be plaintext, server-authenticated TLS, or mTLS.<sup>[[1]](#references)[[3]](#references)</sup>

```bash
# Local host
ss -lntp
netstat -tlnp

# Remote host(s)
nmap -sV -Pn -p 2379,2380,4000,9090,10080,20160,20180 <host>
curl -m 3 -i http://<host>:10080/status
curl -m 3 -ki https://<host>:10080/status
openssl s_client -connect <host>:10080 -servername <host> </dev/null
```

Do not interpret a failed unauthenticated HTTPS request as a closed API. A TLS alert requesting a client certificate indicates an mTLS boundary; a self-signed client certificate being rejected shows that the server validates trust rather than accepting any certificate. With an authorized cluster certificate, retest using `curl --cert client.pem --key client-key.pem --cacert ca.crt`.<sup>[[1]](#references)[[8]](#references)</sup>

## TiDB status API - `10080/tcp`

The status server exposes `/status`, `/metrics`, schema/storage metadata, configuration, and Go profiling handlers. In the audited v8.5.2 router, `GET /` also generated an HTML index from named routes, which makes it a useful first request; exact routes and methods vary by release.<sup>[[4]](#references)[[5]](#references)</sup>

```bash
base=http://<host>:10080
curl -si "$base/"
curl -s "$base/status" | jq .
curl -s "$base/config" | jq .
curl -s "$base/info" | jq .
curl -s "$base/info/all" | jq .
curl -s "$base/schema_storage" | jq .
curl -s "$base/ddl/history" | jq .
curl -s "$base/metrics" | head
```

An unauthenticated `/config` response can disclose advertised addresses, PD endpoints, Unix sockets, temporary and storage directories, log and slow-query filenames, and operational limits. Use those values to build the cluster graph and identify follow-on hosts and paths; configuration disclosure alone is not code execution.<sup>[[1]](#references)</sup>

The same router can include control handlers such as `/ddl/owner/resign`, `/upgrade/{op}`, and table scatter/stop-scatter operations. Confirm exposure with the route index and source/version mapping, but do not invoke state-changing routes outside an explicitly authorized disposable environment.<sup>[[1]](#references)[[5]](#references)</sup>

### Exposed Go `pprof`

TiDB and supporting Go services can publish `net/http/pprof` below `/debug/pprof/`. The index lists available profiles; `cmdline` returns NUL-delimited process arguments, while goroutine, heap, CPU, and trace handlers expose progressively more runtime data and can consume target resources while collecting a profile.<sup>[[1]](#references)[[7]](#references)</sup>

```bash
base=http://<host>:10080
curl -s "$base/debug/pprof/"
curl -s "$base/debug/pprof/cmdline" | tr '\0' ' '; echo
curl -s "$base/debug/pprof/goroutine?debug=1" | head -n 100
curl -s "$base/debug/pprof/heap" -o heap.pb.gz
go tool pprof -top heap.pb.gz
```

The command line can reveal binary and configuration paths; goroutine dumps expose function names and execution state; profiles can reveal memory addresses and other process details useful for exploit development or validating a separate compromise. Prefer the index, `cmdline`, and short textual samples during triage—CPU profiles and traces actively run for a requested duration and can add load.<sup>[[1]](#references)[[7]](#references)</sup>

Repeat the path checks against other discovered Go management listeners. In the assessed deployment, `ng-monitoring-server` exposed its NUL-delimited command line at `localhost:12020/debug/pprof/cmdline`; port `12020` is deployment-specific, not a universal TiDB port.<sup>[[1]](#references)</sup>

An SSRF primitive may reach this listener even when it is not directly routable; see [SSRF-vulnerable internal platforms](../pentesting-web/ssrf-server-side-request-forgery/ssrf-vulnerable-platforms.md#blind-ssrf-canaries-against-internal-software). For Go HTTP routing-specific checks, see [Go `net/http` path handling](pentesting-web/golang.md).

## PD API - `2379/tcp`

PD exposes cluster state at `/pd/api/v1/`. Start with read-only requests to enumerate stores, schedulers, operators, and configuration.<sup>[[4]](#references)[[6]](#references)</sup>

```bash
pd=http://<pd-host>:2379/pd/api/v1
curl -s "$pd/stores" | jq .
curl -s "$pd/schedulers" | jq .
curl -s "$pd/operators" | jq .
curl -s "$pd/config" | jq .
curl -s "$pd/cluster/status" | jq .
```

On the audited route set, the same unauthenticated API surface included state-changing methods: creating/deleting operators or schedulers, updating configuration and placement rules, changing store state/labels/weights/limits, and removing tombstone stores. A successful unauthenticated `GET` proves disclosure, but it does **not** by itself prove that every mutating method is reachable through the deployment's proxies or middleware; validate any write operation only with explicit authorization and a rollback plan.<sup>[[1]](#references)[[6]](#references)</sup>

## TiKV status API - `20180/tcp`

The audited TiKV v8.5.2 status server provided read-only routes such as `/status`, `/metrics`, `/config`, `/engine_type`, `/region`, `/resource_groups`, and `/async_tasks`, plus profiling endpoints below `/debug/pprof/`. These are implemented by TiKV's Rust service even though several paths resemble Go `pprof`.<sup>[[1]](#references)[[10]](#references)</sup>

```bash
tikv=http://<tikv-host>:20180
curl -si "$tikv/status"
curl -s "$tikv/config" | jq .
curl -s "$tikv/engine_type"; echo
curl -s "$tikv/resource_groups" | jq .
curl -s "$tikv/debug/pprof/cmdline" | tr '\0' ' '; echo
curl -s "$tikv/metrics" | head
```

The same router also included `POST /config`, `PUT /config/reload`, log-level changes, and `PUT /pause_grpc` and `/resume_grpc`. Treat these as potentially disruptive administrative primitives: fingerprint them from the source and response methods, but do not execute them on a production cluster merely to prove that the read-only status API is exposed.<sup>[[1]](#references)[[10]](#references)</sup>

## Prometheus and monitoring exposure

The assessed monitoring host exposed Prometheus on `0.0.0.0:9090` without authentication or TLS, alongside Alertmanager, exporters, Grafana, PD, and an `ng-monitoring-server`. Treat the listener set as a topology fingerprint: the Prometheus HTTP API exposes targets and permits PromQL queries, which can disclose component names, addresses, roles, and operating behavior; any enabled management or lifecycle operation must be evaluated separately.<sup>[[1]](#references)[[9]](#references)</sup>

```bash
prom=http://<monitor-host>:9090
curl -s "$prom/api/v1/status/buildinfo" | jq .
curl -s "$prom/api/v1/targets" | jq '.data.activeTargets[] | {scrapeUrl,health,labels}'
curl -sG "$prom/api/v1/query" --data-urlencode 'query=up' | jq .
```

Only claim administrative impact after verifying that a state-changing endpoint is enabled and reachable; an exposed query API and target inventory are already valuable reconnaissance but are not equivalent to host compromise.<sup>[[1]](#references)</sup>

## Detecting plaintext component traffic

TiDB supports TLS between components, but the assessed stock configuration did not enforce it. From an authorized network observation point, capture the component ports and distinguish TLS handshakes from plaintext HTTP or non-TLS component protocols. This validates transport exposure without attempting an active man-in-the-middle attack.<sup>[[1]](#references)[[8]](#references)</sup>

```bash
sudo tcpdump -i <iface> -nn -s0 -w tidb-components.pcap \
'tcp port 2379 or tcp port 2380 or tcp port 10080 or tcp port 20160 or tcp port 20180'

tshark -r tidb-components.pcap -Y 'tls.handshake or http.request' \
-T fields -e frame.time -e ip.src -e ip.dst -e tcp.dstport -e http.request.full_uri
```

Absence of decoded TLS packets is not sufficient on its own: confirm that the capture contains complete new connections, then inspect for a TLS ClientHello with `tshark -Y 'tls.handshake.type == 1'` or test each listener with `openssl s_client`. Keep SQL client TLS on port 4000 conceptually separate from **between-component** TLS for TiDB, PD, TiKV, and their control/status endpoints.<sup>[[3]](#references)[[8]](#references)</sup>

## Hardening checks

Verify that status and control listeners are bound to loopback or a dedicated management network, and that firewalls limit `10080`, `20180`, `2379`, `2380`, `20160`, and monitoring ports to required peers. Where remote management is necessary, require trusted client certificates and verify the configured CA/CN policy; disabling or restricting `pprof` is preferable when profiling is not operationally required.<sup>[[1]](#references)[[8]](#references)</sup>

After enabling component TLS, validate TiDB on `10080`, PD on `2379`, and TiKV on `20160` with the intended CA, certificate, and key. Also repeat the test **without** a client certificate: a securely configured mTLS endpoint should reject it rather than silently falling back to plaintext or server-only TLS.<sup>[[8]](#references)</sup>

The demonstrated attack boundary is primarily internal-network reconnaissance, information disclosure, management-plane abuse, and on-path traffic interception. The assessment did not establish a complete RCE or privilege-escalation chain, so avoid inflating an exposed status endpoint into an unsupported compromise claim.<sup>[[1]](#references)[[2]](#references)</sup>

## References

- [1] [NCC Group - TiDB Security Assessment v1.1 (PDF)](https://www.nccgroup.com/media/qetaerqm/ncc_group_pingcap_e022582_report_2026-06-25_v11.pdf)
- [2] [NCC Group - Public Report: TiDB Security Assessment](https://www.nccgroup.com/research/public-report-tidb-security-assessment/)
- [3] [TiDB documentation - Software, hardware, and network port requirements](https://docs.pingcap.com/tidb/stable/hardware-and-software-requirements/)
- [4] [TiDB documentation - TiDB Monitoring API](https://docs.pingcap.com/tidb/stable/tidb-monitoring-api/)
- [5] [TiDB v8.5.2 status HTTP router source](https://github.com/pingcap/tidb/blob/f43a13324440f92209e2a9f04c0bbe9cf763978d/pkg/server/http_status.go)
- [6] [PD v8.5.2 API router source](https://github.com/tikv/pd/blob/4cd009c4db3c15215341a96521dd53e53c55e5bd/server/api/router.go)
- [7] [Go standard library - `net/http/pprof`](https://pkg.go.dev/net/http/pprof)
- [8] [TiDB documentation - Enable TLS between TiDB components](https://docs.pingcap.com/tidb/stable/enable-tls-between-components/)
- [9] [Prometheus documentation - HTTP API](https://prometheus.io/docs/prometheus/latest/querying/api/)
- [10] [TiKV v8.5.2 status server source](https://github.com/tikv/tikv/blob/a150e4569fda1c64763fda297f4e09775759de4a/src/server/status_server/mod.rs)

{{#include ../banners/hacktricks-training.md}}
6 changes: 6 additions & 0 deletions src/network-services-pentesting/pentesting-web/golang.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ curl --path-as-is -X CONNECT http://gofs.web.jctf.pro/../flag

Compare the response with requests using a normal method and a canonical path. A different response is only an indicator; confirm that the discrepancy crosses an authorization boundary before reporting it.

For a concrete Go service where the HTTP management listener also exposes `pprof`, see:

{{#ref}}
../4000-10080-pentesting-tidb.md
{{#endref}}

## References

- [1] [Go source - historical `ServeMux.Handler` handling of `CONNECT`](https://github.com/golang/go/blob/9bb97ea047890e900dae04202a231685492c4b18/src/net/http/server.go#L2354-L2364)
Expand Down