類Fomo3D游戲漏洞與修復方案全解析

摘要:無論是 Fomo3D山寨版還是正宗原版都擺脫不了“一輪就涼涼”的宿命,這與其智能合約的設計漏洞不無關系瓢喉。本文從合約安全開發(fā)的角度出發(fā)宁赤,詳細分析了類 Fomo3D 游戲的兩個問題,并提出若干個可能的解決方案栓票。希望能有所幫助决左,歡迎感興趣的朋友加入技術社區(qū)討論。

黑客攻擊之下走贪,類 Fomo3D 游戲一蹶不振

Fomo3D游戲已正式進入第三輪佛猛。截止北京時間 9 月 29 日上午 11 點整,本輪獎池僅累積了 97.8988 Ether坠狡,外加上一輪滾入的 680 Ether继找,獎池總金額不足 800

Ether,相較前兩輪的盛況逃沿,可謂慘不忍睹婴渡。

安比(SECBIT)實驗室曾經(jīng)撰文分析了類 Fomo3D 游戲的衰敗現(xiàn)狀幻锁,先來簡單回顧一下 [1]。


圖一:Fomo3D 玩家參與度與入場資金狀況

上圖展示了「Fomo3D 玩家參與度與入場資金狀況」边臼。紅色代表調(diào)用合約參與游戲的人次哄尔,藍色則代表進入游戲合約的資金量。圖左側(cè)出現(xiàn)數(shù)據(jù)曲線最高峰柠并,對應時間分別是 7 月 20 日和 7 月 21 日究飞。這兩天恰好大量媒體瘋狂報道 Fomo3D 這一現(xiàn)象級游戲。當時眾多玩家跟風入場堂鲤,游戲合約的參與次數(shù)和入場資金均達到了最高峰亿傅,入場資金量超過 40,000 Ether,而參與次數(shù)最高超過 18,000 次瘟栖。高峰過后葵擎,F(xiàn)omo3D 游戲熱度驟降,于 8 月 22 日前后結(jié)束第一輪半哟,并隨即進入第二輪酬滤,但游戲熱度已然無法恢復。

盡管如此寓涨,黑客卻沒有停止攻擊盯串。


圖二:Fomo3D 游戲合約被攻擊狀況

上圖是「Fomo3D 游戲合約被攻擊狀況」,第一輪游戲高峰前后以及第二輪開始后戒良,有黑客瘋狂地利用空投漏洞進行攻擊体捏,攫取高額收益 [2]。而在第一輪臨近結(jié)束糯崎,以及第二輪倒計時快結(jié)束之際几缭,則有黑客瘋狂嘗試阻塞交易攻擊,企圖奪取最終大獎 [3]沃呢。

不僅僅是 Fomo3D 原版游戲年栓,其他眾多的類 Fomo3D 山寨游戲,也成為黑客的攻擊目標薄霜。


Fomo3D類游戲參與形式是用 Ether 購買游戲道具某抓,最后一位購買者獲得最終大獎,平時參與者有一定概率獲得空投獎勵惰瓜,分別從主獎池和副獎池中獲取否副。這兩類獎勵是游戲設計層面對參與者的重要激勵。這一設計鸵熟,目的在于利用“隨機”和“競爭”提升游戲趣味度副编,吸引更多人投入資金參與负甸,從而延長游戲時間流强。

然而事與愿違痹届,由于合約代碼存在漏洞,掌握攻擊技巧的黑客能夠以很高的概率持續(xù)獲得空投獎勵打月,而最終大獎也會被黑客利用特殊技巧奪走队腐。普通參與者在這類游戲中幾乎無法獲得這兩種重要獎勵。因此奏篙,他們僅能幻想在每輪游戲開始后第一時間入場柴淘,然后靠后續(xù)他人的資金回本。但是秘通,游戲最重要的兩個激勵機制已然失效为严,無法持續(xù)吸引新資金,最終形成惡性循環(huán)肺稀。

黑客是如何利用這兩個漏洞的第股?項目方難道就無計可施嗎瘪吏?

空投漏洞分析

先看看“空投獎勵”臂聋。

所有投入游戲的 Ether,會有 1% 數(shù)量進到副獎池凿可》比剩空投的概率從 0% 開始涉馅,每增加一筆不小于 0.1 ETH 銷售訂單,空投概率會增加 0.1%黄虱。同時空投獎勵金額與購買金額也掛鉤稚矿,如果購買 0.1 ~ 1 ETH,就有概率贏得 25% 副獎池獎金捻浦,購買越多則比例越大盐捷。游戲界面會鮮明顯示當前中獎概率和獎池金額。

Fomo3D空投獎勵實現(xiàn)存在兩處問題:

[if !supportLists]1.????????[endif]合約中的“隨機數(shù)”可被預測

[if !supportLists]2.????????[endif]判斷調(diào)用者是否是合約地址的方法有漏洞

空投獎勵依靠智能合約內(nèi)生成的“隨機數(shù)”默勾,在 Fomo3D 源碼中由 airdrop() 函數(shù)控制碉渡。

/**

??? *@dev generates a random

number between 0-99 and checks to see if thats

??? * resulted inan airdrop win

??? *@return do we have a winner?

??? */

function airdrop()

??? private

??? view

??? returns(bool)

{

??? uint256 seed= uint256(keccak256(abi.encodePacked(


??????? (block.timestamp).add

??????? (block.difficulty).add

??????? ((uint256(keccak256(abi.encodePacked(block.coinbase)))) / (now)).add

??????? (block.gaslimit).add

??????? ((uint256(keccak256(abi.encodePacked(msg.sender)))) / (now)).add

??????? (block.number)


??? )));

??? if((seed - ((seed / 1000) * 1000)) < airDropTracker_)

??????? return(true);

??? else

??????? return(false);

}

airdrop() 函數(shù)中的“隨機數(shù)” seed 由各種區(qū)塊信息和交易發(fā)起者地址計算得來滞诺。這顯然十分容易預測 [4]习霹。

為了防止合約自動化攻擊淋叶,F(xiàn)omo3D開發(fā)者還使用 isHuman() 來防止合約賬戶參與Fomo3D 游戲处嫌,試圖以此方法來禁止玩家在合約內(nèi)預測中獎隨機數(shù)凝赛。

/**

??? *@dev prevents contracts from

interacting with fomo3d

??? */

modifier isHuman() {

??? address _addr= msg.sender;

??? uint256_codeLength;


??? assembly{_codeLength := extcodesize(_addr)}

??? require(_codeLength == 0, "sorry

humans only");

??? _;

}

這里犯了另一個常見錯誤。extcodesize 操作符用來獲取目標地址上的代碼大小屡立。對于已部署成功的合約罩句,由于其地址對應著特定代碼,extcodesize 的返回值始終大于 0。因此不少人用此方法來判斷目標地址是否是合約坡脐,F(xiàn)omo3D 甚至以此為依據(jù)來阻止合約調(diào)用特定函數(shù)捅暴。但該判斷方法存在明顯漏洞,在構造新合約的過程中(即合約構造方法里)調(diào)用游戲參與函數(shù)即可繞過該限制演痒。這是因為合約在構造過程中,其地址并未對應任何代碼,extcodesize 的返回值為 0 [5]。

上述的兩個安全問題綜合作用,最終導致黑客可以構造攻擊合約,通過合約參與游戲,隨意預測隨機數(shù),進而極大提高自己的勝率 [2]。

如何修復空投漏洞

那么究竟如何解決Fomo3D 的“空投漏洞”?

黑客能夠成功攻擊,是利用了上文列出的兩個漏洞,構造攻擊合約來預測游戲合約中的“隨機數(shù)”梯捕。因此,我們只需完成以下兩件事之一窝撵,使攻擊所需的必要條件不滿足即可:

[if !supportLists]1.????????[endif]防止智能合約中的“隨機數(shù)”預測

[if !supportLists]2.????????[endif]采取更安全的方式判斷調(diào)用者是否是合約

方案一:防范智能合約中的“隨機數(shù)”預測

讓我們先解決“隨機數(shù)”預測的問題碌奉。

智能合約環(huán)境內(nèi)“隨機數(shù)”容易被預測的原因在于婉徘,“隨機數(shù)”產(chǎn)生所依賴的“隨機源”可以被任何人輕易獲得。攻擊者可以構造一個攻擊合約,在相同環(huán)境內(nèi)執(zhí)行“隨機數(shù)”計算公式墙贱,即可得到需要的“隨機數(shù)”热芹,并以之作為下一步行動的判斷依據(jù)。

智能合約內(nèi)幾乎一切可用變量都是公開的魁衙,并且“隨機數(shù)”計算公式需要確保所有節(jié)點執(zhí)行結(jié)果都一致报腔。因此,很難找到十分簡潔的方法來產(chǎn)生無法被預測的“隨機數(shù)”剖淀。

但仍有一些稍復雜但可行的解決方案纯蛾。如開發(fā)者可通過先提交再披露(commit/reveal)、或延遲若干個區(qū)塊開獎纵隔。此外翻诉,還有一些引入外部預言機(Oracle)的方案炮姨,如Oraclize 和 BTCRelay

[6]。

安比(SECBIT)實驗室結(jié)合 Fomo3D 游戲機制碰煌,介紹一種利用當前/未來區(qū)塊的哈希值來防止“隨機數(shù)”被預測的方案 [7]舒岸。

以太坊智能合約中可以通過 block.blockhash() 來獲取特定區(qū)塊的哈希值。該函數(shù)接受參數(shù)為區(qū)塊高度芦圾,可取范圍為除當前區(qū)塊外的最近 256 個區(qū)塊蛾派。當傳入其他值時,該函數(shù)均返回 0个少。


常見不安全的“隨機數(shù)”計算方法洪乍,會讀取當前塊的前一個塊的哈希 block.blockhash(block.number-1) 作為隨機源。而在合約內(nèi)執(zhí)行 block.blockhash(block.number) 返回值為 0稍算。我們無法在合約內(nèi)獲得當前區(qū)塊的哈希典尾,這是因為礦工打包并執(zhí)行交易時役拴,當前區(qū)塊哈希尚未被算出糊探。因此,我們可以認為當前區(qū)塊哈希是未來的河闰,無法預測科平。

我們可以在用戶首次購買道具參與游戲時,記錄其地址姜性、當前區(qū)塊高度 N 至一個數(shù)組中瞪慧,最終拿到一個唯一的 id(如下面 _purchase() 函數(shù)所示)。

function _purchase(address

user) internal {

??? Purchase memoryp= Purchase({

??????? user: user,

??????? commit: uint64(block.number),

??????? randomness: 0

??? });

??? uint id= purchases.push(p) - 1;

??? emitKeysPurchased(id, user, packCount);

}

在接下來的 255 個區(qū)塊內(nèi)部念,用戶可以用該 id 再次參與游戲弃酌,此時高度為 N 的區(qū)塊哈希可正常獲得儡炼,以此來生成“隨機數(shù)”妓湘,判斷用戶是否中獎(如下面 _airdrop() 函數(shù)所示)。

function _airdrop(uint

id) internal returns(bool) {

??? Purchasestorage p=purchases[id];

??? require(p.randomness == 0);

??? require(block.number - 256 < p.commit);

??? require(uint64(block.number) != p.commit);

??? require(p.user == msg.sender);

??? bytes32 bhash= blockhash(p.commit);

??? uint seed= uint(keccak256(abi.encodePacked(bhash, p.user, id)));

??? p.randomness = seed;

??? if((seed - ((seed / 1000) * 1000)) < airDropTracker_)

??????? return(true);

??? else

??????? return(false);

}

255個區(qū)塊之后乌询,用戶參與游戲時的區(qū)塊哈希在合約內(nèi)無法正常獲得榜贴。因此,務必要限制用戶在一定時間范圍內(nèi)查詢是否中獎妹田,并及時參與游戲領取獎勵唬党。當然,為了游戲體驗鬼佣,如果用戶錯失領獎驶拱,也可以參照上面的原理再給他一次機會重新抽獎。結(jié)合游戲規(guī)則晶衷,這里仍有一些技術細節(jié)需注意屯烦,歡迎添加小安同學微信(secbit_xiaoanbi)坷随,加入到「SECBIT 智能合約安全技術群」參與討論。

這種方法也用在知名的區(qū)塊鏈卡牌游戲 Gods Unchained 中驻龟,用來控制用戶所購卡牌稀有程度温眉。當然我們也可以用當前高度后指定數(shù)量(如五個)的區(qū)塊哈希來作為隨機源,原理是一樣的 [8]翁狐。

方案二:防止合約自動化攻擊

另一個問題类溢,我們?nèi)绾闻袛嗾{(diào)用者是否是合約地址?

有一個簡便但是有效的方法露懒。

modifier isHuman() {

??? require(tx.origin == msg.sender, "sorry humans only");

??? _;

}

以太坊安全開發(fā)最佳實踐中推薦盡量不要使用 tx.origin闯冷,因為很多人將 tx.orign 和 msg.sender 混淆。tx.orign 代表的是一筆交易的發(fā)起者懈词,而 msg.sender 代表每一次合約調(diào)用(call)的發(fā)起者蛇耀。

A -> B -> C

如普通賬戶 A 調(diào)用合約 B,合約 B 再調(diào)用合約 C坎弯。在合約 C 內(nèi)纺涤,msg.sender 是合約 B,而 tx.origin 是賬戶 A抠忘。msg.sender 可以是合約地址撩炊,但 tx.origin 永遠不會是合約。因此崎脉,上面的方法可以有效防止合約調(diào)用合約拧咳。

阻塞交易”攻擊分析

再看看“最終大獎”。

Fomo3D類游戲存在倒計時囚灼,在每輪游戲結(jié)束前最后一個購買道具的參與者獲勝骆膝,可以拿走主獎池中近半的資金。因此眾多參與者會在臨近結(jié)束時灶体,發(fā)起購買交易參與游戲阅签,如果能幸運地在最后一刻被礦工打包入塊,即可獲勝赃春。

普通人在游戲快結(jié)束時都是類似的策略:緊盯著時間愉择,調(diào)高 Gas 費用,發(fā)起參與游戲的交易织中,然后閉上眼睛祈禱锥涕,希望自己能是最后一個參與者。然而狭吼,采用這種方法幾乎不可能中獎层坠。

據(jù)安比(SECBIT)實驗室分析,Fomo3D 前兩輪獲獎者使用手法如出一轍刁笙,均在游戲快結(jié)束時破花,發(fā)起攻擊交易谦趣。

獲獎者(黑客)通過提前部署好的攻擊合約,在合約內(nèi)調(diào)用getCurrentRoundInfo() 接口查詢游戲信息座每,重點關注剩余時間最后一位購買者地址前鹅。當游戲剩余時間達到一個閾值,并且最后一個購買者是自己時峭梳,則通過 assert()讓整個交易失敗舰绘,并耗光所有 Gas;當剩余時間很長或最后一個購買者不是自己時葱椭,則不做任何操作捂寿,僅消耗很少的 Gas。


獲獎者(黑客)就是利用這種方法孵运,發(fā)起大量類似的可變神秘交易:在自己極有可能成為中獎者時秦陋,利用這些高額手續(xù)費的神秘交易,吸引礦池優(yōu)先打包治笨,占滿后續(xù)區(qū)塊驳概,從而使得其他玩家購買 key 的交易無法被正常打包,最終加速游戲結(jié)束大磺,并極大地提高自己的中獎概率抡句。

普通玩家只能在游戲快結(jié)束時手動調(diào)高 Gas 費用參與游戲探膊,也有人試圖使用自動腳本在臨近游戲結(jié)束時調(diào)高 Gas Price 發(fā)起參與游戲交易杠愧。與這些盲目的方法相比,黑客的攻擊手法顯然高明許多逞壁。

如何防范“阻塞交易”攻擊

其實流济,這一問題不止會威脅類Fomo3D 游戲。所有采用類似機制腌闯,即需要玩家搶在某個時間范圍內(nèi)完成某種競爭操作的智能合約绳瘟,都會受此威脅。只要游戲獎勵足夠豐厚姿骏,攻擊回報遠大于投入糖声,就會有人利用前文提到的方法來破壞游戲公平性。

方案一:提高攻擊所需成本

要杜絕這一問題分瘦,安比(SECBIT)實驗室建議游戲開發(fā)者蘸泻,從游戲機制入手,切斷游戲最終勝利(獲得某個巨額大獎)和倒計時結(jié)束(最后一個交易被打包)之間的必然聯(lián)系嘲玫,從而使黑客的攻擊獲利概率攻擊意愿都降到最低悦施。

例如,我們可以修改游戲規(guī)則為:每輪游戲結(jié)束前最后一個購買道具的參與者有概率獲得最終大獎去团,并將此概率調(diào)整為一個較低的值抡诞,如 5 %穷蛹。在倒計時結(jié)束但大獎因概率原因沒有正常開出的情況下,合約自動給游戲續(xù)一定時間昼汗。這樣一來肴熏,前面提到的堵塞區(qū)塊、阻止別人參與游戲的技巧顷窒,無法確保攻擊者一定能獲得最終大獎扮超。而黑客持續(xù)進行阻塞交易攻擊需耗費大量 Gas 費用,成本會很高蹋肮,最終會選擇放棄攻擊出刷。

function buyCore(...)

??? private

{

??? ...

??? // check to see if end round needs to be ran

??? if (_now > round_[_rID].end && round_[_rID].ended == false)

??? {

??????? // check to see whether or not this round should end

??????? if shouldRndEnd(lastCommitId) (

??????????? // end the round (distributes pot) & start new round

???????????round_[_rID].ended = true;

??????????? _eventData_= endRound(_eventData_);

??????????? ...

??????? )else {

??????????? ...


updateTimer(_keys, _rID);

??????????? ...

??????? }

??? }

??? ...

}

上面為示例代碼,其中 shouldRndEnd() 函數(shù)用來在倒計時結(jié)束后控制中獎概率坯辩,決定這一輪游戲是否真的結(jié)束馁龟。這里的概率同樣依賴“隨機數(shù)”不能被預測,具體實現(xiàn)原理與前文提到的空投概率控制代碼類似漆魔。

方案二:禁止合約調(diào)用游戲信息查詢接口

Fomo3D最終獲勝者可以輕易攻擊成功的另一個原因是坷檩,游戲合約開放了一個完整的游戲進度信息查詢接口,并且普通賬戶和合約賬戶都可以任意調(diào)用查詢改抡。這方便了黑客在攻擊合約內(nèi)實時查詢游戲狀態(tài)矢炼,進而執(zhí)行不同策略來降低攻擊成本和提高命中率。

modifier isHuman() {

??? require(tx.origin == msg.sender, "sorry humans only");

??? _;

}

function getCurrentRoundInfo()

??? isHuman()

??? public

??? view

??? returns(...)

{

??? ...

}

因此阿纤,針對 Fomo3D 游戲句灌,還有另一個簡易的防范方法。對 getCurrentRoundInfo() 函數(shù)使用前文提到的安全版的 isHuman() 校驗來保護欠拾,就可以有效避免合約自動化攻擊胰锌。

總結(jié)

有安全和公平性問題的Fomo3D 原版以及山寨版,僅是“黑客”掘金的對象藐窄,注定無法吸引更多普通玩家參加资昧。隨著一輪一輪的進行,玩家會逐漸流失荆忍,這些游戲會進一步?jīng)]落格带。

安比(SECBIT)實驗室呼吁后來者吸取教訓,不要再原封不動地復制代碼刹枉,不要試圖僅靠“運營”來吸引新人入場叽唱。作出一些小小的改變,智能合約的安全性會得到很大的提升嘶卧,去中心化游戲才能走得更遠尔觉。

參考文獻

[1] Fomo3D二輪大獎開出,黑客獲獎芥吟,機制漏洞成游戲沒落主因, https://zhuanlan.zhihu.com/p/45330743, 2018/09/25

[2] 智能合約史上最大規(guī)模攻擊手法曝光侦铜,盤點黑客團伙作案細節(jié), https://zhuanlan.zhihu.com/p/42318584, 2018/08/17

[3] Fomo3D 千萬大獎獲得者“特殊攻擊技巧”最全揭露, https://zhuanlan.zhihu.com/p/42742004, 2018/08/23

[4] How to PWN FoMo3D, a beginners guide, https://www.reddit.com/r/ethereum/comments/916xni/how_to_pwn_fomo3d_a_beginners_guide, 2018/07/23

[5] Using EVM assembly to get the address' code size, https://ethereum.stackexchange.com/questions/14015/using-evm-assembly-to-get-the-address-code-size, 2017/04/07

[6] Predicting Random Numbers in Ethereum Smart Contracts, https://blog.positive.com/predicting-random-numbers-in-ethereum-smart-contracts-e5358c6b8620, 2018/02/01

[7] Random Number Generation on Winsome.io?—?Future Blockhashes, https://blog.winsome.io/random-number-generation-on-winsome-io-future-blockhashes-fe44b1c61d35, 2017/05/07

[8] Gods Unchained, https://etherscan.io/address/0x482cf6a9d6b23452c81d4d0f0f139c1414963f89#code, 2018/07/16

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末专甩,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子钉稍,更是在濱河造成了極大的恐慌涤躲,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,539評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件贡未,死亡現(xiàn)場離奇詭異种樱,居然都是意外死亡,警方通過查閱死者的電腦和手機俊卤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評論 3 396
  • 文/潘曉璐 我一進店門嫩挤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人消恍,你說我怎么就攤上這事岂昭。” “怎么了狠怨?”我有些...
    開封第一講書人閱讀 165,871評論 0 356
  • 文/不壞的土叔 我叫張陵约啊,是天一觀的道長。 經(jīng)常有香客問我佣赖,道長恰矩,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,963評論 1 295
  • 正文 為了忘掉前任憎蛤,我火速辦了婚禮外傅,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘蹂午。我一直安慰自己栏豺,他們只是感情好彬碱,可當我...
    茶點故事閱讀 67,984評論 6 393
  • 文/花漫 我一把揭開白布豆胸。 她就那樣靜靜地躺著,像睡著了一般巷疼。 火紅的嫁衣襯著肌膚如雪晚胡。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,763評論 1 307
  • 那天嚼沿,我揣著相機與錄音估盘,去河邊找鬼。 笑死骡尽,一個胖子當著我的面吹牛遣妥,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播攀细,決...
    沈念sama閱讀 40,468評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼箫踩,長吁一口氣:“原來是場噩夢啊……” “哼爱态!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起境钟,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤锦担,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后慨削,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體洞渔,經(jīng)...
    沈念sama閱讀 45,850評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,002評論 3 338
  • 正文 我和宋清朗相戀三年缚态,在試婚紗的時候發(fā)現(xiàn)自己被綠了磁椒。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,144評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡玫芦,死狀恐怖衷快,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情姨俩,我是刑警寧澤蘸拔,帶...
    沈念sama閱讀 35,823評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站环葵,受9級特大地震影響调窍,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜张遭,卻給世界環(huán)境...
    茶點故事閱讀 41,483評論 3 331
  • 文/蒙蒙 一邓萨、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧菊卷,春花似錦缔恳、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,026評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至扑眉,卻和暖如春纸泄,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背腰素。 一陣腳步聲響...
    開封第一講書人閱讀 33,150評論 1 272
  • 我被黑心中介騙來泰國打工聘裁, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人弓千。 一個月前我還...
    沈念sama閱讀 48,415評論 3 373
  • 正文 我出身青樓衡便,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子镣陕,可洞房花燭夜當晚...
    茶點故事閱讀 45,092評論 2 355

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

  • 遇到奇葩姐姐不要氣征唬,要淡定。正好宿舍的逗比美麗姐超級搞笑
    雯婷_3c5e閱讀 110評論 0 0
  • “希望邁過這道坎后茁彭,那些心有不甘卻力所不及的日子也能夠變得有意義总寒。” 好久沒寫長文了嘿 理肺。 會考這兩周發(fā)生了人生變...
    木生皮皮閱讀 857評論 1 0
  • 快樂摄闸,無疑是人人夢寐以求的,那么怎樣才能得到快樂妹萨? 我也時常自問年枕,我快樂嗎?如果不快樂乎完,是為什么熏兄?是真的沒有什么事...
    魚1967閱讀 561評論 4 2