diff options
-rw-r--r-- | README.md | 34 | ||||
-rw-r--r-- | frontend/.eslintrc.js | 2 | ||||
-rw-r--r-- | frontend/src/components/Connection.scss | 1 | ||||
-rw-r--r-- | frontend/src/components/filters/BooleanConnectionsFilter.scss | 2 | ||||
-rw-r--r-- | frontend/src/components/filters/RulesConnectionsFilter.scss | 28 | ||||
-rw-r--r-- | frontend/src/components/filters/StringConnectionsFilter.scss | 4 | ||||
-rw-r--r-- | frontend/src/index.scss | 8 | ||||
-rw-r--r-- | frontend/src/views/App.js | 11 | ||||
-rw-r--r-- | frontend/src/views/App.scss | 2 | ||||
-rw-r--r-- | frontend/src/views/Filters.js | 7 | ||||
-rw-r--r-- | frontend/src/views/Filters.scss | 0 | ||||
-rw-r--r-- | frontend/src/views/Header.js | 10 | ||||
-rw-r--r-- | frontend/src/views/Header.scss | 3 | ||||
-rw-r--r-- | frontend/src/views/Rules.js | 118 | ||||
-rwxr-xr-x | scripts/generate_ping.py | 1 |
15 files changed, 163 insertions, 68 deletions
@@ -12,30 +12,30 @@ The connection flows are saved into a database and can be visualized with the we ## Installation There are two ways to install Caronte: -- with Docker and docker-compose, the fastest and easiest way -- manually installing dependencies and compiling the project +- with Docker and docker-compose, the fastest and easiest way +- manually installing dependencies and compiling the project ### Run with Docker The only things to do are: -- clone the repo, with `git clone https://github.com/eciavatta/caronte.git` -- inside the `caronte` folder, run `docker-compose up --build -d` -- wait for the image to be compiled and open browser at `http://localhost:3333` +- clone the repo, with `git clone https://github.com/eciavatta/caronte.git` +- inside the `caronte` folder, run `docker-compose up --build -d` +- wait for the image to be compiled and open browser at `http://localhost:3333` ### Manually installation The first thing to do is to install the dependencies: -- go >= 1.14 (https://golang.org/doc/install) -- node >= v12 (https://nodejs.org/it/download/) -- yarnpkg (https://classic.yarnpkg.com/en/docs/install/) -- hyperscan >= v5 (https://www.hyperscan.io/downloads/) +- go >= 1.14 [https://golang.org/doc/install](https://golang.org/doc/install) +- node >= v12 [https://nodejs.org/it/download/](https://nodejs.org/it/download/) +- yarnpkg [https://classic.yarnpkg.com/en/docs/install/](https://classic.yarnpkg.com/en/docs/install/) +- hyperscan >= v5 [https://www.hyperscan.io/downloads/](https://www.hyperscan.io/downloads/) Next you need to compile the project, which is composed of two parts: -- the backend, which can be compiled with `go mod download && go build` -- the frontend, which can be compiled with `cd frontend && yarn install && yarn build` +- the backend, which can be compiled with `go mod download && go build` +- the frontend, which can be compiled with `cd frontend && yarn install && yarn build` -Before running Caronte starts an instance of MongoDB (https://docs.mongodb.com/manual/administration/install-community/) that has no authentication. _Be careful not to expose the MongoDB port on the public interface._ +Before running Caronte starts an instance of MongoDB [https://docs.mongodb.com/manual/administration/install-community/](https://docs.mongodb.com/manual/administration/install-community/) that has no authentication. _Be careful not to expose the MongoDB port on the public interface._ Run the binary with `./caronte`. The available configuration options are: -``` +```text -bind-address address where server is bind (default "0.0.0.0") -bind-port port where server is bind (default 3333) -db-name name of database to use (default "caronte") @@ -45,7 +45,7 @@ Run the binary with `./caronte`. The available configuration options are: ## Configuration The configuration takes place at runtime on the first start via the graphical interface (TO BE IMPLEMENTED) or via API. It is necessary to setup: -- the `server_address`: the ip address of the vulnerable machine. Must be the destination address of all the connections in the pcaps. If each vulnerable service has an own ip, this param accept also a CIDR address. The address can be either IPv4 both IPv6 -- the `flag_regex`: the regular expression that matches a flag. Usually provided on the competition rules page -- `auth_required`: if true a basic authentication is enabled to protect the analyzer -- an optional `accounts` array, which contains the credentials of authorized users +- the `server_address`: the ip address of the vulnerable machine. Must be the destination address of all the connections in the pcaps. If each vulnerable service has an own ip, this param accept also a CIDR address. The address can be either IPv4 both IPv6 +- the `flag_regex`: the regular expression that matches a flag. Usually provided on the competition rules page +- `auth_required`: if true a basic authentication is enabled to protect the analyzer +- an optional `accounts` array, which contains the credentials of authorized users diff --git a/frontend/.eslintrc.js b/frontend/.eslintrc.js index 97fb33f..16ff228 100644 --- a/frontend/.eslintrc.js +++ b/frontend/.eslintrc.js @@ -1,4 +1,4 @@ -var OFF = 0, WARN = 1, ERROR = 2; +const OFF = 0, WARN = 1, ERROR = 2; module.exports = exports = { "env": { diff --git a/frontend/src/components/Connection.scss b/frontend/src/components/Connection.scss index 7c8e00c..cb9eb5f 100644 --- a/frontend/src/components/Connection.scss +++ b/frontend/src/components/Connection.scss @@ -42,7 +42,6 @@ &.contains-flag { border-right: 3px solid $color-secondary-2; } - } .connection-popover { diff --git a/frontend/src/components/filters/BooleanConnectionsFilter.scss b/frontend/src/components/filters/BooleanConnectionsFilter.scss index f3d8697..941b967 100644 --- a/frontend/src/components/filters/BooleanConnectionsFilter.scss +++ b/frontend/src/components/filters/BooleanConnectionsFilter.scss @@ -1,7 +1,6 @@ @import '../../colors'; .filter { - .filter-boolean { padding: 0 10px; background-color: $color-primary-2; @@ -22,5 +21,4 @@ color: $color-primary-3; } } - } diff --git a/frontend/src/components/filters/RulesConnectionsFilter.scss b/frontend/src/components/filters/RulesConnectionsFilter.scss index d75066e..5df0006 100644 --- a/frontend/src/components/filters/RulesConnectionsFilter.scss +++ b/frontend/src/components/filters/RulesConnectionsFilter.scss @@ -2,23 +2,16 @@ .react-tags { position: relative; - padding: 0px 6px; + padding: 0 6px; border-radius: 4px; - background-color: $color-primary-2; - - - /* shared font styles */ font-size: 12px; - - /* clicking anywhere will focus the input */ cursor: text; - z-index: 10; } .react-tags.is-focused { - border-color: #B1B1B1; + border-color: #b1b1b1; } .react-tags__selected { @@ -33,11 +26,10 @@ border-radius: 2px; background: $color-primary-4; color: $color-primary-3; - font-size: 11px; } -.react-tags__selected-tag:after { +.react-tags__selected-tag::after { content: '\2715'; color: $color-primary-3; margin-left: 8px; @@ -45,24 +37,19 @@ .react-tags__selected-tag:hover, .react-tags__selected-tag:focus { - border-color: #B1B1B1; + border-color: #b1b1b1; } .react-tags__search { display: inline-block; padding: 7px 10px; - - /* prevent autoresize overflowing the container */ max-width: 100%; } @media screen and (min-width: 30em) { - .react-tags__search { - /* this will become the offsetParent for suggestions */ position: relative; } - } .react-tags__search-input { @@ -71,11 +58,8 @@ padding: 0; border: 0; outline: none; - background-color: $color-primary-2; color: $color-primary-4; - - /* match the font styles */ font-size: inherit; line-height: inherit; } @@ -92,11 +76,9 @@ } @media screen and (min-width: 30em) { - .react-tags__suggestions { width: 240px; } - } .react-tags__suggestions ul { @@ -133,4 +115,4 @@ .react-tags__suggestions li.is-disabled { opacity: 0.5; cursor: auto; -}
\ No newline at end of file +} diff --git a/frontend/src/components/filters/StringConnectionsFilter.scss b/frontend/src/components/filters/StringConnectionsFilter.scss index ecc8d0f..1476616 100644 --- a/frontend/src/components/filters/StringConnectionsFilter.scss +++ b/frontend/src/components/filters/StringConnectionsFilter.scss @@ -53,11 +53,9 @@ position: absolute; right: 10px; top: 10px; - z-index: 10; font-size: 11px; letter-spacing: -0.5px; - color: $color-primary-2; cursor: pointer; @@ -65,4 +63,4 @@ font-weight: 800; } } -}
\ No newline at end of file +} diff --git a/frontend/src/index.scss b/frontend/src/index.scss index 7db5cc5..53ce4dd 100644 --- a/frontend/src/index.scss +++ b/frontend/src/index.scss @@ -1,6 +1,6 @@ @import url('https://fonts.googleapis.com/css2?family=Fira+Code:wght@400;500&display=swap'); -@import-normalize ; +@import-normalize; @import 'colors.scss'; @@ -53,7 +53,8 @@ pre { background-color: $color-secondary-2; border-bottom: 5px solid $color-secondary-1; - &:hover, &:active { + &:hover, + &:active { color: $color-secondary-4; background-color: $color-secondary-1; } @@ -64,7 +65,8 @@ pre { background-color: $color-blue; border-bottom: 5px solid $color-blue-dark; - &:hover, &:active { + &:hover, + &:active { color: $color-blue-light; background-color: $color-blue-dark; } diff --git a/frontend/src/views/App.js b/frontend/src/views/App.js index 14ff7bf..6c101fa 100644 --- a/frontend/src/views/App.js +++ b/frontend/src/views/App.js @@ -1,11 +1,11 @@ import React, {Component} from 'react'; import Header from "./Header"; -import './App.scss'; import MainPane from "./MainPane"; import Footer from "./Footer"; import {BrowserRouter as Router, Route, Switch} from "react-router-dom"; import Services from "./Services"; import Filters from "./Filters"; +import Rules from "./Rules"; class App extends Component { @@ -13,7 +13,8 @@ class App extends Component { super(props); this.state = { servicesWindowOpen: false, - filterWindowOpen: false + filterWindowOpen: false, + rulesWindowOpen: false }; } @@ -25,12 +26,16 @@ class App extends Component { if (this.state.filterWindowOpen) { modal = <Filters onHide={() => this.setState({filterWindowOpen: false})}/>; } + if (this.state.rulesWindowOpen) { + modal = <Rules onHide={() => this.setState({rulesWindowOpen: false})}/>; + } return ( <div className="app"> <Router> <Header onOpenServices={() => this.setState({servicesWindowOpen: true})} - onOpenFilters={() => this.setState({filterWindowOpen: true})}/> + onOpenFilters={() => this.setState({filterWindowOpen: true})} + onOpenRules={() => this.setState({rulesWindowOpen: true})} /> <Switch> <Route path="/connections/:id" children={<MainPane/>}/> <Route path="/" children={<MainPane/>}/> diff --git a/frontend/src/views/App.scss b/frontend/src/views/App.scss deleted file mode 100644 index d5813f9..0000000 --- a/frontend/src/views/App.scss +++ /dev/null @@ -1,2 +0,0 @@ -.app { -} diff --git a/frontend/src/views/Filters.js b/frontend/src/views/Filters.js index 23d3a00..78f0342 100644 --- a/frontend/src/views/Filters.js +++ b/frontend/src/views/Filters.js @@ -7,8 +7,9 @@ class Filters extends Component { constructor(props) { super(props); - this.state = {}; - filtersNames.forEach(elem => this.state[`${elem}_active`] = false); + let newState = {}; + filtersNames.forEach(elem => newState[`${elem}_active`] = false); + this.state = newState; } componentDidMount() { @@ -27,7 +28,7 @@ class Filters extends Component { generateRows(filtersNames) { return filtersNames.map(name => - <tr> + <tr key={name}> <td><input type="checkbox" checked={this.state[`${name}_active`]} onChange={event => this.checkboxChangesHandler(name, event)} /></td> diff --git a/frontend/src/views/Filters.scss b/frontend/src/views/Filters.scss deleted file mode 100644 index e69de29..0000000 --- a/frontend/src/views/Filters.scss +++ /dev/null diff --git a/frontend/src/views/Header.js b/frontend/src/views/Header.js index 007be74..5d0f690 100644 --- a/frontend/src/views/Header.js +++ b/frontend/src/views/Header.js @@ -2,17 +2,15 @@ import React, {Component} from 'react'; import Typed from 'typed.js'; import './Header.scss'; import {Button} from "react-bootstrap"; -import StringConnectionsFilter from "../components/filters/StringConnectionsFilter"; -import {cleanNumber, validateIpAddress, validateMin, validatePort} from "../utils"; -import RulesConnectionsFilter from "../components/filters/RulesConnectionsFilter"; import {filtersDefinitions, filtersNames} from "../components/filters/FiltersDefinitions"; class Header extends Component { constructor(props) { super(props); - this.state = {}; - filtersNames.forEach(elem => this.state[`${elem}_active`] = false); + let newState = {}; + filtersNames.forEach(elem => newState[`${elem}_active`] = false); + this.state = newState; this.fetchStateFromLocalStorage = this.fetchStateFromLocalStorage.bind(this); } @@ -73,7 +71,7 @@ class Header extends Component { <div className="header-buttons"> <Button onClick={this.props.onOpenFilters}>filters</Button> <Button variant="yellow" size="sm">pcaps</Button> - <Button variant="blue">rules</Button> + <Button variant="blue" onClick={this.props.onOpenRules}>rules</Button> <Button variant="red" onClick={this.props.onOpenServices}> services </Button> diff --git a/frontend/src/views/Header.scss b/frontend/src/views/Header.scss index 806e398..e84e758 100644 --- a/frontend/src/views/Header.scss +++ b/frontend/src/views/Header.scss @@ -21,8 +21,5 @@ .filters-bar-wrapper { height: 50px; padding: 8px 0; - - .filters-bar { - } } } diff --git a/frontend/src/views/Rules.js b/frontend/src/views/Rules.js new file mode 100644 index 0000000..3424410 --- /dev/null +++ b/frontend/src/views/Rules.js @@ -0,0 +1,118 @@ +import React, {Component} from 'react'; +import './Services.scss'; +import {Button, ButtonGroup, Col, Container, Form, FormControl, InputGroup, Modal, Row, Table} from "react-bootstrap"; +import axios from "axios"; + +class Rules extends Component { + + constructor(props) { + super(props); + + this.state = { + rules: [] + }; + } + + componentDidMount() { + this.loadRules(); + } + + loadRules() { + axios.get("/api/rules").then(res => this.setState({rules: res.data})); + } + + render() { + let rulesRows = this.state.rules.map(rule => + <tr key={rule.id}> + <td><Button variant="btn-edit" size="sm" + style={{"backgroundColor": rule.color}}>edit</Button></td> + <td>{rule.name}</td> + </tr> + ); + + + return ( + <Modal + {...this.props} + show="true" + size="lg" + aria-labelledby="rules-dialog" + centered + > + <Modal.Header> + <Modal.Title id="rules-dialog"> + ~/rules + </Modal.Title> + </Modal.Header> + <Modal.Body> + <Container> + <Row> + <Col md={7}> + <Table borderless size="sm" className="rules-list"> + <thead> + <tr> + <th><Button size="sm" >new</Button></th> + <th>name</th> + </tr> + </thead> + <tbody> + {rulesRows} + + </tbody> + </Table> + </Col> + <Col md={5}> + <Form> + <Form.Group controlId="servicePort"> + <Form.Label>port:</Form.Label> + <Form.Control type="text" /> + </Form.Group> + + <Form.Group controlId="serviceName"> + <Form.Label>name:</Form.Label> + <Form.Control type="text" /> + </Form.Group> + + <Form.Group controlId="serviceColor"> + <Form.Label>color:</Form.Label> + <ButtonGroup aria-label="Basic example"> + + </ButtonGroup> + <ButtonGroup aria-label="Basic example"> + + </ButtonGroup> + </Form.Group> + + <Form.Group controlId="serviceNotes"> + <Form.Label>notes:</Form.Label> + <Form.Control as="textarea" rows={3} /> + </Form.Group> + </Form> + + + </Col> + + </Row> + + <Row> + <Col md={12}> + <InputGroup> + <FormControl as="textarea" rows={4} className="curl-output" readOnly={true} + /> + </InputGroup> + + </Col> + </Row> + + + </Container> + </Modal.Body> + <Modal.Footer className="dialog-footer"> + <Button variant="red" onClick={this.props.onHide}>close</Button> + </Modal.Footer> + </Modal> + ); + } +} + +export default Rules; diff --git a/scripts/generate_ping.py b/scripts/generate_ping.py index 153a3cb..73454c1 100755 --- a/scripts/generate_ping.py +++ b/scripts/generate_ping.py @@ -1,6 +1,5 @@ #!/usr/bin/env python3 -import struct import socket import socketserver import sys |