root@echelon:~# cat /var/log/cli-essentials/curl.md
// TUTORIAL

[*] cli-essentials #2 – cURL

cURL jest programem wiersza poleceń do transferu danych, który wspiera ponad 25 protokołów, w tym najważniejsze jak HTTP, HTTPS, FTP, POP3, SFTP czy IMAP. W moim artykule skupimy się głównie na HTTP/HTTPS, bo jest to dominujący protokół w nowoczesnych systemach SIEM, SaaS czy API, z którego będziemy korzystać zapewne najczęściej.

cURL warto poznać również ze względu na jego popularność. Znajduje się na Linux, macOS czy Windows 10+, wykorzystywany przez administratorów sieci, zespoły Blue Team i Red Team ze względu na pełną kontrolę i przejrzystość.

Pracując z cURL poznamy jak działa HTTP od środka – nagłówki, metody, status codes, cookies, redirecty czy TLS handshake. Jest to wiedza fundamentalna do pracy w IT.

Zaczniemy od podstawowej składni, która w cURL wygląda tak:

curl [opcje] [URL]

Najprostsze wykorzystanie cURL to podanie adresu URL bez żadnych opcji, zwróci on zawartość strony wprost do terminala:

curl https://httpbun.com

Możemy delikatnie zmodyfikować to zapytanie i wykorzystać pierwszą opcję/flagę:

-o <plik> / --output

Przekieruje to odpowiedź do konkretnego pliku:

curl -o strona.html https://httpbun.com

Przejdźmy w takim razie do zapoznania się z najważniejszymi flagami:

Zapisuje plik pod nazwą wziętą z końcówki URL. Dla przykładu https://archiwum.nask.pl/download/30/4940/NASK-raport-rynek-nazw-domeny-pl-2023.pdf zapisze się jako NASK-raport-rynek-nazw-domeny-pl-2023.pdf.

-O / --remote-name
curl -O https://archiwum.nask.pl/download/30/4940/NASK-raport-rynek-nazw-domeny-pl-2023.pdf

Tryb cichy – normalnie w trakcie działania cURL wyświetla pasek postępu i statystyki pobierania. Tryb cichy wyłącza ten szum.

-s / --silent

Poniższa flaga często działa w parze z -s, ponieważ w trybie cichym tracimy również informacje o błędach, co utrudnia debugowanie. -S przywraca informacje o błędach, dlatego w skryptach możemy spotkać flagę -sS.

-S / --show-error

Kolejna flaga pokazuje szczegółowy output. Rozwiązanie DNS, ustanowienie połączenia TCP, TLS handshake, wersję protokołu i wszystkie nagłówki. Jest to flaga kluczowa przy debugowaniu.

-v / --verbose

Bardziej szczegółowa wersja powyższej komendy z zapisaniem do pliku to:

--trace-ascii <plik>

NAGŁÓWKI I METODY HTTP

Podstawowe zapytanie, które wysyła żądanie typu HEAD zamiast GET. Serwer odpowiada wtedy samymi nagłówkami bez treści. Przydatne do sprawdzenia czy serwer odpowiada i co zwraca Content-Type.

-I / --head

Przykład odpowiedzi dla mojego bloga:

HTTP/2 403 date: Tue, 28 Apr 2026 11:50:16 GMT content-type: text/html; charset=UTF-8 content-length: 5235 accept-ch: Sec-CH-UA-Bitness, Sec-CH-UA-Arch, Sec-CH-UA-Full-Version, Sec-CH-UA-Mobile, Sec-CH-UA-Model, Sec-CH-UA-Platform-Version, Sec-CH-UA-Full-Version-List, Sec-CH-UA-Platform, Sec-CH-UA, UA-Bitness, UA-Arch, UA-Full-Version, UA-Mobile, UA-Model, UA-Platform-Version, UA-Platform, UA cf-mitigated: challenge content-security-policy: default-src 'none'; script-src 'nonce-ptilqWlhT752QmWmX3CTEL' 'unsafe-eval' https://challenges.cloudflare.com; script-src-attr 'none'; style-src 'unsafe-inline'; img-src 'self' https://challenges.cloudflare.com; connect-src 'self' https://challenges.cloudflare.com; frame-src 'self' https://challenges.cloudflare.com blob:; child-src 'self' https://challenges.cloudflare.com blob:; worker-src blob:; form-action http: https:; base-uri 'self' server: cloudflare critical-ch: Sec-CH-UA-Bitness, Sec-CH-UA-Arch, Sec-CH-UA-Full-Version, Sec-CH-UA-Mobile, Sec-CH-UA-Model, Sec-CH-UA-Platform-Version, Sec-CH-UA-Full-Version-List, Sec-CH-UA-Platform, Sec-CH-UA, UA-Bitness, UA-Arch, UA-Full-Version, UA-Mobile, UA-Model, UA-Platform-Version, UA-Platform, UA cross-origin-embedder-policy: require-corp cross-origin-opener-policy: same-origin cross-origin-resource-policy: same-origin origin-agent-cluster: ?1 permissions-policy: accelerometer=(),browsing-topics=(),camera=(),clipboard-read=(),clipboard-write=(),geolocation=(),gyroscope=(),hid=(),interest-cohort=(),magnetometer=(),microphone=(),payment=(),publickey-credentials-get=(),screen-wake-lock=(),serial=(),sync-xhr=(),usb=(),xr-spatial-tracking=(self) referrer-policy: same-origin server-timing: chlray;desc="9f35d93379ae0178" x-content-type-options: nosniff x-frame-options: SAMEORIGIN report-to: {"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=zINMwkykEgAurw39U%2FUPH2fJk0E7Co%2FWZB7%2FtRikW02DcCR3FOgMyxc1PCKoSaSzkIcepuyMeIsHyNyaOWF%2FcKGl6zV7nVmWY7D6jBsByrPhAsJdpDelb1kheWpuEJRxpBA%3D"}]} nel: {"report_to":"cf-nel","success_fraction":0.0,"max_age":604800} cf-ray: 9f35d93379ae0178-WAW alt-svc: h3=":443"; ma=86400

Z nagłówków widzimy, że kod odpowiedzi to 403, ale nie dlatego, że strona nie istnieje. Cloudflare wykrył połączenie cURL i zwrócił JS Challenge, co widać po nagłówkach:

cf-mitigated: challenge server: cloudflare

Poniższa flaga dołącza nagłówki odpowiedzi do outputu. Różnica od -I jest taka, że robi normalne zapytanie GET + treści z -I.

-i / --include

Kolejna flaga pozwala ustawić nagłówek User-Agent. Sam cURL wysyła domyślnie coś w stylu curl/7.88.1, co jest blokowane przez niektóre serwery, jak przekonaliśmy się wcześniej.

-A <string> / --user-agent

Spróbujemy jakiego user-agenta, który będzie podszywać się pod prawdziwą przeglądarkę i sprawdzimy odpowiedź Cloudflare.

Safari na iPhone:

curl -A "Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1" https://echelonwatch.pl

Cloudflare przepuszcza już taki ruch bez problemu. Odpowiedź serwera:

<!DOCTYPE html> <html lang="pl"> <head> <title>EchelonWatch - Monitorowanie cyberzagrożeń</title> <!-- Metadane SEO --> <!-- Meta podstawowe --> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="description" content="ECHELONWATCH – blog o cyberbezpieczeństwie, OSINT, analizie zagrożeń i technologii.">

Ustawienie Referer – ten nagłówek informuje, skąd przyszedł ruch:

-e <url> / --referer

Wysyłka danych w body i zmiana wtedy z GET na POST oraz automatyczne ustawienie Content-Type na application/x-www-form-urlencoded:

-d <dane> / --data

Wersja z kodowaniem w formacie URL:

--data-urlencode

COOKIES

Wysyłka cookie w żądaniu:

-b <cookie> / --cookie

Zapis cookie otrzymanych od serwera do pliku:

-c <plik> / --cookie-jar

SIEĆ I PRZEKIEROWANIA

Podążanie za przekierowaniami. W przypadku, gdy serwer odpowie kodem 3xx (redirect):

-L / --location

Przydatna komenda przy analizie pętli redirectów – pozwala ograniczyć liczbę przekierowań:

--max-redirs <n>

Możemy również wysłać nasz ruch przez proxy, np. -x http://127.0.0.1:8000 przepuści nasz ruch przez Burpa:

-x <proxy> / --proxy

UWIERZYTELNIANIE

Możliwości autoryzacji w HTTP:

-u <user:pass> / --user

Przykładowy wynik komendy, jaki otrzymamy po poprawnym zalogowaniu:

curl -u admin:secret https://httpbin.org/basic-auth/admin/secret { "authenticated": true, "user": "admin" }

FLAGA -w CZYLI ZMIENNE DO FORMATOWANEGO OUTPUTU

Jedna z ciekawszych i rzadziej stosowanych opcji cURLa. Po zakończeniu transferu możemy wpisać sformatowany string zawierający metryki z wykonanej operacji. Działa jak printf – podajemy szablon ze zmiennymi w postaci %{nazwa}, a cURL zastępuje je rzeczywistymi wartościami.

Przykłady zmiennych:

  • %{http_code} – kod odpowiedzi HTTP (200, 404, 500...)
  • %{url_effective} – finalny URL po wszystkich przekierowaniach
  • %{redirect_url} – URL następnego redirectu (jeśli był)
  • %{remote_ip} – adres IP serwera, z którym faktycznie rozmawialiśmy
  • %{remote_port} – port
  • %{ssl_verify_result} – wynik weryfikacji SSL (0 = OK, inne = błąd)
  • %{content_type} – Content-Type odpowiedzi
  • %{num_redirects} – ile razy nastąpiło przekierowanie
  • %{size_download} – ile bajtów pobrano
  • %{size_upload} – ile bajtów wysłano
  • %{speed_download} – średnia prędkość pobierania
  • %{time_namelookup} – czas rozwiązania DNS
  • %{time_connect} – czas nawiązania połączenia TCP
  • %{time_appconnect} – czas TLS handshake
  • %{time_pretransfer} – czas do momentu gotowości do transferu
  • %{time_starttransfer} – czas do pierwszego bajta odpowiedzi (TTFB)
  • %{time_total} – całkowity czas operacji

Przykład:

curl -o /dev/null -s -w "HTTP: %{http_code} | IP: %{remote_ip} | Czas: %{time_total}s\n" https://example.com

Otrzymamy wynik w terminalu:

HTTP: 200 | IP: 172.66.147.243 | Czas: 0.103003s

-o /dev/null wyrzuca body odpowiedzi, -s ukrywa pasek postępu, a -w wypisuje sformatowane dane.

METODY HTTP

Kiedy mamy omówione już najważniejsze flagi, możemy przejść do bardziej praktycznego zastosowania cURL.

Metodę GET już omówiliśmy na samym początku – jest to domyślne zapytanie, więc sprawdźmy działanie metody POST.

Użycie flagi -d automatycznie zmienia metodę na POST, więc flaga -X jest już zbędna, ale dla jasności postanowiłem ją zostawić w tym przykładzie.

curl -X POST https://api.example.com/login -d "user=admin&pass=secret"

PUT

PUT służy do aktualizacji. Składnia pozostaje prawie identyczna jak POST – różni się tylko metoda. Warto pamiętać, że -d domyślnie ustawia Content-Type na application/x-www-form-urlencoded, więc wysyłając JSON do nowoczesnego REST API, należy jawnie nadpisać nagłówek za pomocą -H "Content-Type: application/json", inaczej serwer może go odrzucić lub źle sparsować.

curl -X PUT https://api.example.com/users/123 -H "Content-Type: application/json" -d '{"name":"echelonwatch"}'

DELETE

DELETE nie potrzebuje body, wystarczy URL wskazujący na konkretny zasób:

curl -X DELETE https://api.example.com/users/123

Upload pliku używa formatu multipart/form-data – tego samego, którego używają formularze HTML z <input type="file">. Prefiks @ oznacza „wczytaj z pliku”, a pole description to zwykłe pole tekstowe. Możemy łączyć oba typy w jednym wywołaniu.

curl -F "file=@/path/do/pliku.pdf" -F "description=raport" https://api.example.com/upload

AUTORYZACJA

Basic Auth mamy już za sobą, więc omówmy Bearer Token. Jest to najpopularniejszy mechanizm w nowoczesnych REST API (OAuth 2.0, JWT). Jest to string, który serwer waliduje. Korzystamy z flagi -H:

curl -H "Authorization: Bearer eyJhbGciOi..." https://api.example.com

Kolejną bardzo przydatną opcją jest API Key w nagłówku. Pozwala nam odpytać takie usługi jak VirusTotal czy Shodan:

curl -H "x-apikey: TWOJ_KLUCZ" https://api.example.com

TROCHĘ PRAKTYCZNEGO ZASTOSOWANIA W SOC

Proste sprawdzenie nagłówków serwera bez pobierania treści:

curl -I https://httpbin.org

Odpowiedź:

HTTP/2 200 date: Wed, 29 Apr 2026 18:41:00 GMT content-type: text/html; charset=utf-8 content-length: 9593 server: gunicorn/19.9.0 access-control-allow-origin: * access-control-allow-credentials: true

Błyskawicznie otrzymujemy informacje, jaki webserver jest używany, nagłówki bezpieczeństwa, a jeżeli strona jest za Cloudflare, widzimy CF-RAY i Server: cloudflare.

Śledzenie łańcucha przekierowań jest bardzo przydatne, np. przy analizie phishingu:

curl -sIL https://httpbin.org/redirect/3 | grep -iE "^HTTP|^location:"

Odpowiedź serwera – bardzo fajnie widzimy wszystkie „przystanki”:

HTTP/2 302 location: /relative-redirect/2 HTTP/2 302 location: /relative-redirect/1 HTTP/2 302 location: /get HTTP/2 200

Zastosowanie wspomnianej wcześniej flagi -w.

Body standardowo wyrzucamy za pomocą -o /dev/null i otrzymujemy czasy odpowiedzi dla DNS, TLS itd., co w przypadku anomalii, np. bardzo długiego czasu odpowiedzi, może świadczyć o DNS hijacking, a wysokie TTFB o przeciążeniach serwera.

curl -o /dev/null -s -w \ "DNS: %{time_namelookup}s TCP: %{time_connect}s TLS: %{time_appconnect}s TTFB: %{time_starttransfer}s Total: %{time_total}s " https://httpbin.org

Odpowiedź:

DNS: 0.028969s TCP: 0.155727s TLS: 0.424003s TTFB: 0.574892s Total: 0.575223s

cURL to niezwykle rozbudowane narzędzie, które daje duże możliwości. Jak zwykle nie da się opisać wszystkiego tylko w jednym artykule, ale mam nadzieję, że zachęciłem do korzystania i eksperymentowania z cURL.

« POWRÓT DO LISTY ARTYKUŁÓW

system@echelon:~# cat /etc/privacy_notice.txt

Ta strona używa Google Analytics do zbierania anonimowych informacji o ruchu na stronie. Kontynuując korzystanie z tej strony, wyrażasz zgodę na używanie plików cookie zgodnie z naszą Polityką Prywatności.