備忘録

備忘録

Javaでokhttpを使って全ての証明書を許可する

Ⅰ. はじめに

オレオレ証明書などは以下のエラーを吐いて弾かれてしまいます。
デバッグ時など、とりあえず全部許可したいときのやり方です。

Exception in thread "main" javax.net.ssl.SSLHandshakeException: sun.security.validator.
ValidatorException: PKIX path building failed:
sun.security.provider.certpath.SunCertPathBuilderException:
unable to find valid certification path to requested target

Ⅱ. プログラム

import okhttp3.*;

import javax.net.ssl.*;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

public class Main {

  static class MyX509TrustManager implements X509TrustManager {
    public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException { }
    public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException { }
    public java.security.cert.X509Certificate[] getAcceptedIssuers() {
      return new java.security.cert.X509Certificate[]{};
    }
  }

  private static String okHttpGet() throws Exception {
    // リクエストを作成する
    Request request = new Request.Builder()
        .url("https://example.com/")
        .get()
        .build();

    // OkHttpClient の Bulider を作成する
    OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder();

    // proxyを設定する
    clientBuilder.proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("127.0.0.1", 8008)));
    
    // MyX509TrustManager を割り当てる
    // MyX509TrustManager は全ての証明書を許可するようにしている
    SSLContext sslContext = SSLContext.getInstance("SSL");
    sslContext.init(null, new TrustManager[] { new MyX509TrustManager() }, new java.security.SecureRandom());
    clientBuilder.sslSocketFactory(sslContext.getSocketFactory(), new MyX509TrustManager());

    OkHttpClient client = clientBuilder.build();

    // GET する
    Response response = client.newCall(request).execute();
    return response.body().string();
  }

  public static void main(String[] args) throws Exception{
    String str = okHttpGet();
    System.out.println(str);
  }
}

C#でPublic Key Pinningする

Ⅰ. はじめに

Public Key Pinningとは、SSL証明書のチェックを行うことです。
チェックを行うことで、不正な証明書を検知することができます。

例えばクラッカーはMITMを利用して傍受を試みます。
MITMを利用するとSSL証明書が書き換わる為、
不正な証明書であれば通信を行わないようにすることが出来ます。

Ⅱ. プログラム

Program.cs
ServicePointManager.ServerCertificateValidationCallback += new RemoteCertificateValidationCallback(OnRemoteCertificateValidationCallback);
CertificateValidation.cs
public static bool OnRemoteCertificateValidationCallback(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
  var hashs = new Dictionary<string, string>()
  {
    { "aaa.jp", "6c276e0c4e2fa19d1656df1298d8ff6497d0cc49" },
    { "aab.jp", "7dfc0fd1abf2af11dd2f9503448009f090d529eb" },
    { "aac.jp", "bb1d931851cc679a476021494550573eb1e1148d" }
  };

  if (hashs.ContainsValue(certificate.GetCertHashString().ToLower()))
  {
    // 通信を許可する
    return true;
  }
  else
  {
    // 通信を許可しない
    return false;
  }
}

SSL証明書ハッシュ値は、SSL証明書の「拇印」の値を使います
f:id:kagasu:20170310145511p:plain

「拇印」のコピーについて

「拇印」をそのままコピーするとデータ先頭に謎のデータが付加されています。
テキストエディタやVisualStudioのエディタで見ても見た目は正しい文字列ですが、バイナリで見ると間違っていることが解ります。
面倒ですがコピーしない方が良いです。
f:id:kagasu:20170915111229p:plain

注意

証明書の有効期限を予め確認する必要があります。
上記のサンプルコードの場合、証明書を更新した後にクライアント側を修正しようとしても通信が一切できない状態になります。
アップデートチェックとしてWeb APIを利用しているケースでは致命的になる場合があります。

PythonでPOSTする

Ⅰ. はじめに

PythonでPOSTする方法です。

Ⅱ. プログラム

import requests

# InsecureRequestWarning を非表示にする場合
# from requests.packages.urllib3.exceptions import InsecureRequestWarning
# requests.packages.urllib3.disable_warnings(InsecureRequestWarning)

s = requests.session()

proxies = {
  'http':'http://user:pass@127.0.0.1:8008',
  'https':'https://127.0.0.1:8008'
}

headers = {
  'User-Agent' : 'Mozilla/...',
  # 'Content-Type' : 'application/x-www-form-urlencoded'
}

params = {
  'param1' : 'xxx',
  'param2' : 'yyy'
}

s.proxies = proxies
# 証明書チェックを省く
s.verify = False
s.headers = headers

response = s.post('https://example.com/', params)

# 文字化けする場合はcmdで「chcp 65001」を実行すると治る(Windows)
# 65001 はutf-8
print response.content

Ⅲ. その他

開発環境でMITMを利用したproxy(FiddlerやBurpSuiteやCharlesやmitmproxyなど)
SSL Decryptを有効にしていると以下のエラーが出ます。

requests.exceptions.SSLError:
("bad handshake: Error([('SSL routines', 'ssl3_get_server_certificate', 'certificate verify failed')],)",)
s.verify = False

にするとでなくなります。

VisualStudioで設定したAWSのプロファイルを修正する

Ⅰ. はじめに

AWS Toolkit for Visual Studioを利用しているのが前提です。
VisualStudioに追加したプロファイルの追加、編集、削除するについて説明します。

Ⅱ. やり方

1. AWS Explorer を表示させる

VisualStudioのメニューから
「表示」→「AWS Explorer」を選択します。

2. 追加、編集、削除する

人のアイコンが左から順番に
「追加」、「編集」、「削除」となっています。
f:id:kagasu:20170304201010p:plain

JMPの隠蔽

Ⅰ. はじめに

リバースエンジニアリングのテクニックの1つです。
パターン化しているので覚えておいて損はありません。
主に ASProtect というパッカーが利用する方法です。

Ⅱ. JMPの隠蔽方法

通常の場合

アセンブリでJMPする場合は以下のように書きます。

JMP x

隠蔽の例

push x
retn

push x とすると x がスタックに積まれます。
retn するときはスタックの一番上に積まれた x にジャンプします。
よって、上記2つのコードは全く同じ動作をします。

また、アセンブリ言語レベルで任意のコードを実行する場合、PUSHを利用したほうが楽になります。
JMP の場合 JMP 先のアドレスとの差を計算して第一オペランドに与える必要がありますが、PUSH を利用すると計算の必要が無くなる為です。