コンテンツにスキップ

応答処理と fail_with

HTTP 応答の扱いと、失敗時の fail_with です。Failure 定数は lib/msf/core/module/failure.rb にあります。

res = send_request_cgi(...)
fail_with(Failure::Unreachable, "#{peer} - no response") if res.nil?
code = res.code
body = res.body
headers = res.headers
server = res.headers['Server']
cookies = res.get_cookies
location = res.redirection if res.redirect?

check では CheckCode::*、exploit / run では fail_with を使うのが定石です。

def check
res = send_request_cgi('method' => 'GET', 'uri' => normalize_uri(target_uri.path))
return CheckCode::Unknown('no response') if res.nil?
return CheckCode::Safe('not ExampleApp') unless res.body.include?('ExampleApp')
return CheckCode::Appears('ExampleApp detected')
end
定数使う場面
Failure::BadConfigオプション不足・矛盾
Failure::Unreachable接続できない / res.nil?
Failure::Disconnected途中切断
Failure::NoAccess認証失敗・権限不足
Failure::NotFoundパス / ファイルが無い
Failure::NotVulnerable脆弱でないと分かった
Failure::NoTargettarget 選択が合わない
Failure::UnexpectedReply想定外の応答コード / 本文
Failure::TimeoutExpiredタイムアウト
Failure::PayloadFailedペイロードは送ったがセッションなし
Failure::Unknown切り分け不能
Failure::UserInterruptユーザ中断
fail_with(Failure::NoAccess, "login failed: HTTP #{res.code}") unless res.code == 302
fail_with(Failure::UnexpectedReply, 'token missing') if token.blank?
fail_with(Failure::BadConfig, 'PASSWORD is required') if datastore['PASSWORD'].blank?
%r{Version: (?<version>\d+\.\d+)} =~ res.body
if version && Rex::Version.new(version) <= Rex::Version.new('1.3')
return CheckCode::Appears("Version #{version}")
end
json = res.get_json_document rescue nil
fail_with(Failure::UnexpectedReply, 'invalid json') unless json.is_a?(Hash)

HTML の簡易除去は strip_tags(html) があります。