passivetotal 0.2.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|