Skip to content

Commit 6ff96b5

Browse files
committed
fix(pirania): fix global variable leaks and shell injection in utils.lua
getIpv4AndMac() leaked six global variables (fd, ipv4mac, fd6, ipv6mac, fd4, ipv4) that could corrupt state across concurrent CGI requests in uhttpd's Lua runtime. Add local declarations to all of them. Also add IP address validation before passing to shell commands. The ip_address parameter (from REMOTE_ADDR) was concatenated directly into grep commands without sanitization. A crafted value could execute arbitrary commands. validate_ip() now restricts input to characters valid for IPv4 (digits, dots) or IPv6 (hex, colons, brackets).
1 parent dc8f1aa commit 6ff96b5

1 file changed

Lines changed: 26 additions & 6 deletions

File tree

  • packages/pirania/files/usr/lib/lua/voucher

packages/pirania/files/usr/lib/lua/voucher/utils.lua

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,26 +38,46 @@ local function checkIfIpv4(ip)
3838
end
3939
end
4040

41+
--! Validate that an IP address contains only safe characters
42+
--! Prevents shell injection via crafted REMOTE_ADDR values
43+
local function validate_ip(ip)
44+
if ip == nil or type(ip) ~= "string" then
45+
return false
46+
end
47+
-- IPv4: digits and dots only
48+
if ip:match("^[0-9%.]+$") then
49+
return true
50+
end
51+
-- IPv6: hex, colons, brackets (for [::1] format)
52+
if ip:match("^[0-9a-fA-F:%[%]]+$") then
53+
return true
54+
end
55+
return false
56+
end
57+
4158
--! get ipv4 and MAC from a ip_address that could be ipv4 or ipv6
4259
function utils.getIpv4AndMac(ip_address)
60+
if not validate_ip(ip_address) then
61+
return { ip = nil, mac = nil }
62+
end
4363
local isIpv4 = checkIfIpv4(ip_address)
4464
if (isIpv4) then
4565
local ipv4macCommand = "cat /proc/net/arp | grep "..ip_address.." | awk -F ' ' '{print $4}' | head -n 1"
46-
fd = io.popen(ipv4macCommand, 'r')
47-
ipv4mac = fd:read('*l')
66+
local fd = io.popen(ipv4macCommand, 'r')
67+
local ipv4mac = fd:read('*l')
4868
fd:close()
4969
local res = {}
5070
res.ip = ip_address
5171
res.mac = ipv4mac
5272
return res
5373
else
5474
local ipv6macCommand = "ip neigh | grep "..ip_address.." | awk -F ' ' '{print $5}' | head -n 1"
55-
fd6 = io.popen(ipv6macCommand, 'r')
56-
ipv6mac = fd6:read('*l')
75+
local fd6 = io.popen(ipv6macCommand, 'r')
76+
local ipv6mac = fd6:read('*l')
5777
fd6:close()
5878
local ipv4cCommand = "cat /proc/net/arp | grep "..ipv6mac.." | awk -F ' ' '{print $1}' | head -n 1"
59-
fd4 = io.popen(ipv4cCommand, 'r')
60-
ipv4 = fd4:read('*l')
79+
local fd4 = io.popen(ipv4cCommand, 'r')
80+
local ipv4 = fd4:read('*l')
6181
fd4:close()
6282
local res = {}
6383
res.ip = ipv4

0 commit comments

Comments
 (0)