Giter VIP home page Giter VIP logo

fierce's Introduction

Fierce

CI Coverage Status Dlint Python Versions PyPI Version

Fierce is a DNS reconnaissance tool for locating non-contiguous IP space.

Useful links:

Overview

First, credit where credit is due, fierce was originally written by RSnake along with others at http://ha.ckers.org/. This is simply a conversion to Python 3 to simplify and modernize the codebase.

The original description was very apt, so I'll include it here:

Fierce is a semi-lightweight scanner that helps locate non-contiguous IP space and hostnames against specified domains. It's really meant as a pre-cursor to nmap, unicornscan, nessus, nikto, etc, since all of those require that you already know what IP space you are looking for. This does not perform exploitation and does not scan the whole internet indiscriminately. It is meant specifically to locate likely targets both inside and outside a corporate network. Because it uses DNS primarily you will often find mis-configured networks that leak internal address space. That's especially useful in targeted malware.

Installing

$ python -m pip install fierce
$ fierce -h

OR

$ git clone https://github.com/mschwager/fierce.git
$ cd fierce
$ python -m pip install -r requirements.txt
$ python fierce/fierce.py -h

Requires Python 3.

Using

Let's start with something basic:

$ fierce --domain google.com --subdomains accounts admin ads

Traverse IPs near discovered domains to search for contiguous blocks with the --traverse flag:

$ fierce --domain facebook.com --subdomains admin --traverse 10

Limit nearby IP traversal to certain domains with the --search flag:

$ fierce --domain facebook.com --subdomains admin --search fb.com fb.net

Attempt an HTTP connection on domains discovered with the --connect flag:

$ fierce --domain stackoverflow.com --subdomains mail --connect

Exchange speed for breadth with the --wide flag, which looks for nearby domains on all IPs of the /24 of a discovered domain:

$ fierce --domain facebook.com --wide

Zone transfers are rare these days, but they give us the keys to the DNS castle. zonetransfer.me is a very useful service for testing for and learning about zone transfers:

$ fierce --domain zonetransfer.me

To save the results to a file for later use we can simply redirect output:

$ fierce --domain zonetransfer.me > output.txt

Internal networks will often have large blocks of contiguous IP space assigned. We can scan those as well:

$ fierce --dns-servers 10.0.0.1 --range 10.0.0.0/24

Check out --help for further information:

$ fierce --help

Developing

First, install development packages:

$ python -m pip install -r requirements.txt
$ python -m pip install -r requirements-dev.txt
$ python -m pip install -e .

Testing

$ pytest

Linting

$ flake8

Coverage

$ pytest --cov

fierce's People

Contributors

2xyo avatar m6sec avatar maxkrivich avatar mmiszczyk avatar mschwager avatar radarhere avatar takeshixx avatar timmc avatar tylerkerr avatar z0mbiehunt3r avatar zeedo avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

fierce's Issues

Problem with subdomains and wildcard failure

If the wildcard fails, its type is None
Consequently, this generates an error when each a A query is made on each subdomain because fierce verify the A query result is None or if the found address is the same as the wildcard (which is None here).

Zone transfert not working when DNS is badly configured

Hello,

Found out during a challenge on HackTheBox that when the DNS resolution is pointing to localhost (127.0.0.1), fierce is not able to perform a zone transfert even if zone transfert is possible with dig.
It could happen in a real engagement too.

I updated the code in my PR

ConnectionRefusedError: [Errno 111] Connection refused

Please see the below query.

$fierce --domain facebook.com --wide

NS: a.ns.facebook.com. b.ns.facebook.com.
SOA: a.ns.facebook.com. (69.171.239.12)
Traceback (most recent call last):
  File "/usr/local/bin/fierce", line 11, in <module>
    sys.exit(main())
  File "/usr/local/lib/python3.4/dist-packages/fierce.py", line 284, in main
    fierce(**vars(args))
  File "/usr/local/lib/python3.4/dist-packages/fierce.py", line 185, in fierce
    zone = zone_transfer(master_address, domain)
  File "/usr/local/lib/python3.4/dist-packages/fierce.py", line 110, in zone_transfer
    return dns.zone.from_xfr(dns.query.xfr(address, domain))
  File "/usr/lib/python3/dist-packages/dns/zone.py", line 979, in from_xfr
    for r in xfr:
  File "/usr/lib/python3/dist-packages/dns/query.py", line 412, in xfr
    _net_write(s, tcpmsg, expiration)
  File "/usr/lib/python3/dist-packages/dns/query.py", line 260, in _net_write
    current += sock.send(data[current:])
ConnectionRefusedError: [Errno 111] Connection refused

No idea what causes the error. May be an issue with port number?
Using Python3 on Ubuntu 14.04

TypeError: 'NoneType' object is not subscriptable

File "/usr/local/bin/fierce", line 9, in
load_entry_point('fierce==1.0', 'console_scripts', 'fierce')()
File "/usr/local/lib/python3.5/site-packages/fierce-1.0-py3.5.egg/fierce.py", line 235, in main
File "/usr/local/lib/python3.5/site-packages/fierce-1.0-py3.5.egg/fierce.py", line 137, in fierce
TypeError: 'NoneType' object is not subscriptable

Socket errors with --connect option

Hey guys!

There are several errors when using the --connect page due to the non existence of error handling in the head_request class.

To avoid connection timeouts i have added a two seconds timeout for each domain, and i have additionally passed every exception occuring (there will be at leas two errors at the current script:

  1. ConnectionRefusedError
  2. ConnectionTimedoutError

I have changed the code a bit as a suggestion, for the usability i'd handle the exceptions accordingly and maybe set the timeout as an argument for the user :-)

def head_request(url):
try:
conn = http.client.HTTPConnection(url,timeout=2)
conn.request("HEAD", "/")
except:
return []
resp = conn.getresponse()
conn.close()

best

Patrik

File 'lists/default.txt' missing

Traceback (most recent call last):
File "fierce.py", line 239, in
main()
File "fierce.py", line 236, in main
fierce(**vars(args))
File "fierce.py", line 157, in fierce
subdomains = [sd.strip() for sd in open(kwargs["subdomain_file"]).readlines()]
FileNotFoundError: [Errno 2] No such file or directory: 'lists/default.txt'

The script does not create the file if it does not already exist. Also it seems to be specified by a relative path - if one installs this via pip, presumably this is intended to be executed from any directory, and the relative path would prevent that I think.

stack trace during nearby ip sweep

It looks like when fierce gets something in a dns response it can't parse it breaks..
here's a sanitized version of the cmdline and immediate error results:

./fierce.py --domain asdfasdf.com 
NS: asdfasdf.net. asdfasdf.net.
SOA: asdfasdf.net. (x.x.x.x)
Zone: failure
Wildcard: failure
Found: asdfasdf.asdfasd (x.x.x.x)
Nearby:
{'x.x.x.x': 'x.x.x-120.asdf.asdfasdfk.net.',
 'x.x.x.121': 'x.x.x-121.asdf.asdfasdfk.net.',
 'x.x.x.122': 'x.x.x-122.asdf.asdfasdfk.net.',
 'x.x.x.123': 'x.x.x-123.asdf.asdfasdfk.net.',
 'x.x.x.124': 'x.x.x-124.asdf.asdfasdfk.net.',
 'x.x.x.125': 'x.x.x-125.asdf.kjh.net.',
 'x.x.x.126': 'x.x.x-126.asdf.kjh.net.',
 'x.x.x.127': 'x.x.x-127.asdf.kjh.net.',
 'x.x.x.128': 'x.x.x-128.asdf.kjh.net.',
 'x.x.x.129': 'x.x.x-129.asdf.kjh.net.',
 'x.x.x.130': 'x.x.x-130.asdf.asdfasdfk.net.'}
Traceback (most recent call last):
  File "/usr/local/lib/python3.5/site-packages/dns/resolver.py", line 126, in __init__
    rdclass, rdtype)
  File "/usr/local/lib/python3.5/site-packages/dns/message.py", line 340, in find_rrset
    raise KeyError
KeyError

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/local/lib/python3.5/site-packages/dns/resolver.py", line 136, in __init__
    dns.rdatatype.CNAME)
  File "/usr/local/lib/python3.5/site-packages/dns/message.py", line 340, in find_rrset
    raise KeyError
KeyError

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "./fierce.py", line 210, in <module>
    main()
  File "./fierce.py", line 207, in main
    fierce(**vars(args))
  File "./fierce.py", line 134, in fierce
    record = query(resolver, url, record_type='A')
  File "./fierce.py", line 33, in query
    return resolver.query(domain, record_type)
  File "/usr/local/lib/python3.5/site-packages/dns/resolver.py", line 910, in query
    raise_on_no_answer)
  File "/usr/local/lib/python3.5/site-packages/dns/resolver.py", line 145, in __init__
    raise NoAnswer
dns.resolver.NoAnswer

Version number

It would help if you added a version number and a change log. This would make it easier for the Kali Linux dev team to track.

Traverse expander breaks on IP addresses close to zero

The traverse expander subtracts small numbers from an IP address and constructs new IPs from the results. This breaks when the result goes negative, e.g. traversing backwards from 0.0.0.0.

I had a little trouble reproducing this, but if you have a subdomain that is a CNAME of a domain that resolves to 0.0.0.0, you'll get a stack trace like this:

Traceback (most recent call last):
  File "./fierce/fierce.py", line 486, in <module>
    main()
  File "./fierce/fierce.py", line 480, in main
    fierce(**vars(args))
  File "./fierce/fierce.py", line 373, in fierce
    ips = expander_func(ip)
  File "./fierce/fierce.py", line 173, in traverse_expander
    result = [ipaddress.IPv4Address(ip + i) for i in range(-n, n + 1)]
  File "./fierce/fierce.py", line 173, in <listcomp>
    result = [ipaddress.IPv4Address(ip + i) for i in range(-n, n + 1)]
  File "/usr/lib/python3.5/ipaddress.py", line 575, in __add__
    return self.__class__(int(self) + other)
  File "/usr/lib/python3.5/ipaddress.py", line 1269, in __init__
    self._check_int_address(address)
  File "/usr/lib/python3.5/ipaddress.py", line 420, in _check_int_address
    raise AddressValueError(msg % (address, self._version))
ipaddress.AddressValueError: -5 (< 0) is not permitted as an IPv4 address

I don't have a public domain I can share for this, but if you CNAME something to qa.cloudapp.net it should do the trick. :-)

Timeout from DNS resolver crashes program

If the DNS resolver gets a timeout, the program crashes:

  File "./fierce.py", line 408, in <module>
    main()
  File "./fierce.py", line 405, in main
    fierce(**vars(args))
  File "./fierce.py", line 285, in fierce
    record = query(resolver, url, record_type='A')
  File "./fierce.py", line 96, in query
    resp = resolver.query(domain, record_type, raise_on_no_answer=False)
  File "/usr/local/lib/python3.4/dist-packages/dns/resolver.py", line 1041, in query
    timeout = self._compute_timeout(start)
  File "/usr/local/lib/python3.4/dist-packages/dns/resolver.py", line 858, in _compute_timeout
    raise Timeout(timeout=duration)
dns.exception.Timeout: The DNS operation timed out after 30.00057625770569 seconds

I don't see a way to prevent that, but perhaps exceptions raised for any one subdomain should be reported and suppressed so the program can continue to run.

Problem for two subdomains separated by dot with --subdomain-file

When I use --subdomain-file with subdomains each composed of two subdomains separated by a dot (e.g. "toto.tata"), I do not get an answer.
By putting some print inside fierce, I found that the problem comes from this line : "result = dns.name.Name(tuple(subdomains) + domain.labels)".
It replaces dots in subdomains by ".".
For example, the subdomain "toto.tata" becomes "toto.tata" which causes the DNS request to fail.

Is this an expected behavior ?
Am I not supposed to use the --subdomain-file option with this kind of input?

TypeError: 'float' object cannot be interpreted as an integer

Got this error:

$ fierce --domain example.com
NS: a.iana-servers.net. b.iana-servers.net.
SOA: ns.icann.org. (199.4.138.53)
Zone: failure
Traceback (most recent call last):
  File "/usr/bin/fierce", line 33, in <module>
    sys.exit(load_entry_point('fierce==1.5.0', 'console_scripts', 'fierce')())
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/site-packages/fierce-1.5.0-py3.12.egg/fierce/fierce.py", line 495, in main
    fierce(**vars(args))
  File "/usr/lib/python3.12/site-packages/fierce-1.5.0-py3.12.egg/fierce/fierce.py", line 338, in fierce
    random_subdomain = str(random.randint(1e10, 1e11))  # noqa DUO102, non-cryptographic random use
                           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/random.py", line 336, in randint
    return self.randrange(a, b+1)
           ^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/random.py", line 301, in randrange
    istart = _index(start)
             ^^^^^^^^^^^^^
TypeError: 'float' object cannot be interpreted as an integer

Fixed it by replacing:

random_subdomain = str(random.randint(1e10, 1e11)) 

by

random_subdomain = str(random.randint(10000000000, 99999999999))

The line is:

random_subdomain = str(random.randint(1e10, 1e11)) # noqa DUO102, non-cryptographic random use

`dns.name.EmptyLabel` stack trace

I received this using fierce 1.1.5 (installed via python3-pip) when doing a basic scan of my domain, brainonfire.net, with the 20k subdomain list:

Traceback (most recent call last):
  File "/usr/local/bin/fierce", line 11, in <module>
    sys.exit(main())
  File "/usr/local/lib/python3.4/dist-packages/fierce.py", line 405, in main
    fierce(**vars(args))
  File "/usr/local/lib/python3.4/dist-packages/fierce.py", line 284, in fierce
    url = concatenate_subdomains(domain, [subdomain])
  File "/usr/local/lib/python3.4/dist-packages/fierce.py", line 86, in concatenate_subdomains
    result = dns.name.Name(tuple(subdomains) + domain.labels)
  File "/usr/local/lib/python3.4/dist-packages/dns/name.py", line 329, in __init__
    _validate_labels(self.labels)
  File "/usr/local/lib/python3.4/dist-packages/dns/name.py", line 299, in _validate_labels
    raise EmptyLabel
dns.name.EmptyLabel: A DNS label is empty.

Zone transfer error: REFUSED / NOTAUTH

I'm using the latest git and facing the following issue:

fierce --domain itdefence.asia
NS: ns-77-a.gandi.net. ns-187-b.gandi.net. ns-216-c.gandi.net.
SOA: ns1.gandi.net. (173.246.98.2)
Traceback (most recent call last):
  File "/usr/lib/python-exec/python3.5/fierce", line 11, in <module>
    load_entry_point('fierce==1.2.0', 'console_scripts', 'fierce')()
  File "/usr/lib64/python3.5/site-packages/fierce/fierce.py", line 389, in main
    fierce(**vars(args))
  File "/usr/lib64/python3.5/site-packages/fierce/fierce.py", line 248, in fierce
    zone = zone_transfer(master_address, domain)
  File "/usr/lib64/python3.5/site-packages/fierce/fierce.py", line 120, in zone_transfer
    return dns.zone.from_xfr(dns.query.xfr(address, domain))
  File "/usr/lib64/python3.5/site-packages/dns/zone.py", line 1063, in from_xfr
    for r in xfr:
  File "/usr/lib64/python3.5/site-packages/dns/query.py", line 611, in xfr
    raise TransferError(rcode)
dns.query.TransferError: Zone transfer error: NOTAUTH

I have also seen the "REFUSED" error message with an another domain.

Please also note that I'm using the latest git of dnspython:
dev-python/dnspython-1.16.0_pre20170831

NoneType issues when using DNS file

Here are the raw errors with '...' denoting omitted info:

abraxas@AttackVM:~/recon/fierce$ python3 fierce.py --domain cnn.com --subdomain-file default.txt
.....

Found: access.cnn.com. (64.20.247.69)
Nearby:
{'64.20.247.64': 'mail3.access.cnn.com.'}
Found: alerts.cnn.com. (151.101.24.73)
Found: asia.cnn.com. (157.166.249.13)
Found: at.cnn.com. (157.166.226.26)
Nearby:
{'157.166.226.22': 'io.cnn.net.',
...
}
Traceback (most recent call last):
  File "fierce.py", line 301, in <module>
    main()
  File "fierce.py", line 298, in main
    fierce(**vars(args))
  File "fierce.py", line 223, in fierce
    ip = ipaddress.IPv4Address(record[0].address)
  File "/home/abraxas/.local/lib/python3.5/site-packages/dns/resolver.py", line 192, in __getitem__
    return self.rrset[i]
TypeError: 'NoneType' object is not subscriptable

Another example:

abraxas@AttackVM:~/recon/fierce$ python3 fierce.py --domain .... --subdomain-file default.txt
SOA: ns0.dnsmadeeasy.com. (208.94.148.2)
Zone: failure
Wildcard: failure
Found: backup.....com. 
Nearby:
Traceback (most recent call last):
  File "fierce.py", line 301, in <module>
    main()
  File "fierce.py", line 298, in main
    fierce(**vars(args))
  File "fierce.py", line 246, in fierce
    find_nearby(resolver, ips, filter_func=filter_func)
  File "fierce.py", line 162, in find_nearby
    pprint.pprint({k: v[0].to_text() for k, v in reversed_ips.items() if v})
  File "fierce.py", line 162, in <dictcomp>
    pprint.pprint({k: v[0].to_text() for k, v in reversed_ips.items() if v})
  File "/home/abraxas/.local/lib/python3.5/site-packages/dns/resolver.py", line 186, in __len__
    return len(self.rrset)
TypeError: object of type 'NoneType' has no len()

I cannot get any scans using the files to finish.

Doen't work with cloudflare DNS

netwrkspider@linuxzone:~/fierce$ ./fierce.py --domain 00studios.com --subdomains accounts admin ads
NS: rose.ns.cloudflare.com. nick.ns.cloudflare.com.
SOA: nick.ns.cloudflare.com. (173.245.59.213)
Zone: failure
Wildcard: failure

Zone: failure & Wildcard: failure

When i tru to run the following command fierce --domain example.com --subdomain-file "/usr/share/dirbuster/wordlists/directory-list-2.3-medium.txt" --traverse 255 i get the below err

NS: ns-722.awsdns-26.net. ns-1475.awsdns-56.org. ns-440.awsdns-55.com. ns-1574.awsdns-04.co.uk.
SOA: ns-440.awsdns-55.com. (205.251.193.184)
Zone: failure
Wildcard: failure
Traceback (most recent call last):
  File "/usr/local/bin/fierce", line 8, in <module>
    sys.exit(main())
  File "/usr/local/lib/python3.8/dist-packages/fierce/fierce.py", line 486, in main
    fierce(**vars(args))
  File "/usr/local/lib/python3.8/dist-packages/fierce/fierce.py", line 358, in fierce
    url = concatenate_subdomains(domain, [subdomain])
  File "/usr/local/lib/python3.8/dist-packages/fierce/fierce.py", line 103, in concatenate_subdomains
    result = dns.name.Name(tuple(subdomains) + domain.labels)
  File "/usr/local/lib/python3.8/dist-packages/dns/name.py", line 335, in __init__
    _validate_labels(self.labels)
  File "/usr/local/lib/python3.8/dist-packages/dns/name.py", line 295, in _validate_labels
    raise LabelTooLong
dns.name.LabelTooLong: A DNS label is > 63 octets long.

Timeout during AXFR

I frequently receive a timeout during the zone transfer step that kills fierce. The program hangs for several minutes after printing the SOA, then crashes with the following:

Traceback (most recent call last):
  File "./fierce.py", line 409, in <module>
    main()
  File "./fierce.py", line 406, in main
    fierce(**vars(args))
  File "./fierce.py", line 266, in fierce
    zone = zone_transfer(master_address, domain)
  File "./fierce.py", line 138, in zone_transfer
    return dns.zone.from_xfr(dns.query.xfr(address, domain))
  File "/usr/lib/python3/dist-packages/dns/zone.py", line 979, in from_xfr
    for r in xfr:
  File "/usr/lib/python3/dist-packages/dns/query.py", line 412, in xfr
    _net_write(s, tcpmsg, expiration)
  File "/usr/lib/python3/dist-packages/dns/query.py", line 260, in _net_write
    current += sock.send(data[current:])
TimeoutError: [Errno 110] Connection timed out

This is on current master (9334f0f) but was present in 1.1.5 as well.

FileNotFoundError: [Errno 2] No such file or directory: 'default.txt'

Hi, I have installed the tool as system module using provided setup.py. It installed .txt files into "/usr" prefix as below:

/usr/lists/20000.txt
/usr/lists/5000.txt
/usr/lists/default.txt

The tool is unable to find that location and fails with the following error:

bash$ fierce --domain facebook.com --wide
NS: b.ns.facebook.com. a.ns.facebook.com.
SOA: a.ns.facebook.com. (69.171.239.12)
Zone: failure
Wildcard: failure
Traceback (most recent call last):
  File "/usr/lib/python-exec/python3.5/fierce", line 11, in <module>
    load_entry_point('fierce==1.2.0', 'console_scripts', 'fierce')()
  File "/usr/lib64/python3.5/site-packages/fierce.py", line 405, in main
    fierce(**vars(args))
  File "/usr/lib64/python3.5/site-packages/fierce.py", line 278, in fierce
    kwargs["subdomain_file"]
  File "/usr/lib64/python3.5/site-packages/fierce.py", line 201, in get_subdomains
    return get_stripped_file_lines(subdomain_filename)
  File "/usr/lib64/python3.5/site-packages/fierce.py", line 189, in get_stripped_file_lines
    return [line.strip() for line in open(filename).readlines()]
FileNotFoundError: [Errno 2] No such file or directory: 'default.txt'

The problem seems with find_subdomain_list_file function as it tries to find that location in the current directly only.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.