coolbins/system/usr/share/nmap/scripts/http-exif-spider.nse

540 lines
20 KiB
Plaintext
Raw Normal View History

description = [[
Spiders a site's images looking for interesting exif data embedded in
.jpg files. Displays the make and model of the camera, the date the photo was
taken, and the embedded geotag information.
]]
---
-- @usage
-- nmap --script http-exif-spider -p80,443 <host>
--
-- @output
-- PORT STATE SERVICE REASON
-- 80/tcp open http syn-ack
-- | http-exif-spider:
-- | http://www.javaop.com/Nationalmuseum.jpg
-- | Make: Canon
-- | Model: Canon PowerShot S100\xB4
-- | Date: 2003:03:29 13:35:40
-- | http://www.javaop.com/topleft.jpg
-- |_ GPS: 49.941250,-97.206189 - https://maps.google.com/maps?q=49.94125,-97.20618863493
--
-- @args http-exif-spider.url the url to start spidering. This is a URL
-- relative to the scanned host eg. /default.html (default: /)
author = "Ron Bowes"
license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
categories = {"intrusive"}
local shortport = require 'shortport'
local stdnse = require 'stdnse'
local httpspider = require 'httpspider'
local string = require 'string'
local table = require 'table'
-- These definitions are copied/pasted/reformatted from the jhead-2.96 sourcecode
-- (the code is effectively public domain, but credit where credit's due!)
TAG_INTEROP_INDEX = 0x0001
TAG_INTEROP_VERSION = 0x0002
TAG_IMAGE_WIDTH = 0x0100
TAG_IMAGE_LENGTH = 0x0101
TAG_BITS_PER_SAMPLE = 0x0102
TAG_COMPRESSION = 0x0103
TAG_PHOTOMETRIC_INTERP = 0x0106
TAG_FILL_ORDER = 0x010A
TAG_DOCUMENT_NAME = 0x010D
TAG_IMAGE_DESCRIPTION = 0x010E
TAG_MAKE = 0x010F
TAG_MODEL = 0x0110
TAG_SRIP_OFFSET = 0x0111
TAG_ORIENTATION = 0x0112
TAG_SAMPLES_PER_PIXEL = 0x0115
TAG_ROWS_PER_STRIP = 0x0116
TAG_STRIP_BYTE_COUNTS = 0x0117
TAG_X_RESOLUTION = 0x011A
TAG_Y_RESOLUTION = 0x011B
TAG_PLANAR_CONFIGURATION = 0x011C
TAG_RESOLUTION_UNIT = 0x0128
TAG_TRANSFER_FUNCTION = 0x012D
TAG_SOFTWARE = 0x0131
TAG_DATETIME = 0x0132
TAG_ARTIST = 0x013B
TAG_WHITE_POINT = 0x013E
TAG_PRIMARY_CHROMATICITIES = 0x013F
TAG_TRANSFER_RANGE = 0x0156
TAG_JPEG_PROC = 0x0200
TAG_THUMBNAIL_OFFSET = 0x0201
TAG_THUMBNAIL_LENGTH = 0x0202
TAG_Y_CB_CR_COEFFICIENTS = 0x0211
TAG_Y_CB_CR_SUB_SAMPLING = 0x0212
TAG_Y_CB_CR_POSITIONING = 0x0213
TAG_REFERENCE_BLACK_WHITE = 0x0214
TAG_RELATED_IMAGE_WIDTH = 0x1001
TAG_RELATED_IMAGE_LENGTH = 0x1002
TAG_CFA_REPEAT_PATTERN_DIM = 0x828D
TAG_CFA_PATTERN1 = 0x828E
TAG_BATTERY_LEVEL = 0x828F
TAG_COPYRIGHT = 0x8298
TAG_EXPOSURETIME = 0x829A
TAG_FNUMBER = 0x829D
TAG_IPTC_NAA = 0x83BB
TAG_EXIF_OFFSET = 0x8769
TAG_INTER_COLOR_PROFILE = 0x8773
TAG_EXPOSURE_PROGRAM = 0x8822
TAG_SPECTRAL_SENSITIVITY = 0x8824
TAG_GPSINFO = 0x8825
TAG_ISO_EQUIVALENT = 0x8827
TAG_OECF = 0x8828
TAG_EXIF_VERSION = 0x9000
TAG_DATETIME_ORIGINAL = 0x9003
TAG_DATETIME_DIGITIZED = 0x9004
TAG_COMPONENTS_CONFIG = 0x9101
TAG_CPRS_BITS_PER_PIXEL = 0x9102
TAG_SHUTTERSPEED = 0x9201
TAG_APERTURE = 0x9202
TAG_BRIGHTNESS_VALUE = 0x9203
TAG_EXPOSURE_BIAS = 0x9204
TAG_MAXAPERTURE = 0x9205
TAG_SUBJECT_DISTANCE = 0x9206
TAG_METERING_MODE = 0x9207
TAG_LIGHT_SOURCE = 0x9208
TAG_FLASH = 0x9209
TAG_FOCALLENGTH = 0x920A
TAG_SUBJECTAREA = 0x9214
TAG_MAKER_NOTE = 0x927C
TAG_USERCOMMENT = 0x9286
TAG_SUBSEC_TIME = 0x9290
TAG_SUBSEC_TIME_ORIG = 0x9291
TAG_SUBSEC_TIME_DIG = 0x9292
TAG_WINXP_TITLE = 0x9c9b
TAG_WINXP_COMMENT = 0x9c9c
TAG_WINXP_AUTHOR = 0x9c9d
TAG_WINXP_KEYWORDS = 0x9c9e
TAG_WINXP_SUBJECT = 0x9c9f
TAG_FLASH_PIX_VERSION = 0xA000
TAG_COLOR_SPACE = 0xA001
TAG_PIXEL_X_DIMENSION = 0xA002
TAG_PIXEL_Y_DIMENSION = 0xA003
TAG_RELATED_AUDIO_FILE = 0xA004
TAG_INTEROP_OFFSET = 0xA005
TAG_FLASH_ENERGY = 0xA20B
TAG_SPATIAL_FREQ_RESP = 0xA20C
TAG_FOCAL_PLANE_XRES = 0xA20E
TAG_FOCAL_PLANE_YRES = 0xA20F
TAG_FOCAL_PLANE_UNITS = 0xA210
TAG_SUBJECT_LOCATION = 0xA214
TAG_EXPOSURE_INDEX = 0xA215
TAG_SENSING_METHOD = 0xA217
TAG_FILE_SOURCE = 0xA300
TAG_SCENE_TYPE = 0xA301
TAG_CFA_PATTERN = 0xA302
TAG_CUSTOM_RENDERED = 0xA401
TAG_EXPOSURE_MODE = 0xA402
TAG_WHITEBALANCE = 0xA403
TAG_DIGITALZOOMRATIO = 0xA404
TAG_FOCALLENGTH_35MM = 0xA405
TAG_SCENE_CAPTURE_TYPE = 0xA406
TAG_GAIN_CONTROL = 0xA407
TAG_CONTRAST = 0xA408
TAG_SATURATION = 0xA409
TAG_SHARPNESS = 0xA40A
TAG_DISTANCE_RANGE = 0xA40C
TAG_IMAGE_UNIQUE_ID = 0xA420
TagTable = {}
TagTable[TAG_INTEROP_INDEX] = "InteropIndex"
TagTable[TAG_INTEROP_VERSION] = "InteropVersion"
TagTable[TAG_IMAGE_WIDTH] = "ImageWidth"
TagTable[TAG_IMAGE_LENGTH] = "ImageLength"
TagTable[TAG_BITS_PER_SAMPLE] = "BitsPerSample"
TagTable[TAG_COMPRESSION] = "Compression"
TagTable[TAG_PHOTOMETRIC_INTERP] = "PhotometricInterpretation"
TagTable[TAG_FILL_ORDER] = "FillOrder"
TagTable[TAG_DOCUMENT_NAME] = "DocumentName"
TagTable[TAG_IMAGE_DESCRIPTION] = "ImageDescription"
TagTable[TAG_MAKE] = "Make"
TagTable[TAG_MODEL] = "Model"
TagTable[TAG_SRIP_OFFSET] = "StripOffsets"
TagTable[TAG_ORIENTATION] = "Orientation"
TagTable[TAG_SAMPLES_PER_PIXEL] = "SamplesPerPixel"
TagTable[TAG_ROWS_PER_STRIP] = "RowsPerStrip"
TagTable[TAG_STRIP_BYTE_COUNTS] = "StripByteCounts"
TagTable[TAG_X_RESOLUTION] = "XResolution"
TagTable[TAG_Y_RESOLUTION] = "YResolution"
TagTable[TAG_PLANAR_CONFIGURATION] = "PlanarConfiguration"
TagTable[TAG_RESOLUTION_UNIT] = "ResolutionUnit"
TagTable[TAG_TRANSFER_FUNCTION] = "TransferFunction"
TagTable[TAG_SOFTWARE] = "Software"
TagTable[TAG_DATETIME] = "DateTime"
TagTable[TAG_ARTIST] = "Artist"
TagTable[TAG_WHITE_POINT] = "WhitePoint"
TagTable[TAG_PRIMARY_CHROMATICITIES]= "PrimaryChromaticities"
TagTable[TAG_TRANSFER_RANGE] = "TransferRange"
TagTable[TAG_JPEG_PROC] = "JPEGProc"
TagTable[TAG_THUMBNAIL_OFFSET] = "ThumbnailOffset"
TagTable[TAG_THUMBNAIL_LENGTH] = "ThumbnailLength"
TagTable[TAG_Y_CB_CR_COEFFICIENTS] = "YCbCrCoefficients"
TagTable[TAG_Y_CB_CR_SUB_SAMPLING] = "YCbCrSubSampling"
TagTable[TAG_Y_CB_CR_POSITIONING] = "YCbCrPositioning"
TagTable[TAG_REFERENCE_BLACK_WHITE] = "ReferenceBlackWhite"
TagTable[TAG_RELATED_IMAGE_WIDTH] = "RelatedImageWidth"
TagTable[TAG_RELATED_IMAGE_LENGTH] = "RelatedImageLength"
TagTable[TAG_CFA_REPEAT_PATTERN_DIM]= "CFARepeatPatternDim"
TagTable[TAG_CFA_PATTERN1] = "CFAPattern"
TagTable[TAG_BATTERY_LEVEL] = "BatteryLevel"
TagTable[TAG_COPYRIGHT] = "Copyright"
TagTable[TAG_EXPOSURETIME] = "ExposureTime"
TagTable[TAG_FNUMBER] = "FNumber"
TagTable[TAG_IPTC_NAA] = "IPTC/NAA"
TagTable[TAG_EXIF_OFFSET] = "ExifOffset"
TagTable[TAG_INTER_COLOR_PROFILE] = "InterColorProfile"
TagTable[TAG_EXPOSURE_PROGRAM] = "ExposureProgram"
TagTable[TAG_SPECTRAL_SENSITIVITY] = "SpectralSensitivity"
TagTable[TAG_GPSINFO] = "GPS Dir offset"
TagTable[TAG_ISO_EQUIVALENT] = "ISOSpeedRatings"
TagTable[TAG_OECF] = "OECF"
TagTable[TAG_EXIF_VERSION] = "ExifVersion"
TagTable[TAG_DATETIME_ORIGINAL] = "DateTimeOriginal"
TagTable[TAG_DATETIME_DIGITIZED] = "DateTimeDigitized"
TagTable[TAG_COMPONENTS_CONFIG] = "ComponentsConfiguration"
TagTable[TAG_CPRS_BITS_PER_PIXEL] = "CompressedBitsPerPixel"
TagTable[TAG_SHUTTERSPEED] = "ShutterSpeedValue"
TagTable[TAG_APERTURE] = "ApertureValue"
TagTable[TAG_BRIGHTNESS_VALUE] = "BrightnessValue"
TagTable[TAG_EXPOSURE_BIAS] = "ExposureBiasValue"
TagTable[TAG_MAXAPERTURE] = "MaxApertureValue"
TagTable[TAG_SUBJECT_DISTANCE] = "SubjectDistance"
TagTable[TAG_METERING_MODE] = "MeteringMode"
TagTable[TAG_LIGHT_SOURCE] = "LightSource"
TagTable[TAG_FLASH] = "Flash"
TagTable[TAG_FOCALLENGTH] = "FocalLength"
TagTable[TAG_MAKER_NOTE] = "MakerNote"
TagTable[TAG_USERCOMMENT] = "UserComment"
TagTable[TAG_SUBSEC_TIME] = "SubSecTime"
TagTable[TAG_SUBSEC_TIME_ORIG] = "SubSecTimeOriginal"
TagTable[TAG_SUBSEC_TIME_DIG] = "SubSecTimeDigitized"
TagTable[TAG_WINXP_TITLE] = "Windows-XP Title"
TagTable[TAG_WINXP_COMMENT] = "Windows-XP comment"
TagTable[TAG_WINXP_AUTHOR] = "Windows-XP author"
TagTable[TAG_WINXP_KEYWORDS] = "Windows-XP keywords"
TagTable[TAG_WINXP_SUBJECT] = "Windows-XP subject"
TagTable[TAG_FLASH_PIX_VERSION] = "FlashPixVersion"
TagTable[TAG_COLOR_SPACE] = "ColorSpace"
TagTable[TAG_PIXEL_X_DIMENSION] = "ExifImageWidth"
TagTable[TAG_PIXEL_Y_DIMENSION] = "ExifImageLength"
TagTable[TAG_RELATED_AUDIO_FILE] = "RelatedAudioFile"
TagTable[TAG_INTEROP_OFFSET] = "InteroperabilityOffset"
TagTable[TAG_FLASH_ENERGY] = "FlashEnergy"
TagTable[TAG_SPATIAL_FREQ_RESP] = "SpatialFrequencyResponse"
TagTable[TAG_FOCAL_PLANE_XRES] = "FocalPlaneXResolution"
TagTable[TAG_FOCAL_PLANE_YRES] = "FocalPlaneYResolution"
TagTable[TAG_FOCAL_PLANE_UNITS] = "FocalPlaneResolutionUnit"
TagTable[TAG_SUBJECT_LOCATION] = "SubjectLocation"
TagTable[TAG_EXPOSURE_INDEX] = "ExposureIndex"
TagTable[TAG_SENSING_METHOD] = "SensingMethod"
TagTable[TAG_FILE_SOURCE] = "FileSource"
TagTable[TAG_SCENE_TYPE] = "SceneType"
TagTable[TAG_CFA_PATTERN] = "CFA Pattern"
TagTable[TAG_CUSTOM_RENDERED] = "CustomRendered"
TagTable[TAG_EXPOSURE_MODE] = "ExposureMode"
TagTable[TAG_WHITEBALANCE] = "WhiteBalance"
TagTable[TAG_DIGITALZOOMRATIO] = "DigitalZoomRatio"
TagTable[TAG_FOCALLENGTH_35MM] = "FocalLengthIn35mmFilm"
TagTable[TAG_SUBJECTAREA] = "SubjectArea"
TagTable[TAG_SCENE_CAPTURE_TYPE] = "SceneCaptureType"
TagTable[TAG_GAIN_CONTROL] = "GainControl"
TagTable[TAG_CONTRAST] = "Contrast"
TagTable[TAG_SATURATION] = "Saturation"
TagTable[TAG_SHARPNESS] = "Sharpness"
TagTable[TAG_DISTANCE_RANGE] = "SubjectDistanceRange"
TagTable[TAG_IMAGE_UNIQUE_ID] = "ImageUniqueId"
GPS_TAG_VERSIONID = 0X00
GPS_TAG_LATITUDEREF = 0X01
GPS_TAG_LATITUDE = 0X02
GPS_TAG_LONGITUDEREF = 0X03
GPS_TAG_LONGITUDE = 0X04
GPS_TAG_ALTITUDEREF = 0X05
GPS_TAG_ALTITUDE = 0X06
GPS_TAG_TIMESTAMP = 0X07
GPS_TAG_SATELLITES = 0X08
GPS_TAG_STATUS = 0X09
GPS_TAG_MEASUREMODE = 0X0A
GPS_TAG_DOP = 0X0B
GPS_TAG_SPEEDREF = 0X0C
GPS_TAG_SPEED = 0X0D
GPS_TAG_TRACKREF = 0X0E
GPS_TAG_TRACK = 0X0F
GPS_TAG_IMGDIRECTIONREF = 0X10
GPS_TAG_IMGDIRECTION = 0X11
GPS_TAG_MAPDATUM = 0X12
GPS_TAG_DESTLATITUDEREF = 0X13
GPS_TAG_DESTLATITUDE = 0X14
GPS_TAG_DESTLONGITUDEREF = 0X15
GPS_TAG_DESTLONGITUDE = 0X16
GPS_TAG_DESTBEARINGREF = 0X17
GPS_TAG_DESTBEARING = 0X18
GPS_TAG_DESTDISTANCEREF = 0X19
GPS_TAG_DESTDISTANCE = 0X1A
GPS_TAG_PROCESSINGMETHOD = 0X1B
GPS_TAG_AREAINFORMATION = 0X1C
GPS_TAG_DATESTAMP = 0X1D
GPS_TAG_DIFFERENTIAL = 0X1E
GpsTagTable = {}
GpsTagTable[GPS_TAG_VERSIONID] = "VersionID"
GpsTagTable[GPS_TAG_LATITUDEREF] = "LatitudeRef"
GpsTagTable[GPS_TAG_LATITUDE] = "Latitude"
GpsTagTable[GPS_TAG_LONGITUDEREF] = "LongitudeRef"
GpsTagTable[GPS_TAG_LONGITUDE] = "Longitude"
GpsTagTable[GPS_TAG_ALTITUDEREF] = "AltitudeRef"
GpsTagTable[GPS_TAG_ALTITUDE] = "Altitude"
GpsTagTable[GPS_TAG_TIMESTAMP] = "Timestamp"
GpsTagTable[GPS_TAG_SATELLITES] = "Satellites"
GpsTagTable[GPS_TAG_STATUS] = "Status"
GpsTagTable[GPS_TAG_MEASUREMODE] = "MeasureMode"
GpsTagTable[GPS_TAG_DOP] = "Dop"
GpsTagTable[GPS_TAG_SPEEDREF] = "SpeedRef"
GpsTagTable[GPS_TAG_SPEED] = "Speed"
GpsTagTable[GPS_TAG_TRACKREF] = "TrafRef"
GpsTagTable[GPS_TAG_TRACK] = "Track"
GpsTagTable[GPS_TAG_IMGDIRECTIONREF] = "ImgDirectionRef"
GpsTagTable[GPS_TAG_IMGDIRECTION] = "ImgDirection"
GpsTagTable[GPS_TAG_MAPDATUM] = "MapDatum"
GpsTagTable[GPS_TAG_DESTLATITUDEREF] = "DestLatitudeRef"
GpsTagTable[GPS_TAG_DESTLATITUDE] = "DestLatitude"
GpsTagTable[GPS_TAG_DESTLONGITUDEREF]= "DestLongitudeRef"
GpsTagTable[GPS_TAG_DESTLONGITUDE] = "DestLongitude"
GpsTagTable[GPS_TAG_DESTBEARINGREF] = "DestBearingref"
GpsTagTable[GPS_TAG_DESTBEARING] = "DestBearing"
GpsTagTable[GPS_TAG_DESTDISTANCEREF] = "DestDistanceRef"
GpsTagTable[GPS_TAG_DESTDISTANCE] = "DestDistance"
GpsTagTable[GPS_TAG_PROCESSINGMETHOD]= "ProcessingMethod"
GpsTagTable[GPS_TAG_AREAINFORMATION] = "AreaInformation"
GpsTagTable[GPS_TAG_DATESTAMP] = "Datestamp"
GpsTagTable[GPS_TAG_DIFFERENTIAL] = "Differential"
FMT_BYTE = 1
FMT_STRING = 2
FMT_USHORT = 3
FMT_ULONG = 4
FMT_URATIONAL = 5
FMT_SBYTE = 6
FMT_UNDEFINED = 7
FMT_SSHORT = 8
FMT_SLONG = 9
FMT_SRATIONAL = 10
FMT_SINGLE = 11
FMT_DOUBLE = 12
bytes_per_format = {0,1,1,2,4,8,1,1,2,4,8,4,8}
portrule = shortport.http
---Unpack a rational number from exif. In exif, a rational number is stored
--as a pair of integers - the numerator and the denominator.
--
--@return the new position, and the value.
local function unpack_rational(endian, data, pos)
local v1, v2
v1, v2, pos = string.unpack(endian .. "I4I4", data, pos)
return pos, v1 / v2
end
local function process_gps(data, pos, endian, result)
local value, num_entries
local latitude, latitude_ref, longitude, longitude_ref
-- The first entry in the gps section is a 16-bit size
num_entries, pos = string.unpack(endian .. "I2", data, pos)
-- Loop through the entries to find the fun stuff
for i=1, num_entries do
local tag, format, components, value
tag, format, components, value, pos = string.unpack(endian .. "I2 I2 I4 I4", data, pos)
if(tag == GPS_TAG_LATITUDE or tag == GPS_TAG_LONGITUDE) then
local dummy, gps, h, m, s
dummy, h = unpack_rational(endian, data, value + 8)
dummy, m = unpack_rational(endian, data, dummy)
dummy, s = unpack_rational(endian, data, dummy)
gps = h + (m / 60) + (s / 60 / 60)
if(tag == GPS_TAG_LATITUDE) then
latitude = gps
else
longitude = gps
end
elseif(tag == GPS_TAG_LATITUDEREF) then
-- Get the first byte in the latitude reference as a character
latitude_ref = string.char(value >> 24)
elseif(tag == GPS_TAG_LONGITUDEREF) then
-- Get the first byte in the longitude reference as a character
longitude_ref = string.char(value >> 24)
end
end
if(latitude and longitude) then
-- Normalize the N/S/E/W to positive and negative
if(latitude_ref == 'S') then
latitude = -latitude
end
if(longitude_ref == 'W') then
longitude = -longitude
end
table.insert(result, string.format("GPS: %f,%f - https://maps.google.com/maps?q=%s,%s", latitude, longitude, latitude, longitude))
end
return true, result
end
---Parse the exif data section and return a table. This has only been tested
--in a .jpeg file, but should work for .tiff as well.
local function parse_exif(exif_data)
local sig, marker, size
local tag, format, components, byte_count, value, offset, dummy, data
local status, result
local tiff_header_1, first_offset
-- Initialize the result table
result = {}
-- Read the verify the EXIF header
local header, endian, pos = string.unpack(">c6 I2", exif_data, 1)
if(header ~= "Exif\0\0") then
return false, "Invalid EXIF header"
end
-- Check the endianness - it should only ever be big endian, but it doesn't
-- hurt to check
if(endian == 0x4d4d) then
endian = ">"
elseif(endian == 0x4949) then
endian = "<"
else
return false, "Unrecognized endianness entry"
end
-- Read the first tiff header and the offset to the first data entry (should be 8)
tiff_header_1, first_offset, pos = string.unpack(endian .. "I2 I4", exif_data, pos)
if(tiff_header_1 ~= 0x002A or first_offset ~= 0x00000008) then
return false, "Invalid tiff header"
end
-- Skip over the header, and go to the first offset (subtracting 1 because lua)
pos = first_offset + 8 - 1
-- The first 16-bit value is the number of entries
local num_entries, pos = string.unpack(endian .. "I2", exif_data, pos)
-- Loop through the entries
for i=1,num_entries do
-- Read the entry's header
tag, format, components, value, pos = string.unpack(endian .. "I2 I2 I4 I4", exif_data, pos)
-- Look at the tags we care about
if(tag == TAG_GPSINFO) then
-- If it's a GPSINFO tag, we need to parse the GPS structure
status, result = process_gps(exif_data, value + 8 - 1, endian, result)
if(not(status)) then
return false, result
end
else
value = string.unpack("z", exif_data, value + 8 - 1)
if (tag == TAG_MAKE) then
table.insert(result, string.format("Make: %s", value))
elseif(tag == TAG_MODEL) then
table.insert(result, string.format("Model: %s", value))
elseif(tag == TAG_DATETIME) then
table.insert(result, string.format("Date: %s", value))
end
end
end
return true, result
end
---Parse a jpeg and find the EXIF data section
local function parse_jpeg(s)
local pos, sig, marker, size, exif_data
-- Parse the jpeg header, make sure it's valid (we expect 0xFFD8)
sig, pos = string.unpack(">I2", s, pos)
if(sig ~= 0xFFD8) then
return false, "Unexpected signature"
end
-- Parse the sections to find the exif marker (0xffe1)
while(true) do
marker, size, pos = string.unpack(">I2I2", s, pos)
-- Check if we found the exif metadata section, break if we did
if(marker == 0xffe1) then
break
-- If the marker is nil, we're off the end of the image (and therefore, it wasn't found)
elseif(not(marker)) then
return false, "Could not found EXIF marker"
end
-- Go to the next section (we subtract 2 because of the 2-byte marker we read)
pos = pos + size - 2
end
exif_data, pos = string.unpack(string.format(">c%d", size), s, pos)
return parse_exif(exif_data)
end
function action(host, port)
local pattern = "%.jpg"
local images = {}
local results = {}
-- once we know the pattern we'll be searching for, we can set up the function
local whitelist = function(url)
return string.match(url.file, "%.jpg") or string.match(url.file, "%.jpeg")
end
local crawler = httpspider.Crawler:new( host, port, nil, { scriptname = SCRIPT_NAME, whitelist = { whitelist }} )
if ( not(crawler) ) then
return
end
while(true) do
-- Begin the crawler
local status, r = crawler:crawl()
-- Make sure there's no error
if ( not(status) ) then
if ( r.err ) then
return stdnse.format_output(false, r.reason)
else
break
end
end
-- Check if we got a response, and the response is a .jpg file
if r.response and r.response.body and r.response.status==200 and (string.match(r.url.path, ".jpg") or string.match(r.url.path, ".jpeg")) then
local status, result
stdnse.debug1("Attempting to read exif data from %s", r.url.raw)
status, result = parse_jpeg(r.response.body)
if(not(status)) then
stdnse.debug1("Couldn't read exif from %s: %s", r.url.raw, result)
else
-- If there are any exif results, add them to the result
if(result and #result > 0) then
result['name'] = r.url.raw
table.insert(results, result)
end
end
end
end
return stdnse.format_output(true, results)
end