Skip to content

Commit 1636d94

Browse files
committed
first commit
0 parents  commit 1636d94

7 files changed

+315
-0
lines changed

Hosts.txt

Whitespace-only changes.

Info.csv

Whitespace-only changes.

README.md

+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
2+
<h1 align="center">
3+
<br>
4+
<img src="https://user-images.githubusercontent.com/59805766/222643217-ea37efe1-fd1a-42fe-9081-ce9609cffe70.png" alt="CenQuest"></a>
5+
</h1>
6+
<h4 align="center">A Python script using the Censys API to search for internet-facing hosts based on custom queries</h4>
7+
8+
<p align="center">
9+
<a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/license-MIT-_red.svg"></a>
10+
<a href="https://github.com/ReverseTEN/CenQuest/issues"><img src="https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat"></a>
11+
</p>
12+
13+
<p align="center">
14+
15+
16+
17+
# CenQuest
18+
19+
CenQuest is a Python script that uses the Censys API to search for internet-facing hosts based on custom search queries. It retrieves the IP addresses and port numbers of all matching hosts and stores the results in a file called `Hosts.txt`.
20+
21+
In addition,CenQuest includes a **resume search feature that enables you to pick up where you left off without having to restart the search**. This feature utilizes a CSV file called Info.csv, which keeps track of previously executed search queries and the number of pages retrieved for each query.
22+
23+
## Requirements
24+
25+
To run the script, you need to have the following:
26+
27+
- Python 3.x
28+
- A Censys account with API credentials
29+
30+
Set up your Censys API credentials by creating a file named `config.ini` in the same directory as the script, with the following format:
31+
32+
```
33+
34+
[Censys Api Config]
35+
36+
api=YOUR_CENSYS_UID
37+
secret=YOUR_CENSYS_SECRET
38+
39+
```
40+
41+
42+
## Usage
43+
To use the script, you need to provide a search query and the number of pages you want to retrieve. Here's an example command:
44+
45+
```bash
46+
git clone https://github.com/ReverseTEN/CenQuest.git
47+
cd CenQuest
48+
python cenquest.py [-h] -q QUERY -p PAGES
49+
50+
```
51+
52+
The following arguments are available:
53+
54+
- -h, --help: show the help message and exit.
55+
- -q QUERY, --query QUERY: search query to be executed.
56+
- -p PAGES, --pages PAGES: number of pages to retrieve.
57+
58+
### Example:
59+
60+
```bash
61+
62+
python3 cenquest.py -q "apache" -p 5
63+
64+
```
65+
66+
This will search for hosts with the word "apache" in their banners and retrieve the first 5 pages of results. The results will be written to the `Hosts.txt` file in the same directory as the script.
67+
68+
69+
## Resume Search
70+
71+
CenQuest uses a CSV file called `Info.csv` to keep track of which search queries have already been executed and how many pages of results were obtained for each query. This allows the script to resume a search from where it left off, in case the script is interrupted or terminated prematurely.
72+
73+
74+
## Disclaimer
75+
This script is for educational purposes only. Use it at your own risk.

cenquest.py

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import argparse
2+
import censys
3+
4+
def banner():
5+
print(("""%s
6+
____ ___ _
7+
/ ___| ___ _ __ / _ \ _ _ ___ ___ | |_
8+
| | / _ \ | '_ \ | | | | | | | | / _ \ / __| | __|
9+
| |___ | __/ | | | | | |_| | | |_| | | __/ \__ \ | |_
10+
\____| \___| |_| |_| \__\_\ \__,_| \___| |___/ \__|
11+
12+
%s%s# Coded By ReverseTEN - http://github.com/ReverseTEN%s
13+
""" % ('\033[91m', '\033[0m', '\033[93m', '\033[0m')))
14+
15+
16+
def parse_args():
17+
parser = argparse.ArgumentParser(
18+
description='Search for information using Censys',
19+
epilog='Example usage: python my_script.py -q "80.http.get.headers.server: Apache" -p 3'
20+
)
21+
parser.add_argument('-q', '--query', help='search query', type=str , required=True)
22+
parser.add_argument('-p','--pages',help='number of pages to retrieve',type=int,required=True)
23+
24+
args = parser.parse_args()
25+
return args
26+
27+
28+
if __name__=='__main__':
29+
banner()
30+
args = parse_args()
31+
censys.query=args.query
32+
censys.PageNm=args.pages
33+
censys.run()

censys.py

+192
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
import requests
2+
import csv
3+
import config
4+
5+
6+
Url = 'https://search.censys.io/api/v2'
7+
ch = config.config()
8+
api=ch[0]
9+
secret=ch[1]
10+
query=''
11+
PageNm=int
12+
CheckList=[]
13+
14+
def getIps(ips):
15+
with open('Hosts.txt','a') as f:
16+
f.write(f'{ips}\n')
17+
f.close
18+
19+
20+
def LastActivity(PageNUM,LastPage,Next='N'):
21+
data=[query,PageNUM,LastPage,Next]
22+
with open('Info.csv','a') as csvfile:
23+
writer=csv.writer(csvfile)
24+
writer.writerow(data)
25+
csvfile.close()
26+
27+
28+
29+
30+
def CheckInfo():
31+
32+
with open ('Info.csv','r') as csvf :
33+
try:
34+
reader = csv.reader(csvf)
35+
for row in reader:
36+
if query in list(row):
37+
CheckList.append(row)
38+
lastrow=list.pop(CheckList)
39+
if lastrow[3] == "Y":
40+
print(f"[!] The last page of this query ({lastrow[0]}) is {int(lastrow[1])}. The next page does not exist!")
41+
42+
exit()
43+
x = input(f"[!] This query ({lastrow[0]}) has already been used for {lastrow[1]} pages. Do you want to start from page {int(lastrow[1])+1} onwards? (y/n): ").upper()
44+
45+
if x== 'Y':
46+
return int(lastrow[1]) , lastrow[2]
47+
elif x=='N':
48+
return None
49+
if x!= 'Y' or 'N':
50+
exit()
51+
csvf.close()
52+
except IndexError :
53+
return None
54+
55+
def request():
56+
57+
params = {'q':query,'per_page':0,'virtual_hosts':'EXCLUDE'}
58+
res = requests.post(Url+'/hosts/search',json=params,auth=(api,secret))
59+
payload = res.json()
60+
CheckError(payload['code'])
61+
if payload['status']=='OK':
62+
result = payload["result"]
63+
page=result["links"]["next"]
64+
return page
65+
66+
67+
68+
def getcursor1(pageNum):
69+
cn =1
70+
has_next_key = False
71+
next = ""
72+
params2 = {'cursor':request(),'q':query,'per_page':27,'virtual_hosts':'EXCLUDE'}
73+
res2 = requests.post(Url+'/hosts/search',json=params2,auth=(api,secret))
74+
payload2 = res2.json()
75+
if payload2['code'] ==200:
76+
result = payload2["result"]['hits']
77+
for reader in result:
78+
ip =reader['ip']
79+
services = reader['services']
80+
for port in services:
81+
if port['service_name'] == "HTTP":
82+
print('%s:%s'%(ip,port['port']))
83+
getIps('%s:%s'%(ip,port['port']))
84+
if 'next' in payload2['result']['links']:
85+
has_next_key = True
86+
next=payload2['result']['links']['next']
87+
88+
89+
else:
90+
CheckError(payload2['code'])
91+
92+
while has_next_key and cn !=pageNum :
93+
94+
95+
params3 = {'cursor':next,'q':query,'per_page':25,'virtual_hosts':'EXCLUDE'}
96+
97+
req =requests.post(Url+'/hosts/search',json=params3,auth=(api,secret))
98+
payload3 = req.json()
99+
CheckError(payload3['code'])
100+
result2 = payload3["result"]['hits']
101+
for reader2 in result2:
102+
ip =reader2['ip']
103+
services = reader2['services']
104+
for port in services:
105+
if port['service_name'] == "HTTP":
106+
print('%s:%s'%(ip,port['port']))
107+
getIps('%s:%s'%(ip,port['port']))
108+
if 'next' in payload3['result']['links']:
109+
next=payload3['result']['links']['next']
110+
cn +=1
111+
if cn ==pageNum:
112+
LastActivity(cn,next)
113+
if payload3['result']['links']['next'] == '':
114+
print('The next page does not exist')
115+
LastActivity(cn,next,'Y')
116+
exit()
117+
118+
119+
def getcursor2(LastPage,cursor,numbberOfpages):
120+
cn =LastPage
121+
flag= cn +numbberOfpages
122+
has_next_key = False
123+
next = ""
124+
params2 = {'cursor':cursor,'q':query,'per_page':25,'virtual_hosts':'EXCLUDE'}
125+
res2 = requests.post(Url+'/hosts/search',json=params2,auth=(api,secret))
126+
payload2 = res2.json()
127+
if payload2['code'] ==200:
128+
result = payload2["result"]['hits']
129+
for reader in result:
130+
ip =reader['ip']
131+
services = reader['services']
132+
for port in services:
133+
if port['service_name'] == "HTTP":
134+
print('%s:%s'%(ip,port['port']))
135+
getIps('%s:%s'%(ip,port['port']))
136+
if 'next' in payload2['result']['links']:
137+
has_next_key = True
138+
next=payload2['result']['links']['next']
139+
140+
141+
else:
142+
CheckError(payload2['code'])
143+
144+
while has_next_key and cn !=flag :
145+
params3 = {'cursor':next,'q':query,'per_page':25,'virtual_hosts':'EXCLUDE'}
146+
147+
req =requests.post(Url+'/hosts/search',json=params3,auth=(api,secret))
148+
payload3 = req.json()
149+
CheckError(payload3['code'])
150+
result2 = payload3["result"]['hits']
151+
for reader2 in result2:
152+
ip =reader2['ip']
153+
services = reader2['services']
154+
for port in services:
155+
if port['service_name'] == "HTTP":
156+
print('%s:%s'%(ip,port['port']))
157+
getIps('%s:%s'%(ip,port['port']))
158+
if 'next' in payload3['result']['links']:
159+
next=payload3['result']['links']['next']
160+
cn +=1
161+
if cn ==flag:
162+
LastActivity(cn,next)
163+
if payload3['result']['links']['next'] == '':
164+
print('The next page does not exist')
165+
LastActivity(cn,next,'Y')
166+
exit()
167+
168+
169+
def CheckError(Code):
170+
if Code==400:
171+
print('[!] Invalid search. Your query could not be parsed')
172+
elif Code==401:
173+
print('[!] You must authenticate with a valid API ID and secret.')
174+
elif Code==403:
175+
print('[!] Access was denied for this resource or feature.')
176+
elif Code==422:
177+
print('[!] Invalid cursor')
178+
elif Code==403:
179+
print('[!] Access was denied for this resource or feature.')
180+
elif Code==429:
181+
print('[!] You have used your full quota for this billing period')
182+
183+
184+
def run():
185+
checker= CheckInfo()
186+
if checker ==None:
187+
getcursor1(PageNm)
188+
print('[+] Check Hosts.txt')
189+
elif checker != None:
190+
getcursor2(checker[0],checker[1],PageNm)
191+
print('[+] Check Hosts.txt')
192+

config.ini

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
[Censys Api Config]
2+
3+
api=
4+
secret=

config.py

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import configparser
2+
3+
def config():
4+
5+
config= configparser.ConfigParser()
6+
config.read('config.ini')
7+
if config['Censys Api Config']['api'] =='' or config['Censys Api Config']['secret'] == '':
8+
print("[!] Enter your Api and Secret In Config.ini")
9+
exit()
10+
else:
11+
return config['Censys Api Config']['api'] , config['Censys Api Config']['secret']

0 commit comments

Comments
 (0)