Mirror of metasploit
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

pdf_parse.rb 5.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. # -*- coding: binary -*-
  2. ###
  3. #
  4. # This module provides methods for parsing and interacting
  5. # with the PDF format.
  6. #
  7. ###
  8. module Msf
  9. module Exploit::PDF_Parse
  10. def initialize(info = {})
  11. super
  12. register_options(
  13. [
  14. OptString.new('FILENAME', [ true, 'The file name.', 'some.pdf']),
  15. ], Msf::Exploit::PDF_Parse
  16. )
  17. end
  18. def read_pdf()
  19. stream = IO.read("#{datastore['INFILENAME']}")
  20. return stream
  21. end
  22. def xref_trailer_parse(offset, stream)
  23. a = offset
  24. b = stream.index(/>>/,a) + 2
  25. return stream[a..b]
  26. end
  27. def trailer_parse(xref_trailer)
  28. trailer = Hash.new()
  29. if match = xref_trailer.match(/Size (\d+)/m)
  30. trailer['Size'] = match[1]
  31. end
  32. if match = xref_trailer.match(/Root (\d+ \d)/m)
  33. trailer["Root"] = match[1]
  34. end
  35. if match = xref_trailer.match(/Info (\d+ \d)/m)
  36. trailer["Info"] = match[1]
  37. end
  38. if match = xref_trailer.match(/ID(\[.+\])/m)
  39. trailer["ID"] = match[1]
  40. end
  41. if match = xref_trailer.match(/Prev (\d+)/m)
  42. trailer["Prev"] = match[1]
  43. end
  44. if match = xref_trailer.match(/XRefStm (\d+)/m)
  45. trailer["XRefStm"] = match[1]
  46. end
  47. return trailer
  48. end
  49. def object_locate(xref_trailer,obj_name)
  50. found = false
  51. match = obj_name.match(/(\d+) (\d+)/)
  52. obj = match[1]
  53. gen = match[2]
  54. xrefs_end = xref_trailer.index(/trailer/) - 1
  55. xrefs = xref_trailer[0..xrefs_end]
  56. if gen.to_i != 0
  57. else
  58. len = xrefs.length
  59. match = xrefs.match(/xref\r?\n?(\d+) (\d+)\r?\n?/m)
  60. offset = 0
  61. while offset < len
  62. if match
  63. start_obj = match[1]
  64. num_obj = match[2]
  65. offset = match.end(0)
  66. else
  67. break
  68. end
  69. if start_obj.to_i > obj.to_i
  70. jump = num_obj.to_i * 20
  71. offset += jump
  72. else
  73. if obj.to_i <= ( start_obj.to_i + num_obj.to_i - 1)
  74. jump = (obj.to_i - start_obj.to_i) * 20
  75. offset += jump
  76. found = true
  77. break
  78. else
  79. jump = num_obj.to_i * 20
  80. offset += jump
  81. end
  82. end
  83. xrefs.index(/(\d+) (\d+)\r?\n?/m,offset)
  84. match = Regexp.last_match
  85. end
  86. end
  87. if found
  88. offset_end = offset + 11
  89. return xrefs[offset..offset_end].to_i
  90. else
  91. return nil
  92. end
  93. end
  94. def parse_object(xref_trailers,obj_name,stream)
  95. for xrefs in xref_trailers
  96. offset = object_locate(xrefs,obj_name)
  97. if offset
  98. break
  99. end
  100. end
  101. if offset
  102. stream.index(/endobj/,offset)
  103. object_end = Regexp.last_match.end(0)
  104. return stream[offset..object_end]
  105. else
  106. return nil
  107. end
  108. end
  109. def xref_create(stream,offset,num_obj)
  110. xref = Array.new()
  111. object = String.new()
  112. case
  113. when num_obj.to_s == "1"
  114. obj = stream.index(/(\d+) \d obj/,offset)
  115. if obj
  116. num = obj.to_s
  117. dif = 10 - num.length
  118. out = String.new
  119. while dif > 0
  120. out << "0"
  121. dif -= 1
  122. end
  123. out << num
  124. xref.push("#{out}")
  125. object = "#{Regexp.last_match(1)}"
  126. end
  127. when num_obj.to_s == "*"
  128. len = stream.length
  129. n = offset
  130. while n < len
  131. obj = stream.index(/(\d+) \d obj/,n)
  132. if obj != nil
  133. num = obj.to_s
  134. dif = 10 - num.length
  135. out = String.new
  136. while dif > 0
  137. out << "0"
  138. dif -= 1
  139. end
  140. out << num
  141. xref.push("#{out}")
  142. n = Regexp.last_match.end(0)
  143. if object.empty?
  144. object = "#{Regexp.last_match(1)}"
  145. end
  146. else
  147. break
  148. end
  149. end
  150. end
  151. output = String.new()
  152. output << "#{object} #{xref.length}\r\n"
  153. xref.each {|xref_| output << "#{xref_} 00000 n\r\n"}
  154. return output
  155. end
  156. def parse_pdf(stream)
  157. xref_array = Array.new()
  158. startxrefs = Array.new()
  159. startxref_offsets = Hash.new()
  160. xref_trailers = Array.new()
  161. xref_trailer = Hash.new()
  162. trailers = Array.new()
  163. trailer = Hash.new()
  164. len = stream.length
  165. n = 0
  166. while n < len
  167. obj = stream.index(/startxref\r?\n?/m,n)
  168. if obj != nil
  169. n = Regexp.last_match.end(0)
  170. stream.index(/\d+/,n)
  171. startxref_offsets["#{Regexp.last_match}"] = "#{obj}"
  172. startxrefs.push("#{Regexp.last_match}")
  173. else
  174. break
  175. end
  176. end
  177. xref_trailer = xref_trailer_parse(startxrefs.last.to_i,stream)
  178. xref_trailers.push(xref_trailer)
  179. trailer = trailer_parse(xref_trailer)
  180. trailers.push(trailer)
  181. root_obj = trailers[0].fetch("Root")
  182. while trailer["Prev"]
  183. xref_trailer = xref_trailer_parse(trailer.fetch("Prev").to_i,stream)
  184. xref_trailers.push(xref_trailer)
  185. trailer = trailer_parse(xref_trailer)
  186. trailers.each {|check| if check.fetch("Prev") == trailer["Prev"] then trailer.delete("Prev") end}
  187. if trailer.has_key?("Prev")
  188. trailers.push(trailer)
  189. end
  190. end
  191. return xref_trailers, trailers, startxrefs, root_obj
  192. end
  193. end
  194. end