【JS 逆向百例】復(fù)雜的登錄過程,最新WB逆向

聲明

本文章中所有內(nèi)容僅供學(xué)習(xí)交流,抓包內(nèi)容、敏感網(wǎng)址、數(shù)據(jù)接口均已做脫敏處理,嚴(yán)禁用于商業(yè)用途和非法用途,否則由此產(chǎn)生的一切后果均與作者無關(guān),若有侵權(quán),請(qǐng)聯(lián)系我立即刪除!

逆向目標(biāo)

本次的逆向目標(biāo)是WB的登錄,雖然登錄的加密參數(shù)沒有太多,但是登錄的流程稍微復(fù)雜一點(diǎn),經(jīng)歷了很多次中轉(zhuǎn),細(xì)分下來大約要經(jīng)過九次處理才能成功登錄。

在登錄過程中遇到的加密參數(shù)只有一個(gè),即密碼加密,加密后的密碼在獲取 token 的時(shí)候會(huì)用到,獲取 token 是一個(gè) POST 請(qǐng)求,其 Form Data 里的 sp 值就是加密后的密碼,類似于:e23c5d62dbf9f8364005f331e487873c70d7ab0e8dd2057c3e66d1ae5d2837ef1dcf86......

登錄流程

首先來理清一下登錄流程,每一步特殊的參數(shù)進(jìn)都行了說明,沒有提及的參數(shù)表示是定值,直接復(fù)制即可。

大致流程如下:

  1. 預(yù)登陸

  2. 獲取加密密碼

  3. 獲取 token

  4. 獲取加密后的賬號(hào)

  5. 發(fā)送驗(yàn)證碼

  6. 校驗(yàn)驗(yàn)證碼

  7. 訪問 redirect url

  8. 訪問 crossdomain2 url

  9. 通過 passport url 登錄

1.預(yù)登陸

01.png

預(yù)登陸為 GET 請(qǐng)求,Query String Parameters 中主要包含兩個(gè)比較重要的參數(shù):su:用戶名經(jīng)過 base64 編碼得到,_: 13 位時(shí)間戳,返回的數(shù)據(jù)包含一個(gè) JSON,可用正則提取出來,JSON 里面包含 retcode,servertimepcid,nonce,pubkey,rsakv, exectime 七個(gè)參數(shù)值,其中大多數(shù)值都是后面的請(qǐng)求當(dāng)中要用到的,部分值是加密密碼要用到的,返回?cái)?shù)據(jù)數(shù)示例:

xxxxSSOController.preloginCallBack({
    "retcode": 0,
    "servertime": 1627461942,
    "pcid": "gz-1cd535198c0efe850b96944c7945e8fd514b",
    "nonce": "GWBOCL",
    "pubkey": "EB2A38568661887FA180BDDB5CABD5F21C7BFD59C090CB2D245......",
    "rsakv": 1330428213,
    "exectime": 16
})

2.獲取加密后的密碼

密碼的加密使用的是 RSA 加密,可以通過 Python 或者 JS 來獲取加密后的密碼,JS 加密的逆向在后面拿出來單獨(dú)分析。

3.獲取 token

02.png

這個(gè) token 值在后面的獲取加密手機(jī)號(hào)、發(fā)送驗(yàn)證碼、校驗(yàn)驗(yàn)證碼等步驟中都會(huì)用到,獲取 token 值為 POST 請(qǐng)求,Query String Parameters 的值是固定的:client: ssologin.js(v1.4.19),F(xiàn)orm Data 的值相對(duì)來說比較多,但是除了加密的密碼以外,其他參數(shù)其實(shí)都是可以在第1步預(yù)登陸返回的數(shù)據(jù)里找到,主要的參數(shù)如下:

  • su:用戶名經(jīng)過 base64 加密得到
  • servertime:通過第1步預(yù)登陸返回的 JSON 里面獲取
  • nonce:通過第1步預(yù)登陸返回的 JSON 里面獲取
  • rsakv:通過第1步預(yù)登陸返回的 JSON 里面獲取
  • sp:加密后的密碼
  • prelt:隨機(jī)值

返回?cái)?shù)據(jù)為 HTML 源碼,可以從里面提取 token 值,類似于:2NGFhARzFAFAIp_QwX70Npj8gw4lgj7RbCnByb3RlY3Rpb24.,如果返回的 token 不是這種,則說明賬號(hào)或者密碼錯(cuò)誤。

4.獲取加密后的賬號(hào)

03.png

前面我們遇到的 su 是用戶名經(jīng)過 base64 加密得到,這里它對(duì)用戶名進(jìn)行了進(jìn)一步的加密處理,加密后的用戶名在發(fā)送驗(yàn)證碼和校驗(yàn)驗(yàn)證碼的時(shí)候會(huì)用到,GET 請(qǐng)求,Query String Parameters 的參數(shù)也比較簡(jiǎn)單,token 就是第3步獲取的 token 值,callback_url 是網(wǎng)站的主頁,返回?cái)?shù)據(jù)是 HTML 源碼,可以使用 xpath 語法://input[@name='encrypt_mobile']/@value 來提取加密后的賬號(hào),其值類似于:f2de0b5e333a,這里需要注意的是,即便是同一個(gè)賬號(hào),每次加密的結(jié)果也是不一樣的。

5.發(fā)送驗(yàn)證碼

04.png

發(fā)送驗(yàn)證碼是一個(gè) POST 請(qǐng)求,其參數(shù)也比較簡(jiǎn)單,Query String Parameters 里的 token 是第3步獲取的 token,F(xiàn)orm Data 里的 encrypt_mobile 是第4步獲取的加密后的賬號(hào),返回的數(shù)據(jù)是驗(yàn)證碼發(fā)送的狀態(tài),例如:{'retcode': 20000000, 'msg': 'succ', 'data': []}。

6.校驗(yàn)驗(yàn)證碼

05.png

校驗(yàn)驗(yàn)證碼是一個(gè) POST 請(qǐng)求,其參數(shù)也非常簡(jiǎn)單,Query String Parameters 里的 token 是第3步獲取的 token,F(xiàn)orm Data 里的 encrypt_mobile 是第4步獲取的加密后的賬號(hào),code 是第5步收到的驗(yàn)證碼,返回?cái)?shù)據(jù)是一個(gè) JSON,retcodemsg 代表校驗(yàn)的狀態(tài),redirect url 是校驗(yàn)步驟完成后接著要訪問的頁面,在下一步中要用到,返回的數(shù)據(jù)示例:

{
  "retcode": 20000000,
  "msg": "succ",
  "data": {
    "redirect_url": "https://login.xxxx.com.cn/sso/login.php?entry=xxxxx&returntype=META&crossdomain=1&cdult=3&alt=ALT-NTcxNjMyMTA2OA==-1630292617-yf-78B1DDE6833847576B0DC4B77A6C77C4-1&savestate=30&url=https://xxxxx.com"
  }
}

7.訪問 redirect url

06.png

這一步的請(qǐng)求接口其實(shí)就是第6步返回的 redirect url,GET 請(qǐng)求,類似于:https://login.xxxx.com.cn/sso/login.php?entry=xxxxx&returntype=META......

返回的數(shù)據(jù)是 HTML 源碼,我們要從中提取 crossdomain2 的 URL,提取的結(jié)果類似于:https://login.xxxx.com.cn/crossdomain2.php?action=login&entry=xxxxx......,同樣的,這個(gè) URL 也是接下來需要訪問的頁面。

8.訪問 crossdomain2 url

07.png

這一步的請(qǐng)求接口就是第7步提取的 crossdomain2 url,GET 請(qǐng)求,類似于:https://login.xxxx.com.cn/crossdomain2.php?action=login&entry=xxxxx......

返回的數(shù)據(jù)同樣是 HTML 源碼,我們要從中提取真正的登錄的 URL,提取的結(jié)果類似于:https://passport.xxxxx.com/wbsso/login?ssosavestate=1661828618&url=https......,最后一步只需要訪問這個(gè)真正的登錄 URL 就能實(shí)現(xiàn)登錄操作了。

9.通過 passport url 登錄

08.png

這是最后一步,也是真正的登錄操作,GET 請(qǐng)求,請(qǐng)求接口就是第8步提取的 passport url,類似于:https://passport.xxxxx.com/wbsso/login?ssosavestate=1661828618&url=https......

返回的數(shù)據(jù)包含了登錄結(jié)果、用戶 ID 和用戶名,類似于:

({"result":true,"userinfo":{"uniqueid":"5712321368","displayname":"tomb"}});

自此,WB的完整登錄流程已完成,可以直接拿登錄成功后的 cookies 進(jìn)行其他操作了。

加密密碼逆向

在登錄流程中,第2步是獲取加密后的密碼,在登錄的第3步獲取 token 里,請(qǐng)求的 Query String Parameters 包含了一個(gè)加密參數(shù) sp,這個(gè)就是加密后的密碼,接下來我們對(duì)密碼的加密進(jìn)行逆向分析。

直接全局搜索 sp 關(guān)鍵字,發(fā)現(xiàn)有很多值,這里我們又用到了前面講過的技巧,嘗試搜索 sp=、sp: 或者 var sp 等來縮小范圍,在本案例中,我們嘗試搜索 sp=,可以看到在 index.js 里面只有一個(gè)值,埋下斷點(diǎn)進(jìn)行調(diào)試,可以看到 sp 其實(shí)就是 b 的值:

PS:搜索時(shí)要注意,不能在登錄成功后的頁面進(jìn)行搜索,此時(shí)資源已刷新,重新加載了,加密的 JS 文件已經(jīng)沒有了,需要在登錄界面輸入錯(cuò)誤的賬號(hào)密碼來抓包、搜索、斷點(diǎn)。

09.png

繼續(xù)往上追蹤這個(gè) b 的值,關(guān)鍵代碼有個(gè) if-else 語句,分別埋下斷點(diǎn),經(jīng)過調(diào)試可以看到 b 的值在 if 下面生成:

10.png

分析一下兩行關(guān)鍵代碼:

f.setPublic(me.rsaPubkey, "10001");
b = f.encrypt([me.servertime, me.nonce].join("\t") + "\n" + b)

me.rsaPubkey、me.servertime、me.nonce 都是第1步預(yù)登陸返回的數(shù)據(jù)。

把鼠標(biāo)移到 f.setPublicf.encrypt,可以看到分別是 brbt 函數(shù):

11.png
12.png

分別跟進(jìn)這兩個(gè)函數(shù),可以看到都在一個(gè)匿名函數(shù)下面:

13.png

直接將整個(gè)匿名函數(shù)復(fù)制下來,去掉最外面的匿名函數(shù),進(jìn)行本地調(diào)試,調(diào)試過程中會(huì)提示 navigator 未定義,查看復(fù)制的源碼,里面用到了 navigator.appNamenavigator.appVersion,直接定義即可,或者置空都行。

navigator = {
    appName: "Netscape",
    appVersion: "5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"
}

繼續(xù)調(diào)試會(huì)發(fā)現(xiàn)在 var c = this.doPublic(b); 提示對(duì)象不支持此屬性或方法,搜索 doPublic 發(fā)現(xiàn)有一句 bq.prototype.doPublic = bs;,這里直接將其改為 doPublic = bs; 即可。

分析整個(gè) RSA 加密邏輯,其實(shí)也可以通過 Python 來實(shí)現(xiàn),代碼示例(pubkey 需要補(bǔ)全):

import rsa
import binascii


pre_parameter = {
        "retcode": 0,
        "servertime": 1627461942,
        "pcid": "gz-1cd535198c0efe850b96944c7945e8fd514b",
        "nonce": "GWBOCL",
        "pubkey": "EB2A38568661887FA180BDDB5CABD5F21C7BFD59C090CB2D245......",
        "rsakv": 1330428213,
        "exectime": 16
}

password = '12345678'

public_key = rsa.PublicKey(int(pre_parameter['pubkey'], 16), int('10001', 16))
text = '%s\t%s\n%s' % (pre_parameter['servertime'], pre_parameter['nonce'], password)
encrypted_str = rsa.encrypt(text.encode(), public_key)
encrypted_password = binascii.b2a_hex(encrypted_str).decode()

print(encrypted_password)

完整代碼

GitHub 關(guān)注 K 哥爬蟲,持續(xù)分享爬蟲相關(guān)代碼!歡迎 star !https://github.com/kgepachong/

以下只演示部分關(guān)鍵代碼,不能直接運(yùn)行!完整代碼倉庫地址:https://github.com/kgepachong/crawler/

關(guān)鍵 JS 加密代碼架構(gòu)

navigator = {
    appName: "Netscape",
    appVersion: "5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"
}

function bt(a) {}

function bs(a) {}

function br(a, b) {}

// 此處省略 N 個(gè)函數(shù)

bl.prototype.nextBytes = bk;
doPublic = bs;
bq.prototype.setPublic = br;
bq.prototype.encrypt = bt;
this.RSAKey = bq


function getEncryptedPassword(me, b) {
    br(me.pubkey, "10001");
    b = bt([me.servertime, me.nonce].join("\t") + "\n" + b);
    return b
}

// 測(cè)試樣例
// var me = {
//     "retcode": 0,
//     "servertime": 1627283238,
//     "pcid": "gz-a9243276722ed6d4671f21310e2665c92ba4",
//     "nonce": "N0Y3SZ",
//     "pubkey": "EB2A38568661887FA180BDDB5CABD5F21C7BFD59C090CB2D245A87AC253062882729293E5506350508E7F9AA3BB77F4333231490F915F6D63C55FE2F08A49B353F444AD3993CACC02DB784ABBB8E42A9B1BBFFFB38BE18D78E87A0E41B9B8F73A928EE0CCEE1F6739884B9777E4FE9E88A1BBE495927AC4A799B3181D6442443",
//     "rsakv": "1330428213",
//     "exectime": 13
// }
// var b = '12312312312'  // 密碼
// console.log(getEncryptedPassword(me, b))

Python 登錄關(guān)鍵代碼

#!/usr/bin/env python3
# -*- coding: utf-8 -*-


import re
import json
import time
import base64
import binascii

import rsa
import execjs
import requests
from lxml import etree


# 判斷某些請(qǐng)求是否成功的標(biāo)志
response_success_str = 'succ'

pre_login_url = '脫敏處理,完整代碼關(guān)注 GitHub:https://github.com/kgepachong/crawler'
get_token_url = '脫敏處理,完整代碼關(guān)注 GitHub:https://github.com/kgepachong/crawler'
protection_url = '脫敏處理,完整代碼關(guān)注 GitHub:https://github.com/kgepachong/crawler'
send_code_url = '脫敏處理,完整代碼關(guān)注 GitHub:https://github.com/kgepachong/crawler'
confirm_url = '脫敏處理,完整代碼關(guān)注 GitHub:https://github.com/kgepachong/crawler'

headers = {
    'Host': '脫敏處理,完整代碼關(guān)注 GitHub:https://github.com/kgepachong/crawler',
    'Referer': '脫敏處理,完整代碼關(guān)注 GitHub:https://github.com/kgepachong/crawler',
    'sec-ch-ua': '" Not;A Brand";v="99", "Google Chrome";v="91", "Chromium";v="91"',
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
}
session = requests.session()


def get_pre_parameter(username: str) -> dict:
    su = base64.b64encode(username.encode())
    time_now = str(int(time.time() * 1000))
    params = {
        'entry': '脫敏處理,完整代碼關(guān)注 GitHub:https://github.com/kgepachong/crawler',
        'callback': '脫敏處理,完整代碼關(guān)注 GitHub:https://github.com/kgepachong/crawler',
        'su': su,
        'rsakt': 'mod',
        'checkpin': 1,
        'client': 'ssologin.js(v1.4.19)',
        '_': time_now,
    }
    response = session.get(url=pre_login_url, params=params, headers=headers).text
    parameter_dict = json.loads(re.findall(r'\((.*)\)', response)[0])
    # print('1.【pre parameter】: %s' % parameter_dict)
    return parameter_dict


def get_encrypted_password(pre_parameter: dict, password: str) -> str:
    # 通過 JS 獲取加密后的密碼
    # with open('encrypt.js', 'r', encoding='utf-8') as f:
    #     js = f.read()
    # encrypted_password = execjs.compile(js).call('getEncryptedPassword', pre_parameter, password)
    # # print('2.【encrypted password】: %s' % encrypted_password)
    # return encrypted_password

    # 通過 Python 的 rsa 模塊和 binascii 模塊獲取加密后的密碼
    public_key = rsa.PublicKey(int(pre_parameter['pubkey'], 16), int('10001', 16))
    text = '%s\t%s\n%s' % (pre_parameter['servertime'], pre_parameter['nonce'], password)
    encrypted_str = rsa.encrypt(text.encode(), public_key)
    encrypted_password = binascii.b2a_hex(encrypted_str).decode()
    # print('2.【encrypted password】: %s' % encrypted_password)
    return encrypted_password


def get_token(encrypted_password: str, pre_parameter: dict, username: str) -> str:
    su = base64.b64encode(username.encode())
    data = {
        'entry': '脫敏處理,完整代碼關(guān)注 GitHub:https://github.com/kgepachong/crawler',
        'gateway': 1,
        'from': '',
        'savestate': 7,
        'qrcode_flag': False,
        'useticket': 1,
        'pagerefer': '',
        'vsnf': 1,
        'su': su,
        'service': 'miniblog',
        'servertime': pre_parameter['servertime'],
        'nonce': pre_parameter['nonce'],
        'pwencode': 'rsa2',
        'rsakv': pre_parameter['rsakv'],
        'sp': encrypted_password,
        'sr': '1920*1080',
        'encoding': 'UTF-8',
        'prelt': 38,
        'url': '脫敏處理,完整代碼關(guān)注 GitHub:https://github.com/kgepachong/crawler',
        'returntype': 'META'
    }
    response = session.post(url=get_token_url, headers=headers, data=data)
    # response.encoding = 'gbk'
    ajax_login_url = re.findall(r'replace\("(.*)"\)', response.text)[0]
    token = ajax_login_url.split('token%3D')[-1]
    if 'weibo' not in token:
        # print('3.【token】: %s' % token)
        return token
    else:
        raise Exception('登錄失敗! 用戶名或者密碼錯(cuò)誤!')


def get_encrypted_mobile(token: str) -> str:
    params = {
        'token': token,
        'callback_url': '脫敏處理,完整代碼關(guān)注 GitHub:https://github.com/kgepachong/crawler'
    }
    response = session.get(url=protection_url, params=params, headers=headers)
    tree = etree.HTML(response.text)
    encrypted_mobile = tree.xpath("http://input[@name='encrypt_mobile']/@value")[0]
    # print('4.【encrypted mobile】: %s' % encrypted_mobile)
    return encrypted_mobile


def send_code(token: str, encrypt_mobile: str) -> str:
    params = {'token': token}
    data = {'encrypt_mobile': encrypt_mobile}
    response = session.post(url=send_code_url, params=params, data=data, headers=headers).json()
    if response['msg'] == response_success_str:
        code = input('請(qǐng)輸入驗(yàn)證碼: ')
        # print('5.【code】: %s' % code)
        return code
    else:
        # print('5.【failed to send verification code】: %s' % response)
        raise Exception('驗(yàn)證碼發(fā)送失敗: %s' % response)


def confirm_code(encrypted_mobile: str, code: str, token: str) -> str:
    params = {'token': token}
    data = {
        'encrypt_mobile': encrypted_mobile,
        'code': code
    }
    response = session.post(url=confirm_url, params=params, data=data, headers=headers).json()
    if response['msg'] == response_success_str:
        redirect_url = response['data']['redirect_url']
        # print('6.【redirect url】: %s' % redirect_url)
        return redirect_url
    else:
        # print('6.【驗(yàn)證碼校驗(yàn)失敗】: %s' % response)
        raise Exception('驗(yàn)證碼校驗(yàn)失敗: %s' % response)


def get_cross_domain2_url(redirect_url: str) -> str:
    response = session.get(url=redirect_url, headers=headers).text
    cross_domain2_url = re.findall(r'replace\("(.*)"\)', response)[0]
    # print('7.【cross domain2 url】: %s' % cross_domain2_url)
    return cross_domain2_url


def get_passport_url(cross_domain2_url: str) -> str:
    response = session.get(url=cross_domain2_url, headers=headers).text
    passport_url_str = re.findall(r'setCrossDomainUrlList\((.*)\)', response)[0]
    passport_url = json.loads(passport_url_str)['arrURL'][0]
    # print('8.【passport url】: %s' % passport_url)
    return passport_url


def login(passport_url: str) -> None:
    response = session.get(url=passport_url, headers=headers).text
    login_result = json.loads(response.replace('(', '').replace(');', ''))
    if login_result['result']:
        user_unique_id = login_result['userinfo']['uniqueid']
        user_display_name = login_result['userinfo']['displayname']
        print('登錄成功!用戶 ID:%s,用戶名:%s' % (user_unique_id, user_display_name))
    else:
        raise Exception('登錄失?。?s' % login_result)


def main():
    username = input('請(qǐng)輸入登錄賬號(hào): ')
    password = input('請(qǐng)輸入登錄密碼: ')

    # 1.預(yù)登陸,獲取一個(gè)字典參數(shù),包含后面要用的 servertime、nonce、pubkey、rsakv
    pre_parameter = get_pre_parameter(username)

    # 2.通過 JS 或者 Python 獲取加密后的密碼
    encrypted_password = get_encrypted_password(pre_parameter, password)

    # 3.獲取 token
    token = get_token(encrypted_password, pre_parameter, username)

    # 4.通過 protection url 獲取加密后的手機(jī)號(hào)
    encrypted_mobile = get_encrypted_mobile(token)

    # 5.發(fā)送手機(jī)驗(yàn)證碼
    code = send_code(token, encrypted_mobile)

    # 6.校驗(yàn)驗(yàn)證碼,校驗(yàn)成功則返回一個(gè)重定向的 URL
    redirect_url = confirm_code(encrypted_mobile, code, token)

    # 7.訪問重定向的 URL,提取 crossdomain2 URL
    cross_domain2_url = get_cross_domain2_url(redirect_url)

    # 8.訪問 crossdomain2 URL,提取 passport URL
    passport_url = get_passport_url(cross_domain2_url)

    # 9.訪問 passport URL 進(jìn)行登錄操作
    login(passport_url)


if __name__ == '__main__':
    main()
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,488評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,034評(píng)論 3 414
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 175,327評(píng)論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,554評(píng)論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,337評(píng)論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 54,883評(píng)論 1 321
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,975評(píng)論 3 439
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,114評(píng)論 0 286
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,625評(píng)論 1 332
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,555評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,737評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,244評(píng)論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 43,973評(píng)論 3 345
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,362評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,615評(píng)論 1 280
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,343評(píng)論 3 390
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,699評(píng)論 2 370

推薦閱讀更多精彩內(nèi)容