GO黑帽子学习笔记-3.2 FoFa客户端实现

admin 2022年10月18日08:07:23评论69 views字数 9256阅读30分51秒阅读模式

零基础学go

GO黑帽子学习笔记-3.2 FoFa客户端实现

其实书中写的是Shadon的客户端,但是由于国内还是Fofa用的比较习惯,再加上没有Shadon的API,所以这里还是用Fofa来做替代。

设计步骤

  1. 查看服务的API文档
  2. 设计代码的逻辑结构,以减少代码的复杂性和重复性
  3. 根据需要在Go中定义请求或响应类型
  4. 创建辅助函数和类型以简化初始化、身份认证和通信,从而较少冗长或重复的逻辑
  5. 构造与API消费者函数和类型交互的客户端

设计项目结构

在我们构建API客户端时,应该对其进行结构设计,使函数调用和逻辑独立,这样我们就可以将其实现作为其他项目中的库重用,这样将来就不必要重新发明轮子。

|---cmd
| |---fofa
| |---main.go
|---fofa
|---fofa_api.go

main.go文件定义的main包主要要是用其与客户端进行交互

fofa目录中的文件定义了fofa包,其中包含与fofa之间进行通信所需要的类型和函数,这个包可以成为我们的独立库,我们可以在其他项目中导入并使用这个包。

GO的Module管理

在完成书上的该项目时,其实代码一直没有出现什么大问题,主要问题还是集中在go的module管理上。我在本次项目中,经过各种尝试,使用的方式与书中有些不同的。我将我完成的fofa包扩展为一个go_hack包,并上传到自己的github上,通过go.mod管理方式引用自己在github上的包。后续也计划根据所学知识不断对其进行扩充。

而对于go的mod管理,也是踩了一些坑,最难受的就是,明明刚刚还能运行的文件,当第二天重新运行时,就会报错。最后终于是弄懂了go.mod的管理方式,并且发现自己之前在github上的上传方式也有一定的问题,最后得以解决。

首先go提供了2种包管理方式,一种是go.path,一种是go.mod。其通过参数GO111MODULE="on/auto/no"来控制,当使用on时,则为go.mod管理,no时则为go.path管理。

在go path管理中,go会去$gopath环境变量定义的路径下寻找对应的包。但是,已写的包和网络上的包都放在一切,不方便管理。

而go mod管理中,为了应对go path的缺点,从go1.11版本就推出了go modules包管理方式。开启了这种方式后,寻找出了标准库包时,就会到$GOPATH/pkg/mod目录下查找。

而我们如果需要使用go mod,我们首先需要对go进行一定的设置。

$ go env -w GO111MODULE=on
$ go env -w GOPROXY=https://goproxy.cn,direct

然后我们需要在我们的包的根目录下,使用命令创建go.mod

go mod init github.com/项目分类/项目名

此时,会生成一个go.mod文件。这样我们就创建好了一个mod。然后我们就可以编写我们的mod文件中的内容了,这里有一个注意点,虽然我们创建的包时github.com/项目分类/项目名的方式,但是我们在go代码中仍需要按照package 项目名的方式对这个项目进行编写。

package modname

创建github库并上传的操作就不多说了,此时我们已经创建好了一个gomod,并且将其上传到了github上。然后我们对其修改后,需要提交代码,生成tag。

git add .
git commit -am "add stringsx package content"
git push -u origin master
git tag v1.0.0
git push --tags

这里为什么要弄一个tag出来呢,因为我们可以使用go get -u xxx来获取包最新的tag或者使用go get package@version来获取对应的tag。

go get -u xxx (- u 获取包的最新tag)
go get package@version (version 即 tag)

这里就是第二个坑了,我们需要在对应的go的项目下,再次创建我们对应的mod,这个mod不是指我们上传到github上的库的项目,而是我们引用这个库的项目,在该项目的根目录下使用这些命令来进行获取。

FoFa API获取用户信息

首先,在2022年,fofa的api地址改为了https://api.fofa.info。所以我们首先编写一个常量来存储fofaapi的地址,后续关于api的调用,都需要通过该api地址进行,go创建常量的关键词为const。

首先我们尝试获取用户的身份信息。

GO黑帽子学习笔记-3.2 FoFa客户端实现

我们根据fofa的api信息可以知道,我们首先需要传入两个参数,一个为用户的email,一个为用户的key。所以现在我们需要定义一个结构体,用户可以直接通过定义这个结构体,来传入其相应的email和key。然后编写一个用来创建FoFa_Client的方法。用户通过这个方法,传入email和key,可以直接获取一个定义好的FoFa_Client结构体。

type FoFa_Client struct {
email string
apiKey string
}

func New_FoFa_Client(email string, apiKey string) *FoFa_Client {
return &FoFa_Client{email: email, apiKey: apiKey}
}

然后我们来看我们的查询语法,我们根据fofa的api可以知道,用户信息获取的接口为:

https://fofa.info/api/v1/info/my?email=your_email&key=your_key

并且返回值为下面响应的内容,包含了error、email、username等字段。于是我们定义一个结构体,用于接收fofaapi给我们响应的内容。在go中,我们可以在结构体中的变量后面加上`json:"xxx"`的方式来定义该变量对应的json参数为xxx,这样在我们将json内容转换为结构体或将结构体转换为json时便会十分方便。

type FoFa_APIInfo struct {
Error bool `json:"error"`
Email string `json:"email"`
UserName string `json:"username"`
Fcoin int `json:"fcoin"`
Isvip bool `json:"isvip"`
VipLevel int `json:"vip_level"`
IsVerfied bool `json:"is_verified"`
Avatar string `json:"avatar"`
Message string `json:"message"`
FofaCliVer string `json:"fofacli_ver"`
FofaServer bool `json:"fofa_server"`
}

然后我们继续完成我们的查询方法,因为我们的查询方法需要使用的FoFa_Clinent中的内容,所以我们需要将该方法定义为FoFa_Client的方法(类似于其他语言中的类)我们首先使用fmt.Sprintf()方法,来完成我们对于api接口url及其参数的定义,然后使用http.Get将其发送,会返回两个返回值,一个是接口给我们返回的内容,一个是错误信息。当错误信息为空(nil)时,我们可以认为访问成功,此时定义一个FoFa_APIInfo来接收我们服务器给我们返回的用户数据,并通过json.NewDecoder(a).Decode(b)的方式来将收到的json内容解析到我们的结构体,其中a为我们接收的json内容,b为结构体的地址,这样go会将我们的json解析,并依次给我们的结构体中的参数进行赋值。因为我们这里传入的是地址,所以我们后面只需要返回这个地址,即可将我们刚刚定义的FoFaAPIInfo返回。

func (s *FoFa_Client) APIInfo() (*FoFa_APIInfo, error) {
res, err := http.Get(fmt.Sprintf("%s/api/v1/info/my?email=%s&key=%s", BaseURL, s.email, s.apiKey))
if err != nil {
return nil, err
}
defer res.Body.Close()

var ret FoFa_APIInfo
if err := json.NewDecoder(res.Body).Decode(&ret); err != nil {
return nil, err
}
return &ret, nil
}

此时我们便可以调用这个api接口,来获取用户信息了。

package main

import (
"fmt"

"github.com/haochen1204/go_hack"
)

func main() {
s := go_hack.New_FoFa_Client("xxx", "xxx")
ret, _ := s.APIInfo()
fmt.Println("emali is ", ret.Email)
fmt.Println("username is ", ret.UserName)

如上,我们编写了一个test.go,首先利用New_FoFa_Client创建一个FoFa_Client,然后使用其方法APIInfo来获取信息,并且返回一个FoFa_APIInfo结构体,我们调用其中的Email和UserName,并打印出来。然后我们使用命令创建gomod,使用go get加载我们的github上的go_hack包。

go mod init test
go get github.com/haochen1204/go_hack
go run test.go
GO黑帽子学习笔记-3.2 FoFa客户端实现

成功获取到邮箱和用户名信息。

FoFa API获取主机信息

在上面我们成功获取了用户的个人身份信息,接下来我们需要获取我们查询的信息,首先还是先根据FoFa的API指南来看fofa对于信息查询API接口的定义。

GO黑帽子学习笔记-3.2 FoFa客户端实现

如图,以上内容是我们可以在fofa的查询接口api中传入的参数,fofa会根据我们传入的这些参数对我们的查询数据的返回内容进行修改。其中我们常用的参数为qbase64,这个也是必须参数,我们通过对查询语句的base64加密来查询对应的信息。剩下的一些内容则为一些辅助的参数信息,比我们的fields,可选参数,我们控制该参数可以让fofa返回我们想要的一些主机信息,比如国家、地区等等。还有一个size参数比较重要,我们往往需要根据自己的会员等级对其进行设置,来保证我们能获取到我们所需要的全部信息。

所以,我们首先还是需要创建一个结构体以及对其的New函数,来存储我们需要的查询信息。我们需要注意的是在New_FoFa_InfoSearch中,我们只传入了必须参数qbase64,也就是我们的查询语句,并且对其进行base64加密。至于其他参数,我们都设置为no、0或者false,这样设置的目的是在我们后续的查询时,如果为我们上述设定的值,则默认不启用这些参数,如果用户需要使用这些参数,则需要在New_FoFa_InfoSearch后自行对其进行修改。

type FoFa_InfoSearch struct {
Qbase64 string
Fields string
Page int
Size int
Full bool
}

func New_FoFa_InfoSearch(q string) *FoFa_InfoSearch {
q = base64.StdEncoding.EncodeToString([]byte(q))
p := FoFa_InfoSearch{Qbase64: q, Fields: "no", Page: 0, Size: 0, Full: false}
return &p
}

我们现在完成了FoFa的查询参数,然后看一下响应事例,根据该示例我们可以看到我们查询成功后返回的信息。其中主要的是error,如果error的内容为false,则证明我们查询成功,下面的results中会以二维列表(python说法?)的形式存在,所以我们在go中用于接收时也需要使用二维列表进行接收。

GO黑帽子学习笔记-3.2 FoFa客户端实现
type FoFa_Host struct {
Error bool `json:"error"`
Size int `json:"size"`
Page int `json:"page"`
Mode string `json:"mode"`
Query string `json:"query"`
Results [][]string `json:"results"`
}

然后我们这时便可以将我们刚刚来编写我们的搜索函数了。我们因为在进行信息查询时还需要FoFa的用户身份信息,所以这里还是将HostSearch方法写为FoFa_Client的方法。我们需要传入刚刚上面定义好的查询参数结构体,其会根据我们上面查询参数结构体中的内容编辑我们的API请求,并将返回的json信息进行处理,放到我们刚刚定义好的FoFa_Host结构体中,并将该结构体的地址返回。

具体来看代码,首先我们定义了默认的api请求url,并且在其中增加了用户的邮箱、apikey、加密后的查询语句等必须参数。然后根据我们传入的查询信息结构体中其他可选参数的值进行判断,如果不是我们刚刚设定的默认值,说明用户对其进行了设定,那么我们便需要在请求时加上他,所以我们使用fmt.Sprintf对其进行格式化后加在我们刚刚到url后面。然后我们使用get请求向服务器进行请求,将请求到的数据使用json进行格式化,并存入我们创建的FoFa_Host结构体中,返回该结构体的地址。

func (s *FoFa_Client) HostSearch(q *FoFa_InfoSearch) (*FoFa_Host, error) {
api_url := fmt.Sprintf("%s/api/v1/search/all?email=%s&key=%s&qbase64=%s", BaseURL, s.email, s.apiKey, q.Qbase64)
if q.Fields != "no" {
api_url = api_url + fmt.Sprintf("&fields=%s", q.Fields)
}
if q.Page != 0 {
api_url = api_url + fmt.Sprintf("&page=%d", q.Page)
}
if q.Size != 0 {
api_url = api_url + fmt.Sprintf("&size=%d", q.Page)
}
if q.Full != false {
api_url = api_url + "&full=ture"
}
res, err := http.Get(api_url)
if err != nil {
return nil, err
}
defer res.Body.Close()
var ret FoFa_Host
if err := json.NewDecoder(res.Body).Decode(&ret); err != nil {
return nil, err
}
return &ret, err
}

此时,我们便完成了对于fofa_api的编写,我们仍需要将其上传到我们的github上,并为其创建新的tag。

git add .
git commit -am "add stringsx package content"
git push -u origin master
git tag v1.0.0
git push --tags

然后我们创建一个新的项目,并对其进行inti

go mod init fofa
go get github.com/haochen1204/go_hack

首先我们复制之前的代码,用来获取用户信息,然后使用New_FoFa_InfoSearch来创建一个查询语句,并且修改查询内容,设置为查询ip/port/host/country四个信息,然后调用HostSearch方法进行查询,如果查询的结果正确,那么我们的Results会是一个二维数组,我们通过range来获取他其中的每一个值,也就是一维数组,然后分别打印即可。

package main

import (
"fmt"

"github.com/haochen1204/go_hack"
)

func main() {
s := go_hack.New_FoFa_Client("[email protected]", "1664027a75442dde2fbd7f8825397186")
ret, _ := s.APIInfo()
fmt.Printf("email is %s and UserName is %sn", ret.Email, ret.UserName)
search_msg := go_hack.New_FoFa_InfoSearch("www.haochen1204.com")
search_msg.Fields = "ip,port,host,country"
msg, err := s.HostSearch(search_msg)
if err != nil {
fmt.Println("Fofa error ! ", err)
} else {
fmt.Println(msg.Results)
for _, value := range msg.Results {
fmt.Println(value[0], value[1], value[2],value[3])
}
}
GO黑帽子学习笔记-3.2 FoFa客户端实现

完整代码

package go_hack

import (
"encoding/base64"
"encoding/json"
"fmt"
"net/http"
)

const BaseURL = "https://api.fofa.info"

type FoFa_Client struct {
email string
apiKey string
}

type FoFa_APIInfo struct {
Error bool `json:"error"`
Email string `json:"email"`
UserName string `json:"username"`
Fcoin int `json:"fcoin"`
Isvip bool `json:"isvip"`
VipLevel int `json:"vip_level"`
IsVerfied bool `json:"is_verified"`
Avatar string `json:"avatar"`
Message string `json:"message"`
FofaCliVer string `json:"fofacli_ver"`
FofaServer bool `json:"fofa_server"`
}

type FoFa_Host struct {
Error bool `json:"error"`
Size int `json:"size"`
Page int `json:"page"`
Mode string `json:"mode"`
Query string `json:"query"`
Results [][]string `json:"results"`
}

type FoFa_InfoSearch struct {
Qbase64 string
Fields string
Page int
Size int
Full bool
}

func New_FoFa_Client(email string, apiKey string) *FoFa_Client {
return &FoFa_Client{email: email, apiKey: apiKey}
}

func New_FoFa_InfoSearch(q string) *FoFa_InfoSearch {
q = base64.StdEncoding.EncodeToString([]byte(q))
p := FoFa_InfoSearch{Qbase64: q, Fields: "no", Page: 0, Size: 0, Full: false}
return &p
}

func (s *FoFa_Client) HostSearch(q *FoFa_InfoSearch) (*FoFa_Host, error) {
api_url := fmt.Sprintf("%s/api/v1/search/all?email=%s&key=%s&qbase64=%s", BaseURL, s.email, s.apiKey, q.Qbase64)
if q.Fields != "no" {
api_url = api_url + fmt.Sprintf("&fields=%s", q.Fields)
}
if q.Page != 0 {
api_url = api_url + fmt.Sprintf("&page=%d", q.Page)
}
if q.Size != 0 {
api_url = api_url + fmt.Sprintf("&size=%d", q.Page)
}
if q.Full != false {
api_url = api_url + "&full=ture"
}
res, err := http.Get(api_url)
if err != nil {
return nil, err
}
defer res.Body.Close()
var ret FoFa_Host
if err := json.NewDecoder(res.Body).Decode(&ret); err != nil {
return nil, err
}
return &ret, err
}

func (s *FoFa_Client) APIInfo() (*FoFa_APIInfo, error) {
res, err := http.Get(fmt.Sprintf("%s/api/v1/info/my?email=%s&key=%s", BaseURL, s.email, s.apiKey))
if err != nil {
return nil, err
}
defer res.Body.Close()

var ret FoFa_APIInfo
if err := json.NewDecoder(res.Body).Decode(&ret); err != nil {
return nil, err
}
return &ret, nil
}

星 球 免 费 福 利



 转发公众号本文到朋友圈

 截图到公众号后台第1、3、5名获取免费进入星球


星球的最近主题和星球内部工具一些展示
GO黑帽子学习笔记-3.2 FoFa客户端实现


GO黑帽子学习笔记-3.2 FoFa客户端实现


GO黑帽子学习笔记-3.2 FoFa客户端实现

GO黑帽子学习笔记-3.2 FoFa客户端实现

GO黑帽子学习笔记-3.2 FoFa客户端实现


GO黑帽子学习笔记-3.2 FoFa客户端实现



欢 迎 加 入 星 球 !

GO黑帽子学习笔记-3.2 FoFa客户端实现

关 注 有 礼



关注下方公众号回复“666”可以领取一套精品渗透测试工具集和百度云视频链接。

GO黑帽子学习笔记-3.2 FoFa客户端实现 还在等什么?赶紧点击下方名片关注学习吧!GO黑帽子学习笔记-3.2 FoFa客户端实现


GO黑帽子学习笔记-3.2 FoFa客户端实现



群聊 | 技术交流群-群除我佬


干货|史上最全一句话木马


干货 | CS绕过vultr特征检测修改算法


实战 | 用中国人写的红队服务器搞一次内网穿透练习


实战 | 渗透某培训平台经历


实战 | 一次曲折的钓鱼溯源反制


免责声明
由于传播、利用本公众号渗透安全团队所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,公众号渗透安全团队及作者不为承担任何责任,一旦造成后果请自行承担!如有侵权烦请告知,我们会立即删除并致歉。谢谢!
好文分享收藏赞一下最美点在看哦


原文始发于微信公众号(渗透安全团队):GO黑帽子学习笔记-3.2 FoFa客户端实现

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年10月18日08:07:23
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   GO黑帽子学习笔记-3.2 FoFa客户端实现http://cn-sec.com/archives/1355173.html

发表评论

匿名网友 填写信息