淺析HTTPS中間人攻擊與證書校驗 (轉)

轉自:(https://blog.csdn.net/liuwenjie517333813/article/details/78042819)
難得的一篇好文,把HTTPS,HTTPS下的MITM,證書校驗講清楚了。

0x00 引言

隨著安全的普及,https通信應用越發廣泛,但是由于對https不熟悉導致開發人員頻繁錯誤的使用https,例如最常見的是未校驗https證書從而導致“中間人攻擊”,并且由于修復方案也一直是個坑,導致修復這個問題時踩各種坑,故謹以此文簡單的介紹相關問題。

本文第一節主要講述https的握手過程,第二節主要講述常見的“https中間人攻擊”場景,第三節主要介紹證書校驗修復方案,各位看官可根據自己口味瀏覽。

0x01 Https原理

淺析HTTPS中間人攻擊與證書校驗

首先來看下https的工作原理,上圖大致介紹了https的握手流程,后續我們通過抓包看下每個握手包到底干了些什么神奇的事。

注:本文所有內容以TLS_RSA_WITH_AES_128_CBC_SHA加密組件作為基礎進行說明,其他加密組件以及TLS版本會存在一定差異,例如TLS1.3針對移動客戶端有了很大的改動,現在的ECDHE等密鑰交換算法與RSA作為密鑰交換算法也完全不一樣,所以有些地方和大家實際操作會存在一定出入。

1.1 TCP

TCP的三次握手,這是必須的。


淺析HTTPS中間人攻擊與證書校驗

1.2 Client Hello

淺析HTTPS中間人攻擊與證書校驗

TLS的版本號 隨機數random_c:這個是用來生成最后加密密鑰的因子之一,它包含兩部分,時間戳和隨機數 session-id:用來標識會話,第一次握手時為空,如果以前建立過,可以直接帶過去從而避免完全握手 Cipher Suites加密組件列表:瀏覽器所支持的加密算法的清單客戶端支持的加密簽名算法的列表,讓服務器進行選擇 擴展字段:比如密碼交換算法的參數、請求主機的名字,用于單ip多域名的情況指定域名。

淺析HTTPS中間人攻擊與證書校驗

1.3 Sever Hello

淺析HTTPS中間人攻擊與證書校驗

隨機數rando_s,這個是用來生成最后加密密鑰的因子之一,包含兩部分,時間戳和隨機數 32字節的SID,在我們想要重新連接到該站點的時候可以避免一整套握手過程。 在客戶端提供的加密組件中,服務器選擇了TLS_RSA_WITH_AES_128_CBC_SHA組件。

1.4 Certificate

淺析HTTPS中間人攻擊與證書校驗

證書是https里非常重要的主體,可用來識別對方是否可信,以及用其公鑰做密鑰交換。可以看見證書里面包含證書的頒發者,證書的使用者,證書的公鑰,頒發者的簽名等信息。其中Issuer Name是簽發此證書的CA名稱,用來指定簽發證書的CA的可識別的唯一名稱(DN, Distinguished Name),用于證書鏈的認證,這樣通過各級實體證書的驗證,逐漸上溯到鏈的終止點,即可信任的根CA,如果到達終點在自己的信任列表內未發現可信任的CA則認為此證書不可信。

驗證證書鏈的時候,用上一級的公鑰對證書里的簽名進行解密,還原對應的摘要值,再使用證書信息計算證書的摘要值,最后通過對比兩個摘要值是否相等,如果不相等則認為該證書不可信,如果相等則認為該級證書鏈正確,以此類推對整個證書鏈進行校驗,引用高性能網絡中的證書鏈校驗圖。

淺析HTTPS中間人攻擊與證書校驗
淺析HTTPS中間人攻擊與證書校驗

二級機構的公鑰

淺析HTTPS中間人攻擊與證書校驗

網站證書的簽名

不僅僅進行證書鏈的校驗,此時還會進行另一個協議即Online Certificate Status Protocol, 該協議為證書狀態在線查詢協議,一個實時查詢證書是否吊銷的方式,客戶端發送證書的信息并請求查詢,服務器返回正常、吊銷或未知中的任何一個狀態,這個查詢地址會附在證書中供客戶端使用。

1.5 Server Hello Done

淺析HTTPS中間人攻擊與證書校驗

這是一個零字節信息,用于告訴客戶端整個server hello過程已經結束。

1.6 ClientKeyExchange

淺析HTTPS中間人攻擊與證書校驗

客戶端在驗證證書有效之后發送ClientKeyExchange消息,ClientKeyExchange消息中,會設置48字節的premaster secret,通過密鑰交換算法加密發送premaster secret的值,例如通過 RSA公鑰加密premaster secret的得到Encrypted PreMaster傳給服務端。PreMaster前兩個字節是TLS的版本號,該版本號字段是用來防止版本回退攻擊的。

從握手包到目前為止,已經出現了三個隨機數(客戶端的random_c,服務端的random_s,premaster secret),使用這三個隨機數以及一定的算法即可獲得對稱加密AES的加密主密鑰Master-key,主密鑰的生成非常的精妙,通過閱讀RFC2246文檔以及openssl的函數int master_secret(unsigned char *dest,int len,unsigned char *pre_master_secret,int pms_len,unsigned char *label,unsigned char *seed,int seed_len)可得到主密鑰的生成過程如下:

1 2 PRF(secret, label, seed) = P_MD5(S1, label + seed) XOR P_SHA-1(S2, label + seed);

函數中的參數定義如下:

secret即為pre secret ,label是一個字符串,seed為random_c+random_s,S1為前半部分的pre secret,S2為后半部分的pre secret。分別使用P_MD5()和P_SHA-1進行hash計算得到兩個hash,再使用這兩個hash進行異或得到最終的主密鑰master key,這兩個hash由下面的運算得來:

1 2 3 P_hash(1/2secret, label,seed) = HMAC_hash(1/2secret, A(1) + seed) + HMAC_hash(1/2secret, A(2) + seed) + HMAC_hash(1/2secret, A(3) + seed) + ...

P_hash()是P_MD5()和P_SHA-1()的統稱。

A()的賦值相對比較復雜,變形后如下:

1 2 A(0)=HMAC(md5,1/2secret,strlen(1/2secret), actual_seed(0), strlen(label)+strlen(seed),temp_md5,NULL); //temp_md5數組用于接收最后生成的hash,attual_seed為label和seed結合 A(0) = HMAC(sha,1/2secret,strlen(1/2secret) , actual_seed(0), strlen(label)+strlen(seed),temp_sha,NULL);// temp_sha數組用于接收最后生成的hash,attual_seed為label和seed結合

簡化表達如下:

1 A(i)=HMAC_hash(1/2secret,A(i-1)+seed)

由于只進行一次SHA-1或者MD5產生的hash字節數是不夠的,所以使用迭代的方式產生足夠多的hash,多出來的hash則直接拋棄。例如,使用P_SHA-1()產生64字節的數據,就需要迭代4次(通過A(4)),產生80字節的輸出數據,最后迭代產生的16字節將會被拋棄,只留下64字節的數據,如果使用P_MD5()則需要迭代5次。

1.7 Change Cipher Spec

淺析HTTPS中間人攻擊與證書校驗

發送一個不加密的信息,瀏覽器使用該信息通知服務器后續的通信都采用協商的通信密鑰和加密算法進行加密通信。

1.8 Encrypted Handshake Message

淺析HTTPS中間人攻擊與證書校驗

驗證加密算法的有效性,結合之前所有通信參數的 hash 值與其它相關信息生成一段數據,采用協商密鑰 session secret 與算法進行加密,然后發送給服務器用于數據與握手驗證,通過驗證說明加密算法有效。

1.9 Change_cipher_spec

淺析HTTPS中間人攻擊與證書校驗

Encrypted Handshake Message通過驗證之后,服務器同樣發送 change_cipher_spec 以通知客戶端后續的通信都采用協商的密鑰與算法進行加密通信。這里還有一個New Session Ticket并不是必須的,這是服務器做的優化,后續我們再講解該協議的作用。

1.10 Encrypted Handshake Message

淺析HTTPS中間人攻擊與證書校驗

同樣的,服務端也會發送一個Encrypted Handshake Message供客戶端驗證加密算法有效性。

1.11 Application Data

淺析HTTPS中間人攻擊與證書校驗

經過一大串的的計算之后,終于一切就緒,后續傳輸的數據可通過主密鑰master key進行加密傳輸,加密數據查看圖中的Encrypted Apploication Data字段數據,至此https的一次完整握手以及數據加密傳輸終于完成。

https里還有很多可優化并且很多精妙的設計,例如為了防止經常進行完整的https握手影響性能,于是通過sessionid來避免同一個客戶端重復完成握手,但是又由于sessionid消耗的內存性能比較大,于是又出現了new session ticket,如果客戶端表明它支持Session Ticket并且服務端也支持,那么在TLS握手的最后一步服務器將包含一個“New Session Ticket”信息,其中包含了一個加密通信所需要的信息,這些數據采用一個只有服務器知道的密鑰進行加密。這個Session Ticket由客戶端進行存儲,并可以在隨后的一次會話中添加到 ClientHello消息的SessionTicket擴展中。雖然所有的會話信息都只存儲在客戶端上,但是由于密鑰只有服務器知道,所以Session Ticket仍然是安全的,因此這不僅避免了性能消耗還保證了會話的安全性。

最后我們可以使用openssl命令來直觀的看下https握手的流程:

淺析HTTPS中間人攻擊與證書校驗

0x02 中間人攻擊

https握手過程的證書校驗環節就是為了識別證書的有效性唯一性等等,所以嚴格意義上來說https下不存在中間人攻擊,存在中間人攻擊的前提條件是沒有嚴格的對證書進行校驗,或者人為的信任偽造證書,下面一起看下幾種常見的https“中間人攻擊”場景。

2.1 證書未校驗

由于客戶端沒有做任何的證書校驗,所以此時隨意一張證書都可以進行中間人攻擊,可以使用burp里的這個模塊進行中間人攻擊。

淺析HTTPS中間人攻擊與證書校驗

通過瀏覽器查看實際的https證書,是一個自簽名的偽造證書。

淺析HTTPS中間人攻擊與證書校驗

2.2 部分校驗

做了部分校驗,例如在證書校驗過程中只做了證書域名是否匹配的校驗,可以使用burp的如下模塊生成任意域名的偽造證書進行中間人攻擊。

淺析HTTPS中間人攻擊與證書校驗

實際生成的證書效果,如果只做了域名、證書是否過期等校驗可輕松進行中間人攻擊(由于chrome是做了證書校驗的所以會提示證書不可信任)。

淺析HTTPS中間人攻擊與證書校驗

2.3 證書鏈校驗

如果客戶端對證書鏈做了校驗,那么攻擊難度就會上升一個層次,此時需要人為的信任偽造的證書或者安裝偽造的CA公鑰證書從而間接信任偽造的證書,可以使用burp的如下模塊進行中間人攻擊。

淺析HTTPS中間人攻擊與證書校驗

淺析HTTPS中間人攻擊與證書校驗

可以看見瀏覽器是會報警告的,因為burp的根證書PortSwigger CA并不在瀏覽器可信任列表內,所以由它作為根證書簽發的證書都是不能通過瀏覽器的證書校驗的,如果將PortSwigger CA導入系統設置為可信任證書,那么瀏覽器將不會有任何警告。

2.4 手機客戶端Https數據包抓取

上述第一、二種情況不多加贅述,第三種情況就是我們經常使用的抓手機應用https數據包的方法,即導入代理工具的公鑰證書到手機里,再進行https數據包的抓取。導入手機的公鑰證書在android平臺上稱之為受信任的憑據,在ios平臺上稱之為描述文件,可以通過openssl的命令直接查看我們導入到手機客戶端里的這個PortSwiggerCA.crt

淺析HTTPS中間人攻擊與證書校驗

可以看見是Issuer和Subject一樣的自簽名CA公鑰證書,另外我們也可以通過證書類型就可以知道此為公鑰證書,crt、der格式的證書不支持存儲私鑰或證書路徑(有興趣的同學可查找證書相關信息)。導入CA公鑰證書之后,參考上文的證書校驗過程不難發現通過此方式能通過證書鏈校驗,從而形成中間人攻擊,客戶端使用代理工具的公鑰證書加密隨機數,代理工具使用私鑰解密并計算得到對稱加密密鑰,再對數據包進行解密即可抓取明文數據包。

2.5 中間人攻擊原理

一直在說中間人攻擊,那么中間人攻擊到底是怎么進行的呢,下面我們通過一個流行的MITM開源庫mitmproxy來分析中間人攻擊的原理。中間人攻擊的關鍵在于https握手過程的ClientKeyExchange,由于pre key交換的時候是使用服務器證書里的公鑰進行加密,如果用的偽造證書的公鑰,那么中間人就可以解開該密文得到pre_master_secret計算出用于對稱加密算法的master_key,從而獲取到客戶端發送的數據;然后中間人代理工具再使用其和服務端的master_key加密傳輸給服務端;同樣的服務器返回給客戶端的數據也是經過中間人解密再加密,于是完整的https中間人攻擊過程就形成了,一圖勝千言,來吧。

淺析HTTPS中間人攻擊與證書校驗

通過讀Mitmproxy的源碼發現mitmproxy生成偽造證書的函數如下:

淺析HTTPS中間人攻擊與證書校驗

通過上述函數一張完美偽造的證書就出現了,使用瀏覽器通過mitmproxy做代理看下實際偽造出來的證書。

淺析HTTPS中間人攻擊與證書校驗

可以看到實際的證書是由mimtproxy頒發的,其中的公鑰就是mimtproxy自己的公鑰,后續的加密數據就可以使用mimtproxy的私鑰進行解密了。如果導入了mitmproxy的公鑰證書到客戶端,那么該偽造的證書就可以完美的通過客戶端的證書校驗了。這就是平時為什么導入代理的CA證書到手機客戶端能抓取https的原因。

0x03 App證書校驗

通過上文第一和第二部分的說明,相信大家已經對https有個大概的了解了,那么問題來了,怎樣才能防止這些“中間人攻擊”呢?

app證書校驗已經是一個老生常談的問題了,但是市場上還是有很多的app未做好證書校驗,有些只做了部分校驗,例如檢查證書域名是否匹配證書是否過期,更多數的是根本就不做校驗,于是就造成了中間人攻擊。做證書校驗需要做完全,只做一部分都會導致中間人攻擊,對于安全要求并不是特別高的app可使用如下校驗方式:

查看證書是否過期 服務器證書上的域名是否和服務器的實際域名相匹配 校驗證書鏈

可參考http://drops.wooyun.org/tips/3296,此類校驗方式雖然在導入CA公鑰證書到客戶端之后會造成中間人攻擊,但是攻擊門檻已相對較高,所以對于安全要求不是特別高的app可采用此方法進行防御。對于安全有較高要求一些app(例如金融)上述方法或許還未達到要求,那么此時可以使用如下更安全的校驗方式,將服務端證書打包放到app里,再建立https鏈接時使用本地證書和網絡下發證書進行一致性校驗,可參考安卓官方提供的https連接demo:https://developer.android.com/training/articles/security-ssl.html

#!java
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.InputStream;
import java.net.URL;
import java.security.KeyStore;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
 
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
 
import android.content.Context;
import android.util.Log;
 
public class TestHttpsConnect {
    public static void test(Context mcontext, String name, String weburl) throws Exception {
 
        CertificateFactory cf = CertificateFactory.getInstance("X.509");
        InputStream caInput = new BufferedInputStream(new FileInputStream("baidu.cer"));
        Certificate ca;
        try {
            ca = cf.generateCertificate(caInput);
            System.out.println("ca=" + ((X509Certificate) ca).getSubjectDN());
        } finally {
            caInput.close();
        }
 
        String keyStoreType = KeyStore.getDefaultType();
        KeyStore keyStore = KeyStore.getInstance(keyStoreType);
        keyStore.load(null, null);
        keyStore.setCertificateEntry("ca", ca);
 
        String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
        TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
        tmf.init(keyStore);
 
        SSLContext context = SSLContext.getInstance("TLS");
        context.init(null, tmf.getTrustManagers(), null);
 
        URL url = new URL(weburl);
        HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();
        urlConnection.setSSLSocketFactory(context.getSocketFactory());
        InputStream in = urlConnection.getInputStream();
        ByteArrayOutputStream arrayOutputStream = new ByteArrayOutputStream();
 
        byte[] buffer = new byte[1024];
        int len = -1;
        while ((len = in.read(buffer)) >= 0) {
            arrayOutputStream.write(buffer, 0, len);
        }
 
        Log.e("", arrayOutputStream.toString());
 
    }
 
}

此類校驗即便導入CA公鑰證書也無法進行中間人攻擊,但是相應的維護成本會相對升高,例如服務器證書過期,證書更換時如果app不升級就無法使用,那么可以改一下:

生成一對RSA的公私鑰,公鑰可硬編碼在app,私鑰放服務器。 https握手前可通過服務器下發證書信息,例如公鑰、辦法機構、簽名等,該下發的信息使用服務器里的私鑰進行簽名; 通過app里預置的公鑰驗簽得到證書信息并存在內容中供后續使用; 發起https連接獲取服務器的證書,通過對比兩個證書信息是否一致進行證書校驗。

這樣即可避免強升的問題,但是問題又來了,這樣效率是不是低太多了?答案是肯定的,所以對于安全要求一般的應用使用第一種方法即可,對于一些安全要求較高的例如金融企業可選擇第二種方法。

說了挺多,但是該來的問題還是會來啊!現在的app一般采用混合開發,會使用很多webveiw直接加載html5頁面,上面的方法只解決了java層證書校驗的問題,并沒有涉及到webview里面的證書校驗,對于這種情況怎么辦呢?既然問題來了那么就一起說說解決方案,對于webview加載html5進行證書校驗的方法如下:

webview創建實例加載網頁時通過onPageStart方法返回url地址; 將返回的地址轉發到java層使用上述的證書校驗代碼進行進行校驗; 如果證書校驗出錯則使用stoploading()方法停止網頁加載,證書校驗通過則正常加載。

提供參考代碼如下:

#!java
package com.example.testhttps;
 
import java.io.InputStream;
import java.net.URL;
import java.security.KeyStore;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
 
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
 
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.http.SslError;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.webkit.SslErrorHandler;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Toast;
 
public class TestWebViewActivity extends Activity {
 
    static final String TAB = "MainActivity";
    WebView mWebView;
 
    SSLContext mSslContext;
    KeyStore keyStore;
    TrustManagerFactory tmf;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
 
        setContentView(R.layout.test_webview_acitity);
 
        iniData();
 
        mWebView = (WebView) findViewById(R.id.webView1);
        mWebView.setWebViewClient(new MyWebViewClient());
        mWebView.getSettings().setJavaScriptEnabled(true);
 
        Intent i = getIntent();
        String url = i.getStringExtra("url");
        mWebView.loadUrl(url);
    }
 
    /**
     * 初始化證書
     */
    void iniData() {
        try {
 
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            InputStream caInput = getAssets().open("baidu.cer");
            Certificate ca;
            try {
                ca = cf.generateCertificate(caInput);
                System.out.println("ca=" + ((X509Certificate) ca).getSubjectDN());
            } finally {
                caInput.close();
            }
 
            String keyStoreType = KeyStore.getDefaultType();
            keyStore = KeyStore.getInstance(keyStoreType);
            keyStore.load(null, null);
            keyStore.setCertificateEntry("ca", ca);
 
            String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
            tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
            tmf.init(keyStore);
 
            mSslContext = SSLContext.getInstance("TLS");
            mSslContext.init(null, tmf.getTrustManagers(), null);
        } catch (Exception e) {
            Log.e("", "iniData error");
            e.printStackTrace();
        }
    }
 
    class MyWebViewClient extends WebViewClient {
 
        @Override
        public void onPageStarted(WebView view, String url, Bitmap favicon) {
            // TODO Auto-generated method stub
            super.onPageStarted(view, url, favicon);
 
            // 如果不是https,不用校驗
            if (!url.startsWith("https://")) {
                return;
            }
 
            final WebView tempView = view;
            final String tempurl = url;
 
            /**
             * 測試url校驗,如果不通過,就不加載
             */
            new AsyncTask() {
 
                @Override
                protected Boolean doInBackground(String... params) {
                    // TODO Auto-generated method stub
                    try {
                        // 檢驗證書是否正確
                        URL url = new URL(tempurl);
                        HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();
                        urlConnection.setSSLSocketFactory(mSslContext.getSocketFactory());
                        InputStream in = urlConnection.getInputStream();
                        in.close();
                        // TestHttpsConnect.test(TestWebViewActivity.this,
                        // "baidu.cer", tempurl);
                    } catch (Exception e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                        return false;
                    }
                    return true;
                }
 
                protected void onPostExecute(Boolean result) {
                    if (!result) {
                        Toast.makeText(TestWebViewActivity.this, "證書校驗錯誤", Toast.LENGTH_SHORT).show();
                        tempView.stopLoading();
                    }
                };
 
            }.execute(url);
        }
 
        @Override
        public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
            // TODO Auto-generated method stub
            super.onReceivedSslError(view, handler, error);
            // Log.e(TAB, "onReceivedSslError");
        }
    }
 
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,702評論 6 534
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,615評論 3 419
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,606評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,044評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,826評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,227評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,307評論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,447評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,992評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,807評論 3 355
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,001評論 1 370
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,550評論 5 361
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,243評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,667評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,930評論 1 287
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,709評論 3 393
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,996評論 2 374