Compare commits
8 commits
Author | SHA1 | Date | |
---|---|---|---|
e58be04ddf | |||
1be4255041 | |||
51224453b3 | |||
eff53a9078 | |||
1bcdc4cc1c | |||
5b631a20b1 | |||
b408f2196c | |||
b47ea6fe01 |
2 changed files with 129 additions and 46 deletions
86
README.md
86
README.md
|
@ -2,6 +2,9 @@
|
||||||
|
|
||||||
**CLI-only text pastebin service.**
|
**CLI-only text pastebin service.**
|
||||||
|
|
||||||
|
[Issue tracker](https://git.uphillsecurity.com/cf7/linedump/issues) | `Libera Chat #linedump`
|
||||||
|
|
||||||
|
|
||||||
- Status: Beta - expect minor changes
|
- Status: Beta - expect minor changes
|
||||||
- Instance: [linedump.com](https://linedump.com/)
|
- Instance: [linedump.com](https://linedump.com/)
|
||||||
- Inspired by:
|
- Inspired by:
|
||||||
|
@ -30,7 +33,80 @@
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
Check [linedump.com](https://linedump.com) for now - coming soon.
|
```text
|
||||||
|
█ Upload curl:
|
||||||
|
|
||||||
|
curl -X POST -d "Cheers" https://linedump.com/ # string
|
||||||
|
curl -X POST https://linedump.com --data-binary @- < file.txt # file
|
||||||
|
ip -br a | curl -X POST https://linedump.com --data-binary @- # command output
|
||||||
|
|
||||||
|
|
||||||
|
█ Upload wget:
|
||||||
|
|
||||||
|
echo "Cheers" | wget --post-data=@- -O- https://linedump.com/ # string
|
||||||
|
wget --post-file=file.txt -O- https://linedump.com/ # file
|
||||||
|
ip -br a | wget --post-data=@- -O- https://linedump.com/ # command output
|
||||||
|
|
||||||
|
|
||||||
|
█ Upload Powershell:
|
||||||
|
|
||||||
|
Invoke-RestMethod -Uri "https://linedump.com/" -Method Post -Body "Cheers" # string
|
||||||
|
Invoke-RestMethod -Uri "https://linedump.com/" -Method Post -InFile "file.txt" # file
|
||||||
|
ipconfig | Invoke-RestMethod -Uri "https://linedump.com/" -Method Post -Body { $_ } # command output
|
||||||
|
|
||||||
|
|
||||||
|
█ Download:
|
||||||
|
|
||||||
|
curl https://linedump.com/{path}
|
||||||
|
|
||||||
|
wget -O- https://linedump.com/{path}
|
||||||
|
|
||||||
|
Invoke-RestMethod -Uri "https://linedump.com/{path}"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
██ Encryption Examples with curl ██
|
||||||
|
|
||||||
|
|
||||||
|
█ Upload text:
|
||||||
|
|
||||||
|
echo 'Cheers' | openssl enc -aes-256-cbc -salt -pbkdf2 -base64 -pass pass:yourkey | curl -X POST -d @- https://linedump.com/
|
||||||
|
|
||||||
|
|
||||||
|
█ Upload file:
|
||||||
|
|
||||||
|
openssl enc -aes-256-cbc -pbkdf2 -salt -pass pass:yourkey -base64 < file.txt | curl -sS -X POST https://linedump.com --data-binary @-
|
||||||
|
|
||||||
|
|
||||||
|
█ Upload command output:
|
||||||
|
|
||||||
|
ip -br a | openssl enc -aes-256-cbc -pbkdf2 -salt -pass pass:yourkey -base64 | curl -sS -X POST https://linedump.com --data-binary @-
|
||||||
|
|
||||||
|
|
||||||
|
█ Download:
|
||||||
|
|
||||||
|
curl -s https://linedump.com/{path} | base64 -d | openssl enc -d -aes-256-cbc -pbkdf2 -pass pass:yourkey
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
██ Adv Examples ██
|
||||||
|
|
||||||
|
|
||||||
|
█ Multiple commands:
|
||||||
|
|
||||||
|
{ cmd() { printf "\n# %s\n" "$*"; "$@"; }; \
|
||||||
|
cmd hostname; \
|
||||||
|
cmd ip -br a; \
|
||||||
|
} 2>&1 | curl -X POST https://linedump.com --data-binary @-
|
||||||
|
|
||||||
|
|
||||||
|
█ Continous command:
|
||||||
|
|
||||||
|
(timeout --signal=INT --kill-after=5s 10s \
|
||||||
|
ping 127.1; \
|
||||||
|
echo "--- Terminated ---") | \
|
||||||
|
curl -X POST --data-binary @- https://linedump.com
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
@ -42,7 +118,7 @@ Use with reverse-proxy and HTTPS!
|
||||||
|
|
||||||
| Variable | Description | Default | Required |
|
| Variable | Description | Default | Required |
|
||||||
|----------|-------------|---------|----------|
|
|----------|-------------|---------|----------|
|
||||||
| `DOMAIN` | Domain name used in the application responses and examples | `linedump.com` | No |
|
| `BASEURL` | Base URL used in the application responses and examples | `http://127.0.0.1:8000` | No |
|
||||||
| `DESCRIPTION` | Application description displayed in the root endpoint | `CLI-only pastebin powered by linedump.com` | No |
|
| `DESCRIPTION` | Application description displayed in the root endpoint | `CLI-only pastebin powered by linedump.com` | No |
|
||||||
| `MAX_FILE_SIZE_MB` | Maximum file size limit in megabytes | `50` | No |
|
| `MAX_FILE_SIZE_MB` | Maximum file size limit in megabytes | `50` | No |
|
||||||
| `RATE_LIMIT` | Rate limit for uploads (format: "requests/timeframe") | `50/hour` | No |
|
| `RATE_LIMIT` | Rate limit for uploads (format: "requests/timeframe") | `50/hour` | No |
|
||||||
|
@ -56,6 +132,12 @@ For security concerns or reports, please contact via `hello a t uphillsecurity d
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
- [Github Mirror available](https://github.com/CaffeineFueled1/linedump)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
**Apache License**
|
**Apache License**
|
||||||
|
|
89
main.py
89
main.py
|
@ -10,11 +10,9 @@ import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import hashlib
|
import hashlib
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
from collections import defaultdict
|
|
||||||
import threading
|
|
||||||
|
|
||||||
|
|
||||||
DOMAIN = os.getenv('DOMAIN', 'linedump.com')
|
BASEURL = os.getenv('BASEURL', 'http://127.0.0.1:8000')
|
||||||
DESCRIPTION = os.getenv('DESCRIPTION', 'CLI-only pastebin powered by linedump.com')
|
DESCRIPTION = os.getenv('DESCRIPTION', 'CLI-only pastebin powered by linedump.com')
|
||||||
MAX_FILE_SIZE_MB = int(os.getenv('MAX_FILE_SIZE_MB', '50'))
|
MAX_FILE_SIZE_MB = int(os.getenv('MAX_FILE_SIZE_MB', '50'))
|
||||||
RATE_LIMIT = os.getenv('RATE_LIMIT', '50/hour')
|
RATE_LIMIT = os.getenv('RATE_LIMIT', '50/hour')
|
||||||
|
@ -30,10 +28,6 @@ UPLOAD_DIR = Path("uploads")
|
||||||
UPLOAD_DIR.mkdir(exist_ok=True)
|
UPLOAD_DIR.mkdir(exist_ok=True)
|
||||||
|
|
||||||
MAX_FILE_SIZE = MAX_FILE_SIZE_MB * 1024 * 1024 # Convert MB to bytes
|
MAX_FILE_SIZE = MAX_FILE_SIZE_MB * 1024 * 1024 # Convert MB to bytes
|
||||||
MAX_FILES_PER_IP = 100
|
|
||||||
|
|
||||||
file_counter = defaultdict(int)
|
|
||||||
lock = threading.Lock()
|
|
||||||
|
|
||||||
def generate_random_path(length: int = None) -> str:
|
def generate_random_path(length: int = None) -> str:
|
||||||
if length is None:
|
if length is None:
|
||||||
|
@ -48,11 +42,6 @@ def get_client_ip(request: Request) -> str:
|
||||||
return request.client.host
|
return request.client.host
|
||||||
|
|
||||||
|
|
||||||
def check_file_limit(request: Request) -> bool:
|
|
||||||
client_ip = get_client_ip(request)
|
|
||||||
with lock:
|
|
||||||
return file_counter[client_ip] < MAX_FILES_PER_IP
|
|
||||||
|
|
||||||
def validate_content(content: str) -> bool:
|
def validate_content(content: str) -> bool:
|
||||||
"""Basic validation for content size and encoding"""
|
"""Basic validation for content size and encoding"""
|
||||||
if len(content) > MAX_FILE_SIZE:
|
if len(content) > MAX_FILE_SIZE:
|
||||||
|
@ -73,9 +62,6 @@ def validate_content(content: str) -> bool:
|
||||||
@limiter.limit(RATE_LIMIT)
|
@limiter.limit(RATE_LIMIT)
|
||||||
async def upload_text(request: Request):
|
async def upload_text(request: Request):
|
||||||
|
|
||||||
if not check_file_limit(request):
|
|
||||||
raise HTTPException(status_code=429, detail="File limit exceeded")
|
|
||||||
|
|
||||||
body = await request.body()
|
body = await request.body()
|
||||||
content = body.decode('utf-8', errors='ignore')
|
content = body.decode('utf-8', errors='ignore')
|
||||||
|
|
||||||
|
@ -94,13 +80,8 @@ async def upload_text(request: Request):
|
||||||
try:
|
try:
|
||||||
with open(file_path, 'w', encoding='utf-8') as f:
|
with open(file_path, 'w', encoding='utf-8') as f:
|
||||||
f.write(content)
|
f.write(content)
|
||||||
|
|
||||||
client_ip = get_client_ip(request)
|
return f"{BASEURL}/{random_path}\n"
|
||||||
with lock:
|
|
||||||
file_counter[client_ip] += 1
|
|
||||||
|
|
||||||
base_url = f"https://{request.headers.get('host', request.url.netloc)}"
|
|
||||||
return f"{base_url}/{random_path}\n"
|
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise HTTPException(status_code=500, detail="Failed to save file")
|
raise HTTPException(status_code=500, detail="Failed to save file")
|
||||||
|
@ -124,7 +105,7 @@ async def get_file(file_path: str):
|
||||||
|
|
||||||
@app.get("/", response_class=PlainTextResponse)
|
@app.get("/", response_class=PlainTextResponse)
|
||||||
async def root():
|
async def root():
|
||||||
return f"""C|_| {DOMAIN}
|
return f"""LD {BASEURL}
|
||||||
|
|
||||||
████ General ████
|
████ General ████
|
||||||
|
|
||||||
|
@ -141,32 +122,32 @@ async def root():
|
||||||
|
|
||||||
█ Upload curl:
|
█ Upload curl:
|
||||||
|
|
||||||
curl -X POST -d "Cheers" https://{DOMAIN}/ # string
|
curl -X POST -d "Cheers" {BASEURL}/ # string
|
||||||
curl -X POST https://{DOMAIN} --data-binary @- < file.txt # file
|
curl -X POST {BASEURL} --data-binary @- < file.txt # file
|
||||||
ip -br a | curl -X POST https://{DOMAIN} --data-binary @- # command output
|
ip -br a | curl -X POST {BASEURL} --data-binary @- # command output
|
||||||
|
|
||||||
|
|
||||||
█ Upload wget:
|
█ Upload wget:
|
||||||
|
|
||||||
echo "Cheers" | wget --post-data=@- -O- https://{DOMAIN}/ # string
|
echo "Cheers" | wget --post-data=@- -O- {BASEURL}/ # string
|
||||||
wget --post-file=file.txt -O- https://{DOMAIN}/ # file
|
wget --post-file=file.txt -O- {BASEURL}/ # file
|
||||||
ip -br a | wget --post-data=@- -O- https://{DOMAIN}/ # command output
|
ip -br a | wget --post-data=@- -O- {BASEURL}/ # command output
|
||||||
|
|
||||||
|
|
||||||
█ Upload Powershell:
|
█ Upload Powershell:
|
||||||
|
|
||||||
Invoke-RestMethod -Uri "https://{DOMAIN}/" -Method Post -Body "Cheers" # string
|
Invoke-RestMethod -Uri "{BASEURL}/" -Method Post -Body "Cheers" # string
|
||||||
Invoke-RestMethod -Uri "https://{DOMAIN}/" -Method Post -InFile "file.txt" # file
|
Invoke-RestMethod -Uri "{BASEURL}/" -Method Post -InFile "file.txt" # file
|
||||||
ipconfig | Invoke-RestMethod -Uri "https://{DOMAIN}/" -Method Post -Body {{ $_ }} # command output
|
ipconfig | Invoke-RestMethod -Uri "{BASEURL}/" -Method Post -Body {{ $_ }} # command output
|
||||||
|
|
||||||
|
|
||||||
█ Download:
|
█ Download:
|
||||||
|
|
||||||
curl https://{DOMAIN}/{{path}}
|
curl {BASEURL}/{{path}}
|
||||||
|
|
||||||
wget -O- https://{DOMAIN}/{{path}}
|
wget -O- {BASEURL}/{{path}}
|
||||||
|
|
||||||
Invoke-RestMethod -Uri "https://{DOMAIN}/{{path}}"
|
Invoke-RestMethod -Uri "{BASEURL}/{{path}}"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -176,23 +157,26 @@ Invoke-RestMethod -Uri "https://{DOMAIN}/{{path}}"
|
||||||
█ Upload text:
|
█ Upload text:
|
||||||
|
|
||||||
echo 'Cheers' \
|
echo 'Cheers' \
|
||||||
| openssl enc -aes-256-cbc -pbkdf2 -base64 -pass pass:yourkey \
|
| openssl enc -aes-256-cbc -pbkdf2 -salt -base64 -pass pass:yourkey \
|
||||||
| curl -X POST -d @- https://{DOMAIN}/
|
| curl -X POST -d @- {BASEURL}/
|
||||||
|
|
||||||
|
|
||||||
█ Upload file:
|
█ Upload file:
|
||||||
|
|
||||||
openssl enc -aes-256-cbc -pbkdf2 -salt -pass pass:yourkey -base64 < YOURFILE.txt \
|
openssl enc -aes-256-cbc -pbkdf2 -salt -pass pass:yourkey -base64 < file.txt \
|
||||||
| curl -sS -X POST https://{DOMAIN} --data-binary @-
|
| curl -sS -X POST {BASEURL} --data-binary @-
|
||||||
|
|
||||||
|
|
||||||
█ Upload command output:
|
█ Upload command output:
|
||||||
|
|
||||||
ip -br a \
|
ip -br a \
|
||||||
| openssl enc -aes-256-cbc -pbkdf2 -salt -pass pass:yourkey -base64 \
|
| openssl enc -aes-256-cbc -pbkdf2 -salt -pass pass:yourkey -base64 \
|
||||||
| curl -sS -X POST https://{DOMAIN} --data-binary @-
|
| curl -sS -X POST {BASEURL} --data-binary @-
|
||||||
|
|
||||||
|
|
||||||
█ Download:
|
█ Download:
|
||||||
|
|
||||||
curl -s https://{DOMAIN}/PASTE_THE_ID \
|
curl -s {BASEURL}/{{path}} \
|
||||||
| base64 -d \
|
| base64 -d \
|
||||||
| openssl enc -d -aes-256-cbc -pbkdf2 -pass pass:yourkey
|
| openssl enc -d -aes-256-cbc -pbkdf2 -pass pass:yourkey
|
||||||
|
|
||||||
|
@ -201,18 +185,35 @@ curl -s https://{DOMAIN}/PASTE_THE_ID \
|
||||||
██ Adv Examples ██
|
██ Adv Examples ██
|
||||||
|
|
||||||
|
|
||||||
█ Multiple Commands
|
█ Multiple commands:
|
||||||
|
|
||||||
{{ cmd() {{ printf "\\n# %s\\n" "$*"; "$@"; }}; \\
|
{{ cmd() {{ printf "\\n# %s\\n" "$*"; "$@"; }}; \\
|
||||||
cmd hostname; \\
|
cmd hostname; \\
|
||||||
cmd ip -br a; \\
|
cmd ip -br a; \\
|
||||||
}} 2>&1 | curl -X POST https://{DOMAIN} --data-binary @-
|
}} 2>&1 | curl -X POST {BASEURL} --data-binary @-
|
||||||
|
|
||||||
|
|
||||||
|
█ Continous command:
|
||||||
|
|
||||||
|
(timeout --signal=INT --kill-after=5s 10s \\
|
||||||
|
ping 127.1; \\
|
||||||
|
echo "--- Terminated ---") | \\
|
||||||
|
curl -X POST --data-binary @- {BASEURL}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
████ Further Information ████
|
████ Further Information ████
|
||||||
|
|
||||||
|
|
||||||
More information will follow. Work in Progress.
|
Powered by linedump
|
||||||
|
|
||||||
|
Source:
|
||||||
|
https://git.uphillsecurity.com/cf7/linedump
|
||||||
|
|
||||||
|
License:
|
||||||
|
Apache-2.0
|
||||||
|
https://git.uphillsecurity.com/cf7/linedump/src/branch/main/LICENSE
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue