安全矩阵

 找回密码
 立即注册
搜索
查看: 5419|回复: 0

测试 APP 抓不到数据包该怎么办

[复制链接]

23

主题

58

帖子

279

积分

中级会员

Rank: 3Rank: 3

积分
279
发表于 2020-11-26 19:32:21 | 显示全部楼层 |阅读模式
原文链接:测试 APP 抓不到数据包该怎么办
来自公众号:信安之路
最近几次测试 APP 时,遇到过几次非 http/https 通信的情况,burp、fiddler 等 http 代理工具都无法正常抓到包,经过分析发现 app 是通过 socket 通信的,所以写出来记录下。
socket 与 websocket先来区别下 socket 与 websocket,因为我们在使用 burpsuite 和 fiddler 时,发现 burp 和 fiddler 都是可以抓 websocket 的,所以有必要先区别一下,从本质上来说二者关系并不大,甚至说没啥关系,盗用一张图来说明下二者关系,读者可自行百度、谷歌检索二者关系。

socket 抓包思路为了方便理解,我们自己可以实现一个简单的通过 socket 通信的 APP 和与之其对应的 Server,实现一个简单功能,客户端 APP 发送 socket 消息,模拟平时项目中 APP 调用 socket 相关接口通信,同时接收服务端下发的 socket 消息,客户端 APP 运行如下所示:

服务端通过 ServerSocket 构造器实现 socket 监听绑定即可,运行如下所示:

以上,就简单实现了一个通过 socket 通信的 c/s,通过这种方式发送的数据包,burp 和 fiddler 之类的代理工具是无法抓到的,因为他们本来就属于 http/https/websocket 代理工具,对 socket 是无能为力的,所以我们需要换些思路。
tcpdump+wireshark
这种方式抓包非常通用,不光针对 socket 方式,http/https 等等也是可以的,因为这些两种抓包工具都是直接对流经网卡的数据包进行捕获,不存在区别信息传递使用什么协议,可以通过 tcpdump 将数据包保存成 pcap 格式,然后用 wireshark 打开进行分析,来看下用 tcpdump 抓到的数据包:

客户端发送的数据包

服务端接收的数据包
tcpdump 显示数据包格式不是很友好,导入到 wireshark 或者可用 wireshark 直接抓包,分析起来就比较容易了,可以看到数据传输是通过 socket 传输的:

hook 方式抓包
上述方法虽然抓包很好,但是对于渗透测试来说,我们不仅仅要看到数据包内容,更重要的是还能修改数据包,所以这里还可以使用 hook 方式抓包,在实现 socket 通信的过程,客户端(基于 android6.0 系统)发送消息需要会调用java.io.OutputStream.write() 方法,也有可能是 java.io.PrintWriter.write() 方法,这里以java.io.OutputStream.write 方法为例,这个方法有三个重载,分别是 write(byte[] buffer)、write(int oneByte)、write(byte[] buffer, int offset, int count),通过去阅读 android 源码,可以发现,三者调用关系为 write(byte[] buffer)-> write(byte[] buffer, int offset, int count)-> write(int oneByte),这里直接把源码粘贴过来,方便大家看:

  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one or more
  3. * contributor license agreements. See the NOTICE file distributed with
  4. * this work for additional information regarding copyright ownership.
  5. * The ASF licenses this file to You under the Apache License, Version 2.0
  6. * (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. *
  9. *   http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */

  17. package java.io;

  18. import java.util.Arrays;

  19. /**
  20. * A writable sink for bytes.
  21. *
  22. * <p>Most clients will use output streams that write data to the file system
  23. * ({@link FileOutputStream}), the network ({@link java.net.Socket#getOutputStream()}/{@link
  24. * java.net.HttpURLConnection#getOutputStream()}), or to an in-memory byte array
  25. * ({@link ByteArrayOutputStream}).
  26. *
  27. * <p>Use {@link OutputStreamWriter} to adapt a byte stream like this one into a
  28. * character stream.
  29. *
  30. * <p>Most clients should wrap their output stream with {@link
  31. * BufferedOutputStream}. Callers that do only bulk writes may omit buffering.
  32. *
  33. * <h3>Subclassing OutputStream</h3>
  34. * Subclasses that decorate another output stream should consider subclassing
  35. * {@link FilterOutputStream}, which delegates all calls to the target output
  36. * stream.
  37. *
  38. * <p>All output stream subclasses should override both {@link
  39. * #write(int)} and {@link #write(byte[],int,int) write(byte[],int,int)}. The
  40. * three argument overload is necessary for bulk access to the data. This is
  41. * much more efficient than byte-by-byte access.
  42. *
  43. * @see InputStream
  44. */
  45. public abstract class OutputStream implements Closeable, Flushable {

  46.   /**
  47.    * Default constructor.
  48.    */
  49.   public OutputStream() {
  50.   }

  51.   /**
  52.    * Closes this stream. Implementations of this method should free any
  53.    * resources used by the stream. This implementation does nothing.
  54.    *
  55.    * @throws IOException
  56.    *       if an error occurs while closing this stream.
  57.    */
  58.   public void close() throws IOException {
  59.     /* empty */
  60.   }

  61.   /**
  62.    * Flushes this stream. Implementations of this method should ensure that
  63.    * any buffered data is written out. This implementation does nothing.
  64.    *
  65.    * @throws IOException
  66.    *       if an error occurs while flushing this stream.
  67.    */
  68.   public void flush() throws IOException {
  69.     /* empty */
  70.   }

  71.   /**
  72.    * Equivalent to {@code write(buffer, 0, buffer.length)}.
  73.    */
  74.   public void write(byte[] buffer) throws IOException {
  75.     write(buffer, 0, buffer.length);
  76.   }

  77.   /**
  78.    * Writes {@code count} bytes from the byte array {@code buffer} starting at
  79.    * position {@code offset} to this stream.
  80.    *
  81.    * @param buffer
  82.    *      the buffer to be written.
  83.    * @param offset
  84.    *      the start position in {@code buffer} from where to get bytes.
  85.    * @param count
  86.    *      the number of bytes from {@code buffer} to write to this
  87.    *      stream.
  88.    * @throws IOException
  89.    *       if an error occurs while writing to this stream.
  90.    * @throws IndexOutOfBoundsException
  91.    *       if {@code offset < 0} or {@code count < 0}, or if
  92.    *       {@code offset + count} is bigger than the length of
  93.    *       {@code buffer}.
  94.    */
  95.   public void write(byte[] buffer, int offset, int count) throws IOException {
  96.     Arrays.checkOffsetAndCount(buffer.length, offset, count);
  97.     for (int i = offset; i < offset + count; i++) {
  98.       write(buffer[i]);
  99.     }
  100.   }

  101.   /**
  102.    * Writes a single byte to this stream. Only the least significant byte of
  103.    * the integer {@code oneByte} is written to the stream.
  104.    *
  105.    * @param oneByte
  106.    *      the byte to be written.
  107.    * @throws IOException
  108.    *       if an error occurs while writing to this stream.
  109.    */
  110.   public abstract void write(int oneByte) throws IOException;

  111.   /**
  112.    * Returns true if this writer has encountered and suppressed an error. Used
  113.    * by PrintStreams as an alternative to checked exceptions.
  114.    */
  115.   boolean checkError() {
  116.     return false;
  117.   }
  118. }
复制代码


所以理论上我们去 hook write(byte[] buffer) 这个方法就可以了,这个 hook 代码代码非常简单,这里就不做展示了,可以看看 hook 结果:


到这里,能够 hook 到,就可以按照我们的需求来修改数据包了,当然,我们也需要找一个 APP 来实战下,在市场上的 APP 是否真的有效。

objection
前一篇文章讲 objection 的使用,这里正好可以用 objection watch 一下 java.io.OutputStream 输出流,发现这里面有 close、flush、write 三个方法

Watch 一下 write 方法,观察 app 在处理业务时,是否有该方法的调用

通过 objection 对 write 方法的跟踪,发现确实 socket 通信调用了 write 方法,而且通过堆栈信息,我们还发现了疑似发送数据包的方法,send、request,这里尝试 hook send 方法,发现果然是有用的,输出信息如下:

综上就是最近遇到的关于 socket 抓包的一点想法和实践,虽然平时测试很少遇到 socket 通信的,但是遇到了,就需要解决不是么?不知道大佬们还有没有更好的思路,如果有,还请告诉我。


回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|安全矩阵

GMT+8, 2024-3-29 08:50 , Processed in 0.016339 second(s), 18 queries .

Powered by Discuz! X4.0

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表