Coder Social home page Coder Social logo

ex0dus-0x / fuzzable Goto Github PK

View Code? Open in Web Editor NEW
503.0 12.0 53.0 1.48 MB

Framework for Automating Fuzzable Target Discovery with Static Analysis. Featured at Black Hat Arsenal USA 2022.

License: MIT License

Python 94.01% C++ 5.56% Dockerfile 0.43%
fuzzing reverse-engineering security security-tools static-analysis binary-analysis

fuzzable's Introduction

Fuzzable

Build Status PyPI version Blackhat

Framework for Automating Fuzzable Target Discovery with Static Analysis

example

Introduction

Vulnerability researchers conducting security assessments on software will often harness the capabilities of coverage-guided fuzzing through powerful tools like AFL++ and libFuzzer. This is important as it automates the bughunting process and reveals exploitable conditions in targets quickly. However, when encountering large and complex codebases or closed-source binaries, researchers have to painstakingly dedicate time to manually audit and reverse engineer them to identify functions where fuzzing-based exploration can be useful.

Fuzzable is a framework that integrates both with C/C++ source code and binaries to assist vulnerability researchers in identifying function targets that are viable for fuzzing. This is done by applying several static analysis-based heuristics to pinpoint risky behaviors in the software and the functions that executes them. Researchers can then utilize the framework to generate basic harness templates, which can then be used to hunt for vulnerabilities, or to be integrated as part of a continuous fuzzing pipeline, such as Google's oss-fuzz project.

In addition to running as a standalone tool, Fuzzable is also integrated as a plugin for the Binary Ninja disassembler, with support for other disassembly backends being developed.

Check out the original blog post detailing the tool here, which highlights the technical specifications of the static analysis heuristics and how this tool came about. This tool is also featured at Black Hat Arsenal USA 2022.

Features

  • Supports analyzing binaries (with Angr and Binary Ninja) and source code artifacts (with tree-sitter).
  • Run static analysis both as a standalone CLI tool or a Binary Ninja plugin.
  • Harness generation to ramp up on creating fuzzing campaigns quickly.

Installation

Some binary targets may require some sanitizing (ie. signature matching, or identifying functions from inlining), and therefore fuzzable primarily uses Binary Ninja as a disassembly backend because of it's ability to effectively solve these problems. Therefore, it can be utilized both as a standalone tool and plugin.

Since Binary Ninja isn't accessible to all and there may be a demand to utilize for security assessments and potentially scaling up in the cloud, an angr fallback backend is also supported. I anticipate to incorporate other disassemblers down the road as well (priority: Ghidra).

Command Line (Standalone)

If you have Binary Ninja Commercial, be sure to install the API for standalone headless usage:

$ python3 /Applications/Binary\ Ninja.app/Contents/Resources/scripts/install_api.py

Install with pip:

$ pip install fuzzable

Manual/Development Build

We use poetry for dependency management and building. To do a manual build, clone the repository with the third-party modules:

$ git clone --recursive https://github.com/ex0dus-0x/fuzzable

To install manually:

$ cd fuzzable/

# without poetry
$ pip install .

# with poetry
$ poetry install

# with poetry for a development virtualenv
$ poetry shell

You can now analyze binaries and/or source code with the tool!

# analyzing a single shared object library binary
$ fuzzable analyze examples/binaries/libbasic.so

# analyzing a single C source file
$ fuzzable analyze examples/source/libbasic.c

# analyzing a workspace with multiple C/C++ files and headers
$ fuzzable analyze examples/source/source_bundle/

Binary Ninja Plugin

fuzzable can be easily installed through the Binary Ninja plugin marketplace by going to Binary Ninja > Manage Plugins and searching for it. Here is an example of the fuzzable plugin running, accuracy identifying targets for fuzzing and further vulnerability assessment:

binja_example

Usage

fuzzable comes with various options to help better tune your analysis. More will be supported in future plans and any feature requests made.

Static Analysis Heuristics

To determine fuzzability, fuzzable utilize several heuristics to determine which targets are the most viable to target for dynamic analysis. These heuristics are all weighted differently using the scikit-criteria library, which utilizes multi-criteria decision analysis to determine the best candidates. These metrics and are there weights can be seen here:

Heuristic Description Weight
Fuzz Friendly Name Symbol name implies behavior that ingests file/buffer input 0.3
Risky Sinks Arguments that flow into risky calls (ie memcpy) 0.3
Natural Loops Number of loops detected with the dominance frontier 0.05
Cyclomatic Complexity Complexity of function target based on edges + nodes 0.05
Coverage Depth Number of callees the target traverses into 0.3

As mentioned, check out the technical blog post for a more in-depth look into why and how these metrics are utilized.

Many metrics were largely inspired by Vincenzo Iozzo's original work in 0-knowledge fuzzing.

Every targets you want to analyze is diverse, and fuzzable will not be able to account for every edge case behavior in the program target. Thus, it may be important during analysis to tune these weights appropriately to see if different results make more sense for your use case. To tune these weights in the CLI, simply specify the --score-weights argument:

$ fuzzable analyze <TARGET> --score-weights=0.2,0.2,0.2,0.2,0.2

Analysis Filtering

By default, fuzzable will filter out function targets based on the following criteria:

  • Top-level entry calls - functions that aren't called by any other calls in the target. These are ideal entry points that have potentially very high coverage.
  • Static calls - (source only) functions that are static and aren't exposed through headers.
  • Imports - (binary only) other library dependencies being used by the target's implementations.

To see calls that got filtered out by fuzzable, set the --list_ignored flag:

$ fuzzable analyze --list-ignored <TARGET>

In Binary Ninja, you can turn this setting in Settings > Fuzzable > List Ignored Calls.

In the case that fuzzable falsely filters out important calls that should be analyzed, it is recommended to use --include-* arguments to include them during the run:

# include ALL non top-level calls that were filtered out
$ fuzzable analyze --include-nontop <TARGET>

# include specific symbols that were filtered out
$ fuzzable analyze --include-sym <SYM> <TARGET>

In Binary Ninja, this is supported through Settings > Fuzzable > Include non-top level calls and Symbols to Exclude.

Harness Generation

Now that you have found your ideal candidates to fuzz, fuzzable will also help you generate fuzzing harnesses that are (almost) ready to instrument and compile for use with either a file-based fuzzer (ie. AFL++, Honggfuzz) or in-memory fuzzer (libFuzzer). To do so in the CLI:

# generate harness from a candidate
$ fuzzable create-harness target --symbol-name=some_unsafe_call

# make minimal and necessary modifications to the harness
$ vim target_some_unsafe_call_harness.cpp

# example compilation for AFL-QEMU, which is specified in the comments of the generated harness
$ clang target_some_unsafe_call_harness.cpp -no-pie -o target_some_unsafe_call_harness -ldl

# create your base seeds, ideally should be more well-formed for input
$ mkdir in/
$ echo "seed" >> in/seed

# start black box fuzzing
$ afl-fuzz -Q -m none -i in/ -o out/ -- ./target_some_unsafe_call_harness

If this target is a source codebase, the generic source template will be used.

If the target is a binary, the generic black-box template will be used, which ideally can be used with a fuzzing emulation mode like AFL-QEMU. A copy of the binary will also be created as a shared object if the symbol isn't exported directly to be dlopened using LIEF.

At the moment, this feature is quite rudimentary, as it simply will create a standalone C++ harness populated with the appropriate parameters, and will not auto-generate code that is needed for any runtime behaviors (ie. instantiating and freeing structures). However, the templates created for fuzzable should get still get you running quickly. Here are some ambitious features I would like to implement down the road:

  • Full harness synthesis - harnesses will work directly with absolutely no manual changes needed.
  • Synthesis from potential unit tests using the DeepState framework (Source only).
  • Immediate deployment to a managed continuous fuzzing fleet.

Exporting Reports

fuzzable supports generating reports in various formats. The current ones that are supported are JSON, CSV and Markdown. This can be useful if you are utilizing this as part of automation where you would like to ingest the output in a serializable format.

In the CLI, simply pass the --export argument with a filename with the appropriate extension:

$ fuzzable analyze --export=report.json <TARGET>

In Binary Ninja, go to Plugins > Fuzzable > Export Fuzzability Report > ... and select the format you want to export to and the path you want to write it to.

Contributing

This tool will be continuously developed, and any help from external mantainers are appreciated!

  • Create an issue for feature requests or bugs that you have come across.
  • Submit a pull request for fixes and enhancements that you would like to see contributed to this tool.

License

Fuzzable is licensed under the MIT License.

fuzzable's People

Contributors

bstee615 avatar dependabot[bot] avatar ex0dus-0x avatar marsh-sudo avatar mbhatt1 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

fuzzable's Issues

Harness generation support for C/C++ source

We currently don't support this even though a very basic template exists in templates/linux_source_harness.cpp. When supporting this feature for source, we could approach this as so:

  1. Find the best unit test function candidate that maxmimizes coverage into the fuzzing target we want to generate a harness for.
  2. Extract the implementation of the test and create a DeepState harness from it, or maybe just stick it inside the basic template we already have.
  3. If unable to, return our basic template with enough information we can fill in.

binary reverse error

I can't find function sub_4094ba/sub_41de3a/sub_409149 on IDA.
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┓
┃ Function Signature ┃ Location ┃ Fuzzability Score ┃ Fuzz-Friendly Name ┃ Risky Data Sinks ┃ Natural Loops ┃ Cyclomatic Complexity ┃ Coverage Depth ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━┩
│ main │ 0x406c40 │ 17.05 │ 0 │ 55 │ 1.0 │ 0.0 │ 10 │
│ sub_4094ba │ 0x4094ba │ 8.511538461538462 │ 0 │ 28 │ 0.9538461538461539 │ 0.046153846153846156 │ 1 │
│ sub_41de3a │ 0x41de3a │ 3.8538461538461535 │ 0 │ 12 │ 0.38461538461538464 │ 0.6153846153846154 │ 1 │
│ sub_409149 │ 0x409149 │ 3.3038461538461537 │ 0 │ 10 │ 0.18461538461538463 │ 0.8153846153846154 │ 1 │
│ sub_41949f │ 0x41949f │ 3.0192307692307687 │ 0 │ 9 │ 0.12307692307692308 │ 0.8769230769230769 │ 1 │
│ sub_41743b │ 0x41743b │ 2.4269230769230767 │ 0 │ 7 │ 0.09230769230769231 │ 0.9076923076923077 │ 1 │
│ sub_41b6c0 │ 0x41b6c0 │ 2.4269230769230767 │ 0 │ 7 │ 0.09230769230769231 │ 0.9076923076923077 │ 1 │
│ sub_41dc22 │ 0x41dc22 │ 2.4153846153846152 │ 0 │ 7 │ 0.13846153846153847 │ 0.8615384615384616 │ 1 │
│ sub_407083 │ 0x407083 │ 2.1307692307692307 │ 0 │ 6 │ 0.07692307692307693 │ 0.9230769230769231 │ 1 │
│ sub_409809 │ 0x409809 │ 2.1307692307692307 │ 0 │ 6 │ 0.07692307692307693 │ 0.9230769230769231 │ 1 │
│ sub_416834 │ 0x416834 │ 2.1307692307692307 │ 0 │ 6 │ 0.07692307692307693 │ 0.9230769230769231 │ 1 │
│ sub_417e12 │ 0x417e12 │ 2.1307692307692307 │ 0 │ 6 │ 0.07692307692307693 │ 0.9230769230769231 │ 1 │
│ sub_41dfac │ 0x41dfac │ 2.1307692307692307 │ 0 │ 6 │ 0.07692307692307693 │ 0.9230769230769231 │ 1 │
│ sub_41db42 │ 0x41db42 │ 2.1192307692307693 │ 0 │ 6 │ 0.12307692307692308 │ 0.8769230769230769 │ 1 │
│ sub_414b28 │ 0x414b28 │ 1.8346153846153845 │ 0 │ 5 │ 0.06153846153846154 │ 0.9384615384615385 │ 1 │
│ sub_41bf75 │ 0x41bf75 │ 1.8346153846153845 │ 0 │ 5 │ 0.06153846153846154 │ 0.9384615384615385 │ 1 │
│ sub_41c245 │ 0x41c245 │ 1.8346153846153845 │ 0 │ 5 │ 0.06153846153846154 │ 0.9384615384615385 │ 1 │
│ sub_41c515 │ 0x41c515 │ 1.8346153846153845 │ 0 │ 5 │ 0.06153846153846154 │ 0.9384615384615385 │ 1 │
│ sub_41cf12 │ 0x41cf12 │ 1.8346153846153845 │ 0 │ 5 │ 0.06153846153846154 │ 0.9384615384615385 │ 1 │

Grammar Error in __init__.py

this commit breaks plugin.

you need to change

Settings().register_setting(
    "fuzzable.score_weights",
    """
    {
        "title"         : "Override Score Weights",
        "description"   : "Change default score weights for each metric.",
        "type"          : "array",
        "elementType"   : "string",
        "default"       : {}
    }
""".format(
        DEFAULT_SCORE_WEIGHTS
    ),
)

to

Settings().register_setting(
    "fuzzable.score_weights",
    """
    {{
        "title"         : "Override Score Weights",
        "description"   : "Change default score weights for each metric.",
        "type"          : "array",
        "elementType"   : "string",
        "default"       : {}
    }}
""".format(
        DEFAULT_SCORE_WEIGHTS
    ),
)

Sorry, I don't have time to make PR, but I wanted to let you know.

Repeated calculation of angr CFGFasr leads to low running efficiency and high memory consumption when there are too many function

in AngrAnalysis.init()
self.cfg = self.target.analyses.CFG(
resolve_indirect_jumps=True,
cross_references=True,
force_complete_scan=False,
normalize=True,
symbols=True,
)

the edges of functions is already in self.cfg
the way to get edges of function are followings

for func in self.cfg.functions.values():
print(func.addr, len(func.transition_graph.edges))

so I think the code of function get_cyclomatic_complexity(),

cfg = self.target.analyses.CFGFast(
force_complete_scan=False, start_at_entry=hex(func.addr)
)

This code uses CFGFast to recalculate edges for each function.
Leading to low running efficiency and high memory consumption when there are too many function.

Can we optimize this :)

                                                                                                                                                                                Best regards
                                                                                                                                                                                       XZJ 

windows

Can this tool be applied to Windows? Thanks!

ModuleNotFoundError: No module named 'binaryninja'

C:\Users\user\Desktop\fuzz\png>fuzzable analyze FreeImage.dll
[16:34:21] WARNING Cannot load Binary Ninja as a backend. Attempting to load angr instead. main.py:212
╭─────────────────────────────── Traceback (most recent call last) ────────────────────────────────╮
│ C:\Users\user\AppData\Local\Programs\Python\Python310\lib\site-packages\fuzzable_main_.py:1 │
│ 93 in run_on_file │
│ │
│ 190 │ │ │ │
│ 191 │ │ │ sys.tracebacklimit = 0 │
│ 192 │ │ │ │
│ ❱ 193 │ │ │ from binaryninja.binaryview import BinaryViewType │
│ 194 │ │ │ │
│ 195 │ │ │ bv = BinaryViewType.get_view_of_file(target) │
│ 196 │ │ │ bv.update_analysis_and_wait() │
│ │
│ ╭──────────────────────────── locals ────────────────────────────╮ │
│ │ AngrAnalysis = <class 'fuzzable.analysis.angr.AngrAnalysis'> │ │
│ │ export = None │ │
│ │ extension = '.dll' │ │
│ │ ignore_metrics = True │ │
│ │ include_nontop = False │ │
│ │ include_sym = [] │ │
│ │ list_ignored = False │ │
│ │ score_weights = [0.3, 0.3, 0.05, 0.05, 0.3] │ │
│ │ skip_stripped = False │ │
│ │ skip_sym = [] │ │
│ │ sys = <module 'sys' (built-in)> │ │
│ │ target = WindowsPath('FreeImage.dll') │ │
│ ╰────────────────────────────────────────────────────────────────╯ │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
ModuleNotFoundError: No module named 'binaryninja'

When I analyzed my demo dll, it was normal, but when I analyzed freeimage.dll, there was a problem. It seemed that he did not continue to use angr but chose binary ninja.

Is there a problem with Binaryninja nature_loops function?

def natural_loops(target: Function) -> int:
return sum([bb in bb.dominance_frontier for bb in target.basic_blocks])

The len() function will then return the length of this list, which is the number of basic blocks in target.basic_blocks, not the number of natural loops.

If you want to count the number of basic blocks that exist within their own dominance bounds (actually the number of natural loops), then you should use sum() instead of len().

Binary ninja plugin crashes on "Analyze and Rank functions"

Hi,

I updated the binary ninja plugin today to version 2.0.5 of fuzzable and it crashes every time I run "Analyze and Rank functions".
I am using Binary Ninja version 3.3.3996.

Please find attached the report of the crashed thread:

OS Version: macOS 12.6 (21G115)

Crashed Thread:        0  Dispatch queue: com.apple.main-thread

Exception Type:        EXC_CRASH (SIGABRT)
Exception Codes:       0x0000000000000000, 0x0000000000000000
Exception Note:        EXC_CORPSE_NOTIFY

Application Specific Information:
abort() called


Thread 0 Crashed::  Dispatch queue: com.apple.main-thread
0   libsystem_kernel.dylib        	       0x18204ed98 __pthread_kill + 8
1   libsystem_pthread.dylib       	       0x182083ee0 pthread_kill + 288
2   libsystem_c.dylib             	       0x181fbe340 abort + 168
3   libc++abi.dylib               	       0x18203eb08 abort_message + 132
4   libc++abi.dylib               	       0x18202e938 demangling_terminate_handler() + 312
5   libobjc.A.dylib               	       0x181f24330 _objc_terminate() + 160
6   libc++abi.dylib               	       0x18203dea4 std::__terminate(void (*)()) + 20
7   libc++abi.dylib               	       0x182040c1c __cxxabiv1::failed_throw(__cxxabiv1::__cxa_exception*) + 36
8   libc++abi.dylib               	       0x182040bc8 __cxa_throw + 140
9   libbinaryninjacore.1.dylib    	       0x111f8931c 0x111f50000 + 234268
10  libbinaryninjacore.1.dylib    	       0x111f7e15c 0x111f50000 + 188764
11  libbinaryninjacore.1.dylib    	       0x1127b3350 0x111f50000 + 8794960
12  libbinaryninjacore.1.dylib    	       0x1127b6b24 BNSettingsGetStringList + 192
13  libffi.dylib                  	       0x190314050 ffi_call_SYSV + 80
14  libffi.dylib                  	       0x19031cae8 ffi_call_int + 1208
15  _ctypes.cpython-310-darwin.so 	       0x1100310e0 _ctypes_callproc + 872
16  _ctypes.cpython-310-darwin.so 	       0x11002b91c PyCFuncPtr_call + 216
17  Python                        	       0x11bfed290 _PyObject_MakeTpCall + 136
18  Python                        	       0x11c0e6f0c call_function + 272
19  Python                        	       0x11c0e46bc _PyEval_EvalFrameDefault + 42928
20  Python                        	       0x11c0d8cac _PyEval_Vector + 376
21  Python                        	       0x11c0e6e7c call_function + 128
22  Python                        	       0x11c0e4694 _PyEval_EvalFrameDefault + 42888
23  Python                        	       0x11c0d8cac _PyEval_Vector + 376
24  Python                        	       0x11c0e6e7c call_function + 128
25  Python                        	       0x11c0e461c _PyEval_EvalFrameDefault + 42768
26  Python                        	       0x11c0d8cac _PyEval_Vector + 376
27  Python                        	       0x11c0e6e7c call_function + 128
28  Python                        	       0x11c0e46bc _PyEval_EvalFrameDefault + 42928
29  Python                        	       0x11c0d8cac _PyEval_Vector + 376
30  Python                        	       0x11c0e6e7c call_function + 128
31  Python                        	       0x11c0e4694 _PyEval_EvalFrameDefault + 42888
32  Python                        	       0x11c0d8cac _PyEval_Vector + 376
33  _ctypes.cpython-310-darwin.so 	       0x11002f870 _CallPythonObject + 548
34  libffi.dylib                  	       0x19031cf34 ffi_closure_SYSV_inner + 816
35  libffi.dylib                  	       0x1903141e8 ffi_closure_SYSV + 56
36  libbinaryninjaui.1.dylib      	       0x102b23520 0x102ac0000 + 406816
37  libbinaryninjaui.1.dylib      	       0x102af4b78 UIActionHandler::executeAction(QString const&, UIActionContext const&) + 164
38  libbinaryninjaui.1.dylib      	       0x102b30120 0x102ac0000 + 459040
39  QtCore                        	       0x1024db63c void doActivate<false>(QObject*, int, void**) + 780
40  QtGui                         	       0x101f58164 QAction::activate(QAction::ActionEvent) + 368
41  QtCore                        	       0x1024d418c QObject::event(QEvent*) + 604
42  QtWidgets                     	       0x103220990 QApplicationPrivate::notify_helper(QObject*, QEvent*) + 272
43  QtWidgets                     	       0x103221914 QApplication::notify(QObject*, QEvent*) + 512
44  QtCore                        	       0x102491fb0 QCoreApplication::notifyInternal2(QObject*, QEvent*) + 292
45  QtCore                        	       0x1024932c4 QCoreApplicationPrivate::sendPostedEvents(QObject*, int, QThreadData*) + 1428
46  libqcocoa.dylib               	       0x1019bbf08 QCocoaEventDispatcherPrivate::processPostedEvents() + 312
47  libqcocoa.dylib               	       0x1019bc584 QCocoaEventDispatcherPrivate::postedEventsSourceCallback(void*) + 48
48  CoreFoundation                	       0x182150f94 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 28
49  CoreFoundation                	       0x182150ee0 __CFRunLoopDoSource0 + 208
50  CoreFoundation                	       0x182150be0 __CFRunLoopDoSources0 + 268
51  CoreFoundation                	       0x18214f560 __CFRunLoopRun + 828
52  CoreFoundation                	       0x18214ea84 CFRunLoopRunSpecific + 600
53  HIToolbox                     	       0x18ad8e338 RunCurrentEventLoopInMode + 292
54  HIToolbox                     	       0x18ad8dfc4 ReceiveNextEventCommon + 324
55  HIToolbox                     	       0x18ad8de68 _BlockUntilNextEventMatchingListInModeWithFilter + 72
56  AppKit                        	       0x184cb651c _DPSNextEvent + 860
57  AppKit                        	       0x184cb4e14 -[NSApplication(NSEvent) _nextEventMatchingEventMask:untilDate:inMode:dequeue:] + 1328
58  AppKit                        	       0x184ca6fe0 -[NSApplication run] + 596
59  libqcocoa.dylib               	       0x1019bb394 QCocoaEventDispatcher::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) + 1792
60  QtCore                        	       0x10249b3d0 QEventLoop::exec(QFlags<QEventLoop::ProcessEventsFlag>) + 532
61  QtCore                        	       0x10249264c QCoreApplication::exec() + 128
62  binaryninja                   	       0x10049aedc 0x10046c000 + 192220
63  dyld                          	       0x101b2d08c start + 520

Thread 0 crashed with ARM Thread State (64-bit):
    x0: 0x0000000000000000   x1: 0x0000000000000000   x2: 0x0000000000000000   x3: 0x0000000000000000
    x4: 0x00000001820420c8   x5: 0x000000016f98f740   x6: 0x0000000000000065   x7: 0x0000000000000fe0
    x8: 0x551d38a5e140622e   x9: 0x551d38a4e0fa67ae  x10: 0x0000000000000200  x11: 0x0000000000000031
   x12: 0x0000000000000031  x13: 0x0000600001781f00  x14: 0x00000001820420f2  x15: 0x0000000000000000
   x16: 0x0000000000000148  x17: 0x00000001dc1a7680  x18: 0x0000000000000000  x19: 0x0000000000000006
   x20: 0x0000000101ba0580  x21: 0x0000000000000103  x22: 0x0000000101ba0660  x23: 0x000000013400fd00
   x24: 0x0000000000000000  x25: 0x000000016f98fe50  x26: 0x0000000000000000  x27: 0x0000000000000005
   x28: 0x000000016f9900d0   fp: 0x000000016f98f6b0   lr: 0x0000000182083ee0
    sp: 0x000000016f98f690   pc: 0x000000018204ed98 cpsr: 0x40001000
   far: 0x000000010281d1cc  esr: 0x56000080  Address size fault

Binary Images:
       0x182045000 -        0x18207cfff libsystem_kernel.dylib (*) <a9d87740-9c1d-3468-bf60-720a8d713cba> /usr/lib/system/libsystem_kernel.dylib
       0x18207d000 -        0x182089fff libsystem_pthread.dylib (*) <63c4eef9-69a5-38b1-996e-8d31b66a051d> /usr/lib/system/libsystem_pthread.dylib
       0x181f44000 -        0x181fc5fff libsystem_c.dylib (*) <b25d2080-bb9e-38d6-8236-9cef4b2f11a3> /usr/lib/system/libsystem_c.dylib
       0x18202d000 -        0x182044fff libc++abi.dylib (*) <4e8d8a11-4217-3d56-9d41-5426f7cf307c> /usr/lib/libc++abi.dylib
       0x181f03000 -        0x181f40fff libobjc.A.dylib (*) <ec96f0fa-6341-3e1d-be54-49b544e17f7d> /usr/lib/libobjc.A.dylib
       0x111f50000 -        0x1183affff libbinaryninjacore.1.dylib (*) <d26947a9-7b6f-3e62-8420-2d29cfdc0039> /Applications/Binary Ninja.app/Contents/MacOS/libbinaryninjacore.1.dylib
       0x19030c000 -        0x19031dfff libffi.dylib (*) <2dc42b53-6510-3538-a6d7-30035e16c717> /usr/lib/libffi.dylib
       0x110024000 -        0x110037fff _ctypes.cpython-310-darwin.so (*) <8120cab1-7585-3a51-8a8b-20dd1eb3be05> /opt/homebrew/*/Python.framework/Versions/3.10/lib/python3.10/lib-dynload/_ctypes.cpython-310-darwin.so
       0x11bf84000 -        0x11c257fff org.python.python (3.10.8, (c) 2001-2021 Python Software Foundation.) <f2371089-60d8-3b91-a475-4f4dcb3b84e3> /opt/homebrew/*/Python.framework/Versions/3.10/Python
       0x102ac0000 -        0x1030affff libbinaryninjaui.1.dylib (*) <c318f987-bf40-30da-b238-c5c477a991ee> /Applications/Binary Ninja.app/Contents/MacOS/libbinaryninjaui.1.dylib
       0x102428000 -        0x102893fff org.qt-project.QtCore (6.4) <65a3a1c3-75d3-3748-97e9-48949910701d> /Applications/Binary Ninja.app/Contents/Frameworks/QtCore.framework/Versions/A/QtCore
       0x101bdc000 -        0x1021dffff org.qt-project.QtGui (6.4) <82d6f631-5559-3350-a769-08b6a8540a77> /Applications/Binary Ninja.app/Contents/Frameworks/QtGui.framework/Versions/A/QtGui
       0x103214000 -        0x103657fff org.qt-project.QtWidgets (6.4) <28ae0d49-59cc-32ec-be36-a2b2c235bcd8> /Applications/Binary Ninja.app/Contents/Frameworks/QtWidgets.framework/Versions/A/QtWidgets
       0x1019a4000 -        0x101a3bfff libqcocoa.dylib (*) <3c3914e7-5638-3731-8eb1-d0877d321c9e> /Applications/Binary Ninja.app/Contents/MacOS/qt/platforms/libqcocoa.dylib
       0x1820cc000 -        0x182612fff com.apple.CoreFoundation (6.9) <fc3c193d-0cdb-3569-9f0e-bd2507ca1dbb> /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation
       0x18ad5c000 -        0x18b08ffff com.apple.HIToolbox (2.1.1) <aaf900bd-bfb6-3af0-a8d3-e24bbe1d57f5> /System/Library/Frameworks/Carbon.framework/Versions/A/Frameworks/HIToolbox.framework/Versions/A/HIToolbox
       0x184c75000 -        0x185b2dfff com.apple.AppKit (6.9) <5e432f87-5b58-391a-a542-fa2d909dd210> /System/Library/Frameworks/AppKit.framework/Versions/C/AppKit
       0x10046c000 -        0x1016c3fff com.vector35.binaryninja (3.3.3996) <4bbd5cf1-b1a6-38f9-8022-3bad8e66b771> /Applications/Binary Ninja.app/Contents/MacOS/binaryninja
       0x101b28000 -        0x101b87fff dyld (*) <38ee9fe9-b66d-3066-8c5c-6ddf0d6944c6> /usr/lib/dyld
       0x135800000 -        0x136bd7fff libopenblas64_.0.dylib (*) <3dd132fc-be72-33cc-baf0-4c7df2669307> /opt/homebrew/*/libopenblas64_.0.dylib
       0x170024000 -        0x17128bfff libopenblas.0.dylib (*) <5431bff3-be1a-3fe5-a552-bcdbb3e0536e> /opt/homebrew/*/libopenblas.0.dylib
       0x181fc6000 -        0x18202cfff libc++.1.dylib (*) <3d1e6031-901d-3df1-9e9a-f85ff1c2e803> /usr/lib/libc++.1.dylib

External Modification Summary:
  Calls made by other processes targeting this process:
    task_for_pid: 0
    thread_create: 0
    thread_set_state: 0
  Calls made by this process:
    task_for_pid: 0
    thread_create: 0
    thread_set_state: 0
  Calls made by all processes on this machine:
    task_for_pid: 5
    thread_create: 0
    thread_set_state: 976

site-packages/third_party/tree-sitter-c/src/parser.c not found - the entire third_party folder doesn't exist

Hi, sorry bothering you,
Running fuzzable on any c file/project produces to me this error:

$ fuzzable analyze exiftags
[...]
╭─────────────────────────────── Traceback (most recent call last) ────────────────────────────────╮
│ /home/myasnik/.local/lib/python3.10/site-packages/fuzzable/__main__.py:89 in analyze             │
│                                                                                                  │
│    86 │   if target.is_file():                                                                   │
│    87 │   │   run_on_file(target, mode, score_weights, export, list_ignored)                     │
│    88 │   elif target.is_dir():                                                                  │
│ ❱  89 │   │   run_on_workspace(target, mode, score_weights, export, list_ignored)                │
│    90 │   else:                                                                                  │
│    91 │   │   error(f"Target path `{target}` does not exist")                                    │
│    92                                                                                            │
│                                                                                                  │
│ ╭────────────────── locals ───────────────────╮                                                  │
│ │         debug = False                       │                                                  │
│ │        export = None                        │                                                  │
│ │  list_ignored = False                       │                                                  │
│ │          mode = <AnalysisMode.RECOMMEND: 0> │                                                  │
│ │ score_weights = [0.3, 0.3, 0.05, 0.05, 0.3] │                                                  │
│ │        target = PosixPath('exiftags')       │                                                  │
│ ╰─────────────────────────────────────────────╯                                                  │
│                                                                                                  │
│ /home/myasnik/.local/lib/python3.10/site-packages/fuzzable/__main__.py:163 in run_on_workspace   │
│                                                                                                  │
│   160 │   │   │   "No C/C++ source code found in the workspace. fuzzable currently does not s    │
│   161 │   │   )                                                                                  │
│   162 │                                                                                          │
│ ❱ 163 │   analyzer = AstAnalysis(                                                                │
│   164 │   │   source_files, mode, score_weights=score_weights, basedir=target                    │
│   165 │   )                                                                                      │
│   166 │   log.info(f"Running fuzzable analysis with the {str(analyzer)} analyzer")               │
│                                                                                                  │
│ ╭────────────────────────────────────── locals ──────────────────────────────────────╮           │
│ │             _ = []                                                                 │           │
│ │        export = None                                                               │           │
│ │          file = 'id:000403,src:000253,time:1453128,execs:3687367,op:flip1,pos:187' │           │
│ │         files = []                                                                 │           │
│ │  list_ignored = False                                                              │           │
│ │          mode = <AnalysisMode.RECOMMEND: 0>                                        │           │
│ │ score_weights = [0.3, 0.3, 0.05, 0.05, 0.3]                                        │           │
│ │  source_files = [                                                                  │           │
│ │                 │   PosixPath('exiftags/asahi.c'),                                 │           │
│ │                 │   PosixPath('exiftags/canon.c'),                                 │           │
│ │                 │   PosixPath('exiftags/casio.c'),                                 │           │
│ │                 │   PosixPath('exiftags/exif.c'),                                  │           │
│ │                 │   PosixPath('exiftags/exif.h'),                                  │           │
│ │                 │   PosixPath('exiftags/exifcom.c'),                               │           │
│ │                 │   PosixPath('exiftags/exifgps.c'),                               │           │
│ │                 │   PosixPath('exiftags/exifint.h'),                               │           │
│ │                 │   PosixPath('exiftags/exiftags.c'),                              │           │
│ │                 │   PosixPath('exiftags/exiftime.c'),                              │           │
│ │                 │   ... +18                                                        │           │
│ │                 ]                                                                  │           │
│ │        subdir = 'exiftags/fuzz_out_1/default/hangs'                                │           │
│ │        target = PosixPath('exiftags')                                              │           │
│ ╰────────────────────────────────────────────────────────────────────────────────────╯           │
│                                                                                                  │
│ /home/myasnik/.local/lib/python3.10/site-packages/fuzzable/analysis/ast.py:35 in __init__        │
│                                                                                                  │
│    32 │   │   super().__init__(target, mode, score_weights)                                      │
│    33 │   │                                                                                      │
│    34 │   │   log.debug("Building third-party tree-sitter libraries for C/C++ languages")        │
│ ❱  35 │   │   Language.build_library(                                                            │
│    36 │   │   │   BUILD_PATH,                                                                    │
│    37 │   │   │   [                                                                              │
│    38 │   │   │   │   os.path.join(ROOT_DIR, "third_party/tree-sitter-c"),                       │
│                                                                                                  │
│ ╭─────────────────────────────────── locals ───────────────────────────────────╮                 │
│ │     __class__ = <class 'fuzzable.analysis.ast.AstAnalysis'>                  │                 │
│ │       basedir = PosixPath('exiftags')                                        │                 │
│ │          mode = <AnalysisMode.RECOMMEND: 0>                                  │                 │
│ │ score_weights = [0.3, 0.3, 0.05, 0.05, 0.3]                                  │                 │
│ │          self = <fuzzable.analysis.ast.AstAnalysis object at 0x7f4c4dbfe020> │                 │
│ │        target = [                                                            │                 │
│ │                 │   PosixPath('exiftags/asahi.c'),                           │                 │
│ │                 │   PosixPath('exiftags/canon.c'),                           │                 │
│ │                 │   PosixPath('exiftags/casio.c'),                           │                 │
│ │                 │   PosixPath('exiftags/exif.c'),                            │                 │
│ │                 │   PosixPath('exiftags/exif.h'),                            │                 │
│ │                 │   PosixPath('exiftags/exifcom.c'),                         │                 │
│ │                 │   PosixPath('exiftags/exifgps.c'),                         │                 │
│ │                 │   PosixPath('exiftags/exifint.h'),                         │                 │
│ │                 │   PosixPath('exiftags/exiftags.c'),                        │                 │
│ │                 │   PosixPath('exiftags/exiftime.c'),                        │                 │
│ │                 │   ... +18                                                  │                 │
│ │                 ]                                                            │                 │
│ ╰──────────────────────────────────────────────────────────────────────────────╯                 │
│                                                                                                  │
│ /home/myasnik/.local/lib/python3.10/site-packages/tree_sitter/__init__.py:41 in build_library    │
│                                                                                                  │
│   38 │   │   │   │   source_paths.append(path.join(src_path, "scanner.cc"))                      │
│   39 │   │   │   elif path.exists(path.join(src_path, "scanner.c")):                             │
│   40 │   │   │   │   source_paths.append(path.join(src_path, "scanner.c"))                       │
│ ❱ 41 │   │   source_mtimes = [path.getmtime(__file__)] + [                                       │
│   42 │   │   │   path.getmtime(path_) for path_ in source_paths                                  │
│   43 │   │   ]                                                                                   │
│   44                                                                                             │
│                                                                                                  │
│ ╭─────────────────────────────────────────── locals ───────────────────────────────────────────╮ │
│ │          cpp = False                                                                         │ │
│ │ output_mtime = 0                                                                             │ │
│ │  output_path = '/home/myasnik/.local/lib/python3.10/site-packages/build/lang.so'             │ │
│ │    repo_path = '/home/myasnik/.local/lib/python3.10/site-packages/third_party/tree-sitter-c… │ │
│ │   repo_paths = [                                                                             │ │
│ │                │                                                                             │ │
│ │                '/home/myasnik/.local/lib/python3.10/site-packages/third_party/tree-sitter-c… │ │
│ │                │                                                                             │ │
│ │                '/home/myasnik/.local/lib/python3.10/site-packages/third_party/tree-sitter-c… │ │
│ │                ]                                                                             │ │
│ │ source_paths = [                                                                             │ │
│ │                │                                                                             │ │
│ │                '/home/myasnik/.local/lib/python3.10/site-packages/third_party/tree-sitter-c… │ │
│ │                │                                                                             │ │
│ │                '/home/myasnik/.local/lib/python3.10/site-packages/third_party/tree-sitter-c… │ │
│ │                ]                                                                             │ │
│ │     src_path = '/home/myasnik/.local/lib/python3.10/site-packages/third_party/tree-sitter-c… │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
│                                                                                                  │
│ /home/myasnik/.local/lib/python3.10/site-packages/tree_sitter/__init__.py:42 in <listcomp>       │
│                                                                                                  │
│   39 │   │   │   elif path.exists(path.join(src_path, "scanner.c")):                             │
│   40 │   │   │   │   source_paths.append(path.join(src_path, "scanner.c"))                       │
│   41 │   │   source_mtimes = [path.getmtime(__file__)] + [                                       │
│ ❱ 42 │   │   │   path.getmtime(path_) for path_ in source_paths                                  │
│   43 │   │   ]                                                                                   │
│   44 │   │                                                                                       │
│   45 │   │   compiler = new_compiler()                                                           │
│                                                                                                  │
│ ╭─────────────────────────────────────────── locals ───────────────────────────────────────────╮ │
│ │    .0 = <list_iterator object at 0x7f4c4dbfcf10>                                             │ │
│ │ path_ = '/home/myasnik/.local/lib/python3.10/site-packages/third_party/tree-sitter-c/src/'+8 │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
│                                                                                                  │
│ /usr/lib/python3.10/genericpath.py:55 in getmtime                                                │
│                                                                                                  │
│    52                                                                                            │
│    53 def getmtime(filename):                                                                    │
│    54 │   """Return the last modification time of a file, reported by os.stat()."""              │
│ ❱  55 │   return os.stat(filename).st_mtime                                                      │
│    56                                                                                            │
│    57                                                                                            │
│    58 def getatime(filename):                                                                    │
│                                                                                                  │
│ ╭─────────────────────────────────────────── locals ───────────────────────────────────────────╮ │
│ │ filename = '/home/myasnik/.local/lib/python3.10/site-packages/third_party/tree-sitter-c/src… │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
FileNotFoundError: [Errno 2] No such file or directory: '/home/myasnik/.local/lib/python3.10/site-packages/third_party/tree-sitter-c/src/parser.c'

Maybe it's just that I'm noob and I'm messing somethig.. I hope not to waste your time.
I installed fuzzable as defined in the README (using pip install . in the cloned project folder); I also tried with a virtualenv but nothing changes except as expected the path of libraries used.
I'm running arch linux (fully update) and the latest python version.

Thanks a lot for your help and patience!

Remove analysis modes for analysis inclusion pattern flags

I think using only two modes, recommend and rank to determine what to incorporate in the analysis is not fine-grained and thus decreases usability for the researcher. Naturally recommend mode will always be wanted, but if there are some relevant functions that were filtered out, we'd have to switch to rank mode, which will include all, including those that are definitely not useful.

We'll make fuzzable operate strictly in recommend, and enable new flags:

  • --include-sym - analyze a symbol or symbol(s) that was filtered out
  • --include-nontop - don't filter out only top-level calls for fuzzable analysis, include child nodes too.

I'm going to opt out of doing something like --include-static or --include-imports since I won't imagine a need (and --include-sym would alleviate that for now).

This should also be reflected as an option in disassemblers, or maybe through something nice in the UI (ie checkboxes).

Instrument the execution path of history bugs

Because released patch from vendors might not be correct or researchers could try finding variant of history bugs, the functions on the execution path could also be interesting target to fuzz. Do you think it could considered as one of the metrics?

Arguments for harness generation

Hello!
I got the results of the analysis and now I would like to automatically generate the harness for this functions
screen_fuzzable

I tried to call like this:

# generate harness from a candidate
$ fuzzable create-harness ~/nDPI/src/lib/ndpi_main.c --symbol-name=ndpi_set_bitmask_protocol_detection

But I get an error

Unknown format
[37m[41mfuzzable error:[0m [31mWrong filetype, or does not support synthesizing harnesses for C/C++ source code yet.

TypeError on `fuzzable create-harness`

When I ran fuzzable create-harness examples/binaries/libbasic.so --symbol_name vulnerable_parse_buf --out_harness harness.c in the root directory, I got a TypeError which prevented further execution. I will submit a PR which I think fixes this issue.

Transcript:

❯ fuzzable create-harness examples/binaries/libbasic.so --symbol_name vulnerable_parse_buf --out_harness harness.c         
╭─────────────────────────────── Traceback (most recent call last) ────────────────────────────────╮
│ /home/benjis/code/trace-modeling-oss-fuzz-c/misc/fuzzable/fuzzable/__main__.py:313 in            │
│ create_harness                                                                                   │
│                                                                                                  │
│   310 │                                                                                          │
│   311 │   # if a binary, check if executable or library. if executable, use LIEF to              │
│   312 │   # copy, export the symbol and transform to shared object.                              │
│ ❱ 313 │   binary = lief.parse(target)                                                            │
│   314 │   if binary is None:                                                                     │
│   315 │   │   error(                                                                             │
│   316 │   │   │   "Wrong filetype, or does not support synthesizing harnesses for C/C++ source   │
│                                                                                                  │
│ ╭─────────────────────────────────────────── locals ───────────────────────────────────────────╮ │
│ │        lief = <module 'lief' from                                                            │ │
│ │               '/home/benjis/code/trace-modeling-oss-fuzz-c/venv/lib64/python3.8/site-packag… │ │
│ │ out_harness = PosixPath('harness.c')                                                         │ │
│ │ out_so_name = None                                                                           │ │
│ │ symbol_name = 'vulnerable_parse_buf'                                                         │ │
│ │      target = PosixPath('examples/binaries/libbasic.so')                                     │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
TypeError: PosixPath('examples/binaries/libbasic.so')

undefined symbol: static_assert when trying to run analysis

Hi,
Thanks for creating such a useful piece of software.
Looks like some dependency has changed an now when trying to analyze a source code one gets the following error:

OSError: /usr/local/lib/python3.10/dist-packages/build/lang.so: undefined symbol: static_assert

Indeed looks like the symbol is missing, but I don't know where does the missing dependency come from:

# readelf -s ./lang.so | grep -i assert
     8: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND static_assert
   117: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __assert_fail@GL[...]
   125: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND static_assert

Thanks in advance for any hints.

The system is ubuntu 22.04 and fuzzable was installed via pip install .

Adding some support for automated data structure creation.

Often when you fuzz Windows targets such as Adobe Reader, you go after certain DLLs but they may require you to supply some type of class or data structure. Reversing that out can be a pain. I have a few ideas on how to automate this to some degree. Obviously wouldn't be best perfect but would save time.

binary ninja plugin install broken

It looks like the latest release has broken the binary ninja plugin manager support. I'm removing it from the plugin manager for now, if you'd like to re-add it, please move the binja plugin to a separate folder, add an appropriate plugin.json and let us know and we'll add it back.

Allow user to ignore symbols/files

Three more flags for fuzzable analyze:

  • --ignore_symbol - skip analysis on symbols
  • --ignore_file - for source analysis only, skip file from being parsed with
  • --ignore_dir - for source anlaysis only, skip entire folder of files from being parsed

Be sure to allow user to specify multiple symbols/paths (comma separated).

Maybe it might be even better to allow users to specify regex queries as well?

Demangle C++ symbols for binary analysis

I made a mistake in forgetting that mangled C++ symbol names start with _, and thus analysis on C++ binaries will ignore them altogether.

While this has been since fixed, we should also support demangling these names before displaying ranked results back to the user.

This should be done for both the currently existing Angr and Binary Ninja backends.

LIEF: TypeError: PosixPath()

I get this error on different Linux installations with different target libraries:

$ pip install fuzzable
[...]
$ fuzzable  create-harness liblzma.so --symbol_name=Lzma2Enc_Encode2
╭───────────────────── Traceback (most recent call last) ──────────────────────╮
│ /usr/local/lib/python3.10/dist-packages/fuzzable/__main__.py:313 in          │
│ create_harness                                                               │
│                                                                              │
│   310 │                                                                      │
│   311 │   # if a binary, check if executable or library. if executable, use  │
│   312 │   # copy, export the symbol and transform to shared object.          │
│ ❱ 313 │   binary = lief.parse(target)                                        │
│   314 │   if binary is None:                                                 │
│   315 │   │   error(                                                         │
│   316 │   │   │   "Wrong filetype, or does not support synthesizing harnesse │
│                                                                              │
│ ╭───────────────────────────────── locals ─────────────────────────────────╮ │
│ │        lief = <module 'lief' from                                        │ │
│ │               '/usr/local/lib/python3.10/dist-packages/lief.cpython-310… │ │
│ │ out_harness = None                                                       │ │
│ │ out_so_name = None                                                       │ │
│ │ symbol_name = 'Lzma2Enc_Encode2'                                         │ │
│ │      target = PosixPath('liblzma.so')                                    │ │
│ ╰──────────────────────────────────────────────────────────────────────────╯ │
╰──────────────────────────────────────────────────────────────────────────────╯
TypeError: PosixPath('liblzma.so')

also, please update the README.md to use afl++ qemu_mode, not the outdated and really underperforming vanilla afl one ...

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.