Android证书绑定绕过研究(四)

背景

本文以分析OpenSSL开源代码为切入点,分享扫过证书绑定的逆向思路

逆向思路

  1. 获取关键信息
    • 通过Log信息
    • 通过App报错弹框信息
    • 通过一些常见的报错信息,如verify error、ssl error等
  2. 根据关键信息定位到函数
    • strings命令搜索
    • grep命令搜索
    • IDA搜索
  3. 静态分析
    • 利用IDA Graph进行分支分析
    • 一般是寻找返回值为int的函数
    • 或者是寻找cmp的比较值
  4. 利用Frida Hook关键函数
    • 通过开启/关闭代理开发,对比进行Hook,找出差异点

例子

  1. 获取LOG信息–> SSL error code
  2. 定位函数
  3. 静态分析
    • Google搜索到是openssl源码
    • 耐心分析源码校验的地方
    • 关键点: 一定是调用链相对深入的地方,找到关键的int值,多尝试,坚持
ssl_verify_result_t SSLClientSocketImpl::HandleVerifyResult() {
  // Verification is in progress. Inform BoringSSL it should retry the
  // callback later. The next call to VerifyCertCallback will be a
  // continuation of the same verification, so leave
  // cert_verification_result_ as-is.
  if (cert_verification_result_ == ERR_IO_PENDING)
    return ssl_verify_retry;
  // In BoringSSL's calling convention for asynchronous callbacks,
  // after a callback returns a non-retry value, the operation has
  // completed. Subsequent calls are of new operations with potentially
  // different arguments. Reset cert_verification_result_ to inform
  // VerifyCertCallback not to replay the result on subsequent calls.
  int result = cert_verification_result_;
  cert_verification_result_ = kCertVerifyPending;
  cert_verifier_request_.reset();
  if (!start_cert_verification_time_.is_null()) {
    base::TimeDelta verify_time =
        base::TimeTicks::Now() - start_cert_verification_time_;
    if (result == OK) {
      UMA_HISTOGRAM_TIMES("Net.SSLCertVerificationTime", verify_time);
    } else {
      UMA_HISTOGRAM_TIMES("Net.SSLCertVerificationTimeError", verify_time);
    }
  }
  // Enforce keyUsage extension for RSA leaf certificates chaining up to known
  // roots.
  // TODO(crbug.com/795089): Enforce this unconditionally.
  if (server_cert_verify_result_.is_issued_by_known_root) {
    SSL_set_enforce_rsa_key_usage(ssl_.get(), 1);
  }
  // If the connection was good, check HPKP and CT status simultaneously,
  // but prefer to treat the HPKP error as more serious, if there was one.
  if (result == OK) {
    int ct_result = CheckCTCompliance();
    TransportSecurityState::PKPStatus pin_validity =
        context_->transport_security_state()->CheckPublicKeyPins(
            host_and_port_, server_cert_verify_result_.is_issued_by_known_root,
            server_cert_verify_result_.public_key_hashes, server_cert_.get(),
            server_cert_verify_result_.verified_cert.get(),
            TransportSecurityState::ENABLE_PIN_REPORTS,
            ssl_config_.network_isolation_key, &pinning_failure_log_);
    switch (pin_validity) {
      case TransportSecurityState::PKPStatus::VIOLATED:
        server_cert_verify_result_.cert_status |=
            CERT_STATUS_PINNED_KEY_MISSING;
        result = ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN;
        break;
      case TransportSecurityState::PKPStatus::BYPASSED:
        pkp_bypassed_ = true;
        FALLTHROUGH;
      case TransportSecurityState::PKPStatus::OK:
        // Do nothing.
        break;
    }
    if (result != ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN && ct_result != OK)
      result = ct_result;
  }
  // If no other errors occurred, check whether the connection used a legacy TLS
  // version.
  if (result == OK &&
      SSL_version(ssl_.get()) < context_->config().version_min_warn &&
      base::FeatureList::IsEnabled(features::kLegacyTLSEnforced)) {
    server_cert_verify_result_.cert_status |= CERT_STATUS_LEGACY_TLS;
    // Only set the resulting net error if it hasn't been previously bypassed.
    if (!ssl_config_.IsAllowedBadCert(server_cert_.get(), nullptr))
      result = ERR_SSL_OBSOLETE_VERSION;
  }
  is_fatal_cert_error_ =
      IsCertStatusError(server_cert_verify_result_.cert_status) &&
      result != ERR_CERT_KNOWN_INTERCEPTION_BLOCKED &&
      result != ERR_SSL_OBSOLETE_VERSION &&
      context_->transport_security_state()->ShouldSSLErrorsBeFatal(
          host_and_port_.host());
  if (IsCertificateError(result) && ssl_config_.ignore_certificate_errors) {
    result = OK;
  }
  if (result == OK) {
    return ssl_verify_ok;
  }
  OpenSSLPutNetError(FROM_HERE, result);
  return ssl_verify_invalid;
}

通过源码的字符串(HandleVerifyResult\Net.SSLCertVerificationTime)定位bin文件的位置

利用frida修改x0的值进行试探分析

参考

Google-OpenSSL

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值