1. 数据库的基本操作
GO官方教程:https://golang.google.cn/doc/tutorial/database-access
MongoDB
安装镜像:
sudo docker pull mongo
运行一个mongo容器,端口映射直接使用mongo的默认端口:
docker run --name AMongo -p 27017:27017 mongo
运行客户端,与前一个容器连接:
docker run -it --link AMongo:mongo --rm mongo sh -c 'exec mongo "172.17.0.2:27017/store"'
执行命令:
>db.transactions.insert([
{
"ccnum": "4444333322221111",
"date": "2019-01-05",
"amount": 100.12,
"cvv": "1234",
"exp": "09/2020"
},
{
"ccnum": "4444123456789012",
"date": "2019-01-07",
"amount": 2400.18,
"cvv": "5544",
"exp": "02/2021"
},
{
"ccnum": "4465122334455667",
"date": "2019-01-29",
"amount": 1450.87,
"cvv": "9876",
"exp": "06/2020"
}
]);
> show dbs
admin 0.000GB
config 0.000GB
local 0.000GB
store 0.000GB
> use store
switched to db store
> db.transactions.find()
{ "_id" : ObjectId("621b2859e0ecbb07b4acdd37"), "ccnum" : "4444333322221111", "date" : "2019-01-05", "amount" : 100.12, "cvv" : "1234", "exp" : "09/2020" }
{ "_id" : ObjectId("621b2859e0ecbb07b4acdd38"), "ccnum" : "4444123456789012", "date" : "2019-01-07", "amount" : 2400.18, "cvv" : "5544", "exp" : "02/2021" }
{ "_id" : ObjectId("621b2859e0ecbb07b4acdd39"), "ccnum" : "4465122334455667", "date" : "2019-01-29", "amount" : 1450.87, "cvv" : "9876", "exp" : "06/2020" }
go语言查询需要先下载依赖库:
go get gopkg.in/mgo.v2
连接测试:
package main
import (
"fmt"
"log"
mgo "gopkg.in/mgo.v2"
)
type Transaction struct {
CCNum string `bson:"ccnum"`
Date string `bson:"date"`
Amount float32 `bson:"amount"`
Cvv string `bson:"cvv"`
Expiration string `bson:"exp"`
}
func main() {
// 1. connect to mongo db
session, err := mgo.Dial("127.0.0.1")
if err != nil {
log.Panicln(err)
}
defer session.Close()
// 2. query
results := make([]Transaction, 0)
if err := session.DB("store").C("transactions").Find(nil).All(&results); err != nil {
log.Panicln(err)
}
// 3. output
for _, txn := range results {
fmt.Println(txn.CCNum, txn.Date, txn.Amount, txn.Cvv, txn.Expiration)
}
}
2. 数据库矿工
接下来写一个工具,检查数据库的列名等信息,判断是否为密码、hash等敏感信息,然后窃取。
接口
因为数据库种类很多,所以先创建接口,定义基本的库、表、列结构,以及方法。
type DatabaseMiner interface {
GetSchema() (*Schema, error)
}
type Schema struct {
Databases []Database
}
type Database struct {
Name string
Tables []Table
}
type Table struct {
Name string
Columns []string
}
func getRegex() []*regexp.Regexp {
return []*regexp.Regexp{ // ignore case
regexp.MustCompile(`(?i)social`),
regexp.MustCompile(`(?i)ssn`),
regexp.MustCompile(`(?i)pass(word)?`),
regexp.MustCompile(`(?i)hash`),
regexp.MustCompile(`(?i)ccnum`),
regexp.MustCompile(`(?i)card`),
regexp.MustCompile(`(?i)security`),
regexp.MustCompile(`(?i)key`),
}
}
func Search(m DatabaseMiner) error {
schema, err := m.GetSchema()
if err != nil {
return err
}
re := getRegex()
for _, database := range schema.Databases {
for _, table := range database.Tables {
for _, field := range table.Columns {
for _, r := range re {
if r.MatchString(field) {
fmt.Println(database)
fmt.Printf("[+] HIT: %s\n", field)
}
}
}
}
}
return nil
}
最终的实现是3层遍历:
- 遍历数据库;
- 遍历表;
- 获取一条数据,遍历列名。
MongoDB miner
package main
import (
"flag"
"fmt"
"github.com/blackhat-go/bhg/ch-7/db/dbminer"
"gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson" // binary json
)
type MongoMiner struct {
Host string
session *mgo.Session
}
func (m *MongoMiner) connect() error {
s, err := mgo.Dial(m.Host)
if err != nil {
return err
}
m.session = s
return nil
}
func (m *MongoMiner) GetSchema() (*dbminer.Schema, error) {
var schema = new(dbminer.Schema)
// 1. get databases
dbnames, err := m.session.DatabaseNames()
if err != nil {
return nil, err
}
// 2. get collections of each database
for _, dbname := range dbnames {
var defaultDbs = [3]string{"admin", "config", "local"}
var bContinue = false
for _, defaultDb := range defaultDbs {
if dbname == defaultDb {
bContinue = true
break
}
}
if bContinue {
continue
}
db := dbminer.Database{Name: dbname, Tables: []dbminer.Table{}}
fmt.Printf("find db:%s\n", dbname)
collections, err := m.session.DB(dbname).CollectionNames()
if err != nil {
return nil, err
}
// 3. get docs of each collection
for _, collection := range collections {
table := dbminer.Table{Name: collection, Columns: []string{}}
fmt.Printf("find collection:%s\n", collection)
// query one doc
var docRaw bson.Raw
err := m.session.DB(dbname).C(collection).Find(nil).One(&docRaw)
if err != nil {
return nil, err
}
var doc bson.RawD
if err := docRaw.Unmarshal(&doc); err != nil {
if err != nil {
return nil, err
}
}
// 4. get column names of the doc
for _, col := range doc {
fmt.Printf("find column:%s\n", col.Name)
table.Columns = append(table.Columns, col.Name)
}
db.Tables = append(db.Tables, table)
}
schema.Databases = append(schema.Databases, db)
}
return schema, nil
}
func NewMiner(host string) (*MongoMiner, error) {
m := MongoMiner{Host: host}
err := m.connect()
if err != nil {
return nil, err
}
return &m, nil
}
func main() {
var (
pStrFlagHost = flag.String("host", "", "The host ip of MongoDB.")
// pStrFlagPort = flag.String("port", "", "The port of MongoDB.") 27017 default
)
flag.Parse()
fmt.Printf("host:%s\n", *pStrFlagHost)
mm, err := NewMiner(*pStrFlagHost)
if err != nil {
panic(err)
}
fmt.Printf("NewMiner ok\n")
if err := dbminer.Search(mm); err != nil {
panic(err)
}
}
运行:
sudo go run db/db/mongo/main.go -host 127.0.0.1
host:127.0.0.1
NewMiner ok
find db:store
find collection:transactions
find column:_id
find column:ccnum
find column:date
find column:amount
find column:cvv
find column:exp
[DB] = store
[TABLE] = transactions
[COL] = _id
[COL] = ccnum
[COL] = date
[COL] = amount
[COL] = cvv
[COL] = exp
[+] HIT: ccnum