Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ jobs:

- name: Test
run: go test .
working-directory: cmd/simplehttpserver/
working-directory: cmd/simplehttpserver

- name: Build
run: go build .
Expand Down
6 changes: 1 addition & 5 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,6 @@ linters-settings:
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Fatalf
# lll:
# line-length: 140
maligned:
suggest-new: true
misspell:
locale: US
nolintlint:
Expand Down Expand Up @@ -73,14 +71,12 @@ linters:
- gosimple
- govet
- ineffassign
- interfacer
- maligned
- misspell
- nakedret
- noctx
- nolintlint
- rowserrcheck
- scopelint
- exportloopref
- staticcheck
- structcheck
- stylecheck
Expand Down
1 change: 1 addition & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ RUN apk add --no-cache git
RUN GO111MODULE=auto go get -u -v github.com/projectdiscovery/simplehttpserver/cmd/simplehttpserver

FROM alpine:latest
RUN apk add --no-cache bind-tools ca-certificates
COPY --from=builder /go/bin/simplehttpserver /usr/local/bin/

ENTRYPOINT ["simplehttpserver"]
119 changes: 109 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@
[![Docker Images](https://img.shields.io/docker/pulls/projectdiscovery/simplehttpserver.svg)](https://hub.docker.com/r/projectdiscovery/simplehttpserver)
[![Chat on Discord](https://img.shields.io/discord/695645237418131507.svg?logo=discord)](https://discord.gg/KECAGdH)

simplehttpserver is a go enhanced version of the well known python simplehttpserver.
simplehttpserver is a go enhanced version of the well known python simplehttpserver with in addition a fully customizable TCP server, both supporting TLS.

# Resources

- [Features](#features)
- [Usage](#usage)
- [Installation Instructions](#installation-instructions)
- [Running simplehttpserver](#running-simplehttpserver-in-the-current-folder )
- [Running simplehttpserver](#running-simplehttpserver-in-the-current-folder)
- [Thanks](#thanks)

# Features
Expand All @@ -28,9 +28,11 @@ simplehttpserver is a go enhanced version of the well known python simplehttpser
<br>
</h1>

- File server in arbitrary directory
- Full request/response dump
- Configurable ip address and listening port
- HTTPS support
- File server in arbitrary directory
- Full request/response dump
- Configurable ip address and listening port
- Configurable HTTP/TCP server with customizable response via YAML template


# Installation Instructions
Expand Down Expand Up @@ -70,11 +72,23 @@ simplehttpserver -h

This will display help for the tool. Here are all the switches it supports.

| Flag | Description | Example |
| ------ | ---------------------------------------------------- | --------------------------------------- |
| listen | Configure listening ip:port (default 127.0.0.1:8000) | simplehttpserver -listen 127.0.0.1:8000 |
| path | Fileserver folder (default current directory) | simplehttpserver -path /var/docs |
| v | Verbose (dump request/response, default false) | simplehttpserver -v |
| Flag | Description | Example |
| ----------- | -------------------------------------------------------------------- | ------------------------------------------------- |
| listen | Configure listening ip:port (default 127.0.0.1:8000) | simplehttpserver -listen 127.0.0.1:8000 |
| path | Fileserver folder (default current directory) | simplehttpserver -path /var/docs |
| verbose | Verbose (dump request/response, default false) | simplehttpserver -v |
| tcp | TCP server (default 127.0.0.1:8000) | simplehttpserver -tcp 127.0.0.1:8000 |
| tls | Enable TLS for TCP server | simplehttpserver -tls |
| rules | File containing yaml rules | simplehttpserver -rules rule.yaml | |
| upload | Enable file upload in case of http server | simplehttpserver -upload |
| https | Enable HTTPS in case of http server | simplehttpserver -https |
| cert | HTTPS/TLS certificate (self generated if not specified) | simplehttpserver -cert cert.pem |
| key | HTTPS/TLS certificate private key (self generated if not specified) | simplehttpserver -key cert.key |
| domain | Domain name to use for the self-generated certificate | simplehttpserver -domain projectdiscovery.io |
| basic-auth | Basic auth (username:password) | simplehttpserver -basic-auth user:password |
| realm | Basic auth message | simplehttpserver -realm "insert the credentials" |
| version | Show version | simplehttpserver -version |
| silent | Show only results | simplehttpserver -silent |

### Running simplehttpserver in the current folder

Expand All @@ -87,6 +101,91 @@ This will run the tool exposing the current directory on port 8000
2021/01/11 21:41:15 [::1]:50181 "GET /favicon.ico HTTP/1.1" 404 19
```

### Running simplehttpserver in the current folder with HTTPS

This will run the tool exposing the current directory on port 8000 over HTTPS with user provided certificate:

```sh
▶ simplehttpserver -https -cert cert.pen -key cert.key
2021/01/11 21:40:48 Serving . on http://0.0.0.0:8000/...
2021/01/11 21:41:15 [::1]:50181 "GET / HTTP/1.1" 200 383
2021/01/11 21:41:15 [::1]:50181 "GET /favicon.ico HTTP/1.1" 404 19
```

Instead, to run with self-signed certificate and specific domain name:
```sh
▶ simplehttpserver -https -domain localhost
2021/01/11 21:40:48 Serving . on http://0.0.0.0:8000/...
2021/01/11 21:41:15 [::1]:50181 "GET / HTTP/1.1" 200 383
2021/01/11 21:41:15 [::1]:50181 "GET /favicon.ico HTTP/1.1" 404 19
```

### Running simplehttpserver with basic auth and file upload

This will run the tool and will request the user to enter username and password before authorizing file uploads

```sh
▶ simplehttpserver -basic-auth root:root -upload
2021/01/11 21:40:48 Serving . on http://0.0.0.0:8000/...
```

To upload files use the following curl request with basic auth header:
```sh
▶ curl -v --user 'root:root' --upload-file file.txt http://localhost:8000/file.txt
```

### Running TCP server with custom responses

This will run the tool as TLS TCP server and enable custom responses based on YAML templates:

```sh
▶ simplehttpserver -rule rules.yaml -tcp -tls -domain localhost
```

The rules are written as follows:
```yaml
rules:
- match: regex
response: response data
```

For example to handle two different paths simulating an HTTP server or SMTP commands:
```yaml
rules:
# HTTP Requests
- match: GET /path1
response: |
HTTP/1.0 200 OK
Server: httpd/2.0
x-frame-options: SAMEORIGIN
x-xss-protection: 1; mode=block
Date: Fri, 16 Apr 2021 14:30:32 GMT
Content-Type: text/html
Connection: close

<HTML><HEAD><script>top.location.href='/Main_Login.asp';</script>
</HEAD></HTML>
- match: GET /path2
response: |
HTTP/1.0 404 OK
Server: httpd/2.0

<HTML><HEAD></HEAD><BODY>Not found</BODY></HTML>
# SMTP Commands
- match: "EHLO example.com"
response: |
250-localhost Nice to meet you, [127.0.0.1]
250-PIPELINING
250-8BITMIME
250-SMTPUTF8
250-AUTH LOGIN PLAIN
250 STARTTLS
- match: "MAIL FROM: <noreply@example.com>"
response: 250 Accepted
- match: "RCPT TO: <test@example.com>"
response: 250 Accepted
```

# Thanks

simplehttpserver is made with 🖤 by the [projectdiscovery](https://projectdiscovery.io) team. Community contributions have made the project what it is. See the **[Thanks.md](https://github.com/projectdiscovery/simplehttpserver/blob/master/THANKS.md)** file for more details.
8 changes: 5 additions & 3 deletions cmd/simplehttpserver/simplehttpserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@ import (
func main() {
// Parse the command line flags and read config files
options := runner.ParseOptions()
runner, err := runner.New(options)
r, err := runner.New(options)
if err != nil {
gologger.Fatal().Msgf("Could not create runner: %s\n", err)
}

runner.Run()
runner.Close()
if err := r.Run(); err != nil {
gologger.Info().Msgf("%s\n", err)
}
defer r.Close() //nolint
}
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
module github.com/projectdiscovery/simplehttpserver

go 1.15
go 1.14

require (
github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2
github.com/projectdiscovery/gologger v1.1.4
github.com/projectdiscovery/sslcert v0.0.0-20210416140253-8f56bec1bb5e
gopkg.in/yaml.v2 v2.4.0
)
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/projectdiscovery/gologger v1.1.4 h1:qWxGUq7ukHWT849uGPkagPKF3yBPYAsTtMKunQ8O2VI=
github.com/projectdiscovery/gologger v1.1.4/go.mod h1:Bhb6Bdx2PV1nMaFLoXNBmHIU85iROS9y1tBuv7T5pMY=
github.com/projectdiscovery/sslcert v0.0.0-20210416140253-8f56bec1bb5e h1:IZa08TUGbU7I0HUb9QQt/8wuu2fPZqfnMXwWhtMxei8=
github.com/projectdiscovery/sslcert v0.0.0-20210416140253-8f56bec1bb5e/go.mod h1:jSp8W5zIkNPxAqVdcoFlfv0K5cqogTe65fMinR0Fvuk=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
Expand Down
2 changes: 1 addition & 1 deletion internal/runner/banner.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const banner = `
`

// Version is the current version
const Version = `0.0.1`
const Version = `0.0.2`

// showBanner is used to show the banner to the user
func showBanner() {
Expand Down
11 changes: 11 additions & 0 deletions internal/runner/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@ package runner
import (
"flag"
"os"
"path/filepath"
"strings"

"github.com/projectdiscovery/gologger"
"github.com/projectdiscovery/gologger/levels"
)

// Options of the tool
type Options struct {
ListenAddress string
Folder string
Expand Down Expand Up @@ -91,3 +93,12 @@ func (options *Options) configureOutput() {
gologger.DefaultLogger.SetMaxLevel(levels.LevelSilent)
}
}

// FolderAbsPath of the fileserver folder
func (options *Options) FolderAbsPath() string {
abspath, err := filepath.Abs(options.Folder)
if err != nil {
return options.Folder
}
return abspath
}
17 changes: 12 additions & 5 deletions internal/runner/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ type Runner struct {
httpServer *httpserver.HTTPServer
}

// New instance of runner
func New(options *Options) (*Runner, error) {
r := Runner{options: options}
// Check if the process can listen on the specified ip:port
Expand All @@ -27,7 +28,7 @@ func New(options *Options) (*Runner, error) {
}

if r.options.EnableTCP {
serverTCP, err := tcpserver.New(tcpserver.Options{
serverTCP, err := tcpserver.New(&tcpserver.Options{
Listen: r.options.ListenAddress,
TLS: r.options.TCPWithTLS,
Domain: "local.host",
Expand Down Expand Up @@ -65,27 +66,33 @@ func New(options *Options) (*Runner, error) {
return &r, nil
}

// Run logic
func (r *Runner) Run() error {
if r.options.EnableTCP {
gologger.Print().Msgf("Serving TCP rule based server on tcp://%s", r.options.ListenAddress)
return r.serverTCP.ListenAndServe()
}

if r.options.HTTPS {
gologger.Print().Msgf("Serving %s on https://%s/...", r.options.Folder, r.options.ListenAddress)
gologger.Print().Msgf("Serving %s on https://%s/", r.options.FolderAbsPath(), r.options.ListenAddress)
return r.httpServer.ListenAndServeTLS()
}

gologger.Print().Msgf("Serving %s on http://%s/...", r.options.Folder, r.options.ListenAddress)
gologger.Print().Msgf("Serving %s on http://%s/", r.options.FolderAbsPath(), r.options.ListenAddress)
return r.httpServer.ListenAndServe()
}

// Close the listening services
func (r *Runner) Close() error {
if r.serverTCP != nil {
r.serverTCP.Close()
if err := r.serverTCP.Close(); err != nil {
return err
}
}
if r.httpServer != nil {
r.httpServer.Close()
if err := r.httpServer.Close(); err != nil {
return err
}
}
return nil
}
8 changes: 6 additions & 2 deletions pkg/binder/binder.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,22 @@ import (
"net"

"github.com/phayes/freeport"
"github.com/projectdiscovery/gologger"
)

// CanListenOn the specified address
func CanListenOn(address string) bool {
listener, err := net.Listen("tcp4", address)
if err != nil {
return false
}
defer listener.Close()
if err := listener.Close(); err != nil {
gologger.Info().Msgf("%s\n", err)
}
return true
}

// GetRandomListenAddress from the specified one
func GetRandomListenAddress(currentAddress string) (string, error) {
addrOrig, _, err := net.SplitHostPort(currentAddress)
if err != nil {
Expand All @@ -28,5 +33,4 @@ func GetRandomListenAddress(currentAddress string) (string, error) {
}

return net.JoinHostPort(addrOrig, fmt.Sprintf("%d", newPort)), nil

}
2 changes: 2 additions & 0 deletions pkg/binder/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// Package binder contains binding helpers
package binder
2 changes: 2 additions & 0 deletions pkg/httpserver/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// Package httpserver contains the http server logic
package httpserver
Loading