diff --git a/nselib/coap.lua b/nselib/coap.lua
index 636b67b38..49e0fc508 100644
--- a/nselib/coap.lua
+++ b/nselib/coap.lua
@@ -1,4 +1,3 @@
-local bin = require "bin"
local comm = require "comm"
local json = require "json"
local lpeg = require "lpeg"
@@ -329,22 +328,23 @@ COAP.header.build = function(options)
code = COAP.header.codes.build(code)
-- Build the fixed portion of the header.
- local pkt = ""
ver = ver << 6
mtype = mtype << 4
- pkt = pkt .. bin.pack("C", ver | mtype | tkl)
- pkt = pkt .. code
- pkt = pkt .. bin.pack(">S", id)
- pkt = pkt .. token
+ local pkt = {
+ string.pack("B", ver | mtype | tkl),
+ code,
+ string.pack(">I2", id),
+ token,
+ }
-- Include optional portions of the header.
if options["options"] then
- pkt = pkt .. COAP.header.options.build(options.options)
+ pkt[#pkt+1] = COAP.header.options.build(options.options)
end
- return pkt
+ return table.concat(pkt)
end
--- Parses a CoAP message header.
@@ -361,9 +361,6 @@ end
-- string containing the error message on failure.
COAP.header.parse = function(buf, pos)
assert(type(buf) == "string")
- if #buf < 4 then
- return false, "Cannot parse a string of less than four bytes."
- end
if not pos or pos == 0 then
pos = 1
@@ -371,14 +368,11 @@ COAP.header.parse = function(buf, pos)
assert(type(pos) == "number")
assert(pos <= #buf)
- if pos + 4 - 1 > #buf then
+ if #buf - pos + 1 < 4 then
return false, "Fixed header extends past end of buffer."
end
- local pos, ver_type_tkl, code, id = bin.unpack("CA>S", buf, pos)
- if not pos then
- return false, "Failed to parse fixed header."
- end
+ local ver_type_tkl, code, id, pos = string.unpack(">Bc1I2", buf, pos)
-- Parse the fixed header.
local hdr = {}
@@ -486,7 +480,7 @@ COAP.header.codes.build = function(name)
class = class << 5
- return bin.pack("C", class | detail)
+ return string.pack("B", class | detail)
end
--- Parses a CoAP request or response code.
@@ -511,7 +505,7 @@ COAP.header.codes.parse = function(buf, pos)
assert(type(pos) == "number")
assert(pos <= #buf)
- local pos, id = bin.unpack("C", buf, pos)
+ local id, pos = string.unpack("B", buf, pos)
if not pos then
return false, id
end
@@ -1462,20 +1456,8 @@ COAP.header.options.value.uint.build = function(val)
if val == 0 then
return ""
end
-
- if val <= 255 then
- return bin.pack("C", val)
- end
-
- if val <= 65535 then
- return bin.pack(">S", val)
- end
-
- if val <= 16777215 then
- return bin.pack(">I", val):sub(2, 5)
- end
-
- return bin.pack(">I", val)
+ -- strip leading null bytes to use smallest space
+ return string.pack(">I16", val):gsub("^\0*","")
end
--- Parses a CoAP message Uint header option value.
@@ -1490,25 +1472,15 @@ end
COAP.header.options.value.uint.parse = function(buf)
assert(type(buf) == "string")
assert(#buf >= 0)
- assert(#buf <= 4)
+ assert(#buf <= 16)
if #buf == 0 then
return 0
end
- local val, pos
- if #buf == 1 then
- pos, val = bin.unpack("C", buf)
- elseif #buf == 2 then
- pos, val = bin.unpack(">S", buf)
- elseif #buf == 3 then
- pos, val = bin.unpack(">I", string.char(0x00) .. buf)
- else
- pos, val = bin.unpack(">I", buf)
- end
+ local val = string.unpack(">I" .. #buf, buf)
-- There should be no way for this to fail.
- assert(pos)
assert(val)
assert(type(val) == "number")
@@ -1567,19 +1539,18 @@ COAP.header.options.delta_length.build = function(delta, length)
end
if num <= 268 then
- return 13, bin.pack("C", num - 13)
+ return 13, string.pack("B", num - 13)
end
- return 14, bin.pack(">S", num - 269)
+ return 14, string.pack(">I2", num - 269)
end
local d1, d2 = build(delta)
local l1, l2 = build(length)
d1 = d1 << 4
- bin.pack("C", d1 | l1)
- return bin.pack("C", d1 | l1) .. d2 .. l2
+ return string.pack("B", d1 | l1) .. d2 .. l2
end
--- Parse the variable-length option delta and length field.
@@ -1613,7 +1584,7 @@ COAP.header.options.delta_length.parse = function(buf, pos)
assert(type(pos) == "number")
assert(pos <= #buf)
- local pos, delta_and_length = bin.unpack("C", buf, pos)
+ local delta_and_length, pos = string.unpack("B", buf, pos)
if not pos then
return false, nil, nil, delta_and_length
end
@@ -1636,20 +1607,20 @@ COAP.header.options.delta_length.parse = function(buf, pos)
if delta == 13 then
required_bytes = required_bytes + 1
- dspec = "C"
+ dspec = "B"
elseif delta == 14 then
required_bytes = required_bytes + 2
delta = 269
- dspec = ">S"
+ dspec = ">I2"
end
if length == 13 then
required_bytes = required_bytes + 1
- lspec = "C"
+ lspec = "B"
elseif length == 14 then
required_bytes = required_bytes + 2
length = 269
- lspec = ">S"
+ lspec = ">I2"
end
if pos + required_bytes - 1 > #buf then
@@ -1659,7 +1630,7 @@ COAP.header.options.delta_length.parse = function(buf, pos)
-- Extract the remaining bytes of each field.
if dspec then
local num
- pos, num = bin.unpack(dspec, buf, pos)
+ num, pos = string.unpack(dspec, buf, pos)
if not pos then
return false, nil, nil, num
end
@@ -1668,7 +1639,7 @@ COAP.header.options.delta_length.parse = function(buf, pos)
if lspec then
local num
- pos, num = bin.unpack(lspec, buf, pos)
+ num, pos = string.unpack(lspec, buf, pos)
if not pos then
return false, nil, nil, num
end
@@ -2426,7 +2397,7 @@ local tests = {
{
{["name"] = "etag", ["value"] = "ETAGETAG"},
},
- bin.pack("CA", 0x48, "ETAGETAG")
+ "\x48ETAGETAG"
},
{
-- Before
@@ -2450,7 +2421,7 @@ local tests = {
{["name"] = "uri_path", ["value"] = "foo"},
{["name"] = "max_age", ["value"] = 0},
},
- bin.pack("CAC", 0xB3, "foo", 0x30)
+ "\xB3foo\x30"
},
{
-- Before
@@ -2463,7 +2434,7 @@ local tests = {
{["name"] = "uri_path", ["value"] = ".well-known"},
{["name"] = "uri_path", ["value"] = "core"},
},
- bin.pack("CACA", 0xBB, ".well-known", 0x04, "core")
+ "\xBB.well-known\x04core"
},
{
-- Before
@@ -2482,14 +2453,7 @@ local tests = {
{["name"] = "uri_path", ["value"] = "core"},
{["name"] = "max_age", ["value"] = 0},
},
- bin.pack(
- "CACCACAC",
- 0x48, "ETAGETAG", -- ID: 4, Delta: 4
- 0x10, -- ID: 5, Delta: 1
- 0x6B, ".well-known", -- ID: 11, Delta: 6
- 0x04, "core", -- ID: 11, Delta: 0
- 0x30 -- ID: 14, Delta: 3
- )
+ "\x48ETAGETAG\x10\x6B.well-known\x04core\x30"
},
}
@@ -2537,15 +2501,7 @@ local tests = {
{["name"] = "uri_path", ["value"] = "core"},
},
},
- bin.pack(
- "CC>SACACA",
- 0x48,
- 0x01,
- 0x1234,
- "nmapcoap",
- 0xBB, ".well-known",
- 0x04, "core"
- )
+ "\x48\x01\x12\x34nmapcoap\xBB.well-known\x04core"
},
}
diff --git a/nselib/dhcp.lua b/nselib/dhcp.lua
index 575c508dc..bffa0cae0 100644
--- a/nselib/dhcp.lua
+++ b/nselib/dhcp.lua
@@ -14,7 +14,6 @@
-- o Added possibility to override transaction id
-- o Added WPAD action
-local bin = require "bin"
local datetime = require "datetime"
local ipOps = require "ipOps"
local math = require "math"
@@ -67,7 +66,7 @@ local function read_ip(data, pos, length)
local results = {}
for i=1, length, 4 do
local value
- pos, value = bin.unpack(">I", data, pos)
+ value, pos = string.unpack(">I4", data, pos)
table.insert(results, ipOps.fromdword(value))
end
@@ -75,7 +74,7 @@ local function read_ip(data, pos, length)
end
else
local value
- pos, value = bin.unpack(">I", data, pos)
+ value, pos = string.unpack(">I4", data, pos)
return pos, ipOps.fromdword(value)
end
@@ -89,7 +88,8 @@ end
--@return The new position (will always be pos + length, no matter what we think it should be)
--@return The value of the field, or nil if the field length was wrong.
local function read_string(data, pos, length)
- return bin.unpack(string.format("A%d", length), data, pos)
+ local value, pos = string.unpack(("c%d"):format(length), data, pos)
+ return pos, value
end
---Read a single byte. Print an error if the length isn't 1.
@@ -105,7 +105,8 @@ local function read_1_byte(data, pos, length)
pos = pos + length
return pos, nil
end
- return bin.unpack("C", data, pos)
+ local value, pos = string.unpack("B", data, pos)
+ return pos, value
end
---Read a message type. This is a single-byte value that's looked up in the request_types_str
@@ -163,7 +164,8 @@ local function read_2_bytes(data, pos, length)
pos = pos + length
return pos, nil
end
- return bin.unpack(">S", data, pos)
+ local value, pos = string.unpack(">I2", data, pos)
+ return pos, value
end
@@ -185,7 +187,7 @@ local function read_2_bytes_list(data, pos, length)
local results = {}
for i=1, length, 2 do
local value
- pos, value = bin.unpack(">S", data, pos)
+ value, pos = string.unpack(">I2", data, pos)
table.insert(results, value)
end
@@ -207,7 +209,8 @@ local function read_4_bytes(data, pos, length)
pos = pos + length
return pos, nil
end
- return bin.unpack(">I", data, pos)
+ local value, pos = string.unpack(">I4", data, pos)
+ return pos, value
end
---Read a 4-byte unsigned little endian value, and interpret it as a time offset value. Print an
@@ -225,7 +228,7 @@ local function read_time(data, pos, length)
pos = pos + length
return pos, nil
end
- pos, result = bin.unpack(">I", data, pos)
+ result, pos = string.unpack(">I4", data, pos)
return pos, datetime.format_time(result)
end
@@ -426,34 +429,32 @@ function dhcp_build(request_type, ip_address, mac_address, options, request_opti
end
-- Header
- packet = packet .. bin.pack(">CCCC", overrides['op'] or 1, overrides['htype'] or 1, overrides['hlen'] or 6, overrides['hops'] or 0) -- BOOTREQUEST, 10mb ethernet, 6 bytes long, 0 hops
+ packet = packet .. string.pack(">BBBB", overrides['op'] or 1, overrides['htype'] or 1, overrides['hlen'] or 6, overrides['hops'] or 0) -- BOOTREQUEST, 10mb ethernet, 6 bytes long, 0 hops
packet = packet .. ( overrides['xid'] or transaction_id ) -- Transaction ID =
- packet = packet .. bin.pack(">SS", overrides['secs'] or 0, overrides['flags'] or 0x0000) -- Secs, flags
+ packet = packet .. string.pack(">I2I2", overrides['secs'] or 0, overrides['flags'] or 0x0000) -- Secs, flags
packet = packet .. ip_address -- Client address
- packet = packet .. bin.pack("I", overrides['cookie'] or 0x63825363) -- Magic cookie
+ packet = packet .. string.pack(">I4", overrides['cookie'] or 0x63825363) -- Magic cookie
-- Options
- packet = packet .. bin.pack(">CCC", 0x35, 1, request_type) -- Request type
+ packet = packet .. string.pack(">BBB", 0x35, 1, request_type) -- Request type
for _, option in ipairs(options or {}) do
- packet = packet .. bin.pack(">C", option.number)
- if ( "string" == option.type ) then
- packet = packet .. bin.pack("p", option.value)
- elseif( "ip" == option.type ) then
- packet = packet .. bin.pack(">CI", 4, option.value)
+ packet = packet .. string.pack(">B", option.number)
+ if ( "string" == option.type or "ip" == option.type ) then
+ packet = packet .. string.pack("s1", option.value)
end
end
- packet = packet .. bin.pack(">CCA", 0x37, #request_options, request_options) -- Request options
- packet = packet .. bin.pack(">CCI", 0x33, 4, lease_time or 1) -- Lease time
+ packet = packet .. string.pack(">Bs1", 0x37, request_options) -- Request options
+ packet = packet .. string.pack(">BBI4", 0x33, 4, lease_time or 1) -- Lease time
- packet = packet .. bin.pack(">C", 0xFF) -- Termination
+ packet = packet .. "\xFF" -- Termination
return true, strbuf.dump(packet)
end
@@ -473,26 +474,26 @@ function dhcp_parse(data, transaction_id)
local result = {}
-- Receive the first bit and make sure we got the correct operation back
- pos, result['op'], result['htype'], result['hlen'], result['hops'] = bin.unpack(">CCCC", data, pos)
+ result.op, result.htype, result.hlen, result.hops, pos = string.unpack(">BBBB", data, pos)
if(result['op'] ~= 2) then
return false, string.format("DHCP server returned invalid reply ('op' wasn't BOOTREPLY (it was 0x%02x))", result['op'])
end
-- Confirm the transaction id
- pos, result['xid'] = bin.unpack("A4", data, pos)
+ result.xid, pos = string.unpack("c4", data, pos)
if(result['xid'] ~= transaction_id) then
return false, string.format("DHCP server returned invalid reply (transaction id didn't match (%s != %s))", result['xid'], transaction_id)
end
-- Unpack the secs, flags, addresses, sname, and file
- pos, result['secs'], result['flags'] = bin.unpack(">SS", data, pos)
- pos, result['ciaddr'] = bin.unpack(">I", data, pos)
- pos, result['yiaddr'] = bin.unpack(">I", data, pos)
- pos, result['siaddr'] = bin.unpack(">I", data, pos)
- pos, result['giaddr'] = bin.unpack(">I", data, pos)
- pos, result['chaddr'] = bin.unpack("A16", data, pos)
- pos, result['sname'] = bin.unpack("A64", data, pos)
- pos, result['file'] = bin.unpack("A128", data, pos)
+ result.secs, result.flags,
+ result.ciaddr,
+ result.yiaddr,
+ result.siaddr,
+ result.giaddr,
+ result.chaddr,
+ result.sname,
+ result.file, pos = string.unpack(">I2I2 I4I4I4I4 c16 c64 c128", data, pos)
-- Convert the addresses to strings
result['ciaddr_str'] = ipOps.fromdword(result['ciaddr'])
@@ -501,7 +502,7 @@ function dhcp_parse(data, transaction_id)
result['giaddr_str'] = ipOps.fromdword(result['giaddr'])
-- Confirm the cookie
- pos, result['cookie'] = bin.unpack(">I", data, pos)
+ result.cookie, pos = string.unpack(">I4", data, pos)
if(result['cookie'] ~= 0x63825363) then
return false, "DHCP server returned invalid reply (the magic cookie was invalid)"
end
@@ -515,7 +516,7 @@ function dhcp_parse(data, transaction_id)
end
local option, length
- pos, option, length = bin.unpack(">CC", data, pos)
+ option, length, pos = string.unpack(">BB", data, pos)
-- Check for termination condition
if(option == 0xFF) then
@@ -611,10 +612,10 @@ end
--@return The parsed response, as a table.
function make_request(target, request_type, ip_address, mac_address, options, request_options, overrides, lease_time)
-- A unique id that identifies this particular session (and lets us filter out what we don't want to see)
- local transaction_id = overrides and overrides['xid'] or bin.pack("I", ipOps.todword(ip_address)), mac_address, options, request_options, overrides, lease_time, transaction_id)
+ local status, packet = dhcp_build(request_type, ipOps.ip_to_str(ip_address), mac_address, options, request_options, overrides, lease_time, transaction_id)
if(not(status)) then
stdnse.debug1("dhcp: Couldn't build packet: " .. packet)
return false, "Couldn't build packet: " .. packet
diff --git a/nselib/mqtt.lua b/nselib/mqtt.lua
index 6e20ed9e7..822ef680a 100644
--- a/nselib/mqtt.lua
+++ b/nselib/mqtt.lua
@@ -920,7 +920,8 @@ MQTT.utf8_parse = function(buf, pos)
return false, ("Buffer at position %d has no space for a %d-byte UTF-8 string."):format(pos, str_length)
end
- return string.unpack(">s2", buf, pos)
+ local value, pos = string.unpack(">s2", buf, pos)
+ return pos, value
end
--- Prefix the body of an MQTT packet with a fixed header.
diff --git a/nselib/mysql.lua b/nselib/mysql.lua
index 2c2143d28..2e84431b5 100644
--- a/nselib/mysql.lua
+++ b/nselib/mysql.lua
@@ -7,7 +7,6 @@
--
-- @author Patrik Karlsson
-local bin = require "bin"
local nmap = require "nmap"
local stdnse = require "stdnse"
local string = require "string"
@@ -91,7 +90,7 @@ local function decodeHeader( data, pos )
local response = {}
local pos, tmp = pos or 1, 0
- pos, tmp = bin.unpack( "> 24 )
@@ -121,42 +120,38 @@ function receiveGreeting( socket )
end
local is_error
- pos, is_error = bin.unpack( "C", data, pos )
+ is_error, pos = string.unpack("B", data, pos)
if ( is_error == 0xff ) then
- pos, response.errorcode = bin.unpack( " 0 then
- pos, tmp, _ = bin.unpack("A" .. (math.max(13, auth_plugin_len - 8) - 1) .. "x", data, pos)
+ tmp, pos = string.unpack("c" .. (math.max(13, auth_plugin_len - 8) - 1) .. "x", data, pos)
response.salt = response.salt .. tmp
end
if response.extcapabilities & ExtCapabilities.SupportsAuthPlugins > 0 then
- response.auth_plugin_name = bin.unpack("z", data, pos)
+ response.auth_plugin_name = string.unpack("z", data, pos)
end
end
elseif response.proto == 9 then
- pos, response.auth_plugin_data = bin.unpack( "z", data, pos )
+ response.auth_plugin_data, pos = string.unpack( "z", data, pos )
else
stdnse.debug2("Unknown MySQL protocol version: %d", response.proto)
end
@@ -189,8 +184,8 @@ local function createLoginHash(pass, salt)
hash_stage3 = openssl.sha1( salt .. hash_stage2 )
for pos=1, hash_stage1:len() do
- _, b1 = bin.unpack( "C", hash_stage1, pos )
- _, b2 = bin.unpack( "C", hash_stage3, pos )
+ b1 = string.unpack( "B", hash_stage1, pos )
+ b2 = string.unpack( "B", hash_stage3, pos )
reply[pos] = string.char( b2 ~ b1 )
end
@@ -244,7 +239,7 @@ function loginRequest( socket, params, username, password, salt )
hash = createLoginHash( password, salt )
end
- local packet = bin.pack( " 0 then
- pos, response.errorcode = bin.unpack( "length and type
function decodeField( data, pos )
- local header, len
- local def, _
+ local _
local field = {}
- pos, len = bin.unpack( "C", data, pos )
- pos, field.catalog = bin.unpack( "A" .. len, data, pos )
-
- pos, len = bin.unpack( "C", data, pos )
- pos, field.database = bin.unpack( "A" .. len, data, pos )
-
- pos, len = bin.unpack( "C", data, pos )
- pos, field.table = bin.unpack( "A" .. len, data, pos )
-
- pos, len = bin.unpack( "C", data, pos )
- pos, field.orig_table = bin.unpack( "A" .. len, data, pos )
-
- pos, len = bin.unpack( "C", data, pos )
- pos, field.name = bin.unpack( "A" .. len, data, pos )
-
- pos, len = bin.unpack( "C", data, pos )
- pos, field.orig_name = bin.unpack( "A" .. len, data, pos )
-
- -- should be 0x0C
- pos, _ = bin.unpack( "C", data, pos )
-
- -- charset, in my case 0x0800
- pos, _ = bin.unpack( " 0 then
- local _, b = bin.unpack("C", data, pos )
+ local b = string.unpack("B", data, pos )
-- Is this the EOF packet?
if b == EOF_MARKER then
@@ -465,13 +441,11 @@ end
-- @return number containing the amount of fields
function decodeResultSetHeader( data )
- local _, fields
-
if data:len() ~= HEADER_SIZE + 1 then
return false, "Result set header was incorrect"
end
- _, fields = bin.unpack( "C", data, HEADER_SIZE + 1 )
+ local fields = string.unpack( "B", data, HEADER_SIZE + 1 )
return true, fields
end
@@ -486,16 +460,16 @@ end
-- @return rows table containing row tables
function decodeDataPackets( data, count )
- local len, pos = 0, 1, 1
- local header, row, rows = {}, {}, {}
+ local pos = 1
+ local rows = {}
- while pos < data:len() do
- row = {}
+ while pos <= data:len() do
+ local row = {}
+ local header
pos, header = decodeHeader( data, pos )
for i=1, count do
- pos, len = bin.unpack("C", data, pos )
- pos, row[i] = bin.unpack("A" .. len, data, pos)
+ row[i], pos = string.unpack("s1", data, pos)
end
table.insert( rows, row )
@@ -521,7 +495,7 @@ function sqlQuery( socket, query )
local packet, packet_len, pos, header
local status, fields, field_count, rows, rs
- packet = bin.pack("