Serverless概述
无服务器(Serverless)不是表示没有服务器,而是表示当您在使用Serverless时,您无需关心底层的资源,也无需登录服务器和优化服务器,只需关注最核心的代码片段,即可跳过复杂的、繁琐的基本工作。
Serverless 拥有近乎无限的扩容能力,空闲时,不运行任何资源。代码运行无状态,可以轻易实现快速迭代、极速部署。
什么是云函数
函数即服务提供了一种直接在云上运行无状态的、短暂的、由事件触发的代码的能力。
函数即服务和传统应用架构不同,函数服务提供的是事件触发式的运行方式,云函数不是始终运行的状态,而是在事件发生时由事件触发运行,并且在一次运行的过程中处理这一次事件。因此在云函数的代码中,仅需考虑针对一个事件的处理流程,而针对大量事件的高并发处理,由平台实现云函数的多实例并发来支持。
云函数(Serverless Cloud Function,SCF)是为企业和开发者们提供的无服务器执行环境,帮助您在无需购买和管理服务器的情况下运行代码。您只需使用平台支持的语言编写核心代码并设置代码运行的条件。
云函数无法长驻,调用的时候创建,执行完之后立即就销毁,所以无法直接保存状态。
云函数功能特性:
以函数为扩展单位,虚拟化运行时环境(Runtime),是现有计算资源的最小单位,具有完全自动、一键部署、高度可扩展等
使用云函数时,您只需使用平台支持的语言(Python、Node.js、PHP、Golang、Java 及 Custom Runtime)编写代码。而云平台将完全管理底层计算资源,包括服务器 CPU、内存、网络和其他配置/资源维护、代码部署、弹性伸缩、负载均衡、安全升级、资源运行情况监控等。
Serverless 帮助用户脱离繁冗的开发配置工作,只需关注业务代码逻辑的编写,不用任何的基础设施建设、管理与运维开销。该服务模式降低了研发门槛,提升业务构建效率,获得了大量企业和开发者的支持。
云函数(Serverless Cloud Function,SCF)提供代码部署、镜像部署两种部署方式,支持事件函数和 Web 函数两种函数类型。
SCF 事件函数有三个基本概念:执行方法、函数入参和函数返回。
执行方法
执行方法:对应项目的主函数,是程序执行的起点。
在调用云函数时,首先会寻找执行方法作为入口,执行用户的代码。用户需以文件名.执行方法名的形式进行设置。
用户设置的执行方法为 index.handler,则 SCF 平台会首先寻找代码程序包中的 index 文件,并找到该文件中的 handler 方法开始执行。
函数入参
函数入参,是指函数在被触发调用时所传递给函数的内容。
通常情况下,函数入参包括 event 和 context 两部分,但根据开发语言和环境的不同,入参个数可能有所不同
· event入参
event 参数类型为 dict,event 中包含了触发函数执行的基本信息,可以是平台定义的格式,也可以自定义格式。函数被触发开始执行后,可以在代码内部对 event 进行处理。
有两种方法可以触发云函数 SCF 执行:
1. 通过调用 云 API 触发函数执行。
2. 通过绑定 触发器 触发函数执行。
· context入参
context 为 SCF 平台提供的入参,将 context 入参传递给执行方法,代码可通过解析 context 入参对象,获取到运行环境及当前请求的相关信息。
函数返回
SCF 平台会获取到云函数执行完成后的返回值,并根据下表中不同的触发方式进行处理。
同步触发
Ø 通过 API 网关、云 API 同步 invoke 触发函数的方式为同步触发。
Ø 使用同步方式触发的函数在执行期间,SCF 平台不会返回触发结果。
Ø 在函数执行完成后,SCF 平台会将函数返回值封装为 JSON 格式并返回给调用方。
Ø 异步触发
Ø 使用异步方式触发的云函数,SCF 平台接收触发事件后,会返回触发请求 ID 。
Ø 在函数执行完成后,函数的返回值会封装为 JSON 格式并存储在日志中。
Ø 用户可在函数执行完成后,通过返回的请求 ID 查询日志获取该异步触发函数的返回值。
触发器和触发源
任何可以产生事件,触发云函数执行的均可以被称为触发器或触发源。触发器在本身产生事件后,通过将事件传递给云函数来触发函数运行。
触发器在触发函数时,可以根据自身特点,使用同步或异步方式触发函数。同步方式触发函数时,触发器将等待函数执行完成并获取到函数执行结果;异步方式触发函数时,触发器将仅触发函数而忽略函数执行结果。
腾讯云云函数在和腾讯云的某些产品或服务对接时,也有自身实现的一些特殊方式,例如推(PUSH)模式和拉(PULL)模式。
推模式:触发器主动将事件推送至云函数平台并触发函数运行。
拉模式:云函数平台通过拉取模块,从触发器中拉取到事件并触发云函数运行。
触发事件
触发器在触发函数时会将事件传递给云函数。事件在传递时以一个特定的数据结构体现,数据结构格式在传递时均为 JSON 格式,并以函数 event 入参的方式传递给云函数。
触发事件的 JSON 数据内容,在不同的语言环境下将会转换为各自语言的数据结构或对象,无需在代码中自行进行从 JSON 结构到数据结构的转换。
例如,在 Python 环境中,JSON 数据内容会转变为一个复杂 dict 对象,即函数的入参 event 就是一个 Python 的复杂 dict 对象。而在 Golang 或 Java 中,入参是一个需要和 event 数据结构可以匹配的对象。
Serverless 扫描技术
云函数端口扫描
# -*- coding: utf8 -*-
from socket import *
def main_handler(event, context):
IP=event["queryString"]["ip"]
port=event["queryString"]["port"]
try:
conn=socket(AF_INET,SOCK_STREAM)
res=conn.connect_ex((str(IP),int(port)))
conn.send('Hello,World!'.encode("utf8"))
results=conn.recv(25)
if res==0:
conn.close()
return port
except Exception as err:
print(err)
finally:
print("")
conn.close()
return None
函数管理 -> 触发管理
扫描器
#!/usr/bin/env python
# encoding: utf-8
import grequests
def main():
serverless = ["https://service-xxx-xxx.sh.apigw.tencentcs.com/release/http_proxy"]
resp, num = [], 0
port_one = [22, 53, 80, 81, 82, 83, 111, 9096, 9291, 9080, 6379, 5900, 9090, 443]
port_two = [8088, 8080, 4566, 6666, 10001, 2443, 3306, 3389, 7001, 9099, 135, 23]
try:
ip = input("\033[31;32mPlease Input IP Address:\033[0m")
print("")
for server in serverless:
num += 1
port_list = port_one if num == 1 else port_two
for port in port_list:
serverless_one = f"{server}?ip={ip}&port={port}"
resp.append(grequests.get(
serverless_one,
timeout=5
)
)
res_list = grequests.map(resp)
for res in res_list:
if res.text != "null" and res.text.find("errorCode") == -1:
print('[+]{}/tcp OPEN'.format(res.text))
except Exception as err:
print(err)
pass
if __name__ == '__main__':
main()
云函数目录扫描
选择Python3.6,3.7有问题。
# -*- coding: utf8 -*-
import requests
def main_handler(event, context):
headers=event["headers"]
url=event["queryString"]["url"]
path = event["queryString"]["path"]
crake_url=str(url+path)
try:
r = requests.get(crake_url,timeout=5,headers=headers,verify=False)
status = r.status_code
except Exception:
status = None
pass
return status,crake_url
创建触发器为API
#!/usr/bin/env python
# encoding: utf-8
import random
import requests
def dict_read(dict_file, num):
dict_list = []
with open(dict_file, "r", encoding='utf-8') as ip_text:
lines = ip_text.readlines()[:7] if num == 1 else ip_text.readlines()[7:]
for line in lines:
dict_list.append(line.strip("\n"))
return dict_list
def main():
from get_ua_header import UA
number = 0
severless = ["https://service-o1u1x736-1301587401.gz.apigw.tencentcs.com/release/dir_scan"]
try:
url = input("\033[31;32mplease input url:\033[0m")
dict_file_path = input("\033[32;32mplease input crash dict path:\033[0m")
print("")
for server in severless:
number += 1
for path in dict_read(dict_file_path, number):
headers = {
"User-Agent": random.choice(UA),
}
serverless_one = f"{server}?path={path}&url={url}"
r = requests.get(serverless_one, headers=headers)
print(r.text)
except Exception as err:
print(err)
if __name__ == '__main__':
main()
云函数连接WebShell
# -*- coding: utf8 -*-
import requests
import json
def geturl(urlstr):
jurlstr = json.dumps(urlstr)
dict_url = json.loads(jurlstr)
return dict_url['u']
def main_handler(event, context):
url = geturl(event['queryString'])
postdata = event['body']
headers=event['headers']
resp=requests.post(url,data=postdata,headers=headers,verify=False)
response={
"isBase64Encoded": False,
"statusCode": 200,
"headers": {'Content-Type': 'text/html;charset='+resp.apparent_encoding},
"body": resp.text
}
return response
创建API触发器访问:
https://service-xxxx-xxxxx.gz.apigw.tencentcs.com/release/saulGoodman?u=http://111.111.111.111/shell.php