-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
implement basic sqli service #1
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
sqli-play |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
.PHONY: default | ||
default: help | ||
|
||
DOCKER_DBIMAGE=mysql:8.0.28 | ||
DOCKER_DBCNT=mysqlinjection | ||
DOCKER_DBNAME=sqli | ||
DOCKER_DBUSER=root | ||
DOCKER_DBPASS=123456 | ||
DOCKER_DBHOST=0.0.0.0 | ||
DOCKER_DBPORT=3306 | ||
DOCKER_DBADDR=$(DOCKER_DBHOST):$(DOCKER_DBPORT) | ||
|
||
ASROOT=sudo | ||
ifeq (, $(shell which $(ASROOT) 2>/dev/null)) | ||
ASROOT=doas | ||
endif | ||
|
||
|
||
.PHONY: db | ||
db: ## Start db | ||
-$(ASROOT) docker rm -vf $(DOCKER_DBCNT) | ||
$(ASROOT) docker run --rm --name $(DOCKER_DBCNT) \ | ||
--net host \ | ||
-e MYSQL_ROOT_PASSWORD=$(DOCKER_DBPASS) \ | ||
-e MYSQL_DATABASE=$(DOCKER_DBNAME) \ | ||
-d $(DOCKER_DBIMAGE) | ||
# check if database is ready | ||
@while !(make dbtest 2>/dev/null 1>/dev/null); do echo -n "."; sleep 1; done | ||
|
||
$(ASROOT) docker run -i --net host --rm $(DOCKER_DBIMAGE) mysql \ | ||
-h $(DOCKER_DBHOST) -u$(DOCKER_DBUSER) -p$(DOCKER_DBPASS) \ | ||
-D $(DOCKER_DBNAME) < populate.sql | ||
|
||
|
||
.PHONY:dbcli | ||
dbcli: ## connects and retrieves a database a shell. | ||
@docker run -it --net host --rm mysql mysql -h $(DOCKER_DBHOST) \ | ||
-u$(DOCKER_DBUSER) -p$(DOCKER_DBPASS) -D $(DOCKER_DBNAME) | ||
|
||
|
||
.PHONY: dbtest | ||
dbtest: ## test db connectivity | ||
@docker run -it --net host --rm mysql mysql -h $(DOCKER_DBHOST) \ | ||
-u$(DOCKER_DBUSER) -p$(DOCKER_DBPASS) -D $(DOCKER_DBNAME) \ | ||
-e "show status;" >/dev/null | ||
|
||
|
||
.PHONY: build | ||
build: ## build sqli | ||
go build -o ./sqli-play | ||
|
||
|
||
.PHONY: up | ||
up: db run ## build, setup db and start sqli service. | ||
|
||
|
||
.PHONY: run | ||
run: build ## run | ||
@DBNAME=$(DOCKER_DBNAME) \ | ||
DBUSER=$(DOCKER_DBUSER) \ | ||
DBPASS=$(DOCKER_DBPASS) \ | ||
DBADDR=$(DOCKER_DBADDR) \ | ||
./sqli-play | ||
|
||
|
||
.PHONY: help | ||
help: ## Show this help message. | ||
@echo "usage: make [target] ..." | ||
@echo | ||
@echo -e "targets:" | ||
@egrep '.*?:.*?## [^$$]*?$$' ${MAKEFILE_LIST} | \ | ||
sed -r 's/(.*?):\ .*?\#\# (.+?)/\1:\t\2/g' |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -1,2 +1,20 @@ | ||||||||||||||||||||||||||||||||||||||
# sqli-playground | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
A SQL Injection vulnerable service for teaching how to identify and explore the | ||||||||||||||||||||||||||||||||||||||
issue. | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
# help | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
``` | ||||||||||||||||||||||||||||||||||||||
$ make help | ||||||||||||||||||||||||||||||||||||||
usage: make [target] ... | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
targets: | ||||||||||||||||||||||||||||||||||||||
db: Start db | ||||||||||||||||||||||||||||||||||||||
dbcli: connects and retrieves a database a shell. | ||||||||||||||||||||||||||||||||||||||
dbtest: test db connectivity | ||||||||||||||||||||||||||||||||||||||
build: build sqli | ||||||||||||||||||||||||||||||||||||||
up: build, setup db and start sqli service. | ||||||||||||||||||||||||||||||||||||||
run: run | ||||||||||||||||||||||||||||||||||||||
help: Show this help message. | ||||||||||||||||||||||||||||||||||||||
``` | ||||||||||||||||||||||||||||||||||||||
Comment on lines
+6
to
+20
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Rationale: Copying the help here will only make the docs eventually outdated. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
module github.com/madlambda/sqli-playground | ||
|
||
go 1.17 | ||
|
||
require github.com/go-sql-driver/mysql v1.6.0 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= | ||
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
package main | ||
|
||
import ( | ||
"database/sql" | ||
"fmt" | ||
"log" | ||
"net/http" | ||
"os" | ||
|
||
_ "github.com/go-sql-driver/mysql" | ||
) | ||
|
||
var ( | ||
dbuser, dbpass, dbaddr, dbname string | ||
) | ||
|
||
func main() { | ||
fmt.Println("sqli example") | ||
|
||
dbuser = getenv("DBUSER") | ||
dbpass = getenv("DBPASS") | ||
dbaddr = getenv("DBADDR") | ||
dbname = getenv("DBNAME") | ||
|
||
checkdb() | ||
|
||
http.HandleFunc("/news", newsHandler) | ||
|
||
err := http.ListenAndServe(":8080", nil) | ||
abortif(err != nil, "failed to start http server: %v", err) | ||
} | ||
|
||
type newsDetail struct { | ||
title string | ||
body string | ||
} | ||
|
||
func newsHandler(w http.ResponseWriter, r *http.Request) { | ||
db, err := sql.Open("mysql", dbconn()) | ||
if err != nil { | ||
httpError(w, "failed to connect to database") | ||
return | ||
} | ||
|
||
defer db.Close() | ||
|
||
var news []newsDetail | ||
var query = "SELECT title,body from news" | ||
|
||
filters, ok := r.URL.Query()["filter"] | ||
if ok && len(filters) > 0 && len(filters[0]) > 1 { | ||
query += " WHERE title LIKE '%" + filters[0] + "%'" | ||
} | ||
|
||
rows, err := db.Query(query) | ||
if err != nil { | ||
httpError(w, "failed to execute query: %s (error: %v)", query, err) | ||
return | ||
} | ||
|
||
for rows.Next() { | ||
var entry newsDetail | ||
err = rows.Scan(&entry.title, &entry.body) | ||
if err == sql.ErrNoRows { | ||
break | ||
} | ||
|
||
if err != nil { | ||
// We return the error message in the HTTP response to easily | ||
// exploit it. Later we can have an option to hide them, so we can | ||
// also teach how to blindly recognize the errors. | ||
httpError(w, "failed to scan resultset: %s (error: %v)", query, err) | ||
return | ||
} | ||
|
||
news = append(news, entry) | ||
} | ||
|
||
renderNews(w, news) | ||
} | ||
|
||
func renderNews(w http.ResponseWriter, news []newsDetail) { | ||
w.WriteHeader(http.StatusOK) | ||
w.Header().Add("Content-Type", "text/plain; charset=utf-8") | ||
|
||
writeBanner(w) | ||
for _, entry := range news { | ||
writeNews(w, entry.title, entry.body) | ||
} | ||
writeFooter(w) | ||
} | ||
|
||
func writeNews(w http.ResponseWriter, title, body string) { | ||
fmt.Fprintf(w, "-> %s\n", title) | ||
fmt.Fprintf(w, " %s\n\n", body) | ||
} | ||
|
||
func writeBanner(w http.ResponseWriter) { | ||
fmt.Fprintf(w, | ||
`+------------------------------------------------------------------------------+ | ||
| madlambda news network | | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🤣 🚀 |
||
+------------------------------------------------------------------------------+ | ||
`) | ||
} | ||
|
||
func writeFooter(w http.ResponseWriter) { | ||
fmt.Fprintf(w, | ||
`+-----------------------------------------------------------------------------+ | ||
| Copyright (c) madlambda | | ||
+------------------------------------------------------------------------------+`) | ||
} | ||
|
||
func httpError(w http.ResponseWriter, format string, args ...interface{}) { | ||
w.WriteHeader(http.StatusInternalServerError) | ||
fmt.Fprintf(w, format, args...) | ||
|
||
log.Printf("error: "+format, args...) | ||
} | ||
|
||
func getenv(name string) string { | ||
val := os.Getenv(name) | ||
abortif(val == "", "env %s does not exists or is empty", name) | ||
return val | ||
} | ||
|
||
func abortif(cond bool, format string, args ...interface{}) { | ||
if cond { | ||
abort(format, args...) | ||
} | ||
} | ||
|
||
func abort(format string, args ...interface{}) { | ||
fmt.Fprintf(os.Stderr, format+"\n", args...) | ||
os.Exit(1) | ||
} | ||
|
||
func dbconn() string { | ||
return sprintf("%s:%s@tcp(%s)/%s?charset=utf8", dbuser, dbpass, dbaddr, dbname) | ||
} | ||
|
||
func checkdb() { | ||
db, err := sql.Open("mysql", dbconn()) | ||
abortif(err != nil, "failed to open db connection: %v", err) | ||
|
||
db.Close() | ||
} | ||
|
||
var sprintf = fmt.Sprintf |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,26 @@ | ||||||
CREATE TABLE IF NOT EXISTS users ( | ||||||
id INT(6) NOT NULL AUTO_INCREMENT PRIMARY KEY, | ||||||
user VARCHAR(255) NOT NULL, | ||||||
pass VARCHAR(255) NOT NULL | ||||||
); | ||||||
|
||||||
CREATE TABLE IF NOT EXISTS news ( | ||||||
id INT(6) NOT NULL AUTO_INCREMENT PRIMARY KEY, | ||||||
title VARCHAR(255) NOT NULL, | ||||||
body VARCHAR(1024) NOT NULL | ||||||
); | ||||||
|
||||||
INSERT INTO users (user,pass) VALUES | ||||||
("admin", "very-secret-pass"), | ||||||
("i4k", "****************"), | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
😆 |
||||||
("katz", "i love alan kay"); | ||||||
|
||||||
INSERT INTO news (title,body) VALUES | ||||||
( | ||||||
"BITCOIN FALLS BELOW $38,000 AS EVERGROW SET TO BREAK NEW CRYPTO RECORDS", | ||||||
"Bitcoin price has fallen to below $38,000 for the second time in 2022. Cryptocurrency largest token has struggled since starting the year at $47,000 and despite a rally in early February Bitcoin price is back where it was a month ago. A combination of factors means that investors are increasingly avoiding risk, and in the current climate risk means Bitcoin." | ||||||
), | ||||||
( | ||||||
"Russia retreats from crypto ban as it pushes rules for industry", | ||||||
"Russias Ministry of Finance is planning to regulate cryptocurrencies in the country, despite earlier calls by the central bank for a ban on crypto." | ||||||
); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Missing a newline |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would be very curious if we can't make this work with podman 100% sudoless, this sudo stuff/sudo group shit on docker always annoyed me x_x. But unrelated to the PR, just sharing etc.