passivetotal 0.2.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/README.md +24 -17
- data/lib/passivetotal/api.rb +285 -87
- data/lib/passivetotal/cli.rb +32 -11
- data/lib/passivetotal/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d1844555714450cff7c7fdf042d3bd9888e300eb
|
4
|
+
data.tar.gz: a1b743c9a386b12981e533cbbcdfcd60568bcede
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b154abc61be44ad6be8b96afcdaff311022d18722f26192d6cb498a31f872be038c7ffec72a5a8b1255ca378d30271b32419ea89282a3c514e9dc47c89cb92ba
|
7
|
+
data.tar.gz: 51432b063381d9169e6694577ff42eec84b7f58ca5dddfebcb767fdb4958fa715663193e7e162cfd477f3cc31f7f53a9981c113b29ddee9fcb0b157c448b294d
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -22,9 +22,10 @@ Or install it yourself as:
|
|
22
22
|
|
23
23
|
Included in the gem is a command-line tool, passivetotal, with the following usage:
|
24
24
|
|
25
|
-
Usage: passivetotal [-
|
25
|
+
Usage: bin/passivetotal [-v] [-u <username>] [-k <apikey>] <action flag> <query> [-i <value>]
|
26
26
|
-h Help
|
27
27
|
-v Verbose output
|
28
|
+
-u <username> Sets the Username, defaults to the environment variable PASSIVETOTAL_USERNAME
|
28
29
|
-k <apikey> Sets the APIKEY, defaults to the environment variable PASSIVETOTAL_APIKEY
|
29
30
|
ACTIONS (You have to select one, last one wins) -m <ip or dom> Queries metadata for given IP or domain
|
30
31
|
-p <ip or dom> Queries passive DNS data for given IP or domain
|
@@ -36,35 +37,37 @@ Included in the gem is a command-line tool, passivetotal, with the following usa
|
|
36
37
|
-s <dom> Queries the subdomains for a given domain
|
37
38
|
-d <dom> Queries (or sets) if a domain is a dynamic DNS domain
|
38
39
|
-x <ip> Queries (or sets) if a given IP is a sinkhole
|
39
|
-
-l <
|
40
|
+
-l <hash> Queries for SSL certificates/IP addresses associated with a given SHA-1 hash
|
41
|
+
-H <ip or hash> Queries for SSL certificate history associated with a given IP or SHA-1 hash
|
42
|
+
-T <ip or dom> Queries for Tracker information associated with a given IP or domain
|
43
|
+
-o <ip or dom> Queries for OSINT on a given IP or domain
|
40
44
|
SETTING VALUES -i <value> Sets the value, used in conjuntion with -c, -t, -e, -w, -d, or -x
|
41
45
|
Valid values for -i depend on what it's used with:
|
42
|
-
-c :
|
46
|
+
-c : malicious, non-malicious, suspicious, unknown
|
43
47
|
-t : <a tag name consisting of characters: [a-zA-Z_]>
|
44
48
|
-e, -w, -d, -x: true, false
|
45
|
-
|
46
49
|
## Usage
|
47
50
|
|
48
|
-
# Initialize the API wrapper with an apikey (using the default endpoint URL of https://
|
49
|
-
pt = PassiveTotal::API.new(apikey)
|
51
|
+
# Initialize the API wrapper with an apikey (using the default endpoint URL of https://api.passivetotal.org/v2/)
|
52
|
+
pt = PassiveTotal::API.new(user, apikey)
|
50
53
|
# Create an array to shove results into
|
51
|
-
res =
|
52
|
-
# query
|
53
|
-
res << @pt.
|
54
|
-
# query
|
55
|
-
res << @pt.
|
54
|
+
res = Array.new
|
55
|
+
# query enrichment for the domain, www.passivetotal.org
|
56
|
+
res << @pt.enrichment('www.passivetotal.org')
|
57
|
+
# query enrichment for the ipv4 address, 107.170.89.121
|
58
|
+
res << @pt.enrichment('107.170.89.121')
|
56
59
|
# query passive DNS results for the domain, www.passivetotal.org
|
57
60
|
res << @pt.passive('www.passivetotal.org')
|
58
61
|
# query passive DNS results for the ipv4 address, 107.170.89.121
|
59
62
|
res << @pt.passive('107.170.89.121')
|
60
63
|
# query for subdomains of passivetotal.org
|
61
|
-
res << @pt.subdomains('passivetotal.org')
|
64
|
+
#res << @pt.subdomains('passivetotal.org')
|
62
65
|
# query for unique IPv4 resolutions of passivetotal.org
|
63
66
|
res << @pt.unique('passivetotal.org')
|
64
67
|
# query for the classification of www.passivetotal.org
|
65
68
|
res << @pt.classification('www.passivetotal.org')
|
66
69
|
# set the classification of www.passivetotal.org as benign
|
67
|
-
res << @pt.classification('www.passivetotal.org', '
|
70
|
+
res << @pt.classification('www.passivetotal.org', 'non-malicious')
|
68
71
|
# query for the tags associated with www.chrisleephd.us
|
69
72
|
res << @pt.tags('www.chrisleephd.us')
|
70
73
|
# add the "cool" tag to www.chrisleephd.us
|
@@ -84,13 +87,17 @@ Included in the gem is a command-line tool, passivetotal, with the following usa
|
|
84
87
|
# flag www.passivetotal.org as not a dynamic dns domain/host
|
85
88
|
res << @pt.dynamic('www.passivetotal.org', false)
|
86
89
|
# check if www.passivetotal.org is being watched
|
87
|
-
res << @pt.
|
90
|
+
res << @pt.monitor('www.passivetotal.org')
|
88
91
|
# unwatch www.passivetotal.org
|
89
|
-
res << @pt.
|
90
|
-
# list SSL certificates associated with IPV4 address 104.131.121.205
|
91
|
-
res << @pt.ssl_certificate('104.131.121.205')
|
92
|
+
res << @pt.monitor('www.passivetotal.org', false)
|
92
93
|
# list sites associated with SSL certificates with SHA-1 hash of e9a6647d6aba52dc47b3838c920c9ee59bad7034
|
93
94
|
res << @pt.ssl_certificate('e9a6647d6aba52dc47b3838c920c9ee59bad7034')
|
95
|
+
# list sites associated with SSL certificates with SHA-1 hash of e9a6647d6aba52dc47b3838c920c9ee59bad7034
|
96
|
+
res << @pt.ssl_certificate('2317683628587350290823564500811277499', 'serialNumber')
|
97
|
+
# retrieve certificate history based on SHA-1 hash of e9a6647d6aba52dc47b3838c920c9ee59bad7034
|
98
|
+
res << @pt.ssl_certificate_history('e9a6647d6aba52dc47b3838c920c9ee59bad7034')
|
99
|
+
# retrieve certificate history from IPv4 address of 52.8.228.23
|
100
|
+
res << @pt.ssl_certificate_history('52.8.228.23')
|
94
101
|
# dump all this glorious information to feast your eyes upon
|
95
102
|
pp res
|
96
103
|
|
data/lib/passivetotal/api.rb
CHANGED
@@ -9,10 +9,12 @@ require 'passivetotal/version'
|
|
9
9
|
module PassiveTotal # :nodoc:
|
10
10
|
|
11
11
|
class InvalidAPIKeyError < ArgumentError; end
|
12
|
+
class APIUsageError < StandardError; end
|
13
|
+
class ExceededQuotaError < StandardError; end
|
12
14
|
|
13
15
|
class Transaction < Struct.new(:query, :response, :response_time); end
|
14
16
|
class Query < Struct.new(:api, :query, :set, :url, :parameters); end
|
15
|
-
class Response < Struct.new(:json, :success, :
|
17
|
+
class Response < Struct.new(:json, :success, :results); end
|
16
18
|
|
17
19
|
# The API class wraps the PassiveTotal.org web API for all the verbs that it supports
|
18
20
|
# See https://www.passivetotal.org/api/docs for the API documentation.
|
@@ -23,167 +25,309 @@ module PassiveTotal # :nodoc:
|
|
23
25
|
TLDS = "abb,abbott,abogado,ac,academy,accenture,accountant,accountants,active,actor,ad,ads,adult,ae,aeg,aero,af,afl,ag,agency,ai,aig,airforce,al,allfinanz,alsace,am,amsterdam,an,android,ao,apartments,aq,aquarelle,ar,archi,army,arpa,as,asia,associates,at,attorney,au,auction,audio,auto,autos,aw,ax,axa,az,azure,ba,band,bank,bar,barclaycard,barclays,bargains,bauhaus,bayern,bb,bbc,bbva,bd,be,beer,berlin,best,bf,bg,bh,bharti,bi,bible,bid,bike,bing,bingo,bio,biz,bj,black,blackfriday,bloomberg,blue,bm,bmw,bn,bnl,bnpparibas,bo,boats,bond,boo,boutique,br,bradesco,bridgestone,broker,brother,brussels,bs,bt,budapest,build,builders,business,buzz,bv,bw,by,bz,bzh,ca,cab,cafe,cal,camera,camp,cancerresearch,canon,capetown,capital,caravan,cards,care,career,careers,cars,cartier,casa,cash,casino,cat,catering,cba,cbn,cc,cd,center,ceo,cern,cf,cfa,cfd,cg,ch,channel,chat,cheap,chloe,christmas,chrome,church,ci,cisco,citic,city,ck,cl,claims,cleaning,click,clinic,clothing,cloud,club,cm,cn,co,coach,codes,coffee,college,cologne,com,commbank,community,company,computer,condos,construction,consulting,contractors,cooking,cool,coop,corsica,country,coupons,courses,cr,credit,creditcard,cricket,crown,crs,cruises,cu,cuisinella,cv,cw,cx,cy,cymru,cyou,cz,dabur,dad,dance,date,dating,datsun,day,dclk,de,deals,degree,delivery,democrat,dental,dentist,desi,design,dev,diamonds,diet,digital,direct,directory,discount,dj,dk,dm,dnp,do,docs,dog,doha,domains,doosan,download,drive,durban,dvag,dz,earth,eat,ec,edu,education,ee,eg,email,emerck,energy,engineer,engineering,enterprises,epson,equipment,er,erni,es,esq,estate,et,eu,eurovision,eus,events,everbank,exchange,expert,exposed,express,fail,faith,fan,fans,farm,fashion,feedback,fi,film,finance,financial,firmdale,fish,fishing,fit,fitness,fj,fk,flights,florist,flowers,flsmidth,fly,fm,fo,foo,football,forex,forsale,foundation,fr,frl,frogans,fund,furniture,futbol,fyi,ga,gal,gallery,garden,gb,gbiz,gd,gdn,ge,gent,genting,gf,gg,ggee,gh,gi,gift,gifts,gives,gl,glass,gle,global,globo,gm,gmail,gmo,gmx,gn,gold,goldpoint,golf,goo,goog,google,gop,gov,gp,gq,gr,graphics,gratis,green,gripe,gs,gt,gu,guge,guide,guitars,guru,gw,gy,hamburg,hangout,haus,healthcare,help,here,hermes,hiphop,hitachi,hiv,hk,hm,hn,hockey,holdings,holiday,homedepot,homes,honda,horse,host,hosting,hoteles,hotmail,house,how,hr,ht,hu,ibm,icbc,icu,id,ie,ifm,il,im,immo,immobilien,in,industries,infiniti,info,ing,ink,institute,insure,int,international,investments,io,iq,ir,irish,is,it,iwc,java,jcb,je,jetzt,jewelry,jlc,jll,jm,jo,jobs,joburg,jp,juegos,kaufen,kddi,ke,kg,kh,ki,kim,kitchen,kiwi,km,kn,koeln,komatsu,kp,kr,krd,kred,kw,ky,kyoto,kz,la,lacaixa,land,lasalle,lat,latrobe,law,lawyer,lb,lc,lds,lease,leclerc,legal,lgbt,li,liaison,lidl,life,lighting,limited,limo,link,lk,loan,loans,lol,london,lotte,lotto,love,lr,ls,lt,ltda,lu,lupin,luxe,luxury,lv,ly,ma,madrid,maif,maison,management,mango,market,marketing,markets,marriott,mba,mc,md,me,media,meet,melbourne,meme,memorial,men,menu,mg,mh,miami,microsoft,mil,mini,mk,ml,mm,mma,mn,mo,mobi,moda,moe,monash,money,montblanc,mormon,mortgage,moscow,motorcycles,mov,movie,movistar,mp,mq,mr,ms,mt,mtn,mtpc,mu,museum,mv,mw,mx,my,mz,na,nadex,nagoya,name,navy,nc,ne,nec,net,netbank,network,neustar,new,news,nexus,nf,ng,ngo,nhk,ni,nico,ninja,nissan,nl,no,np,nr,nra,nrw,ntt,nu,nyc,nz,office,okinawa,om,omega,one,ong,onl,online,ooo,oracle,org,organic,osaka,otsuka,ovh,pa,page,panerai,paris,partners,parts,party,pe,pf,pg,ph,pharmacy,philips,photo,photography,photos,physio,piaget,pics,pictet,pictures,pink,pizza,pk,pl,place,play,plumbing,plus,pm,pn,pohl,poker,porn,post,pr,praxi,press,pro,prod,productions,prof,properties,property,ps,pt,pub,pw,py,qa,qpon,quebec,racing,re,realtor,recipes,red,redstone,rehab,reise,reisen,reit,ren,rent,rentals,repair,report,republican,rest,restaurant,review,reviews,rich,ricoh,rio,rip,ro,rocks,rodeo,rs,rsvp,ru,ruhr,run,rw,ryukyu,sa,saarland,sale,samsung,sandvik,sandvikcoromant,sap,sarl,saxo,sb,sc,sca,scb,schmidt,scholarships,school,schule,schwarz,science,scor,scot,sd,se,seat,sener,services,sew,sex,sexy,sg,sh,shiksha,shoes,show,shriram,si,singles,site,sj,sk,ski,sky,skype,sl,sm,sn,sncf,so,soccer,social,software,sohu,solar,solutions,sony,soy,space,spiegel,spreadbetting,sr,st,starhub,statoil,study,style,su,sucks,supplies,supply,support,surf,surgery,suzuki,sv,swatch,swiss,sx,sy,sydney,systems,sz,taipei,tatar,tattoo,tax,taxi,tc,td,team,tech,technology,tel,telefonica,temasek,tennis,tf,tg,th,thd,theater,tickets,tienda,tips,tires,tirol,tj,tk,tl,tm,tn,to,today,tokyo,tools,top,toray,toshiba,tours,town,toys,tr,trade,trading,training,travel,trust,tt,tui,tv,tw,tz,ua,ug,uk,university,uno,uol,us,uy,uz,va,vacations,vc,ve,vegas,ventures,versicherung,vet,vg,vi,viajes,video,villas,vision,vista,vistaprint,vlaanderen,vn,vodka,vote,voting,voto,voyage,vu,wales,walter,wang,watch,webcam,website,wed,wedding,weir,wf,whoswho,wien,wiki,williamhill,win,windows,wme,work,works,world,ws,wtc,wtf,xbox,xerox,xin,xn--1qqw23a,xn--30rr7y,xn--3bst00m,xn--3ds443g,xn--3e0b707e,xn--45brj9c,xn--45q11c,xn--4gbrim,xn--55qw42g,xn--55qx5d,xn--6frz82g,xn--6qq986b3xl,xn--80adxhks,xn--80ao21a,xn--80asehdb,xn--80aswg,xn--90a3ac,xn--90ais,xn--9et52u,xn--b4w605ferd,xn--c1avg,xn--cg4bki,xn--clchc0ea0b2g2a9gcd,xn--czr694b,xn--czrs0t,xn--czru2d,xn--d1acj3b,xn--d1alf,xn--estv75g,xn--fiq228c5hs,xn--fiq64b,xn--fiqs8s,xn--fiqz9s,xn--fjq720a,xn--flw351e,xn--fpcrj9c3d,xn--fzc2c9e2c,xn--gecrj9c,xn--h2brj9c,xn--hxt814e,xn--i1b6b1a6a2e,xn--imr513n,xn--io0a7i,xn--j1amh,xn--j6w193g,xn--kcrx77d1x4a,xn--kprw13d,xn--kpry57d,xn--kput3i,xn--l1acc,xn--lgbbat1ad8j,xn--mgb9awbf,xn--mgba3a4f16a,xn--mgbaam7a8h,xn--mgbab2bd,xn--mgbayh7gpa,xn--mgbbh1a71e,xn--mgbc0a9azcg,xn--mgberp4a5d4ar,xn--mgbpl2fh,xn--mgbx4cd0ab,xn--mxtq1m,xn--ngbc5azd,xn--node,xn--nqv7f,xn--nqv7fs00ema,xn--nyqy26a,xn--o3cw4h,xn--ogbpf8fl,xn--p1acf,xn--p1ai,xn--pgbs0dh,xn--q9jyb4c,xn--qcka1pmc,xn--rhqv96g,xn--s9brj9c,xn--ses554g,xn--unup4y,xn--vermgensberater-ctb,xn--vermgensberatung-pwb,xn--vhquv,xn--vuq861b,xn--wgbh1c,xn--wgbl6a,xn--xhq521b,xn--xkc2al3hye2a,xn--xkc2dl3a5ee0h,xn--y9a3aq,xn--yfro4i67o,xn--ygbi2ammx,xn--zfr164b,xxx,xyz,yachts,yandex,ye,yodobashi,yoga,yokohama,youtube,yt,za,zip,zm,zone,zuerich,zw".split(/,/)
|
24
26
|
|
25
27
|
# initialize a new PassiveTotal::API object
|
28
|
+
# username: the email address associated with your PassiveTotal API key.
|
26
29
|
# apikey: is 64-hexcharacter string
|
27
|
-
# endpoint: base URL for the web service, defaults to https://
|
28
|
-
def initialize(apikey, endpoint = 'https://
|
30
|
+
# endpoint: base URL for the web service, defaults to https://api.passivetotal.org/v2/
|
31
|
+
def initialize(username, apikey, endpoint = 'https://api.passivetotal.org/v2/')
|
29
32
|
unless apikey =~ /^[a-fA-F0-9]{64}$/
|
30
33
|
raise ArgumentError.new("apikey must be a 64 character hex string")
|
31
34
|
end
|
35
|
+
@username = username
|
32
36
|
@apikey = apikey
|
33
37
|
@endpoint = endpoint
|
34
38
|
end
|
35
39
|
|
36
|
-
#
|
40
|
+
# Account : Get account details your account.
|
41
|
+
def account
|
42
|
+
get('account')
|
43
|
+
end
|
44
|
+
|
45
|
+
# Account History : Get history associated with your account.
|
46
|
+
def account_history
|
47
|
+
get('account/history')
|
48
|
+
end
|
49
|
+
|
50
|
+
# history is an alias for account_history
|
51
|
+
alias_method :history, :account_history
|
52
|
+
|
53
|
+
# Account notifications : Get notifications that have been posted to your account.
|
54
|
+
def account_notifications
|
55
|
+
get('account/notifications')
|
56
|
+
end
|
57
|
+
|
58
|
+
# notifications is an alias for account_notifications
|
59
|
+
alias_method :notifications, :account_notifications
|
60
|
+
|
61
|
+
# Account organization : Get details about the organization your account is associated with.
|
62
|
+
def account_organization
|
63
|
+
get('account/organization')
|
64
|
+
end
|
65
|
+
|
66
|
+
# organization is an alias for account_organization
|
67
|
+
alias_method :organization, :account_organization
|
68
|
+
|
69
|
+
# Account organization teamstream : Get the teamstream for the organization your account is associated with.
|
70
|
+
def account_organization_teamstream
|
71
|
+
get('account/organization/teamstream')
|
72
|
+
end
|
73
|
+
|
74
|
+
# teamstream is an alias for account_organization_teamstream
|
75
|
+
alias_method :teamstream, :account_organization_teamstream
|
76
|
+
|
77
|
+
# Account sources : Get source details for a specific source.
|
78
|
+
def account_sources(source)
|
79
|
+
get('account/sources', {'source' => source})
|
80
|
+
end
|
81
|
+
|
82
|
+
# sources is an alias for account_sources
|
83
|
+
alias_method :sources, :account_sources
|
84
|
+
|
85
|
+
|
86
|
+
# Passive provides a complete passive DNS picture for a domain or IP address including first/last seen values, deconflicted values, sources used, unique counts and enrichment for all values.
|
37
87
|
# query: A domain or IP address to query
|
38
|
-
def
|
88
|
+
def passive(query)
|
39
89
|
is_valid_with_error(__method__, [:ipv4, :domain], query)
|
40
90
|
if domain?(query)
|
41
91
|
query = normalize_domain(query)
|
42
92
|
end
|
43
|
-
get(
|
93
|
+
get('dns/passive', {'query' => query})
|
44
94
|
end
|
45
|
-
|
95
|
+
|
46
96
|
# Passive provides a complete passive DNS picture for a domain or IP address including first/last seen values, deconflicted values, sources used, unique counts and enrichment for all values.
|
47
97
|
# query: A domain or IP address to query
|
48
|
-
def
|
98
|
+
def passive_unique(query)
|
49
99
|
is_valid_with_error(__method__, [:ipv4, :domain], query)
|
50
100
|
if domain?(query)
|
51
101
|
query = normalize_domain(query)
|
52
102
|
end
|
53
|
-
get(
|
54
|
-
end
|
55
|
-
|
56
|
-
# Subdomains provides a comprehensive view of all known subdomains for a registered domain with associated passive DNS information. This call is best used to understand the activity of a particular domain over a period of time. Passive DNS information is only deconflicted at the subdomain level, not across the entire domain.
|
57
|
-
# query: A domain to query
|
58
|
-
def subdomains(query)
|
59
|
-
is_valid_with_error(__method__, [:domain], query)
|
60
|
-
query = normalize_domain(query)
|
61
|
-
get(__method__, query)
|
103
|
+
get('dns/passive/unique', {'query' => query})
|
62
104
|
end
|
63
|
-
|
64
|
-
#
|
105
|
+
|
106
|
+
# unique is an alias for passive_unique
|
107
|
+
alias_method :unique, :passive_unique
|
108
|
+
|
109
|
+
# Enrichment : Enrich the given query with metadata
|
65
110
|
# query: A domain or IP address to query
|
66
|
-
def
|
111
|
+
def enrichment(query)
|
67
112
|
is_valid_with_error(__method__, [:ipv4, :domain], query)
|
68
113
|
if domain?(query)
|
69
114
|
query = normalize_domain(query)
|
70
115
|
end
|
71
|
-
get(
|
116
|
+
get('enrichment', {'query' => query})
|
72
117
|
end
|
73
118
|
|
74
|
-
#
|
75
|
-
|
119
|
+
# metadata is an alias for enrichment
|
120
|
+
alias_method :metadata, :enrichment
|
121
|
+
|
122
|
+
# osint: Get opensource intelligence data
|
76
123
|
# query: A domain or IP address to query
|
77
|
-
|
78
|
-
def classification(query, set=nil)
|
124
|
+
def osint(query)
|
79
125
|
is_valid_with_error(__method__, [:ipv4, :domain], query)
|
80
126
|
if domain?(query)
|
81
127
|
query = normalize_domain(query)
|
82
128
|
end
|
83
|
-
|
84
|
-
|
129
|
+
get('enrichment/osint', {'query' => query})
|
130
|
+
end
|
131
|
+
|
132
|
+
# subdomains: Get subdomains using a wildcard query
|
133
|
+
# query: A domain with wildcard, e.g., *.passivetotal.org
|
134
|
+
def subdomains(query)
|
135
|
+
get('enrichment/subdomains', {'query' => query})
|
136
|
+
end
|
137
|
+
|
138
|
+
# whois: Get WHOIS data for a domain or IP address
|
139
|
+
# query: ipv4, domain, or, if you specify a field, any value for that field
|
140
|
+
# field: field name to query if not the default ip/domain field
|
141
|
+
# field names: domain, email, name, organization, address, phone, nameserver
|
142
|
+
def whois(query, field=nil)
|
143
|
+
if field
|
144
|
+
is_valid_with_error(__method__, [:whois_field], field)
|
145
|
+
get('whois/search', {'field' => field, 'query' => query})
|
85
146
|
else
|
86
|
-
is_valid_with_error(__method__, [:
|
87
|
-
|
147
|
+
is_valid_with_error(__method__, [:ipv4, :domain], query)
|
148
|
+
if domain?(query)
|
149
|
+
query = normalize_domain(query)
|
150
|
+
end
|
151
|
+
get('whois', {'query' => query, 'compact_record' => 'false'})
|
88
152
|
end
|
89
153
|
end
|
154
|
+
|
155
|
+
# Add a user-tag to an IP or domain
|
156
|
+
# query: A domain or IP address to tag
|
157
|
+
# tag: Value used to tag query value. Should only consist of alphanumeric, underscores and hyphen values
|
158
|
+
def add_tag(query, tag)
|
159
|
+
is_valid_with_error(__method__, [:ipv4, :domain], query)
|
160
|
+
is_valid_with_error(__method__, [:tag], tag)
|
161
|
+
post('actions/tags', { 'query' => query, 'tags' => [tag] })
|
162
|
+
end
|
90
163
|
|
91
|
-
#
|
92
|
-
#
|
93
|
-
#
|
94
|
-
|
95
|
-
|
96
|
-
is_valid_with_error(__method__, [:
|
164
|
+
# Remove a user-tag to an IP or domain
|
165
|
+
# query: A domain or IP address to remove a tag from
|
166
|
+
# tag: Value used to tag query value. Should only consist of alphanumeric, underscores and hyphen values
|
167
|
+
def remove_tag(query, tag)
|
168
|
+
is_valid_with_error(__method__, [:ipv4, :domain], query)
|
169
|
+
is_valid_with_error(__method__, [:tag], tag)
|
170
|
+
delete('actions/tags', { 'query' => query, 'tags' => [tag] })
|
171
|
+
end
|
172
|
+
|
173
|
+
# PassiveTotal uses the notion of classifications to highlight table rows a certain color based on how they have been rated.
|
174
|
+
# PassiveTotal::API#classification() queries if only one argument is given, and sets if both are given
|
175
|
+
# query: A domain or IP address to query
|
176
|
+
def classification(query, set=nil)
|
177
|
+
is_valid_with_error(__method__, [:ipv4, :domain], query)
|
178
|
+
if domain?(query)
|
179
|
+
query = normalize_domain(query)
|
180
|
+
end
|
97
181
|
if set.nil?
|
98
|
-
get(
|
182
|
+
get('actions/classification', {'query' => query})
|
99
183
|
else
|
100
|
-
is_valid_with_error(__method__, [:
|
101
|
-
post(
|
184
|
+
is_valid_with_error(__method__.to_s, [:classification], set)
|
185
|
+
post('actions/classification', { 'query' => query, 'classification' => set })
|
102
186
|
end
|
103
187
|
end
|
104
188
|
|
105
189
|
# PassiveTotal allows users to notate if a domain or IP address have ever been compromised. These values aid in letting users know that a site may be benign, but it was used in an attack at some point in time.
|
106
190
|
# PassiveTotal::API#ever_compromised() queries if only one argument is given, and sets if both are given
|
107
191
|
# query: A domain or IP address to query
|
108
|
-
# set:
|
192
|
+
# set: a boolean flag
|
109
193
|
def ever_compromised(query, set=nil)
|
110
194
|
is_valid_with_error(__method__, [:ipv4, :domain], query)
|
111
195
|
if domain?(query)
|
112
196
|
query = normalize_domain(query)
|
113
197
|
end
|
114
198
|
if set.nil?
|
115
|
-
get(
|
199
|
+
get('actions/ever-compromised', {'query' => query})
|
116
200
|
else
|
117
201
|
is_valid_with_error(__method__, [:bool], set)
|
118
|
-
post(
|
202
|
+
post('actions/ever-compromised', { 'query' => query, 'status' => set })
|
119
203
|
end
|
120
204
|
end
|
121
205
|
|
206
|
+
alias_method :compromised, :ever_compromised
|
207
|
+
|
122
208
|
# PassiveTotal allows users to notate if a domain is associated with a dynamic DNS provider.
|
123
209
|
# PassiveTotal::API#dynamic() queries if only one argument is given, and sets if both are given
|
124
210
|
# query: A domain to query
|
125
|
-
# set:
|
211
|
+
# set: a boolean flag
|
126
212
|
def dynamic(query, set=nil)
|
127
213
|
is_valid_with_error(__method__, [:domain], query)
|
128
214
|
query = normalize_domain(query)
|
129
215
|
if set.nil?
|
130
|
-
get(
|
216
|
+
get('actions/dynamic-dns', {'query' => query})
|
131
217
|
else
|
132
218
|
is_valid_with_error(__method__, [:bool], set)
|
133
|
-
post(
|
219
|
+
post('actions/dynamic-dns', { 'query' => query, 'status' => set })
|
134
220
|
end
|
135
221
|
end
|
136
222
|
|
137
|
-
# PassiveTotal allows users to
|
138
|
-
# PassiveTotal::API#
|
139
|
-
# query: A domain
|
140
|
-
# set:
|
141
|
-
def
|
223
|
+
# PassiveTotal allows users to notate if an ip or domain is "monitored".
|
224
|
+
# PassiveTotal::API#monitor() queries if only one argument is given, and sets if both are given
|
225
|
+
# query: A domain to query
|
226
|
+
# set: a boolean flag
|
227
|
+
def monitor(query, set=nil)
|
142
228
|
is_valid_with_error(__method__, [:ipv4, :domain], query)
|
143
229
|
if domain?(query)
|
144
230
|
query = normalize_domain(query)
|
145
231
|
end
|
146
232
|
if set.nil?
|
147
|
-
get(
|
233
|
+
get('actions/monitor', {'query' => query})
|
234
|
+
else
|
235
|
+
is_valid_with_error(__method__, [:bool], set)
|
236
|
+
post('actions/monitor', { 'query' => query, 'status' => set })
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
# monitoring is an alias for monitor
|
241
|
+
alias_method :monitoring, :monitor
|
242
|
+
alias_method :watching, :monitor
|
243
|
+
|
244
|
+
# PassiveTotal allows users to notate if an IP address is a known sinkhole. These values are shared globally with everyone in the platform.
|
245
|
+
# PassiveTotal::API#sinkhole() queries if only one argument is given, and sets if both are given
|
246
|
+
# query: An IP address to set as a sinkhole or not
|
247
|
+
# set: a boolean flag
|
248
|
+
def sinkhole(query, set=nil)
|
249
|
+
is_valid_with_error(__method__, [:ipv4], query)
|
250
|
+
if set.nil?
|
251
|
+
get('actions/sinkhole', {'query' => query})
|
148
252
|
else
|
149
253
|
is_valid_with_error(__method__, [:bool], set)
|
150
|
-
post(
|
254
|
+
post('actions/sinkhole', { 'query' => query, 'status' => set })
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
|
259
|
+
# PassiveTotal uses three types of tags (user, global, and temporal) in order to provide context back to the user.
|
260
|
+
# query: A domain or IP address to query
|
261
|
+
# set: if supplied, adds a tag to an entity
|
262
|
+
def tags(query, set=nil)
|
263
|
+
is_valid_with_error(__method__, [:ipv4, :domain], query)
|
264
|
+
if domain?(query)
|
265
|
+
query = normalize_domain(query)
|
266
|
+
end
|
267
|
+
if set.nil?
|
268
|
+
get('actions/tags', {'query' => query})
|
269
|
+
else
|
270
|
+
is_valid_with_error(__method__, [:tag], set)
|
271
|
+
post('actions/tag', { 'query' => query, 'tags' => [set] })
|
151
272
|
end
|
152
273
|
end
|
153
274
|
|
275
|
+
# Search Tags : Search for items based on tag value
|
154
276
|
# PassiveTotal uses three types of tags (user, global, and temporal) in order to provide context back to the user.
|
155
277
|
# query: A domain or IP address to query
|
156
|
-
def
|
278
|
+
def tags_search(query)
|
157
279
|
is_valid_with_error(__method__, [:ipv4, :domain], query)
|
158
|
-
|
280
|
+
if domain?(query)
|
281
|
+
query = normalize_domain(query)
|
282
|
+
end
|
283
|
+
get('actions/tags/search', {'query' => query})
|
159
284
|
end
|
160
285
|
|
161
|
-
#
|
162
|
-
# query: A
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
286
|
+
# PassiveTotal collects and provides SSL certificates as an enrichment point when possible. Beyond the certificate data itself, PassiveTotal keeps a record of the IP address of where the certificate was found and the time in which it was collected.
|
287
|
+
# query: A SHA-1 hash to query
|
288
|
+
def ssl_certificate_history(query)
|
289
|
+
is_valid_with_error(__method__, [:ipv4, :hash], query)
|
290
|
+
get('ssl-certificate/history', {'query' => query})
|
291
|
+
end
|
292
|
+
|
293
|
+
# ssl_certificate: returns details about SSL certificates
|
294
|
+
# query: SHA-1 has to query, or, if field is set, a valid value for that field
|
295
|
+
# field: the certificate field to query upon
|
296
|
+
# certificate fields: issuer_surname, subject_organizationName, issuer_country, issuer_organizationUnitName, fingerprint, subject_organizationUnitName, serialNumber, subject_emailAddress, subject_country, issuer_givenName, subject_commonName, issuer_commonName, issuer_stateOrProvinceName, issuer_province, subject_stateOrProvinceName, sha1, sslVersion, subject_streetAddress, subject_serialNumber, issuer_organizationName, subject_surname, subject_localityName, issuer_streetAddress, issuer_localityName, subject_givenName, subject_province, issuer_serialNumber, issuer_emailAddress
|
297
|
+
def ssl_certificate(query, field=nil)
|
298
|
+
if field.nil?
|
299
|
+
is_valid_with_error(__method__, [:hash], query)
|
300
|
+
get('ssl-certificate', {'query' => query})
|
301
|
+
else
|
302
|
+
is_valid_with_error(__method__, [:ssl_field], field)
|
303
|
+
get_params('ssl-certificate/search', { 'query' => query, 'field' => field })
|
304
|
+
end
|
168
305
|
end
|
169
306
|
|
170
|
-
#
|
171
|
-
# query:
|
172
|
-
|
173
|
-
def remove_tag(query, tag)
|
307
|
+
# PassiveTotal tracks some interesting metadata about a host
|
308
|
+
# query: a hostname or ip address
|
309
|
+
def components(query)
|
174
310
|
is_valid_with_error(__method__, [:ipv4, :domain], query)
|
175
|
-
|
176
|
-
|
311
|
+
if domain?(query)
|
312
|
+
query = normalize_domain(query)
|
313
|
+
end
|
314
|
+
get('host-attributes/components', {'query' => query})
|
177
315
|
end
|
178
316
|
|
179
|
-
#
|
180
|
-
# query:
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
317
|
+
# trackers: Get all tracking codes for a domain or IP address.
|
318
|
+
# query: ip or domain, or, if type is supplied, a valid tracker ID
|
319
|
+
# type: A valid tracker type to search:
|
320
|
+
# tracker types: YandexMetricaCounterId, ClickyId, GoogleAnalyticsAccountNumber, NewRelicId, MixpanelId, GoogleAnalyticsTrackingId
|
321
|
+
def trackers(query, type=nil)
|
322
|
+
if type.nil?
|
323
|
+
is_valid_with_error(__method__, [:ipv4, :domain], query)
|
324
|
+
if domain?(query)
|
325
|
+
query = normalize_domain(query)
|
326
|
+
end
|
327
|
+
get('host-attributes/trackers', {'query' => query})
|
328
|
+
else
|
329
|
+
is_valid_with_error(__method__, [:tracker_type], type)
|
330
|
+
get('trackers/search', {'query' => query, 'type' => type})
|
187
331
|
end
|
188
332
|
end
|
189
333
|
|
@@ -215,7 +359,7 @@ module PassiveTotal # :nodoc:
|
|
215
359
|
|
216
360
|
# returns true if the given string matches a valid classification
|
217
361
|
def classification?(c)
|
218
|
-
not [
|
362
|
+
not ["malicious", "non-malicious", "suspicious", "unknown"].index(c).nil?
|
219
363
|
end
|
220
364
|
|
221
365
|
# returns true is the given object matches true or false
|
@@ -232,34 +376,56 @@ module PassiveTotal # :nodoc:
|
|
232
376
|
false
|
233
377
|
end
|
234
378
|
|
379
|
+
def ssl_field?(f)
|
380
|
+
return false if f.nil?
|
381
|
+
not ["issuerSurname", "subjectOrganizationName", "issuerCountry", "issuerOrganizationUnitName",
|
382
|
+
"fingerprint", "subjectOrganizationUnitName", "serialNumber", "subjectEmailAddress", "subjectCountry",
|
383
|
+
"issuerGivenName", "subjectCommonName", "issuerCommonName", "issuerStateOrProvinceName", "issuerProvince",
|
384
|
+
"subjectStateOrProvinceName", "sha1", "sslVersion", "subjectStreetAddress", "subjectSerialNumber",
|
385
|
+
"issuerOrganizationName", "subjectSurname", "subjectLocalityName", "issuerStreetAddress",
|
386
|
+
"issuerLocalityName", "subjectGivenName", "subjectProvince", "issuerSerialNumber", "issuerEmailAddress"].index(f).nil?
|
387
|
+
end
|
388
|
+
|
389
|
+
def whois_field?(f)
|
390
|
+
return false if f.nil?
|
391
|
+
not ["domain", "email", "name", "organization", "address", "phone", "nameserver"].index(f).nil?
|
392
|
+
end
|
393
|
+
|
394
|
+
def tracker_type?(t)
|
395
|
+
return false if t.nil?
|
396
|
+
not ["YandexMetricaCounterId", "ClickyId", "GoogleAnalyticsAccountNumber", "NewRelicId", "MixpanelId", "GoogleAnalyticsTrackingId"].index(t).nil?
|
397
|
+
end
|
398
|
+
|
235
399
|
# lowercases and removes a trailing period (if one exists) from a domain name
|
236
400
|
def normalize_domain(domain)
|
237
401
|
return domain.downcase.gsub(/\.$/,'')
|
238
402
|
end
|
239
403
|
|
240
404
|
# helper function to perform an HTTP GET against the web API
|
241
|
-
def get(api,
|
242
|
-
|
405
|
+
def get(api, params={})
|
406
|
+
url2json(:GET, "#{@endpoint}#{api}", params)
|
407
|
+
end
|
408
|
+
|
409
|
+
# helper function to perform an HTTP GET against the web API
|
410
|
+
def get_params(api, params)
|
243
411
|
url2json(:GET, "#{@endpoint}#{api}", params)
|
244
412
|
end
|
245
413
|
|
246
414
|
# helper function to perform an HTTP POST against the web API
|
247
|
-
def post(api,
|
248
|
-
params = { 'api_key' => @apikey, 'query' => query, api => set }
|
415
|
+
def post(api, params)
|
249
416
|
url2json(:POST, "#{@endpoint}#{api}", params)
|
250
417
|
end
|
251
418
|
|
252
|
-
# helper function to perform an HTTP
|
253
|
-
def
|
254
|
-
|
255
|
-
url2json(:POST, "#{@endpoint}#{api}", params)
|
419
|
+
# helper function to perform an HTTP DELETE against the web API
|
420
|
+
def delete(api, params)
|
421
|
+
url2json(:DELETE, "#{@endpoint}#{api}", params)
|
256
422
|
end
|
257
|
-
|
423
|
+
|
258
424
|
# main helper function to perform HTTP interactions with the web API.
|
259
425
|
def url2json(method, url, params)
|
260
426
|
if method == :GET
|
261
427
|
url << "?" + params.map{|k,v| "#{k}=#{v}"}.join("&")
|
262
|
-
end
|
428
|
+
end
|
263
429
|
url = URI.parse url
|
264
430
|
http = Net::HTTP.new(url.host, url.port)
|
265
431
|
http.use_ssl = (url.scheme == 'https')
|
@@ -268,10 +434,24 @@ module PassiveTotal # :nodoc:
|
|
268
434
|
request = nil
|
269
435
|
if method == :GET
|
270
436
|
request = Net::HTTP::Get.new(url.request_uri)
|
271
|
-
|
437
|
+
elsif method == :POST
|
272
438
|
request = Net::HTTP::Post.new(url.request_uri)
|
439
|
+
form_data = params.to_json
|
440
|
+
request.content_type = 'application/json'
|
441
|
+
request.body = form_data
|
442
|
+
elsif method == :DELETE
|
443
|
+
request = Net::HTTP::Delete.new(url.request_uri)
|
444
|
+
form_data = params.to_json
|
445
|
+
request.content_type = 'application/json'
|
446
|
+
request.body = form_data
|
447
|
+
elsif method == :HEAD
|
448
|
+
request = Net::HTTP::Head.new(url.request_uri)
|
449
|
+
request.set_form_data(params)
|
450
|
+
elsif method == :PUT
|
451
|
+
request = Net::HTTP::Put.new(url.request_uri)
|
273
452
|
request.set_form_data(params)
|
274
453
|
end
|
454
|
+
request.basic_auth(@username, @apikey)
|
275
455
|
request.add_field("User-Agent", "Ruby/#{RUBY_VERSION} passivetotal rubygem v#{PassiveTotal::VERSION}")
|
276
456
|
t1 = Time.now
|
277
457
|
response = http.request(request)
|
@@ -280,9 +460,21 @@ module PassiveTotal # :nodoc:
|
|
280
460
|
|
281
461
|
obj = Transaction.new(
|
282
462
|
Query.new(method, params['query'], params[method] || params['tag'], url, params),
|
283
|
-
Response.new(response.body,
|
463
|
+
Response.new(response.body, response.code == '200', data),
|
284
464
|
delta
|
285
465
|
)
|
466
|
+
|
467
|
+
if data['error']
|
468
|
+
message = data['error']['message']
|
469
|
+
case message
|
470
|
+
when "API key provided does not match any user."
|
471
|
+
raise InvalidAPIKeyError.new(obj)
|
472
|
+
when "Quota has been exceeded!"
|
473
|
+
raise ExceededQuotaError.new(obj)
|
474
|
+
else
|
475
|
+
raise APIUsageError.new(obj)
|
476
|
+
end
|
477
|
+
end
|
286
478
|
|
287
479
|
return obj
|
288
480
|
end
|
@@ -302,6 +494,12 @@ module PassiveTotal # :nodoc:
|
|
302
494
|
return true if tag?(item)
|
303
495
|
elsif type == :bool
|
304
496
|
return true if bool?(item)
|
497
|
+
elsif type == :ssl_field
|
498
|
+
return true if ssl_field?(item)
|
499
|
+
elsif type == :whois_field
|
500
|
+
return true if whois_field?(item)
|
501
|
+
elsif type == :tracker_type
|
502
|
+
return true if tracker_type?(item)
|
305
503
|
end
|
306
504
|
end
|
307
505
|
return false
|
data/lib/passivetotal/cli.rb
CHANGED
@@ -20,6 +20,7 @@ module PassiveTotal # :nodoc:
|
|
20
20
|
opts = GetoptLong.new(
|
21
21
|
[ '--help', '-h', GetoptLong::NO_ARGUMENT ],
|
22
22
|
[ '--debug', '-v', GetoptLong::NO_ARGUMENT ],
|
23
|
+
[ '--username', '-u', GetoptLong::REQUIRED_ARGUMENT ],
|
23
24
|
[ '--apikey', '-k', GetoptLong::REQUIRED_ARGUMENT ],
|
24
25
|
[ '--metadata', '-m', GetoptLong::REQUIRED_ARGUMENT ],
|
25
26
|
[ '--passive', '-p', GetoptLong::REQUIRED_ARGUMENT ],
|
@@ -31,6 +32,9 @@ module PassiveTotal # :nodoc:
|
|
31
32
|
[ '--dynamic', '-d', GetoptLong::REQUIRED_ARGUMENT ],
|
32
33
|
[ '--watching', '-w', GetoptLong::REQUIRED_ARGUMENT ],
|
33
34
|
[ '--sslcertificate', '-l', GetoptLong::REQUIRED_ARGUMENT ],
|
35
|
+
[ '--ssl_history', '-H', GetoptLong::REQUIRED_ARGUMENT ],
|
36
|
+
[ '--trackers', '-T', GetoptLong::REQUIRED_ARGUMENT ],
|
37
|
+
[ '--osint', '-o', GetoptLong::REQUIRED_ARGUMENT ],
|
34
38
|
[ '--set', '-i', GetoptLong::REQUIRED_ARGUMENT ]
|
35
39
|
)
|
36
40
|
|
@@ -39,7 +43,8 @@ module PassiveTotal # :nodoc:
|
|
39
43
|
:query => nil,
|
40
44
|
:set => nil,
|
41
45
|
:debug => false,
|
42
|
-
:apikey => ENV['PASSIVETOTAL_APIKEY']
|
46
|
+
:apikey => ENV['PASSIVETOTAL_APIKEY'],
|
47
|
+
:username => ENV['PASSIVETOTAL_USERNAME']
|
43
48
|
}
|
44
49
|
|
45
50
|
opts.each do |opt, arg|
|
@@ -48,6 +53,8 @@ module PassiveTotal # :nodoc:
|
|
48
53
|
options[:method] = :usage
|
49
54
|
when '--debug'
|
50
55
|
options[:debug] = true
|
56
|
+
when '--username'
|
57
|
+
options[:username] = arg
|
51
58
|
when '--apikey'
|
52
59
|
options[:apikey] = arg
|
53
60
|
when '--metadata'
|
@@ -80,6 +87,15 @@ module PassiveTotal # :nodoc:
|
|
80
87
|
when '--sslcertificate'
|
81
88
|
options[:method] = :ssl_certificate
|
82
89
|
options[:query] = arg
|
90
|
+
when '--ssl_history'
|
91
|
+
options[:method] = :ssl_certificate_history
|
92
|
+
options[:query] = arg
|
93
|
+
when '--trackers'
|
94
|
+
options[:method] = :trackers
|
95
|
+
options[:query] = arg
|
96
|
+
when '--osint'
|
97
|
+
options[:method] = :osint
|
98
|
+
options[:query] = arg
|
83
99
|
when '--set'
|
84
100
|
options[:set] = arg.dup
|
85
101
|
else
|
@@ -100,11 +116,12 @@ module PassiveTotal # :nodoc:
|
|
100
116
|
|
101
117
|
if options[:debug]
|
102
118
|
$stderr.puts "PassiveTotal CLI Options"
|
103
|
-
$stderr.puts "
|
104
|
-
$stderr.puts "
|
105
|
-
$stderr.puts "
|
106
|
-
$stderr.puts "
|
107
|
-
$stderr.puts "
|
119
|
+
$stderr.puts " username: #{options[:username]}"
|
120
|
+
$stderr.puts " apikey: #{options[:apikey]}"
|
121
|
+
$stderr.puts " debug: #{options[:debug]}"
|
122
|
+
$stderr.puts " method: #{options[:method]}"
|
123
|
+
$stderr.puts " query: #{options[:query]}"
|
124
|
+
$stderr.puts " set: #{options[:set]}"
|
108
125
|
end
|
109
126
|
|
110
127
|
return options
|
@@ -112,9 +129,10 @@ module PassiveTotal # :nodoc:
|
|
112
129
|
|
113
130
|
# returns a string containing the usage information
|
114
131
|
def self.usage
|
115
|
-
help_text = "Usage: #{$0} [-
|
132
|
+
help_text = "Usage: #{$0} [-v] [-u <username>] [-k <apikey>] <action flag> <query> [-i <value>]\n"
|
116
133
|
help_text << "-h Help\n"
|
117
134
|
help_text << "-v Verbose output\n"
|
135
|
+
help_text << "-u <username> Sets the Username, defaults to the environment variable PASSIVETOTAL_USERNAME\n"
|
118
136
|
help_text << "-k <apikey> Sets the APIKEY, defaults to the environment variable PASSIVETOTAL_APIKEY\n"
|
119
137
|
help_text << "ACTIONS (You have to select one, last one wins)"
|
120
138
|
help_text << " -m <ip or dom> Queries metadata for given IP or domain\n"
|
@@ -127,11 +145,14 @@ module PassiveTotal # :nodoc:
|
|
127
145
|
help_text << " -s <dom> Queries the subdomains for a given domain\n"
|
128
146
|
help_text << " -d <dom> Queries (or sets) if a domain is a dynamic DNS domain\n"
|
129
147
|
help_text << " -x <ip> Queries (or sets) if a given IP is a sinkhole\n"
|
130
|
-
help_text << " -l <
|
148
|
+
help_text << " -l <hash> Queries for SSL certificates/IP addresses associated with a given SHA-1 hash\n"
|
149
|
+
help_text << " -H <ip or hash> Queries for SSL certificate history associated with a given IP or SHA-1 hash\n"
|
150
|
+
help_text << " -T <ip or dom> Queries for Tracker information associated with a given IP or domain\n"
|
151
|
+
help_text << " -o <ip or dom> Queries for OSINT on a given IP or domain\n"
|
131
152
|
help_text << "SETTING VALUES"
|
132
153
|
help_text << " -i <value> Sets the value, used in conjuntion with -c, -t, -e, -w, -d, or -x\n"
|
133
154
|
help_text << " Valid values for -i depend on what it's used with:\n"
|
134
|
-
help_text << " -c :
|
155
|
+
help_text << " -c : malicious, non-malicious, suspicious, unknown\n"
|
135
156
|
help_text << " -t : <a tag name consisting of characters: [a-zA-Z_]>\n"
|
136
157
|
help_text << " -e, -w, -d, -x: true, false\n"
|
137
158
|
help_text
|
@@ -141,14 +162,14 @@ module PassiveTotal # :nodoc:
|
|
141
162
|
def self.run(args)
|
142
163
|
options = parse_command_line(args)
|
143
164
|
return usage() if options[:method] == :usage
|
144
|
-
pt = PassiveTotal::API.new(options[:apikey])
|
165
|
+
pt = PassiveTotal::API.new(options[:username], options[:apikey])
|
145
166
|
if pt.respond_to?(options[:method])
|
146
167
|
if options[:set]
|
147
168
|
data = pt.send(options[:method], options[:query], options[:set])
|
148
169
|
else
|
149
170
|
data = pt.send(options[:method], options[:query])
|
150
171
|
end
|
151
|
-
data.response.results['response_time'] = data.
|
172
|
+
data.response.results['response_time'] = data.response_time
|
152
173
|
return JSON.pretty_generate(data.response.results)
|
153
174
|
end
|
154
175
|
return ''
|
data/lib/passivetotal/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: passivetotal
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- chrislee35
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-02-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: json
|