Advertisement
opexxx

Automate2.0.sh

May 2nd, 2014
278
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Bash 16.90 KB | None | 0 0
  1. #!/bin/bash
  2.  
  3. ####################################################
  4. # Automate2.0.sh was created by Glenn P. Edwards Jr.
  5. #       http://hiddenillusion.blogspot.com
  6. #               @hiddenillusion
  7. # Version 0.1
  8. # Date: 2012
  9. # Compatability: written/tested for volatility 2.0
  10. ####################################################
  11. # To - Do #
  12. # General
  13. #   - latest windows branch isn't working with malware.py so moved that trunk to "windows_latest" folder and put stable 2.0 branch as "windows"
  14. #   - fails when the memory image has spaces in its name ...
  15. #   - add update functionality to get latest trunk/branches?
  16. # windows alpha changes
  17. #   - Plugins
  18. #       - evtlogs (XP/W2k3 only)
  19. #   - win version specific checks
  20.  
  21. # Defining some stuff...
  22. Date=`date +%m-%d-%Y_%T`
  23.  
  24. # Volatility locations
  25. vol_win="/path/to/volatility/vol.py" #stable release
  26. vol_alpha="/path/to/volatility_alpha/vol.py"
  27. vol_linux="/path/to/volatility_linux/vol.py"
  28. vol_mac="/path/to/volatility_mac/vol.py"
  29.  
  30. ########################################
  31. # Define the overall volatility branches
  32. ########################################
  33. # - This array should contain what you defined above
  34. #   so you can choose which branch to use if the default
  35. #   test for profile identification fails.
  36. vol_branches=("$vol_win" "$vol_alpha" "$vol_linux" "$vol_mac");
  37.  
  38. YARA_Rules="/path/to/rules.yara"
  39. # Change if you only want to use a single YARA rules file, otherwise it will put all listed in array
  40. #YARA_Rules=(`find /path/to/yara/rules -type f -iname *.yara -exec ls {} \;`);
  41.  
  42. Usage()
  43. {
  44. version=1.1
  45. echo "[*] `basename $0` version: $version written by Glenn P. Edwards Jr."
  46.     echo "Usage : `basename $0` [options]"
  47.                 echo "  OPTIONS:"
  48.                 echo "          Required"
  49.                 echo "          -f <file>       : set the memory dump file"
  50.                 echo ""
  51.                 echo "          Optional"
  52.                 echo "          -b              : specify which branch to use instead of using the default"                
  53.                 echo "          -c              : convert memory dump to a raw DD image and save it to PWD (crashdump, hibernation file etc.)"
  54.                 echo "          -d              : enable dumping of carved files (DLL/EXE/SYS)"
  55.                 echo "          -j              : set how many forked processes/jobs to use (default is 10)"
  56.                 echo "          -o <directory>  : set the case directory (PWD is set by default)"
  57.                 echo "          -P              : specify which profile to use instead of trying to auto determine it"
  58.                 echo "          -t <mm:ss>      : set the time out for how long a plugin can run (default is 5 mins)"
  59.                 echo "          -h              : print this message"
  60.     exit
  61. }
  62.  
  63. while getopts "b:cdf:hj:o:t:P:" opt ;do
  64.     case $opt in
  65.     b) Vol_Specified=$OPTARG;;         
  66.     c) Convert=yes;;
  67.     d) Dump=yes;;
  68.     f) MemDump=$OPTARG;;
  69.     h) Usage
  70.         exit;;
  71.     j) Jobs=$OPTARG;;
  72.     o) Case_Dir=$OPTARG;;
  73.     t) Timer=$OPTARG;;
  74.     P) Profile_Specified=$OPTARG;;
  75.     esac
  76. done
  77.  
  78. # Taking a look at the options provided
  79. if [[ -z $MemDump ]]; then
  80.      Usage
  81.      exit
  82. fi
  83.  
  84. if [[ $Convert == "yes" ]]; then
  85.     echo "[-] Trying to convert the memory dump..."
  86.     $vol_win -f $MemDump imagecopy -O converted.$Date.raw
  87.     wait
  88.     if [ -f converted.$Date.raw ]; then
  89.         echo "[-] Converted file saved to : `echo $PWD/converted.$Date.raw`"
  90.     fi
  91.     exit
  92. fi
  93.  
  94. if [[ -z $Jobs ]]; then
  95.     Jobs=10
  96. fi
  97.  
  98. # Making sure we have the required directories created
  99. if [[ -z $Case_Dir ]]; then
  100.         Case_Dir=`echo $PWD`
  101. else
  102.     if [ -d $Case_Dir ]; then
  103.         echo "[-] The Case Dir '$Case_Dir' already exists...this analysis will be created as a subdirectory"
  104.     else
  105.         mkdir $Case_Dir
  106.         if [[ $? -ne 0 ]]; then
  107.             echo "[!] Failed to make the Case Dir '$Case_Dir'...incorrect permissions?"
  108.             exit 1
  109.         fi
  110.     fi
  111. fi
  112.  
  113. # Just for safe keepings - in case something like the $Date variable is changed
  114. Mem_Dir="$Case_Dir/memory_analysis.$Date"
  115. if [ -d $Mem_Dir ]; then
  116.     echo "[!] The Mem Dir '$Mem_Dir' already exists - this must be unique"
  117.     exit 1
  118. else
  119.     mkdir $Mem_Dir
  120. fi
  121.  
  122. #####################################
  123. # Plugins to run for a given analysis
  124. #####################################
  125. # - Add/Remove/Modify parameters as needed.
  126.  
  127. # General plugins to use for _any_ Windows image profile
  128. win_general_plugins=("psscan" "pslist" "psxview" "dlllist" "handles" "mutantscan" "svcscan" "ssdt" "filescan" "vadinfo" "callbacks" "modules" "modscan" "ldrmodules -v" "driverirp --verbose");
  129.  
  130. ##################################################
  131. # Specific plugins based on image profiles version
  132. ##################################################
  133. # - v2.0 didn't include the profile specific stuff so this is manual
  134. winxp_network_plugins=("connscan" "sockets" "sockscan" "connections");
  135. win7_network_plugins=("netscan");
  136. linux_plugins=("linux_arp" "linux_cpuinfo" "linux_dmesg" "linux_dump_map" "linux_ifconfig" "linux_list_open_files" "linux_lsmod" "linux_mount" "linux_netstat" "linux_proc_maps" "linux_route" "linux_route_cache" "linux_task_list_ps" "linux_task_list_psaux" "linux_tasklist_kmem_cache");
  137. # mac_plugins=(....)
  138.  
  139. ##############################################################
  140. # Dump plugins which require special switches/dump directories
  141. ##############################################################
  142. if [[ $Dump == "yes" ]]; then
  143.         defined_dumps=("dlldump" "moddump" "vaddump" "zeroaccess");
  144.         for plugin in "${defined_dumps[@]}"; do
  145.                 if [ ! -d $Mem_Dir/$plugin ]; then
  146.                     mkdir $Mem_Dir/$plugin
  147.                 fi
  148.                 dump_plugins=("${dump_plugins[@]}" "$plugin -D $Mem_Dir/$plugin");
  149.         done
  150. fi
  151.  
  152. ###########################################
  153. # Setting up a log of the analysis process
  154. ###########################################
  155. process_log="$Mem_Dir/process.log"
  156. exec &> >(tee -a $process_log)
  157.  
  158. #####################################################
  159. # Start the timer to see how long the analysis takes
  160. #####################################################
  161. tic=$(date +%s)
  162.  
  163. ###############################################################################
  164. # Setting up a log for killing hung plugins based on the timeout value supplied
  165. ###############################################################################
  166. # - This is because I've encounted certain plugins hanging during analysis so to
  167. #   make sure they don't halt the process from completing we need a safety timer.  
  168. #   It isn't an _exact_ timer since it's not spawned with the cmd but saves
  169. #   resources and is just a safety net.  It's bash to it's nothing crazy, but it
  170. #   gets the job done.
  171. touch "$Mem_Dir/fpids.$$.tmp"
  172. forked_pids="$Mem_Dir/fpids.$$.tmp"
  173.  
  174. if ! [[ -z $Timer ]]; then
  175.     if ! [[ $Timer =~ [0-9]{2}:[0-9]{2} ]]; then
  176.         echo "[!] Timer value is incorrect"
  177.         exit 1
  178.     fi
  179. else
  180.     Timer="05:00"  
  181.  
  182. fi
  183.  
  184. timer_loop ( ){
  185.     Duration=`date "+%s" -d "$Timer"`
  186.     tmp_file=`mktemp`                        
  187.     while [ -f $tmp_file ]; do
  188.         rm $tmp_file
  189.         cat $forked_pids | grep -v "^$" | while read pid; do
  190.             ps | grep $pid > /dev/null
  191.             if [ $? -eq 0 ] ;then
  192.                 touch $tmp_file
  193.                 ptime=`ps -p $pid -o pid,etime | awk '{print $2}' | tail -1 | grep -v ELAPSED`
  194.                 psec=`date "+%s" -d "$ptime"`
  195.                 if [ $psec -gt $Duration ]; then
  196.                     echo "[-] Killing PID: $pid , ptime: $ptime > Timer: $Timer"
  197.                     kill -9 $pid &> /dev/null
  198.                 fi
  199.                 sleep 5s   
  200.             fi
  201.         done
  202.     done
  203. }
  204.  
  205.  
  206. main() {
  207.     echo "[+] Analysis started at: `date`"
  208.         echo "[-] Forking set to : '$Jobs' jobs"
  209.         display_timer=$(echo "$Timer" | awk -F: '{print $1 "m", $2 "s"}')
  210.         echo "[-] Plugin timer set to : '$display_timer'"
  211.         echo "[-] Running the script as PID: $$"
  212.         echo "[+] Case Dir set to :  '$Case_Dir'"
  213.         echo "[+] Memory Dir set to : '$Mem_Dir'"
  214.  
  215.         ########################################
  216.         # Functions to fork the plugin analysis
  217.         ########################################
  218.         # - again, it's bash so don't hate.        
  219.         run_win_plugins ( ){
  220.         echo "[-] Syntax executed : $Vol_Specified -f $MemDump --profile=$Profile_Specified $cmd" | tee &>> $process_log $Mem_Dir/$cmd_log.txt
  221.         $vol_win -f $MemDump --profile=$Profile_Specified $cmd >> $Mem_Dir/$cmd_log.txt & pid=$!
  222.         echo $pid >> $forked_pids
  223.         echo "[-] - Forking PID: $pid" &>> $process_log
  224.         }
  225.         run_linux_plugins ( ){
  226.         echo "[-] Syntax executed : $vol_linux -f $MemDump --profile=$Profile_Specified $cmd_log" | tee &>> $process_log $Mem_Dir/$cmd_log.txt
  227.         $vol_linux -f $MemDump --profile=$Profile_Specified $cmd_log >> $Mem_Dir/$cmd_log.txt & pid=$!
  228.         echo $pid >> $forked_pids
  229.         }
  230.         run_procexedump_plugin ( ){
  231.         echo "[-] Syntax executed : $Vol_Specified -f $MemDump --profile=$Profile_Specified -p $p procexedump -D $Mem_Dir/procexedump" | tee &>> $process_log $Mem_Dir/procexedump.txt
  232.         $Vol_Specified -f $MemDump --profile=$Profile_Specified -p $p procexedump -D $Mem_Dir/procexedump >> $Mem_Dir/procexedump.txt & pid=$!
  233.         echo $pid >> $forked_pids
  234.         echo "[-] PID $pid: --- Forking procexedump" &>> $process_log
  235.         }
  236.     run_malfind_plugin ( ){
  237.         echo "[-] Syntax executed : $Vol_Specified -f $MemDump --profile=$Profile_Specified malfind -Y $rule -D $Mem_Dir/malfind" | tee &>> $process_log $Mem_Dir/malfind.txt
  238.         $Vol_Specified -f $MemDump --profile=$Profile_Specified malfind -Y $rule -D $Mem_Dir/malfind >> $Mem_Dir/malfind.txt & pid=$!
  239.         echo $pid >> $forked_pids
  240.         echo "[-] PID $pid: --- Forking malfind" &>> $process_log
  241.         }
  242.  
  243.     ###########################################################
  244.     # Run specific plugins based on the image profiles' version
  245.     ###########################################################
  246.     if [[ $Profile_Specified == Linux* ]]; then
  247.         plugins=("${linux_plugins[@]}")
  248.        
  249.         # Parse the commands from the Linux array
  250.         for cmd in "${plugins[@]}"; do
  251.             cmd_log=`echo $cmd | awk '{print $1}'`
  252.             run_win_plugins $cmd & pid=$!
  253.             while [ `jobs | wc -l` -ge $Jobs ]; do
  254.                 sleep 1s
  255.             done
  256.             echo "[-] PID $pid: -- Starting $cmd"
  257.         done
  258.        
  259.         # Cleanup for hung Linux plugins
  260.         timer_loop
  261.  
  262.     elif [[ $Profile_Specified == WinXP* ]] || [[ $Profile_Specified == Win2K3* ]]; then
  263.             plugins=("${win_general_plugins[@]}" "${winxp_network_plugins[@]}")
  264.     elif [[ $Profile_Specified == Vista* ]] || [[ $Profile_Specified == Win7* ]]; then
  265.             plugins=("${win_general_plugins[@]}" "${win7_network_plugins[@]}")
  266.     fi
  267.    
  268.     if [[ $Dump == "yes" ]]; then
  269.         echo "[+] Dumping is enabled... this may take some time"
  270.         plugins=("${plugins[@]}" "${dump_plugins[@]}")
  271.     fi     
  272.    
  273.     # Parse the commands from the Windows array(s)
  274.     for cmd in "${plugins[@]}"; do
  275.         cmd_log=`echo $cmd | awk '{print $1}'`
  276.         run_win_plugins & pid=$!
  277.         while [ `jobs | wc -l` -ge $Jobs ]; do
  278.             sleep 1s
  279.         done
  280.         echo "[-] PID $pid: -- Starting $cmd_log"
  281.     done
  282.  
  283.     # Cleanup for hung Windows plugins
  284.     timer_loop
  285.  
  286.     # mac profile ...
  287.  
  288.     if [[ $Dump == "yes" ]]; then      
  289.     # procexedump is being run separately because the way it's being called is dependent on psscan
  290.     # results to feed what it should dump. I wanted to use psscan instead of the default pslist it uses
  291.     # and I didn't want to have to create another plugin/modify the source because I wanted this script
  292.     # to work out of the box without any additional requirements - and as such, you get this ... I know
  293.     # it's definitely not the best as it adds much much more than is needed but oh well.
  294.     # If you take out any of the plugins which produce the output for the files which are being waited
  295.     # for below it will cause an infinite loop so make sure to comment these out if you choose to not
  296.     # include these plugins.
  297.         while true; do
  298.             if [[ -f $Mem_Dir/psscan.txt ]] && ! [[ `lsof | grep $Mem_Dir/psscan.txt &> /dev/null` ]]; then
  299.                 echo "[-] PID $$: -- Started procexedump"
  300.                         if [ ! -d $Mem_Dir/procexedump ]; then
  301.                             mkdir $Mem_Dir/procexedump
  302.                         fi
  303.                         cat $Mem_Dir/psscan.txt | awk '{print $3}'| while read p; do
  304.                             if [[ "$p" =~ [0-9]+ ]]; then
  305.                                 run_procexedump_plugin &
  306.                                     while [ `jobs | wc -l` -ge $Jobs ]; do
  307.                                         sleep 1s
  308.                                     done
  309.                             fi
  310.                         done
  311.                 break
  312.             else
  313.                 sleep 5s
  314.             fi
  315.         done   
  316.    
  317.         # Passing all YARA rule files defined above to malfind
  318.         echo "[-] PID $$: -- Started malfind"
  319.         if [ ! -d $Mem_Dir/malfind ]; then
  320.             mkdir $Mem_Dir/malfind
  321.         fi
  322.         for rule in "${YARA_Rules[@]}"; do
  323.             run_malfind_plugin &
  324.             while [ `jobs | wc -l` -ge $Jobs ]; do
  325.                 sleep 1s
  326.             done
  327.         done
  328.        
  329.         # Cleanup for hung dump plugins
  330.         timer_loop
  331.     fi
  332.  
  333.     #######################
  334.     # Post-processing stuff
  335.     #######################
  336.     # - If you take out any of the plugins which produce the output for the files
  337.     #   which are being waited for below it will cause an infinite loop so make
  338.     #   sure to comment these out if you choose to not include these plugins.
  339.     # - This can obviously be seperated so it doesn't halt your initial memory analysis
  340.     while true; do
  341.         if [[ -f $Mem_Dir/ssdt.txt ]] && ! [[ `lsof | grep $Mem_Dir/ssdt.txt &> /dev/null` ]]; then
  342.             mv $Mem_Dir/ssdt.txt $Mem_Dir/ssdt.tmp
  343.             cat $Mem_Dir/ssdt.tmp | egrep -v -i '(ntoskrnl|win32k)' > $Mem_Dir/ssdt.txt
  344.             rm $Mem_Dir/ssdt.tmp
  345.             break
  346.         else
  347.             sleep 5s
  348.         fi
  349.     done
  350.  
  351.     while true; do
  352.         if [[ -f $Mem_Dir/handles.txt ]] && ! [[ `lsof | grep $Mem_Dir/handles.txt &> /dev/null` ]]; then                
  353.             mv $Mem_Dir/handles.txt $Mem_Dir/handles.tmp
  354.             cat $Mem_Dir/handles.tmp | awk '{ if($4 !~ /^$/) {print $0}}' | grep -v "''" > $Mem_Dir/handles.txt
  355.             rm $Mem_Dir/handles.tmp    
  356.             break
  357.         else
  358.             sleep 5s
  359.         fi
  360.     done
  361. }
  362.  
  363. selector() {
  364.         echo "[!] Could not determine a profile to use.  Verify this is a valid memory dump and that it isn't corrupt or have spaces in its name."
  365.         echo "[-] Would you like to choose a different volatility branch for profile identification? [y/n]"
  366.         read answer
  367.         if [[ $answer == "y" ]]; then
  368.                 count=0
  369.                 echo "[-] Available volatility branches to select from:"
  370.                 for branch in "${vol_branches[@]}"; do
  371.                         echo "$count. $branch"
  372.                         ((count++))
  373.                 done
  374.                 echo "[-] Enter the selected branch #:"
  375.                 read branch_choice
  376.                 selected_branch=$(echo ${vol_branches[$branch_choice]})
  377.                 if [[ -z $selected_branch ]]; then
  378.                         echo "[-] Selected branch not found ... did you mistype it?"
  379.                         exit 1
  380.                 fi
  381.  
  382.                 echo "[-] Selected branch to use is : '$selected_branch'"
  383.                 echo "[-] Determining profiles available for selected branch..."
  384.                 profile_list=(`$selected_branch --info | awk '/PROFILES/ ,/^$/' | grep -v '^$'  | awk  'FNR>2' | awk -F- '{print $1}'`)
  385.  
  386.                 count=0
  387.                 for pro in "${profile_list[@]}"; do
  388.                     echo "$count. $pro"
  389.                     ((count++))
  390.                 done
  391.  
  392.                 echo "[-] Enter the selected profile #."
  393.                 read profile_choice
  394.                 selected_profile=$(echo ${profile_list[$profile_choice]})
  395.                 if [[ -z $selected_profile ]]; then
  396.                         echo "[-] Selected profile not found ... did you mistype it?"
  397.                         exit 1
  398.                 elif [[ "$profile_choice" =~ [0-9]+ ]]; then
  399.                     echo "[-] Selected profile to use is : '$selected_profile'"
  400.                     Vol_Specified=$selected_branch
  401.                     Profile_Specified=$selected_profile
  402.                     main
  403.  
  404.                 else
  405.                     exit
  406.                 fi
  407.         else
  408.             exit
  409.         fi
  410. }
  411.  
  412. # Using the default stable Windows branch listed below, unless explicitly defined
  413. if [[ -z $Vol_Specified ]]; then
  414.     Vol_Specified=$vol_win
  415.     echo "[-] Using the default Volatility branch : $Vol_Specified"
  416. else
  417.     echo "[-] Volatility branch manually set to : $Vol_Specified"
  418. fi
  419.  
  420. # Trying to identify which profile to feed volatility by taking the first match, unless explicitly defined
  421. if [[ -z $Profile_Specified ]]; then
  422.     Profile_Specified=`$Vol_Specified imageinfo -f $MemDump | grep "Suggested Profile" | awk '{print $4}' | sed 's/,$//'`
  423.     echo "[+] Trying to identify the image"
  424.     echo "[-] The identified profile to use is: $Profile_Specified"
  425. else
  426.     echo "[-] Profile manually set to : $Profile_Specified"
  427. fi
  428.  
  429. if [[ $Profile_Specified == Win* ]] || [[ $Profile_Specified == Vista* ]] || [[ $Profile_Specified == Linux* ]]; then
  430.     main
  431. else
  432.     selector
  433. fi
  434. # mac profile...
  435.  
  436. # Delete any empty files that were produced & the forked pid trackers
  437. echo "[-] Deleting any empty directories/files from analysis"
  438. find $Mem_Dir -type f -size 0 -exec rm -v {} \; &>> $process_log
  439. find $Mem_Dir -type d -empty -exec rm -rfv {} \; &>> $process_log
  440. rm -rfv $forked_pids &>> $process_log
  441.  
  442. # End the analysis timer
  443. toc=$(date +%s)
  444. total=$(expr $toc - $tic)
  445. min=$(expr $total / 60)
  446. sec=$(expr $total % 60)
  447. echo "Analysis took :" $min"m":$sec"s"
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement