Skip to content

Commit 4d7c334

Browse files
committed
Adapt censys to new platform search
Use the new censys sdk for better stability in API updates. As censys now returns multiple endpoints per search, we now iterate over every endpoint and create a new result. This also changes the way ip are saved in the raw response, as we dont have the problem anymore, as we have one ip per endpoint.
1 parent 6a159bf commit 4d7c334

File tree

9 files changed

+72
-165
lines changed

9 files changed

+72
-165
lines changed

.github/workflows/provider-integration.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ jobs:
2121
- name: Integration Tests
2222
env:
2323
GH_ACTION: true
24-
CENSYS_API_KEY: ${{secrets.CENSYS_API_SECRET}}
24+
CENSYS_API_KEY: ${{secrets.CENSYS_ORGANIZATION_ID}}
2525
FOFA_API_KEY: ${{secrets.FOFA_KEY}}
2626
SHODAN_API_KEY: ${{secrets.SHODAN_API_KEY}}
2727
ZOOMEYE_API_KEY: ${{secrets.ZOOMEYE_API_KEY}}

README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -135,8 +135,8 @@ shodan:
135135
- SHODAN_API_KEY_1
136136
- SHODAN_API_KEY_2
137137
censys:
138-
- CENSYS_API_ID_1:CENSYS_API_SECRET_1
139-
- CENSYS_API_ID_2:CENSYS_API_SECRET_2
138+
- CENSYS_API_TOKEN_1:CENSYS_ORGANIZATION_ID_1
139+
- CENSYS_API_TOKEN_2:CENSYS_ORGANIZATION_ID_2
140140
fofa:
141141
- FOFA_EMAIL_1:FOFA_KEY_1
142142
- FOFA_EMAIL_2:FOFA_KEY_2
@@ -178,8 +178,8 @@ alternatively you can also set the API key as environment variable in your bash
178178
179179
```yaml
180180
export SHODAN_API_KEY=xxx
181-
export CENSYS_API_ID=xxx
182-
export CENSYS_API_SECRET=xxx
181+
export CENSYS_API_TOKEN=xxx
182+
export CENSYS_ORGANIZATION_ID=xxx
183183
export FOFA_EMAIL=xxx
184184
export FOFA_KEY=xxx
185185
export QUAKE_TOKEN=xxx
@@ -195,7 +195,7 @@ export ONYPHE_API_KEY=xxx
195195
export DRIFTNET_API_KEY=xxx
196196
```
197197

198-
Required API keys can be obtained by signing up on following platform [Shodan](https://account.shodan.io/register), [Censys](https://censys.io/register), [Fofa](https://fofa.info/toLogin), [Quake](https://quake.360.net/quake/#/index), [Hunter](https://user.skyeye.qianxin.com/user/register?next=https%3A//hunter.qianxin.com/api/uLogin&fromLogin=1), ZoomEye [china](https://api.zoomeye.org) - [worldwide](https://api.zoomeye.hk), [Netlas](https://app.netlas.io/registration/), [CriminalIP](https://www.criminalip.io/register), [Publicwww](https://publicwww.com/profile/signup.html), Google [[1]](https://developers.google.com/custom-search/v1/introduction#identify_your_application_to_google_with_api_key),[[2]](https://programmablesearchengine.google.com/controlpanel/create), [Onyphe](https://search.onyphe.io/signup) and [Driftnet](https://driftnet.io/auth?state=signup).
198+
Required API keys can be obtained by signing up on following platform [Shodan](https://account.shodan.io/register), [Censys](https://docs.censys.com/reference/get-started), [Fofa](https://fofa.info/toLogin), [Quake](https://quake.360.net/quake/#/index), [Hunter](https://user.skyeye.qianxin.com/user/register?next=https%3A//hunter.qianxin.com/api/uLogin&fromLogin=1), ZoomEye [china](https://api.zoomeye.org) - [worldwide](https://api.zoomeye.hk), [Netlas](https://app.netlas.io/registration/), [CriminalIP](https://www.criminalip.io/register), [Publicwww](https://publicwww.com/profile/signup.html), Google [[1]](https://developers.google.com/custom-search/v1/introduction#identify_your_application_to_google_with_api_key),[[2]](https://programmablesearchengine.google.com/controlpanel/create), [Onyphe](https://search.onyphe.io/signup) and [Driftnet](https://driftnet.io/auth?state=signup).
199199

200200
### ZoomEye API
201201

go.mod

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ module github.com/projectdiscovery/uncover
33
go 1.23.0
44

55
require (
6+
github.com/censys/censys-sdk-go v0.19.1
67
github.com/hashicorp/golang-lru v0.5.4
78
github.com/julienschmidt/httprouter v1.3.0
89
github.com/logrusorgru/aurora v2.0.3+incompatible
@@ -63,6 +64,7 @@ require (
6364
github.com/dlclark/regexp2 v1.11.4 // indirect
6465
github.com/docker/go-units v0.5.0 // indirect
6566
github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 // indirect
67+
github.com/ericlagergren/decimal v0.0.0-20221120152707-495c53812d05 // indirect
6668
github.com/fatih/color v1.15.0 // indirect
6769
github.com/gaissmai/bart v0.17.8 // indirect
6870
github.com/go-ole/go-ole v1.2.6 // indirect

go.sum

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ github.com/bits-and-blooms/bitset v1.13.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6
3434
github.com/bits-and-blooms/bloom/v3 v3.5.0 h1:AKDvi1V3xJCmSR6QhcBfHbCN4Vf8FfxeWkMNQfmAGhY=
3535
github.com/bits-and-blooms/bloom/v3 v3.5.0/go.mod h1:Y8vrn7nk1tPIlmLtW2ZPV+W7StdVMor6bC1xgpjMZFs=
3636
github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
37+
github.com/censys/censys-sdk-go v0.19.1 h1:CG8rQKgwrKuoICd3oU0uddALMfJnboeMkDg/e74HYyc=
38+
github.com/censys/censys-sdk-go v0.19.1/go.mod h1:DgPz5NgL+EfoueXLPG9UG1e7hS0OhtlywgpkIuu3ZRE=
3739
github.com/charmbracelet/glamour v0.8.0 h1:tPrjL3aRcQbn++7t18wOpgLyl8wrOHUEDS7IZ68QtZs=
3840
github.com/charmbracelet/glamour v0.8.0/go.mod h1:ViRgmKkf3u5S7uakt2czJ272WSg2ZenlYEZXT2x7Bjw=
3941
github.com/charmbracelet/lipgloss v0.13.0 h1:4X3PPeoWEDCMvzDvGmTajSyYPcZM4+y8sCA/SsA3cjw=
@@ -62,6 +64,8 @@ github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDD
6264
github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 h1:iFaUwBSo5Svw6L7HYpRu/0lE3e0BaElwnNO1qkNQxBY=
6365
github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5/go.mod h1:qssHWj60/X5sZFNxpG4HBPDHVqxNm4DfnCKgrbZOT+s=
6466
github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY=
67+
github.com/ericlagergren/decimal v0.0.0-20221120152707-495c53812d05 h1:S92OBrGuLLZsyM5ybUzgc/mPjIYk2AZqufieooe98uw=
68+
github.com/ericlagergren/decimal v0.0.0-20221120152707-495c53812d05/go.mod h1:M9R1FoZ3y//hwwnJtO51ypFGwm8ZfpxPT/ZLtO1mcgQ=
6569
github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
6670
github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
6771
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=

sources/agent/censys/censys.go

Lines changed: 56 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
package censys
22

33
import (
4+
"context"
45
"encoding/json"
5-
"fmt"
6-
"net/http"
7-
"net/url"
86

97
"errors"
108

9+
censyssdkgo "github.com/censys/censys-sdk-go"
10+
"github.com/censys/censys-sdk-go/models/components"
11+
"github.com/censys/censys-sdk-go/models/operations"
1112
"github.com/projectdiscovery/uncover/sources"
1213
)
1314

1415
const (
15-
URL = "https://search.censys.io/api/v2/hosts/search?q=%s&per_page=%d&virtual_hosts=INCLUDE"
1616
MaxPerPage = 100
1717
)
1818

@@ -23,9 +23,10 @@ func (agent *Agent) Name() string {
2323
}
2424

2525
func (agent *Agent) Query(session *sources.Session, query *sources.Query) (chan sources.Result, error) {
26-
if session.Keys.CensysToken == "" || session.Keys.CensysSecret == "" {
26+
if session.Keys.CensysToken == "" || session.Keys.CensysOrgId == "" {
2727
return nil, errors.New("empty censys keys")
2828
}
29+
2930
results := make(chan sources.Result)
3031

3132
go func() {
@@ -39,76 +40,82 @@ func (agent *Agent) Query(session *sources.Session, query *sources.Query) (chan
3940
PerPage: MaxPerPage,
4041
Cursor: nextCursor,
4142
}
42-
censysResponse := agent.query(URL, session, censysRequest, results)
43+
censysResponse := agent.query(session, censysRequest, results)
4344
if censysResponse == nil {
4445
break
4546
}
46-
nextCursor = censysResponse.Results.Links.Next
47-
if nextCursor == "" || numberOfResults > query.Limit || len(censysResponse.Results.Hits) == 0 {
47+
hasNextCursor := false
48+
if censysResponse.ResponseEnvelopeSearchQueryResponse.Result.NextPageToken != nil {
49+
hasNextCursor = true
50+
}
51+
52+
if hasNextCursor || numberOfResults > query.Limit || len(censysResponse.ResponseEnvelopeSearchQueryResponse.Result.Hits) == 0 {
4853
break
4954
}
50-
numberOfResults += len(censysResponse.Results.Hits)
55+
nextCursor = censysResponse.ResponseEnvelopeSearchQueryResponse.Result.NextPageToken
56+
numberOfResults += len(censysResponse.ResponseEnvelopeSearchQueryResponse.Result.Hits)
5157
}
5258
}()
5359

5460
return results, nil
5561
}
5662

57-
func (agent *Agent) queryURL(session *sources.Session, URL string, censysRequest *CensysRequest) (*http.Response, error) {
58-
censysURL := fmt.Sprintf(URL, url.QueryEscape(censysRequest.Query), censysRequest.PerPage)
59-
if censysRequest.Cursor != "" {
60-
censysURL += fmt.Sprintf("&cursor=%s", censysRequest.Cursor)
61-
}
62-
request, err := sources.NewHTTPRequest(http.MethodGet, censysURL, nil)
63-
if err != nil {
64-
return nil, err
65-
}
66-
request.Header.Set("Accept", "application/json")
67-
request.SetBasicAuth(session.Keys.CensysToken, session.Keys.CensysSecret)
68-
return session.Do(request, agent.Name())
63+
func (agent *Agent) queryURL(session *sources.Session, censysRequest *CensysRequest) (*operations.V3GlobaldataSearchQueryResponse, error) {
64+
ctx := context.Background()
65+
66+
s := censyssdkgo.New(
67+
censyssdkgo.WithOrganizationID(session.Keys.CensysOrgId),
68+
censyssdkgo.WithSecurity(session.Keys.CensysToken),
69+
censyssdkgo.WithClient(
70+
session.Client.HTTPClient,
71+
),
72+
)
73+
74+
return s.GlobalData.Search(ctx, operations.V3GlobaldataSearchQueryRequest{
75+
SearchQueryInputBody: components.SearchQueryInputBody{
76+
PageSize: censyssdkgo.Int64(MaxPerPage),
77+
Query: censysRequest.Query,
78+
PageToken: &censysRequest.Cursor,
79+
},
80+
})
81+
6982
}
7083

71-
func (agent *Agent) query(URL string, session *sources.Session, censysRequest *CensysRequest, results chan sources.Result) *CensysResponse {
84+
func (agent *Agent) query(session *sources.Session, censysRequest *CensysRequest, results chan sources.Result) *operations.V3GlobaldataSearchQueryResponse {
7285
// query certificates
73-
resp, err := agent.queryURL(session, URL, censysRequest)
86+
resp, err := agent.queryURL(session, censysRequest)
7487
if err != nil {
7588
results <- sources.Result{Source: agent.Name(), Error: err}
7689
// httputil.DrainResponseBody(resp)
7790
return nil
7891
}
7992

80-
censysResponse := &CensysResponse{}
81-
if err := json.NewDecoder(resp.Body).Decode(censysResponse); err != nil {
82-
results <- sources.Result{Source: agent.Name(), Error: err}
83-
return nil
84-
}
93+
if result := resp.ResponseEnvelopeSearchQueryResponse.Result; result != nil {
94+
for _, censysResult := range result.Hits {
8595

86-
for _, censysResult := range censysResponse.Results.Hits {
87-
result := sources.Result{Source: agent.Name()}
88-
if ip, ok := censysResult["ip"]; ok {
89-
result.IP = ip.(string)
90-
}
91-
if name, ok := censysResult["name"]; ok {
92-
result.Host = name.(string)
93-
}
94-
if services, ok := censysResult["services"]; ok {
95-
for _, serviceData := range services.([]interface{}) {
96-
if serviceData, ok := serviceData.(map[string]interface{}); ok {
97-
result.Port = int(serviceData["port"].(float64))
98-
raw, _ := json.Marshal(censysResult)
99-
result.Raw = raw
100-
results <- result
96+
for _, host := range censysResult.WebpropertyV1.Resource.Endpoints {
97+
result := sources.Result{Source: agent.Name()}
98+
if host.IP != nil {
99+
result.IP = *host.IP
101100
}
101+
if host.Hostname != nil {
102+
result.Host = *host.Hostname
103+
}
104+
if host.Port != nil {
105+
result.Port = *host.Port
106+
}
107+
if host.HTTP != nil && host.HTTP.URI != nil {
108+
result.Url = *host.HTTP.URI
109+
}
110+
raw, _ := json.Marshal(host)
111+
result.Raw = raw
112+
results <- result
102113
}
103-
} else {
104-
raw, _ := json.Marshal(censysResult)
105-
result.Raw = raw
106-
// only ip
107-
results <- result
114+
108115
}
109116
}
110117

111-
return censysResponse
118+
return resp
112119
}
113120

114121
type CensysRequest struct {

sources/agent/censys/example.json

Lines changed: 0 additions & 87 deletions
This file was deleted.

sources/agent/censys/response.go

Lines changed: 0 additions & 19 deletions
This file was deleted.

sources/keys.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package sources
22

33
type Keys struct {
44
CensysToken string
5-
CensysSecret string
5+
CensysOrgId string
66
Shodan string
77
FofaEmail string
88
FofaKey string
@@ -22,7 +22,7 @@ type Keys struct {
2222
}
2323

2424
func (keys Keys) Empty() bool {
25-
return keys.CensysSecret == "" &&
25+
return keys.CensysOrgId == "" &&
2626
keys.CensysToken == "" &&
2727
keys.Shodan == "" &&
2828
keys.FofaEmail == "" &&

sources/provider.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ func (provider *Provider) GetKeys() Keys {
5656
parts := strings.Split(censysKeys, ":")
5757
if len(parts) == 2 {
5858
keys.CensysToken = parts[0]
59-
keys.CensysSecret = parts[1]
59+
keys.CensysOrgId = parts[1]
6060
}
6161
}
6262

@@ -163,7 +163,7 @@ func (provider *Provider) LoadProviderKeysFromEnv() {
163163
return arr
164164
}
165165
provider.Fofa = appendIfAllExists(provider.Fofa, "FOFA_EMAIL", "FOFA_KEY")
166-
provider.Censys = appendIfAllExists(provider.Censys, "CENSYS_API_ID", "CENSYS_API_SECRET")
166+
provider.Censys = appendIfAllExists(provider.Censys, "CENSYS_API_TOKEN", "CENSYS_ORGANIZATION_ID")
167167
provider.Google = appendIfAllExists(provider.Google, "GOOGLE_API_KEY", "GOOGLE_API_CX")
168168
provider.Odin = appendIfExists(provider.Odin, "ODIN_API_KEY")
169169
provider.BinaryEdge = appendIfExists(provider.BinaryEdge, "BINARYEDGE_API_KEY")

0 commit comments

Comments
 (0)